Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 25 additions & 68 deletions samples/rust_generated/my_game/sample/vec_3_generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, <Self as ::flatbuffers::Push>::size()) };
dst.copy_from_slice(src);
dst.copy_from_slice(&self.0);
}

#[inline]
Expand Down Expand Up @@ -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::<<f32 as ::flatbuffers::EndianScalar>::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::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
mem.assume_init()
})
let mut bytes = [0u8; 4];
bytes.copy_from_slice(&self.0[0..0 + 4]);
::flatbuffers::EndianScalar::from_little_endian(
<<f32 as ::flatbuffers::EndianScalar>::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::<<f32 as ::flatbuffers::EndianScalar>::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::<<f32 as ::flatbuffers::EndianScalar>::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::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
mem.assume_init()
})
let mut bytes = [0u8; 4];
bytes.copy_from_slice(&self.0[4..4 + 4]);
::flatbuffers::EndianScalar::from_little_endian(
<<f32 as ::flatbuffers::EndianScalar>::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::<<f32 as ::flatbuffers::EndianScalar>::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::<<f32 as ::flatbuffers::EndianScalar>::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::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
mem.assume_init()
})
let mut bytes = [0u8; 4];
bytes.copy_from_slice(&self.0[8..8 + 4]);
::flatbuffers::EndianScalar::from_little_endian(
<<f32 as ::flatbuffers::EndianScalar>::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::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
}
self.0[8..8 + 4].copy_from_slice(&x_le.to_ne_bytes());
}

pub fn unpack(&self) -> Vec3T {
Expand Down
6 changes: 6 additions & 0 deletions scripts/generate_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
115 changes: 54 additions & 61 deletions src/idl_gen_rust.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, <Self as ::flatbuffers::Push>::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_ += "";

Expand Down Expand Up @@ -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));
Expand All @@ -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";

Expand Down
Loading
Loading