From 4cbe9439da172b54f109688d7ce2039727fb7ac3 Mon Sep 17 00:00:00 2001 From: Akhil Mittra Date: Mon, 9 Nov 2026 09:52:52 +0000 Subject: [PATCH] [Rust] Generate struct accessors without raw pointer operations Struct accessors generated by `flatc --rust` used ptr::copy_nonoverlapping, MaybeUninit::assume_init, ptr::copy with pointer arithmetic, slice::from_raw_parts and raw pointer casts. They were in bounds only because the generator computes offsets correctly; nothing at the Rust level enforced it. Generate them as bounds-checked slices of the struct's [u8; N] storage instead: scalars use {from,to}_ne_bytes on the type's EndianScalar::Scalar, array setters convert element by element, Push copies self.0, and nested struct getters use the bounds-checked follow_cast_ref. A wrong size is now a type error and a wrong offset a panic, never an out-of-bounds access. No runtime API change. This also fixes arrays of enums wider than one byte on big-endian hosts: they were copied in host byte order instead of little-endian, so the wire bytes were swapped and values read back through the Object API were wrong. Adds tests/rust_struct_accessors_test.fbs and struct_accessors_test.rs, which check exact wire bytes (so they catch endianness bugs on the MIPS CI job) and guard against raw pointer operations reappearing in generated struct code. --- .../my_game/sample/vec_3_generated.rs | 93 ++---- scripts/generate_code.py | 6 + src/idl_gen_rust.cpp | 115 ++++--- .../my_game/example/array_struct_generated.rs | 126 +++----- .../example/large_array_struct_generated.rs | 62 ++-- .../example/nested_struct_generated.rs | 69 ++--- .../other_name_space/unused_generated.rs | 33 +- tests/include_test1_generated.rs | 33 +- .../other_name_space/unused_generated.rs | 33 +- tests/include_test2_generated.rs | 33 +- .../my_game/example/ability_generated.rs | 63 ++-- .../example/struct_of_structs_generated.rs | 24 +- .../struct_of_structs_of_structs_generated.rs | 10 +- .../my_game/example/test_generated.rs | 63 ++-- .../my_game/example/vec_3_generated.rs | 160 +++------- .../other_name_space/unused_generated.rs | 33 +- .../my_game/example/ability_generated.rs | 63 ++-- .../example/struct_of_structs_generated.rs | 24 +- .../struct_of_structs_of_structs_generated.rs | 10 +- .../my_game/example/test_generated.rs | 63 ++-- .../my_game/example/vec_3_generated.rs | 160 +++------- .../other_name_space/unused_generated.rs | 33 +- .../struct_in_nested_ns_generated.rs | 63 ++-- .../object_generated.rs | 33 +- .../possibly_reserved_words_generated.rs | 123 ++------ tests/rust_struct_accessors_test.fbs | 31 ++ tests/rust_struct_accessors_test/mod.rs | 15 + .../accessors_generated.rs | 281 ++++++++++++++++++ .../holder_generated.rs | 229 ++++++++++++++ .../huge_enum_generated.rs | 103 +++++++ .../inner_generated.rs | 122 ++++++++ .../wide_enum_generated.rs | 107 +++++++ .../tests/struct_accessors_test.rs | 165 ++++++++++ 33 files changed, 1542 insertions(+), 1039 deletions(-) create mode 100644 tests/rust_struct_accessors_test.fbs create mode 100644 tests/rust_struct_accessors_test/mod.rs create mode 100644 tests/rust_struct_accessors_test/rust_struct_accessors_test/accessors_generated.rs create mode 100644 tests/rust_struct_accessors_test/rust_struct_accessors_test/holder_generated.rs create mode 100644 tests/rust_struct_accessors_test/rust_struct_accessors_test/huge_enum_generated.rs create mode 100644 tests/rust_struct_accessors_test/rust_struct_accessors_test/inner_generated.rs create mode 100644 tests/rust_struct_accessors_test/rust_struct_accessors_test/wide_enum_generated.rs create mode 100644 tests/rust_usage_test/tests/struct_accessors_test.rs diff --git a/samples/rust_generated/my_game/sample/vec_3_generated.rs b/samples/rust_generated/my_game/sample/vec_3_generated.rs index ec5b1ccd17..eebd8da604 100644 --- a/samples/rust_generated/my_game/sample/vec_3_generated.rs +++ b/samples/rust_generated/my_game/sample/vec_3_generated.rs @@ -49,8 +49,7 @@ impl<'b> ::flatbuffers::Push for Vec3 { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Vec3 as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -86,91 +85,49 @@ impl<'a> Vec3 { "MyGame.Sample.Vec3" } + #[allow(clippy::identity_op)] pub fn x(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_x(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn y(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[4..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[4..4 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_y(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[4..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[4..4 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn z(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[8..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[8..8 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_z(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[8..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[8..8 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> Vec3T { diff --git a/scripts/generate_code.py b/scripts/generate_code.py index b754ec58f6..91d124ebeb 100755 --- a/scripts/generate_code.py +++ b/scripts/generate_code.py @@ -411,6 +411,12 @@ def glob(path, pattern): schema="rust_namer_test.fbs", ) +flatc( + RUST_OPTS, + prefix="rust_struct_accessors_test", + schema="rust_struct_accessors_test.fbs", +) + flatc( BASE_OPTS + PYTHON_OPTS, schema="arrays_test.fbs", diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp index d62bbffa4d..5d44523953 100644 --- a/src/idl_gen_rust.cpp +++ b/src/idl_gen_rust.cpp @@ -2819,11 +2819,10 @@ class RustGenerator : public BaseGenerator { code_ += ""; code_ += " #[inline]"; code_ += " unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {"; - code_ += - " let src = unsafe { ::core::slice::from_raw_parts(self as " - "*const " - "{{STRUCT_TY}} as *const u8, ::size()) };"; - code_ += " dst.copy_from_slice(src);"; + // Structs are `#[repr(transparent)]` wrappers around their little-endian + // wire bytes, so they can be pushed without reinterpreting `self` through + // a raw pointer. + code_ += " dst.copy_from_slice(&self.0);"; code_ += " }"; code_ += ""; @@ -2900,18 +2899,26 @@ class RustGenerator : public BaseGenerator { } // Generate accessor methods for the struct. + // + // Struct accessors only ever touch `self.0`, a fixed-size `[u8; N]`, at + // offsets computed by the schema compiler. They are generated without raw + // pointer arithmetic: every byte range is an explicit, bounds-checked + // slice of `self.0` and scalar conversion goes through `{to,from}_ne_bytes` + // on the type's `EndianScalar::Scalar`. A wrong offset or size can then + // only cause a compile error or a panic, never an out-of-bounds access. ForAllStructFields(struct_def, [&](const FieldDef& field) { this->GenComment(field.doc_comment); + code_.SetValue("FIELD_SIZE", NumToString(InlineSize(field.value.type))); // Getter. if (IsStruct(field.value.type)) { code_ += "pub fn {{FIELD}}(&self) -> &{{FIELD_TYPE}} {"; code_ += " // Safety:"; - code_ += " // Created from a valid Table for this object"; - code_ += " // Which contains a valid struct in this slot"; + code_ += " // `{{FIELD_TYPE}}` is a `#[repr(transparent)]`"; + code_ += " // wrapper around `[u8; {{FIELD_SIZE}}]` (alignment 1)"; + code_ += " // and `follow_cast_ref` bounds-checks the bytes."; code_ += - " unsafe {" - " &*(self.0[{{FIELD_OFFSET}}..].as_ptr() as *const" - " {{FIELD_TYPE}}) }"; + " unsafe { ::flatbuffers::follow_cast_ref::<{{FIELD_TYPE}}>(" + "&self.0, {{FIELD_OFFSET}}) }"; } else if (IsArray(field.value.type)) { code_.SetValue("ARRAY_SIZE", NumToString(field.value.type.fixed_length)); @@ -2928,81 +2935,67 @@ class RustGenerator : public BaseGenerator { "{{FIELD_OFFSET}}) " "}"; } else { + code_ += "#[allow(clippy::identity_op)]"; // If FIELD_OFFSET=0. code_ += "pub fn {{FIELD}}(&self) -> {{FIELD_TYPE}} {"; + code_ += " let mut bytes = [0u8; {{FIELD_SIZE}}];"; code_ += - " let mut mem = ::core::mem::MaybeUninit::" - "<<{{FIELD_TYPE}} as " - "::flatbuffers::EndianScalar>::Scalar>::uninit();"; - code_ += " // Safety:"; - code_ += " // Created from a valid Table for this object"; - code_ += " // Which contains a valid value in this slot"; - code_ += " ::flatbuffers::EndianScalar::from_little_endian(unsafe {"; - code_ += " ::core::ptr::copy_nonoverlapping("; - code_ += " self.0[{{FIELD_OFFSET}}..].as_ptr(),"; - code_ += " mem.as_mut_ptr() as *mut u8,"; + " bytes.copy_from_slice(" + "&self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}} + {{FIELD_SIZE}}]);"; + code_ += " ::flatbuffers::EndianScalar::from_little_endian("; code_ += - " ::core::mem::size_of::<<{{FIELD_TYPE}} as " - "::flatbuffers::EndianScalar>::Scalar>(),"; - code_ += " );"; - code_ += " mem.assume_init()"; - code_ += " })"; + " <<{{FIELD_TYPE}} as ::flatbuffers::EndianScalar>::Scalar>" + "::from_ne_bytes(bytes),"; + code_ += " )"; } code_ += "}\n"; // Setter. if (IsStruct(field.value.type)) { - code_.SetValue("FIELD_SIZE", NumToString(InlineSize(field.value.type))); code_ += "#[allow(clippy::identity_op)]"; // If FIELD_OFFSET=0. code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {"; code_ += " self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}} + {{FIELD_SIZE}}]" ".copy_from_slice(&x.0)"; } else if (IsArray(field.value.type)) { - if (GetFullType(field.value.type) == ftArrayOfBuiltin) { - code_.SetValue("ARRAY_ITEM", - GetTypeGet(field.value.type.VectorType())); - code_.SetValue( - "ARRAY_ITEM_SIZE", - NumToString(InlineSize(field.value.type.VectorType()))); + code_.SetValue("ARRAY_ITEM_SIZE", + NumToString(InlineSize(field.value.type.VectorType()))); + code_ += "#[allow(clippy::identity_op)]"; // If FIELD_OFFSET=0. + if (GetFullType(field.value.type) == ftArrayOfStruct) { + // Struct elements already hold their little-endian wire bytes. + code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {"; + code_ += + " let dst = &mut self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}} + " + "{{FIELD_SIZE}}];"; + code_ += + " for (chunk, item) in " + "dst.chunks_exact_mut({{ARRAY_ITEM_SIZE}}).zip(x.iter()) {"; + code_ += " chunk.copy_from_slice(&item.0);"; + code_ += " }"; + } else { + // Scalars and enums are converted to little-endian element by + // element, so the wire format is correct on big-endian hosts too. code_ += "pub fn set_{{FIELD}}(&mut self, items: &{{FIELD_TYPE}}) " "{"; - code_ += " // Safety:"; - code_ += " // Created from a valid Table for this object"; - code_ += " // Which contains a valid array in this slot"; code_ += - " unsafe { ::flatbuffers::emplace_scalar_array(&mut self.0, " - "{{FIELD_OFFSET}}, items) };"; - } else { - code_.SetValue("FIELD_SIZE", - NumToString(InlineSize(field.value.type))); - code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {"; - code_ += " // Safety:"; - code_ += " // Created from a valid Table for this object"; - code_ += " // Which contains a valid array in this slot"; - code_ += " unsafe {"; - code_ += " ::core::ptr::copy("; - code_ += " x.as_ptr() as *const u8,"; - code_ += " self.0.as_mut_ptr().add({{FIELD_OFFSET}}),"; - code_ += " {{FIELD_SIZE}},"; - code_ += " );"; + " let dst = &mut self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}} + " + "{{FIELD_SIZE}}];"; + code_ += + " for (chunk, item) in " + "dst.chunks_exact_mut({{ARRAY_ITEM_SIZE}}).zip(items.iter()) {"; + code_ += + " let item_le = " + "::flatbuffers::EndianScalar::to_little_endian(*item);"; + code_ += " chunk.copy_from_slice(&item_le.to_ne_bytes());"; code_ += " }"; } } else { + code_ += "#[allow(clippy::identity_op)]"; // If FIELD_OFFSET=0. code_ += "pub fn set_{{FIELD}}(&mut self, x: {{FIELD_TYPE}}) {"; code_ += " let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);"; - code_ += " // Safety:"; - code_ += " // Created from a valid Table for this object"; - code_ += " // Which contains a valid value in this slot"; - code_ += " unsafe {"; - code_ += " ::core::ptr::copy_nonoverlapping("; - code_ += " &x_le as *const _ as *const u8,"; - code_ += " self.0[{{FIELD_OFFSET}}..].as_mut_ptr(),"; code_ += - " ::core::mem::size_of::<<{{FIELD_TYPE}} as " - "::flatbuffers::EndianScalar>::Scalar>(),"; - code_ += " );"; - code_ += " }"; + " self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}} + {{FIELD_SIZE}}]" + ".copy_from_slice(&x_le.to_ne_bytes());"; } code_ += "}\n"; diff --git a/tests/arrays_test/my_game/example/array_struct_generated.rs b/tests/arrays_test/my_game/example/array_struct_generated.rs index e7b2222ec3..47b3f5e3bd 100644 --- a/tests/arrays_test/my_game/example/array_struct_generated.rs +++ b/tests/arrays_test/my_game/example/array_struct_generated.rs @@ -52,8 +52,7 @@ impl<'b> ::flatbuffers::Push for ArrayStruct { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const ArrayStruct as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -95,33 +94,19 @@ impl<'a> ArrayStruct { "MyGame.Example.ArrayStruct" } + #[allow(clippy::identity_op)] pub fn a(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_a(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn b(&'a self) -> ::flatbuffers::Array<'a, i32, 15> { @@ -132,40 +117,28 @@ impl<'a> ArrayStruct { unsafe { ::flatbuffers::Array::follow(&self.0, 4) } } + #[allow(clippy::identity_op)] pub fn set_b(&mut self, items: &[i32; 15]) { - // Safety: - // Created from a valid Table for this object - // Which contains a valid array in this slot - unsafe { ::flatbuffers::emplace_scalar_array(&mut self.0, 4, items) }; + let dst = &mut self.0[4..4 + 60]; + for (chunk, item) in dst.chunks_exact_mut(4).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); + } } + #[allow(clippy::identity_op)] pub fn c(&self) -> i8 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[64..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 1]; + bytes.copy_from_slice(&self.0[64..64 + 1]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_c(&mut self, x: i8) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[64..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[64..64 + 1].copy_from_slice(&x_le.to_ne_bytes()); } pub fn d(&'a self) -> ::flatbuffers::Array<'a, NestedStruct, 2> { @@ -176,46 +149,27 @@ impl<'a> ArrayStruct { unsafe { ::flatbuffers::Array::follow(&self.0, 72) } } + #[allow(clippy::identity_op)] pub fn set_d(&mut self, x: &[NestedStruct; 2]) { - // Safety: - // Created from a valid Table for this object - // Which contains a valid array in this slot - unsafe { - ::core::ptr::copy( - x.as_ptr() as *const u8, - self.0.as_mut_ptr().add(72), - 64, - ); + let dst = &mut self.0[72..72 + 64]; + for (chunk, item) in dst.chunks_exact_mut(32).zip(x.iter()) { + chunk.copy_from_slice(&item.0); } } + #[allow(clippy::identity_op)] pub fn e(&self) -> i32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[136..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[136..136 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_e(&mut self, x: i32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[136..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[136..136 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn f(&'a self) -> ::flatbuffers::Array<'a, i64, 2> { @@ -226,11 +180,13 @@ impl<'a> ArrayStruct { unsafe { ::flatbuffers::Array::follow(&self.0, 144) } } + #[allow(clippy::identity_op)] pub fn set_f(&mut self, items: &[i64; 2]) { - // Safety: - // Created from a valid Table for this object - // Which contains a valid array in this slot - unsafe { ::flatbuffers::emplace_scalar_array(&mut self.0, 144, items) }; + let dst = &mut self.0[144..144 + 16]; + for (chunk, item) in dst.chunks_exact_mut(8).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); + } } pub fn unpack(&self) -> ArrayStructT { diff --git a/tests/arrays_test/my_game/example/large_array_struct_generated.rs b/tests/arrays_test/my_game/example/large_array_struct_generated.rs index cbcd021b8a..cbdc780433 100644 --- a/tests/arrays_test/my_game/example/large_array_struct_generated.rs +++ b/tests/arrays_test/my_game/example/large_array_struct_generated.rs @@ -51,8 +51,7 @@ impl<'b> ::flatbuffers::Push for LargeArrayStruct { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const LargeArrayStruct as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -100,11 +99,13 @@ impl<'a> LargeArrayStruct { unsafe { ::flatbuffers::Array::follow(&self.0, 0) } } + #[allow(clippy::identity_op)] pub fn set_d(&mut self, items: &[u8; 64]) { - // Safety: - // Created from a valid Table for this object - // Which contains a valid array in this slot - unsafe { ::flatbuffers::emplace_scalar_array(&mut self.0, 0, items) }; + let dst = &mut self.0[0..0 + 64]; + for (chunk, item) in dst.chunks_exact_mut(1).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); + } } pub fn e(&'a self) -> ::flatbuffers::Array<'a, f32, 64> { @@ -115,11 +116,13 @@ impl<'a> LargeArrayStruct { unsafe { ::flatbuffers::Array::follow(&self.0, 64) } } + #[allow(clippy::identity_op)] pub fn set_e(&mut self, items: &[f32; 64]) { - // Safety: - // Created from a valid Table for this object - // Which contains a valid array in this slot - unsafe { ::flatbuffers::emplace_scalar_array(&mut self.0, 64, items) }; + let dst = &mut self.0[64..64 + 256]; + for (chunk, item) in dst.chunks_exact_mut(4).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); + } } pub fn f(&'a self) -> ::flatbuffers::Array<'a, bool, 64> { @@ -130,11 +133,13 @@ impl<'a> LargeArrayStruct { unsafe { ::flatbuffers::Array::follow(&self.0, 320) } } + #[allow(clippy::identity_op)] pub fn set_f(&mut self, items: &[bool; 64]) { - // Safety: - // Created from a valid Table for this object - // Which contains a valid array in this slot - unsafe { ::flatbuffers::emplace_scalar_array(&mut self.0, 320, items) }; + let dst = &mut self.0[320..320 + 64]; + for (chunk, item) in dst.chunks_exact_mut(1).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); + } } pub fn g(&'a self) -> ::flatbuffers::Array<'a, NestedStruct, 64> { @@ -145,16 +150,11 @@ impl<'a> LargeArrayStruct { unsafe { ::flatbuffers::Array::follow(&self.0, 384) } } + #[allow(clippy::identity_op)] pub fn set_g(&mut self, x: &[NestedStruct; 64]) { - // Safety: - // Created from a valid Table for this object - // Which contains a valid array in this slot - unsafe { - ::core::ptr::copy( - x.as_ptr() as *const u8, - self.0.as_mut_ptr().add(384), - 2048, - ); + let dst = &mut self.0[384..384 + 2048]; + for (chunk, item) in dst.chunks_exact_mut(32).zip(x.iter()) { + chunk.copy_from_slice(&item.0); } } @@ -166,16 +166,12 @@ impl<'a> LargeArrayStruct { unsafe { ::flatbuffers::Array::follow(&self.0, 2432) } } - pub fn set_h(&mut self, x: &[TestEnum; 64]) { - // Safety: - // Created from a valid Table for this object - // Which contains a valid array in this slot - unsafe { - ::core::ptr::copy( - x.as_ptr() as *const u8, - self.0.as_mut_ptr().add(2432), - 64, - ); + #[allow(clippy::identity_op)] + pub fn set_h(&mut self, items: &[TestEnum; 64]) { + let dst = &mut self.0[2432..2432 + 64]; + for (chunk, item) in dst.chunks_exact_mut(1).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); } } diff --git a/tests/arrays_test/my_game/example/nested_struct_generated.rs b/tests/arrays_test/my_game/example/nested_struct_generated.rs index bf81a3cc35..a628905910 100644 --- a/tests/arrays_test/my_game/example/nested_struct_generated.rs +++ b/tests/arrays_test/my_game/example/nested_struct_generated.rs @@ -50,8 +50,7 @@ impl<'b> ::flatbuffers::Push for NestedStruct { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const NestedStruct as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -97,40 +96,28 @@ impl<'a> NestedStruct { unsafe { ::flatbuffers::Array::follow(&self.0, 0) } } + #[allow(clippy::identity_op)] pub fn set_a(&mut self, items: &[i32; 2]) { - // Safety: - // Created from a valid Table for this object - // Which contains a valid array in this slot - unsafe { ::flatbuffers::emplace_scalar_array(&mut self.0, 0, items) }; + let dst = &mut self.0[0..0 + 8]; + for (chunk, item) in dst.chunks_exact_mut(4).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); + } } + #[allow(clippy::identity_op)] pub fn b(&self) -> TestEnum { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[8..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 1]; + bytes.copy_from_slice(&self.0[8..8 + 1]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_b(&mut self, x: TestEnum) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[8..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[8..8 + 1].copy_from_slice(&x_le.to_ne_bytes()); } pub fn c(&'a self) -> ::flatbuffers::Array<'a, TestEnum, 2> { @@ -141,16 +128,12 @@ impl<'a> NestedStruct { unsafe { ::flatbuffers::Array::follow(&self.0, 9) } } - pub fn set_c(&mut self, x: &[TestEnum; 2]) { - // Safety: - // Created from a valid Table for this object - // Which contains a valid array in this slot - unsafe { - ::core::ptr::copy( - x.as_ptr() as *const u8, - self.0.as_mut_ptr().add(9), - 2, - ); + #[allow(clippy::identity_op)] + pub fn set_c(&mut self, items: &[TestEnum; 2]) { + let dst = &mut self.0[9..9 + 2]; + for (chunk, item) in dst.chunks_exact_mut(1).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); } } @@ -162,11 +145,13 @@ impl<'a> NestedStruct { unsafe { ::flatbuffers::Array::follow(&self.0, 16) } } + #[allow(clippy::identity_op)] pub fn set_d(&mut self, items: &[i64; 2]) { - // Safety: - // Created from a valid Table for this object - // Which contains a valid array in this slot - unsafe { ::flatbuffers::emplace_scalar_array(&mut self.0, 16, items) }; + let dst = &mut self.0[16..16 + 16]; + for (chunk, item) in dst.chunks_exact_mut(8).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); + } } pub fn unpack(&self) -> NestedStructT { diff --git a/tests/include_test1/my_game/other_name_space/unused_generated.rs b/tests/include_test1/my_game/other_name_space/unused_generated.rs index d19375f178..b507043d47 100644 --- a/tests/include_test1/my_game/other_name_space/unused_generated.rs +++ b/tests/include_test1/my_game/other_name_space/unused_generated.rs @@ -47,8 +47,7 @@ impl<'b> ::flatbuffers::Push for Unused { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Unused as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -80,33 +79,19 @@ impl<'a> Unused { "MyGame.OtherNameSpace.Unused" } + #[allow(clippy::identity_op)] pub fn a(&self) -> i32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_a(&mut self, x: i32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> UnusedT { diff --git a/tests/include_test1_generated.rs b/tests/include_test1_generated.rs index a0417f317b..66856ef83e 100644 --- a/tests/include_test1_generated.rs +++ b/tests/include_test1_generated.rs @@ -289,8 +289,7 @@ pub mod my_game { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Unused as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -322,33 +321,19 @@ pub mod my_game { "MyGame.OtherNameSpace.Unused" } + #[allow(clippy::identity_op)] pub fn a(&self) -> i32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_a(&mut self, x: i32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> UnusedT { diff --git a/tests/include_test2/my_game/other_name_space/unused_generated.rs b/tests/include_test2/my_game/other_name_space/unused_generated.rs index d19375f178..b507043d47 100644 --- a/tests/include_test2/my_game/other_name_space/unused_generated.rs +++ b/tests/include_test2/my_game/other_name_space/unused_generated.rs @@ -47,8 +47,7 @@ impl<'b> ::flatbuffers::Push for Unused { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Unused as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -80,33 +79,19 @@ impl<'a> Unused { "MyGame.OtherNameSpace.Unused" } + #[allow(clippy::identity_op)] pub fn a(&self) -> i32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_a(&mut self, x: i32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> UnusedT { diff --git a/tests/include_test2_generated.rs b/tests/include_test2_generated.rs index a0417f317b..66856ef83e 100644 --- a/tests/include_test2_generated.rs +++ b/tests/include_test2_generated.rs @@ -289,8 +289,7 @@ pub mod my_game { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Unused as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -322,33 +321,19 @@ pub mod my_game { "MyGame.OtherNameSpace.Unused" } + #[allow(clippy::identity_op)] pub fn a(&self) -> i32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_a(&mut self, x: i32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> UnusedT { diff --git a/tests/monster_test/my_game/example/ability_generated.rs b/tests/monster_test/my_game/example/ability_generated.rs index df8c8a6e6b..042a1c1b33 100644 --- a/tests/monster_test/my_game/example/ability_generated.rs +++ b/tests/monster_test/my_game/example/ability_generated.rs @@ -48,8 +48,7 @@ impl<'b> ::flatbuffers::Push for Ability { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Ability as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -83,33 +82,19 @@ impl<'a> Ability { "MyGame.Example.Ability" } + #[allow(clippy::identity_op)] pub fn id(&self) -> u32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_id(&mut self, x: u32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } @@ -123,33 +108,19 @@ impl<'a> Ability { let key = self.id(); key.cmp(&val) } + #[allow(clippy::identity_op)] pub fn distance(&self) -> u32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[4..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[4..4 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_distance(&mut self, x: u32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[4..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[4..4 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> AbilityT { diff --git a/tests/monster_test/my_game/example/struct_of_structs_generated.rs b/tests/monster_test/my_game/example/struct_of_structs_generated.rs index 8231985d18..dc5f2dce4a 100644 --- a/tests/monster_test/my_game/example/struct_of_structs_generated.rs +++ b/tests/monster_test/my_game/example/struct_of_structs_generated.rs @@ -49,8 +49,7 @@ impl<'b> ::flatbuffers::Push for StructOfStructs { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const StructOfStructs as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -88,9 +87,10 @@ impl<'a> StructOfStructs { pub fn a(&self) -> &Ability { // Safety: - // Created from a valid Table for this object - // Which contains a valid struct in this slot - unsafe { &*(self.0[0..].as_ptr() as *const Ability) } + // `Ability` is a `#[repr(transparent)]` + // wrapper around `[u8; 8]` (alignment 1) + // and `follow_cast_ref` bounds-checks the bytes. + unsafe { ::flatbuffers::follow_cast_ref::(&self.0, 0) } } #[allow(clippy::identity_op)] @@ -100,9 +100,10 @@ impl<'a> StructOfStructs { pub fn b(&self) -> &Test { // Safety: - // Created from a valid Table for this object - // Which contains a valid struct in this slot - unsafe { &*(self.0[8..].as_ptr() as *const Test) } + // `Test` is a `#[repr(transparent)]` + // wrapper around `[u8; 4]` (alignment 1) + // and `follow_cast_ref` bounds-checks the bytes. + unsafe { ::flatbuffers::follow_cast_ref::(&self.0, 8) } } #[allow(clippy::identity_op)] @@ -112,9 +113,10 @@ impl<'a> StructOfStructs { pub fn c(&self) -> &Ability { // Safety: - // Created from a valid Table for this object - // Which contains a valid struct in this slot - unsafe { &*(self.0[12..].as_ptr() as *const Ability) } + // `Ability` is a `#[repr(transparent)]` + // wrapper around `[u8; 8]` (alignment 1) + // and `follow_cast_ref` bounds-checks the bytes. + unsafe { ::flatbuffers::follow_cast_ref::(&self.0, 12) } } #[allow(clippy::identity_op)] diff --git a/tests/monster_test/my_game/example/struct_of_structs_of_structs_generated.rs b/tests/monster_test/my_game/example/struct_of_structs_of_structs_generated.rs index 3f972894b9..b779eca398 100644 --- a/tests/monster_test/my_game/example/struct_of_structs_of_structs_generated.rs +++ b/tests/monster_test/my_game/example/struct_of_structs_of_structs_generated.rs @@ -47,8 +47,7 @@ impl<'b> ::flatbuffers::Push for StructOfStructsOfStructs { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const StructOfStructsOfStructs as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -82,9 +81,10 @@ impl<'a> StructOfStructsOfStructs { pub fn a(&self) -> &StructOfStructs { // Safety: - // Created from a valid Table for this object - // Which contains a valid struct in this slot - unsafe { &*(self.0[0..].as_ptr() as *const StructOfStructs) } + // `StructOfStructs` is a `#[repr(transparent)]` + // wrapper around `[u8; 20]` (alignment 1) + // and `follow_cast_ref` bounds-checks the bytes. + unsafe { ::flatbuffers::follow_cast_ref::(&self.0, 0) } } #[allow(clippy::identity_op)] diff --git a/tests/monster_test/my_game/example/test_generated.rs b/tests/monster_test/my_game/example/test_generated.rs index ae5341a28e..05aea25c4d 100644 --- a/tests/monster_test/my_game/example/test_generated.rs +++ b/tests/monster_test/my_game/example/test_generated.rs @@ -48,8 +48,7 @@ impl<'b> ::flatbuffers::Push for Test { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Test as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -83,62 +82,34 @@ impl<'a> Test { "MyGame.Example.Test" } + #[allow(clippy::identity_op)] pub fn a(&self) -> i16 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 2]; + bytes.copy_from_slice(&self.0[0..0 + 2]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_a(&mut self, x: i16) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 2].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn b(&self) -> i8 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[2..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 1]; + bytes.copy_from_slice(&self.0[2..2 + 1]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_b(&mut self, x: i8) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[2..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[2..2 + 1].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> TestT { diff --git a/tests/monster_test/my_game/example/vec_3_generated.rs b/tests/monster_test/my_game/example/vec_3_generated.rs index 53e7677eaf..60476f7892 100644 --- a/tests/monster_test/my_game/example/vec_3_generated.rs +++ b/tests/monster_test/my_game/example/vec_3_generated.rs @@ -52,8 +52,7 @@ impl<'b> ::flatbuffers::Push for Vec3 { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Vec3 as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -95,156 +94,87 @@ impl<'a> Vec3 { "MyGame.Example.Vec3" } + #[allow(clippy::identity_op)] pub fn x(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_x(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn y(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[4..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[4..4 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_y(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[4..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[4..4 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn z(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[8..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[8..8 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_z(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[8..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[8..8 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn test1(&self) -> f64 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[16..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 8]; + bytes.copy_from_slice(&self.0[16..16 + 8]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_test1(&mut self, x: f64) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[16..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[16..16 + 8].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn test2(&self) -> Color { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[24..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 1]; + bytes.copy_from_slice(&self.0[24..24 + 1]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_test2(&mut self, x: Color) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[24..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[24..24 + 1].copy_from_slice(&x_le.to_ne_bytes()); } pub fn test3(&self) -> &Test { // Safety: - // Created from a valid Table for this object - // Which contains a valid struct in this slot - unsafe { &*(self.0[26..].as_ptr() as *const Test) } + // `Test` is a `#[repr(transparent)]` + // wrapper around `[u8; 4]` (alignment 1) + // and `follow_cast_ref` bounds-checks the bytes. + unsafe { ::flatbuffers::follow_cast_ref::(&self.0, 26) } } #[allow(clippy::identity_op)] diff --git a/tests/monster_test/my_game/other_name_space/unused_generated.rs b/tests/monster_test/my_game/other_name_space/unused_generated.rs index d19375f178..b507043d47 100644 --- a/tests/monster_test/my_game/other_name_space/unused_generated.rs +++ b/tests/monster_test/my_game/other_name_space/unused_generated.rs @@ -47,8 +47,7 @@ impl<'b> ::flatbuffers::Push for Unused { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Unused as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -80,33 +79,19 @@ impl<'a> Unused { "MyGame.OtherNameSpace.Unused" } + #[allow(clippy::identity_op)] pub fn a(&self) -> i32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_a(&mut self, x: i32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> UnusedT { diff --git a/tests/monster_test_serialize/my_game/example/ability_generated.rs b/tests/monster_test_serialize/my_game/example/ability_generated.rs index aba446c6d0..09c8faae0d 100644 --- a/tests/monster_test_serialize/my_game/example/ability_generated.rs +++ b/tests/monster_test_serialize/my_game/example/ability_generated.rs @@ -50,8 +50,7 @@ impl<'b> ::flatbuffers::Push for Ability { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Ability as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -97,33 +96,19 @@ impl<'a> Ability { "MyGame.Example.Ability" } + #[allow(clippy::identity_op)] pub fn id(&self) -> u32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_id(&mut self, x: u32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } @@ -137,33 +122,19 @@ impl<'a> Ability { let key = self.id(); key.cmp(&val) } + #[allow(clippy::identity_op)] pub fn distance(&self) -> u32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[4..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[4..4 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_distance(&mut self, x: u32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[4..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[4..4 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> AbilityT { diff --git a/tests/monster_test_serialize/my_game/example/struct_of_structs_generated.rs b/tests/monster_test_serialize/my_game/example/struct_of_structs_generated.rs index 17b8d7cf0e..e49212118c 100644 --- a/tests/monster_test_serialize/my_game/example/struct_of_structs_generated.rs +++ b/tests/monster_test_serialize/my_game/example/struct_of_structs_generated.rs @@ -51,8 +51,7 @@ impl<'b> ::flatbuffers::Push for StructOfStructs { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const StructOfStructs as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -103,9 +102,10 @@ impl<'a> StructOfStructs { pub fn a(&self) -> &Ability { // Safety: - // Created from a valid Table for this object - // Which contains a valid struct in this slot - unsafe { &*(self.0[0..].as_ptr() as *const Ability) } + // `Ability` is a `#[repr(transparent)]` + // wrapper around `[u8; 8]` (alignment 1) + // and `follow_cast_ref` bounds-checks the bytes. + unsafe { ::flatbuffers::follow_cast_ref::(&self.0, 0) } } #[allow(clippy::identity_op)] @@ -115,9 +115,10 @@ impl<'a> StructOfStructs { pub fn b(&self) -> &Test { // Safety: - // Created from a valid Table for this object - // Which contains a valid struct in this slot - unsafe { &*(self.0[8..].as_ptr() as *const Test) } + // `Test` is a `#[repr(transparent)]` + // wrapper around `[u8; 4]` (alignment 1) + // and `follow_cast_ref` bounds-checks the bytes. + unsafe { ::flatbuffers::follow_cast_ref::(&self.0, 8) } } #[allow(clippy::identity_op)] @@ -127,9 +128,10 @@ impl<'a> StructOfStructs { pub fn c(&self) -> &Ability { // Safety: - // Created from a valid Table for this object - // Which contains a valid struct in this slot - unsafe { &*(self.0[12..].as_ptr() as *const Ability) } + // `Ability` is a `#[repr(transparent)]` + // wrapper around `[u8; 8]` (alignment 1) + // and `follow_cast_ref` bounds-checks the bytes. + unsafe { ::flatbuffers::follow_cast_ref::(&self.0, 12) } } #[allow(clippy::identity_op)] diff --git a/tests/monster_test_serialize/my_game/example/struct_of_structs_of_structs_generated.rs b/tests/monster_test_serialize/my_game/example/struct_of_structs_of_structs_generated.rs index 743baba232..d2de8a6dff 100644 --- a/tests/monster_test_serialize/my_game/example/struct_of_structs_of_structs_generated.rs +++ b/tests/monster_test_serialize/my_game/example/struct_of_structs_of_structs_generated.rs @@ -49,8 +49,7 @@ impl<'b> ::flatbuffers::Push for StructOfStructsOfStructs { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const StructOfStructsOfStructs as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -95,9 +94,10 @@ impl<'a> StructOfStructsOfStructs { pub fn a(&self) -> &StructOfStructs { // Safety: - // Created from a valid Table for this object - // Which contains a valid struct in this slot - unsafe { &*(self.0[0..].as_ptr() as *const StructOfStructs) } + // `StructOfStructs` is a `#[repr(transparent)]` + // wrapper around `[u8; 20]` (alignment 1) + // and `follow_cast_ref` bounds-checks the bytes. + unsafe { ::flatbuffers::follow_cast_ref::(&self.0, 0) } } #[allow(clippy::identity_op)] diff --git a/tests/monster_test_serialize/my_game/example/test_generated.rs b/tests/monster_test_serialize/my_game/example/test_generated.rs index ed1bffa036..64c75ee884 100644 --- a/tests/monster_test_serialize/my_game/example/test_generated.rs +++ b/tests/monster_test_serialize/my_game/example/test_generated.rs @@ -50,8 +50,7 @@ impl<'b> ::flatbuffers::Push for Test { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Test as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -97,62 +96,34 @@ impl<'a> Test { "MyGame.Example.Test" } + #[allow(clippy::identity_op)] pub fn a(&self) -> i16 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 2]; + bytes.copy_from_slice(&self.0[0..0 + 2]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_a(&mut self, x: i16) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 2].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn b(&self) -> i8 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[2..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 1]; + bytes.copy_from_slice(&self.0[2..2 + 1]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_b(&mut self, x: i8) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[2..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[2..2 + 1].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> TestT { diff --git a/tests/monster_test_serialize/my_game/example/vec_3_generated.rs b/tests/monster_test_serialize/my_game/example/vec_3_generated.rs index 3d2d611992..4d8c2c1817 100644 --- a/tests/monster_test_serialize/my_game/example/vec_3_generated.rs +++ b/tests/monster_test_serialize/my_game/example/vec_3_generated.rs @@ -54,8 +54,7 @@ impl<'b> ::flatbuffers::Push for Vec3 { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Vec3 as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -113,156 +112,87 @@ impl<'a> Vec3 { "MyGame.Example.Vec3" } + #[allow(clippy::identity_op)] pub fn x(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_x(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn y(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[4..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[4..4 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_y(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[4..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[4..4 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn z(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[8..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[8..8 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_z(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[8..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[8..8 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn test1(&self) -> f64 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[16..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 8]; + bytes.copy_from_slice(&self.0[16..16 + 8]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_test1(&mut self, x: f64) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[16..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[16..16 + 8].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn test2(&self) -> Color { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[24..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 1]; + bytes.copy_from_slice(&self.0[24..24 + 1]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_test2(&mut self, x: Color) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[24..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[24..24 + 1].copy_from_slice(&x_le.to_ne_bytes()); } pub fn test3(&self) -> &Test { // Safety: - // Created from a valid Table for this object - // Which contains a valid struct in this slot - unsafe { &*(self.0[26..].as_ptr() as *const Test) } + // `Test` is a `#[repr(transparent)]` + // wrapper around `[u8; 4]` (alignment 1) + // and `follow_cast_ref` bounds-checks the bytes. + unsafe { ::flatbuffers::follow_cast_ref::(&self.0, 26) } } #[allow(clippy::identity_op)] diff --git a/tests/monster_test_serialize/my_game/other_name_space/unused_generated.rs b/tests/monster_test_serialize/my_game/other_name_space/unused_generated.rs index 99540dba58..698e8b2523 100644 --- a/tests/monster_test_serialize/my_game/other_name_space/unused_generated.rs +++ b/tests/monster_test_serialize/my_game/other_name_space/unused_generated.rs @@ -49,8 +49,7 @@ impl<'b> ::flatbuffers::Push for Unused { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Unused as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -93,33 +92,19 @@ impl<'a> Unused { "MyGame.OtherNameSpace.Unused" } + #[allow(clippy::identity_op)] pub fn a(&self) -> i32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_a(&mut self, x: i32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> UnusedT { diff --git a/tests/namespace_test/namespace_a/namespace_b/struct_in_nested_ns_generated.rs b/tests/namespace_test/namespace_a/namespace_b/struct_in_nested_ns_generated.rs index 79034a6c1a..61a4a8d8c5 100644 --- a/tests/namespace_test/namespace_a/namespace_b/struct_in_nested_ns_generated.rs +++ b/tests/namespace_test/namespace_a/namespace_b/struct_in_nested_ns_generated.rs @@ -48,8 +48,7 @@ impl<'b> ::flatbuffers::Push for StructInNestedNS { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const StructInNestedNS as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -83,62 +82,34 @@ impl<'a> StructInNestedNS { "NamespaceA.NamespaceB.StructInNestedNS" } + #[allow(clippy::identity_op)] pub fn a(&self) -> i32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_a(&mut self, x: i32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn b(&self) -> i32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[4..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[4..4 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_b(&mut self, x: i32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[4..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[4..4 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> StructInNestedNST { diff --git a/tests/private_annotation_test/object_generated.rs b/tests/private_annotation_test/object_generated.rs index 05c18ac07d..2953563f24 100644 --- a/tests/private_annotation_test/object_generated.rs +++ b/tests/private_annotation_test/object_generated.rs @@ -47,8 +47,7 @@ impl<'b> ::flatbuffers::Push for Object { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const Object as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -80,33 +79,19 @@ impl<'a> Object { "Object" } + #[allow(clippy::identity_op)] pub fn value(&self) -> i32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_value(&mut self, x: i32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> ObjectT { diff --git a/tests/rust_namer_test/rust_namer_test/possibly_reserved_words_generated.rs b/tests/rust_namer_test/rust_namer_test/possibly_reserved_words_generated.rs index 4d42002344..978e4ee9a5 100644 --- a/tests/rust_namer_test/rust_namer_test/possibly_reserved_words_generated.rs +++ b/tests/rust_namer_test/rust_namer_test/possibly_reserved_words_generated.rs @@ -50,8 +50,7 @@ impl<'b> ::flatbuffers::Push for PossiblyReservedWords { #[inline] unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { - let src = unsafe { ::core::slice::from_raw_parts(self as *const PossiblyReservedWords as *const u8, ::size()) }; - dst.copy_from_slice(src); + dst.copy_from_slice(&self.0); } #[inline] @@ -89,120 +88,64 @@ impl<'a> PossiblyReservedWords { "RustNamerTest.PossiblyReservedWords" } + #[allow(clippy::identity_op)] pub fn follow_(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[0..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[0..0 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_follow_(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[0..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[0..0 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn push_(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[4..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[4..4 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_push_(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[4..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[4..4 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn size(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[8..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[8..8 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_size(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[8..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[8..8 + 4].copy_from_slice(&x_le.to_ne_bytes()); } + #[allow(clippy::identity_op)] pub fn alignment(&self) -> f32 { - let mut mem = ::core::mem::MaybeUninit::<::Scalar>::uninit(); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - ::flatbuffers::EndianScalar::from_little_endian(unsafe { - ::core::ptr::copy_nonoverlapping( - self.0[12..].as_ptr(), - mem.as_mut_ptr() as *mut u8, - ::core::mem::size_of::<::Scalar>(), - ); - mem.assume_init() - }) + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[12..12 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) } + #[allow(clippy::identity_op)] pub fn set_alignment(&mut self, x: f32) { let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); - // Safety: - // Created from a valid Table for this object - // Which contains a valid value in this slot - unsafe { - ::core::ptr::copy_nonoverlapping( - &x_le as *const _ as *const u8, - self.0[12..].as_mut_ptr(), - ::core::mem::size_of::<::Scalar>(), - ); - } + self.0[12..12 + 4].copy_from_slice(&x_le.to_ne_bytes()); } pub fn unpack(&self) -> PossiblyReservedWordsT { diff --git a/tests/rust_struct_accessors_test.fbs b/tests/rust_struct_accessors_test.fbs new file mode 100644 index 0000000000..ca3711f878 --- /dev/null +++ b/tests/rust_struct_accessors_test.fbs @@ -0,0 +1,31 @@ +// Exercises the accessors generated for Rust structs: scalars, enums wider +// than one byte, fixed-size arrays of scalars/enums/structs, and nested +// structs. The tests check the exact little-endian wire bytes, so they also +// catch endianness bugs when run on big-endian targets. + +namespace RustStructAccessorsTest; + +enum WideEnum : short { Zero = 0, A = 1, B = 258, C = -2 } + +enum HugeEnum : ulong { Zero = 0, X = 1, Y = 72623859790382856 } + +struct Inner { + v:ushort; +} + +struct Accessors { + e:[WideEnum:3]; + h:[HugeEnum:2]; + inners:[Inner:2]; + f:float; + flags:[bool:2]; + one:WideEnum; + nested:Inner; + d:double; +} + +table Holder { + a:Accessors; +} + +root_type Holder; diff --git a/tests/rust_struct_accessors_test/mod.rs b/tests/rust_struct_accessors_test/mod.rs new file mode 100644 index 0000000000..1d6ed6b513 --- /dev/null +++ b/tests/rust_struct_accessors_test/mod.rs @@ -0,0 +1,15 @@ +// Automatically generated by the Flatbuffers compiler. Do not modify. +// @generated +pub mod rust_struct_accessors_test { + use super::*; + mod wide_enum_generated; + pub use self::wide_enum_generated::*; + mod huge_enum_generated; + pub use self::huge_enum_generated::*; + mod inner_generated; + pub use self::inner_generated::*; + mod accessors_generated; + pub use self::accessors_generated::*; + mod holder_generated; + pub use self::holder_generated::*; +} // rust_struct_accessors_test diff --git a/tests/rust_struct_accessors_test/rust_struct_accessors_test/accessors_generated.rs b/tests/rust_struct_accessors_test/rust_struct_accessors_test/accessors_generated.rs new file mode 100644 index 0000000000..f046154bfb --- /dev/null +++ b/tests/rust_struct_accessors_test/rust_struct_accessors_test/accessors_generated.rs @@ -0,0 +1,281 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// @generated +extern crate alloc; +use super::*; + +// struct Accessors, aligned to 8 +#[repr(transparent)] +#[derive(Clone, Copy, PartialEq)] +pub struct Accessors(pub [u8; 48]); + +impl Default for Accessors { + fn default() -> Self { + Self([0; 48]) + } +} + +impl ::core::fmt::Debug for Accessors { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + f.debug_struct("Accessors") + .field("e", &self.e()) + .field("h", &self.h()) + .field("inners", &self.inners()) + .field("f", &self.f()) + .field("flags", &self.flags()) + .field("one", &self.one()) + .field("nested", &self.nested()) + .field("d", &self.d()) + .finish() + } +} + +impl ::flatbuffers::SimpleToVerifyInSlice for Accessors {} + +impl<'a> ::flatbuffers::Follow<'a> for Accessors { + type Inner = &'a Accessors; + + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + unsafe { <&'a Accessors>::follow(buf, loc) } + } +} + +impl<'a> ::flatbuffers::Follow<'a> for &'a Accessors { + type Inner = &'a Accessors; + + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) } + } +} + +impl<'b> ::flatbuffers::Push for Accessors { + type Output = Accessors; + + #[inline] + unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { + dst.copy_from_slice(&self.0); + } + + #[inline] + fn alignment() -> ::flatbuffers::PushAlignment { + ::flatbuffers::PushAlignment::new(8) + } +} + +impl<'a> ::flatbuffers::Verifiable for Accessors { + #[inline] + fn run_verifier( + v: &mut ::flatbuffers::Verifier, pos: usize + ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> { + v.in_buffer::(pos) + } +} + +impl<'a> Accessors { + #[allow(clippy::too_many_arguments)] + pub fn new( + e: &[WideEnum; 3], + h: &[HugeEnum; 2], + inners: &[Inner; 2], + f: f32, + flags: &[bool; 2], + one: WideEnum, + nested: &Inner, + d: f64, + ) -> Self { + let mut s = Self([0; 48]); + s.set_e(e); + s.set_h(h); + s.set_inners(inners); + s.set_f(f); + s.set_flags(flags); + s.set_one(one); + s.set_nested(nested); + s.set_d(d); + s + } + + pub const fn get_fully_qualified_name() -> &'static str { + "RustStructAccessorsTest.Accessors" + } + + pub fn e(&'a self) -> ::flatbuffers::Array<'a, WideEnum, 3> { + // Safety: + // Created from a valid Table for this object + // Which contains a valid array in this slot + use ::flatbuffers::Follow; + unsafe { ::flatbuffers::Array::follow(&self.0, 0) } + } + + #[allow(clippy::identity_op)] + pub fn set_e(&mut self, items: &[WideEnum; 3]) { + let dst = &mut self.0[0..0 + 6]; + for (chunk, item) in dst.chunks_exact_mut(2).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); + } + } + + pub fn h(&'a self) -> ::flatbuffers::Array<'a, HugeEnum, 2> { + // Safety: + // Created from a valid Table for this object + // Which contains a valid array in this slot + use ::flatbuffers::Follow; + unsafe { ::flatbuffers::Array::follow(&self.0, 8) } + } + + #[allow(clippy::identity_op)] + pub fn set_h(&mut self, items: &[HugeEnum; 2]) { + let dst = &mut self.0[8..8 + 16]; + for (chunk, item) in dst.chunks_exact_mut(8).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); + } + } + + pub fn inners(&'a self) -> ::flatbuffers::Array<'a, Inner, 2> { + // Safety: + // Created from a valid Table for this object + // Which contains a valid array in this slot + use ::flatbuffers::Follow; + unsafe { ::flatbuffers::Array::follow(&self.0, 24) } + } + + #[allow(clippy::identity_op)] + pub fn set_inners(&mut self, x: &[Inner; 2]) { + let dst = &mut self.0[24..24 + 4]; + for (chunk, item) in dst.chunks_exact_mut(2).zip(x.iter()) { + chunk.copy_from_slice(&item.0); + } + } + + #[allow(clippy::identity_op)] + pub fn f(&self) -> f32 { + let mut bytes = [0u8; 4]; + bytes.copy_from_slice(&self.0[28..28 + 4]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) + } + + #[allow(clippy::identity_op)] + pub fn set_f(&mut self, x: f32) { + let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); + self.0[28..28 + 4].copy_from_slice(&x_le.to_ne_bytes()); + } + + pub fn flags(&'a self) -> ::flatbuffers::Array<'a, bool, 2> { + // Safety: + // Created from a valid Table for this object + // Which contains a valid array in this slot + use ::flatbuffers::Follow; + unsafe { ::flatbuffers::Array::follow(&self.0, 32) } + } + + #[allow(clippy::identity_op)] + pub fn set_flags(&mut self, items: &[bool; 2]) { + let dst = &mut self.0[32..32 + 2]; + for (chunk, item) in dst.chunks_exact_mut(1).zip(items.iter()) { + let item_le = ::flatbuffers::EndianScalar::to_little_endian(*item); + chunk.copy_from_slice(&item_le.to_ne_bytes()); + } + } + + #[allow(clippy::identity_op)] + pub fn one(&self) -> WideEnum { + let mut bytes = [0u8; 2]; + bytes.copy_from_slice(&self.0[34..34 + 2]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) + } + + #[allow(clippy::identity_op)] + pub fn set_one(&mut self, x: WideEnum) { + let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); + self.0[34..34 + 2].copy_from_slice(&x_le.to_ne_bytes()); + } + + pub fn nested(&self) -> &Inner { + // Safety: + // `Inner` is a `#[repr(transparent)]` + // wrapper around `[u8; 2]` (alignment 1) + // and `follow_cast_ref` bounds-checks the bytes. + unsafe { ::flatbuffers::follow_cast_ref::(&self.0, 36) } + } + + #[allow(clippy::identity_op)] + pub fn set_nested(&mut self, x: &Inner) { + self.0[36..36 + 2].copy_from_slice(&x.0) + } + + #[allow(clippy::identity_op)] + pub fn d(&self) -> f64 { + let mut bytes = [0u8; 8]; + bytes.copy_from_slice(&self.0[40..40 + 8]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) + } + + #[allow(clippy::identity_op)] + pub fn set_d(&mut self, x: f64) { + let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); + self.0[40..40 + 8].copy_from_slice(&x_le.to_ne_bytes()); + } + + pub fn unpack(&self) -> AccessorsT { + AccessorsT { + e: self.e().into(), + h: self.h().into(), + inners: { let inners = self.inners(); ::flatbuffers::array_init(|i| inners.get(i).unpack()) }, + f: self.f(), + flags: self.flags().into(), + one: self.one(), + nested: self.nested().unpack(), + d: self.d(), + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct AccessorsT { + pub e: [WideEnum; 3], + pub h: [HugeEnum; 2], + pub inners: [InnerT; 2], + pub f: f32, + pub flags: [bool; 2], + pub one: WideEnum, + pub nested: InnerT, + pub d: f64, +} +impl Default for AccessorsT { + fn default() -> Self { + Self { + e: ::flatbuffers::array_init(|_| Default::default()), + h: ::flatbuffers::array_init(|_| Default::default()), + inners: ::flatbuffers::array_init(|_| Default::default()), + f: 0.0, + flags: [false; 2], + one: WideEnum::Zero, + nested: Default::default(), + d: 0.0, + } + } +} + +impl AccessorsT { + pub fn pack(&self) -> Accessors { + Accessors::new( + &self.e, + &self.h, + &::flatbuffers::array_init(|i| self.inners[i].pack()), + self.f, + &self.flags, + self.one, + &self.nested.pack(), + self.d, + ) + } +} diff --git a/tests/rust_struct_accessors_test/rust_struct_accessors_test/holder_generated.rs b/tests/rust_struct_accessors_test/rust_struct_accessors_test/holder_generated.rs new file mode 100644 index 0000000000..3ce554a74a --- /dev/null +++ b/tests/rust_struct_accessors_test/rust_struct_accessors_test/holder_generated.rs @@ -0,0 +1,229 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// @generated +extern crate alloc; +use super::*; + +pub enum HolderOffset {} + +#[derive(Copy, Clone, PartialEq)] +pub struct Holder<'a> { + pub _tab: ::flatbuffers::Table<'a>, +} + +impl<'a> ::flatbuffers::Follow<'a> for Holder<'a> { + type Inner = Holder<'a>; + + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: unsafe { ::flatbuffers::Table::new(buf, loc) } } + } +} + +impl<'a> Holder<'a> { + pub const VT_A: ::flatbuffers::VOffsetT = 4; + + pub const fn get_fully_qualified_name() -> &'static str { + "RustStructAccessorsTest.Holder" + } + + #[inline] + pub unsafe fn init_from_table(table: ::flatbuffers::Table<'a>) -> Self { + Holder { _tab: table } + } + + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: ::flatbuffers::Allocator + 'bldr>( + _fbb: &'mut_bldr mut ::flatbuffers::FlatBufferBuilder<'bldr, A>, + args: &'args HolderArgs<'args> + ) -> ::flatbuffers::WIPOffset> { + let mut builder = HolderBuilder::new(_fbb); + if let Some(x) = args.a { builder.add_a(x); } + builder.finish() + } + + pub fn unpack(&self) -> HolderT { + let a = self.a().map(|x| { + x.unpack() + }); + HolderT { + a, + } + } + + #[inline] + pub fn a(&self) -> Option<&'a Accessors> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Holder::VT_A, None)} + } +} + +impl ::flatbuffers::Verifiable for Holder<'_> { + #[inline] + fn run_verifier( + v: &mut ::flatbuffers::Verifier, pos: usize + ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> { + v.visit_table(pos)? + .visit_field::("a", Self::VT_A, false)? + .finish(); + Ok(()) + } +} + +pub struct HolderArgs<'a> { + pub a: Option<&'a Accessors>, +} + +impl<'a> Default for HolderArgs<'a> { + #[inline] + fn default() -> Self { + HolderArgs { + a: None, + } + } +} + +pub struct HolderBuilder<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> { + fbb_: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>, + start_: ::flatbuffers::WIPOffset<::flatbuffers::TableUnfinishedWIPOffset>, +} + +impl<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> HolderBuilder<'a, 'b, A> { + #[inline] + pub fn add_a(&mut self, a: &Accessors) { + self.fbb_.push_slot_always::<&Accessors>(Holder::VT_A, a); + } + + #[inline] + pub fn new(_fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>) -> HolderBuilder<'a, 'b, A> { + let start = _fbb.start_table(); + HolderBuilder { + fbb_: _fbb, + start_: start, + } + } + + #[inline] + pub fn finish(self) -> ::flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + ::flatbuffers::WIPOffset::new(o.value()) + } +} + +impl ::core::fmt::Debug for Holder<'_> { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + let mut ds = f.debug_struct("Holder"); + ds.field("a", &self.a()); + ds.finish() + } +} + +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq)] +pub struct HolderT { + pub a: Option, +} + +impl Default for HolderT { + fn default() -> Self { + Self { + a: None, + } + } +} + +impl HolderT { + pub fn pack<'b, A: ::flatbuffers::Allocator + 'b>( + &self, + _fbb: &mut ::flatbuffers::FlatBufferBuilder<'b, A> + ) -> ::flatbuffers::WIPOffset> { + let a_tmp = self.a.as_ref().map(|x| x.pack()); + let a = a_tmp.as_ref(); + Holder::create(_fbb, &HolderArgs{ + a, + }) + } +} + +/// Verifies that a buffer of bytes contains a `Holder` +/// and returns it. +/// Note that verification is still experimental and may not +/// catch every error, or be maximally performant. For the +/// previous, unchecked, behavior use +/// `root_as_holder_unchecked`. +#[inline] +pub fn root_as_holder(buf: &[u8]) -> Result, ::flatbuffers::InvalidFlatbuffer> { + ::flatbuffers::root::(buf) +} + +/// Verifies that a buffer of bytes contains a size prefixed +/// `Holder` and returns it. +/// Note that verification is still experimental and may not +/// catch every error, or be maximally performant. For the +/// previous, unchecked, behavior use +/// `size_prefixed_root_as_holder_unchecked`. +#[inline] +pub fn size_prefixed_root_as_holder(buf: &[u8]) -> Result, ::flatbuffers::InvalidFlatbuffer> { + ::flatbuffers::size_prefixed_root::(buf) +} + +/// Verifies, with the given options, that a buffer of bytes +/// contains a `Holder` and returns it. +/// Note that verification is still experimental and may not +/// catch every error, or be maximally performant. For the +/// previous, unchecked, behavior use +/// `root_as_holder_unchecked`. +#[inline] +pub fn root_as_holder_with_opts<'b, 'o>( + opts: &'o ::flatbuffers::VerifierOptions, + buf: &'b [u8], +) -> Result, ::flatbuffers::InvalidFlatbuffer> { + ::flatbuffers::root_with_opts::>(opts, buf) +} + +/// Verifies, with the given verifier options, that a buffer of +/// bytes contains a size prefixed `Holder` and returns +/// it. Note that verification is still experimental and may not +/// catch every error, or be maximally performant. For the +/// previous, unchecked, behavior use +/// `root_as_holder_unchecked`. +#[inline] +pub fn size_prefixed_root_as_holder_with_opts<'b, 'o>( + opts: &'o ::flatbuffers::VerifierOptions, + buf: &'b [u8], +) -> Result, ::flatbuffers::InvalidFlatbuffer> { + ::flatbuffers::size_prefixed_root_with_opts::>(opts, buf) +} + +/// Assumes, without verification, that a buffer of bytes contains a Holder and returns it. +/// # Safety +/// Callers must trust the given bytes do indeed contain a valid `Holder`. +#[inline] +pub unsafe fn root_as_holder_unchecked(buf: &[u8]) -> Holder<'_> { + unsafe { ::flatbuffers::root_unchecked::(buf) } +} + +/// Assumes, without verification, that a buffer of bytes contains a size prefixed Holder and returns it. +/// # Safety +/// Callers must trust the given bytes do indeed contain a valid size prefixed `Holder`. +#[inline] +pub unsafe fn size_prefixed_root_as_holder_unchecked(buf: &[u8]) -> Holder<'_> { + unsafe { ::flatbuffers::size_prefixed_root_unchecked::(buf) } +} + +#[inline] +pub fn finish_holder_buffer<'a, 'b, A: ::flatbuffers::Allocator + 'a>( + fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>, + root: ::flatbuffers::WIPOffset> +) { + fbb.finish(root, None); +} + +#[inline] +pub fn finish_size_prefixed_holder_buffer<'a, 'b, A: ::flatbuffers::Allocator + 'a>( + fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>, + root: ::flatbuffers::WIPOffset> +) { + fbb.finish_size_prefixed(root, None); +} diff --git a/tests/rust_struct_accessors_test/rust_struct_accessors_test/huge_enum_generated.rs b/tests/rust_struct_accessors_test/rust_struct_accessors_test/huge_enum_generated.rs new file mode 100644 index 0000000000..f5370a81bb --- /dev/null +++ b/tests/rust_struct_accessors_test/rust_struct_accessors_test/huge_enum_generated.rs @@ -0,0 +1,103 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// @generated +extern crate alloc; +use super::*; + +#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MIN_HUGE_ENUM: u64 = 0; + +#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MAX_HUGE_ENUM: u64 = 72623859790382856; + +#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] +#[allow(non_camel_case_types)] +pub const ENUM_VALUES_HUGE_ENUM: [HugeEnum; 3] = [ + HugeEnum::Zero, + HugeEnum::X, + HugeEnum::Y, +]; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[repr(transparent)] +pub struct HugeEnum(pub u64); + +#[allow(non_upper_case_globals)] +impl HugeEnum { + pub const Zero: Self = Self(0); + pub const X: Self = Self(1); + pub const Y: Self = Self(72623859790382856); + + pub const ENUM_MIN: u64 = 0; + pub const ENUM_MAX: u64 = 72623859790382856; + pub const ENUM_VALUES: &'static [Self] = &[ + Self::Zero, + Self::X, + Self::Y, + ]; + + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> Option<&'static str> { + match self { + Self::Zero => Some("Zero"), + Self::X => Some("X"), + Self::Y => Some("Y"), + _ => None, + } + } +} + +impl ::core::fmt::Debug for HugeEnum { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + if let Some(name) = self.variant_name() { + f.write_str(name) + } else { + f.write_fmt(format_args!("", self.0)) + } + } +} + +impl<'a> ::flatbuffers::Follow<'a> for HugeEnum { + type Inner = Self; + + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) }; + Self(b) + } +} + +impl ::flatbuffers::Push for HugeEnum { + type Output = HugeEnum; + + #[inline] + unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { + unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) }; + } +} + +impl ::flatbuffers::EndianScalar for HugeEnum { + type Scalar = u64; + + #[inline] + fn to_little_endian(self) -> u64 { + self.0.to_le() + } + + #[inline] + #[allow(clippy::wrong_self_convention)] + fn from_little_endian(v: u64) -> Self { + let b = u64::from_le(v); + Self(b) + } +} + +impl<'a> ::flatbuffers::Verifiable for HugeEnum { + #[inline] + fn run_verifier( + v: &mut ::flatbuffers::Verifier, pos: usize + ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> { + u64::run_verifier(v, pos) + } +} + +impl ::flatbuffers::SimpleToVerifyInSlice for HugeEnum {} diff --git a/tests/rust_struct_accessors_test/rust_struct_accessors_test/inner_generated.rs b/tests/rust_struct_accessors_test/rust_struct_accessors_test/inner_generated.rs new file mode 100644 index 0000000000..916344e9a0 --- /dev/null +++ b/tests/rust_struct_accessors_test/rust_struct_accessors_test/inner_generated.rs @@ -0,0 +1,122 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// @generated +extern crate alloc; +use super::*; + +// struct Inner, aligned to 2 +#[repr(transparent)] +#[derive(Clone, Copy, PartialEq)] +pub struct Inner(pub [u8; 2]); + +impl Default for Inner { + fn default() -> Self { + Self([0; 2]) + } +} + +impl ::core::fmt::Debug for Inner { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + f.debug_struct("Inner") + .field("v", &self.v()) + .finish() + } +} + +impl ::flatbuffers::SimpleToVerifyInSlice for Inner {} + +impl<'a> ::flatbuffers::Follow<'a> for Inner { + type Inner = &'a Inner; + + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + unsafe { <&'a Inner>::follow(buf, loc) } + } +} + +impl<'a> ::flatbuffers::Follow<'a> for &'a Inner { + type Inner = &'a Inner; + + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + unsafe { ::flatbuffers::follow_cast_ref::(buf, loc) } + } +} + +impl<'b> ::flatbuffers::Push for Inner { + type Output = Inner; + + #[inline] + unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { + dst.copy_from_slice(&self.0); + } + + #[inline] + fn alignment() -> ::flatbuffers::PushAlignment { + ::flatbuffers::PushAlignment::new(2) + } +} + +impl<'a> ::flatbuffers::Verifiable for Inner { + #[inline] + fn run_verifier( + v: &mut ::flatbuffers::Verifier, pos: usize + ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> { + v.in_buffer::(pos) + } +} + +impl<'a> Inner { + #[allow(clippy::too_many_arguments)] + pub fn new( + v: u16, + ) -> Self { + let mut s = Self([0; 2]); + s.set_v(v); + s + } + + pub const fn get_fully_qualified_name() -> &'static str { + "RustStructAccessorsTest.Inner" + } + + #[allow(clippy::identity_op)] + pub fn v(&self) -> u16 { + let mut bytes = [0u8; 2]; + bytes.copy_from_slice(&self.0[0..0 + 2]); + ::flatbuffers::EndianScalar::from_little_endian( + <::Scalar>::from_ne_bytes(bytes), + ) + } + + #[allow(clippy::identity_op)] + pub fn set_v(&mut self, x: u16) { + let x_le = ::flatbuffers::EndianScalar::to_little_endian(x); + self.0[0..0 + 2].copy_from_slice(&x_le.to_ne_bytes()); + } + + pub fn unpack(&self) -> InnerT { + InnerT { + v: self.v(), + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct InnerT { + pub v: u16, +} +impl Default for InnerT { + fn default() -> Self { + Self { + v: 0, + } + } +} + +impl InnerT { + pub fn pack(&self) -> Inner { + Inner::new( + self.v, + ) + } +} diff --git a/tests/rust_struct_accessors_test/rust_struct_accessors_test/wide_enum_generated.rs b/tests/rust_struct_accessors_test/rust_struct_accessors_test/wide_enum_generated.rs new file mode 100644 index 0000000000..e998cd74c8 --- /dev/null +++ b/tests/rust_struct_accessors_test/rust_struct_accessors_test/wide_enum_generated.rs @@ -0,0 +1,107 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// @generated +extern crate alloc; +use super::*; + +#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MIN_WIDE_ENUM: i16 = -2; + +#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MAX_WIDE_ENUM: i16 = 258; + +#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] +#[allow(non_camel_case_types)] +pub const ENUM_VALUES_WIDE_ENUM: [WideEnum; 4] = [ + WideEnum::C, + WideEnum::Zero, + WideEnum::A, + WideEnum::B, +]; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[repr(transparent)] +pub struct WideEnum(pub i16); + +#[allow(non_upper_case_globals)] +impl WideEnum { + pub const C: Self = Self(-2); + pub const Zero: Self = Self(0); + pub const A: Self = Self(1); + pub const B: Self = Self(258); + + pub const ENUM_MIN: i16 = -2; + pub const ENUM_MAX: i16 = 258; + pub const ENUM_VALUES: &'static [Self] = &[ + Self::C, + Self::Zero, + Self::A, + Self::B, + ]; + + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> Option<&'static str> { + match self { + Self::C => Some("C"), + Self::Zero => Some("Zero"), + Self::A => Some("A"), + Self::B => Some("B"), + _ => None, + } + } +} + +impl ::core::fmt::Debug for WideEnum { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + if let Some(name) = self.variant_name() { + f.write_str(name) + } else { + f.write_fmt(format_args!("", self.0)) + } + } +} + +impl<'a> ::flatbuffers::Follow<'a> for WideEnum { + type Inner = Self; + + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + let b = unsafe { ::flatbuffers::read_scalar_at::(buf, loc) }; + Self(b) + } +} + +impl ::flatbuffers::Push for WideEnum { + type Output = WideEnum; + + #[inline] + unsafe fn push(&self, dst: &mut [u8], _written_len: usize) { + unsafe { ::flatbuffers::emplace_scalar::(dst, self.0) }; + } +} + +impl ::flatbuffers::EndianScalar for WideEnum { + type Scalar = i16; + + #[inline] + fn to_little_endian(self) -> i16 { + self.0.to_le() + } + + #[inline] + #[allow(clippy::wrong_self_convention)] + fn from_little_endian(v: i16) -> Self { + let b = i16::from_le(v); + Self(b) + } +} + +impl<'a> ::flatbuffers::Verifiable for WideEnum { + #[inline] + fn run_verifier( + v: &mut ::flatbuffers::Verifier, pos: usize + ) -> Result<(), ::flatbuffers::InvalidFlatbuffer> { + i16::run_verifier(v, pos) + } +} + +impl ::flatbuffers::SimpleToVerifyInSlice for WideEnum {} diff --git a/tests/rust_usage_test/tests/struct_accessors_test.rs b/tests/rust_usage_test/tests/struct_accessors_test.rs new file mode 100644 index 0000000000..4acbf36b89 --- /dev/null +++ b/tests/rust_usage_test/tests/struct_accessors_test.rs @@ -0,0 +1,165 @@ +//! Tests for the accessors `flatc` generates for Rust structs. +//! +//! Struct getters and setters are generated without raw pointer operations: +//! every field access is a bounds-checked slice of the struct's `[u8; N]` +//! storage. These tests pin down the exact little-endian wire bytes those +//! accessors produce, so they also catch endianness bugs when run on a +//! big-endian target (for example `cargo miri test --target +//! s390x-unknown-linux-gnu`, or the project's MIPS CI job). +#![no_std] + +#[cfg(not(feature = "no_std"))] +extern crate std; + +extern crate alloc; + +#[allow(dead_code, unused_imports, clippy::all)] +#[path = "../../rust_struct_accessors_test/mod.rs"] +mod rust_struct_accessors_test_generated; + +use crate::rust_struct_accessors_test_generated::rust_struct_accessors_test::*; + +/// `HugeEnum::Y` in little-endian byte order. +const HUGE_Y_LE: [u8; 8] = [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]; + +fn example() -> Accessors { + Accessors::new( + &[WideEnum::B, WideEnum::C, WideEnum::A], + &[HugeEnum::Y, HugeEnum::X], + &[Inner::new(0xA1B2), Inner::new(0x0304)], + 1.5, + &[true, false], + WideEnum::C, + &Inner::new(0xBEEF), + -2.0, + ) +} + +/// The wire bytes of `example()`, written out by hand from the schema layout. +#[rustfmt::skip] +const EXAMPLE_BYTES: [u8; 48] = [ + // e: [WideEnum; 3] at 0 = [B (0x0102), C (-2), A (1)] + 0x02, 0x01, 0xFE, 0xFF, 0x01, 0x00, + // padding + 0x00, 0x00, + // h: [HugeEnum; 2] at 8 = [Y, X] + 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // inners: [Inner; 2] at 24 + 0xB2, 0xA1, 0x04, 0x03, + // f: f32 at 28 = 1.5 (0x3FC00000) + 0x00, 0x00, 0xC0, 0x3F, + // flags: [bool; 2] at 32 + 0x01, 0x00, + // one: WideEnum at 34 = C (-2) + 0xFE, 0xFF, + // nested: Inner at 36 + 0xEF, 0xBE, + // padding + 0x00, 0x00, + // d: f64 at 40 = -2.0 (0xC000000000000000) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, +]; + +fn check_example_getters(a: &Accessors) { + assert_eq!(a.e().iter().collect::>(), [WideEnum::B, WideEnum::C, WideEnum::A]); + assert_eq!(a.h().get(0), HugeEnum::Y); + assert_eq!(a.h().get(1), HugeEnum::X); + assert_eq!(a.inners().get(0).v(), 0xA1B2); + assert_eq!(a.inners().get(1).v(), 0x0304); + assert_eq!(a.f(), 1.5); + assert_eq!(a.flags().get(0), true); + assert_eq!(a.flags().get(1), false); + assert_eq!(a.one(), WideEnum::C); + assert_eq!(a.nested().v(), 0xBEEF); + assert_eq!(a.d(), -2.0); +} + +#[test] +fn struct_setters_write_little_endian_wire_bytes() { + assert_eq!(example().0, EXAMPLE_BYTES); +} + +#[test] +fn struct_getters_read_little_endian_wire_bytes() { + check_example_getters(&Accessors(EXAMPLE_BYTES)); +} + +#[test] +fn struct_enum_array_setter_converts_each_element_to_little_endian() { + // Regression test: arrays of enums used to be copied with a raw + // `ptr::copy` of their in-memory (host-endian) representation, which + // produced big-endian wire bytes on big-endian hosts. + let mut a = Accessors::default(); + a.set_e(&[WideEnum::B, WideEnum::C, WideEnum::A]); + assert_eq!(a.0[0..6], [0x02, 0x01, 0xFE, 0xFF, 0x01, 0x00]); + a.set_h(&[HugeEnum::Y, HugeEnum::X]); + assert_eq!(a.0[8..16], HUGE_Y_LE); + assert_eq!(a.0[16..24], [1, 0, 0, 0, 0, 0, 0, 0]); +} + +#[test] +fn struct_setters_only_touch_their_own_bytes() { + let mut a = Accessors([0x55; 48]); + a.set_one(WideEnum::B); + a.set_nested(&Inner::new(0x0A0B)); + a.set_flags(&[false, true]); + for (i, byte) in a.0.iter().enumerate() { + let expected = match i { + 32 => 0x00, + 33 => 0x01, + 34 => 0x02, + 35 => 0x01, + 36 => 0x0B, + 37 => 0x0A, + _ => 0x55, + }; + assert_eq!(*byte, expected, "unexpected byte at offset {}", i); + } +} + +#[test] +fn struct_round_trips_through_builder_and_verifier() { + let mut builder = flatbuffers::FlatBufferBuilder::new(); + let a = example(); + let root = Holder::create(&mut builder, &HolderArgs { a: Some(&a) }); + builder.finish(root, None); + + let holder = root_as_holder(builder.finished_data()).unwrap(); + let read = holder.a().unwrap(); + assert_eq!(read.0, EXAMPLE_BYTES); + check_example_getters(read); +} + +#[test] +fn struct_object_api_round_trips() { + let unpacked = example().unpack(); + assert_eq!(unpacked.e, [WideEnum::B, WideEnum::C, WideEnum::A]); + assert_eq!(unpacked.h, [HugeEnum::Y, HugeEnum::X]); + assert_eq!(unpacked.pack().0, EXAMPLE_BYTES); +} + +#[test] +fn generated_struct_accessors_do_not_use_raw_pointer_operations() { + // Guards the code generator: struct accessors must stay expressible as + // bounds-checked slice operations on the struct's byte array. + let sources = [ + include_str!("../../rust_struct_accessors_test/rust_struct_accessors_test/accessors_generated.rs"), + include_str!("../../rust_struct_accessors_test/rust_struct_accessors_test/inner_generated.rs"), + ]; + for source in sources.iter() { + for forbidden in [ + "copy_nonoverlapping", + "ptr::copy", + "from_raw_parts", + "MaybeUninit", + "emplace_scalar_array", + "as *const", + "as *mut", + ] + .iter() + { + assert!(!source.contains(forbidden), "generated struct code uses `{}`", forbidden); + } + } +}