From 1da0a2dfac4bd9a6876a7c39c4eea5eeefc36aa2 Mon Sep 17 00:00:00 2001 From: Casper Date: Fri, 22 Jan 2021 13:07:32 -0500 Subject: [PATCH] Rust Object API (#6070) * inital commit of rust object api * Required fields support. * clang fallthrough * Fix unused variables * just don't fall through * remove comment * s/panic/unreachable * Tests for object API * Added defaults * deleted unintentionally added files and updated .bat file * fix bat file * clang format * Cargo clippy checks * remove commented out code * clippy allows * Remove matches! macro since we're not yet at Rust v1.42 * install clippy in RustTest.sh * move line Co-authored-by: Casper Neo --- rust/flexbuffers/src/builder/mod.rs | 4 +- rust/flexbuffers/src/builder/value.rs | 7 +- rust/flexbuffers/src/flexbuffer_type.rs | 2 +- rust/flexbuffers/src/lib.rs | 4 + samples/monster_generated.rs | 208 +++- samples/sample_binary.rs | 3 +- samples/sample_flexbuffers.rs | 1 + src/idl_gen_rust.cpp | 952 +++++++++++---- tests/RustTest.sh | 39 +- tests/generate_code.bat | 4 +- tests/generate_code.sh | 4 +- tests/include_test/include_test1_generated.rs | 4 +- .../sub/include_test2_generated.rs | 8 +- tests/monster_test_generated.rs | 1018 ++++++++++++++++- .../namespace_test1_generated.rs | 50 +- .../namespace_test2_generated.rs | 112 +- tests/optional_scalars_generated.rs | 203 +++- .../bin/flatbuffers_alloc_check.rs | 2 +- tests/rust_usage_test/bin/monster_example.rs | 2 +- .../rust_usage_test/tests/integration_test.rs | 44 + .../tests/optional_scalars_test.rs | 10 + 21 files changed, 2362 insertions(+), 319 deletions(-) diff --git a/rust/flexbuffers/src/builder/mod.rs b/rust/flexbuffers/src/builder/mod.rs index e71acd0db..46ee79e3d 100644 --- a/rust/flexbuffers/src/builder/mod.rs +++ b/rust/flexbuffers/src/builder/mod.rs @@ -242,9 +242,7 @@ impl<'a> Builder { let address = self.buffer.len(); for &b in xs.iter() { self.buffer.push(b as u8); - for _ in 0..width as u8 { - self.buffer.push(0); // Well this seems wasteful. - } + self.buffer.resize(self.buffer.len() + width as usize, 0); } self.values.push(Value::Reference { fxb_type: FlexBufferType::VectorBool, diff --git a/rust/flexbuffers/src/builder/value.rs b/rust/flexbuffers/src/builder/value.rs index f230c34f1..88ff7b985 100644 --- a/rust/flexbuffers/src/builder/value.rs +++ b/rust/flexbuffers/src/builder/value.rs @@ -129,9 +129,10 @@ impl Value { !self.is_inline() } pub fn is_key(&self) -> bool { - match self { - Value::Key(_) => true, - _ => false, + if let Value::Key(_) = self { + true + } else { + false } } pub fn is_typed_vector_or_map(&self) -> bool { diff --git a/rust/flexbuffers/src/flexbuffer_type.rs b/rust/flexbuffers/src/flexbuffer_type.rs index 5b57de85f..eda51955d 100644 --- a/rust/flexbuffers/src/flexbuffer_type.rs +++ b/rust/flexbuffers/src/flexbuffer_type.rs @@ -134,7 +134,7 @@ impl FlexBufferType { /// Returns true if called on a map, vector, typed vector, or fixed length typed vector. pub fn is_vector(self) -> bool { let d = self as u8; - 9 <= d && d < 25 || self == VectorBool + (9..25).contains(&d) || self == VectorBool } /// True iff the binary format stores the length. /// This applies to Blob, String, Maps, and Vectors of variable length. diff --git a/rust/flexbuffers/src/lib.rs b/rust/flexbuffers/src/lib.rs index 20983b792..5e98702b9 100644 --- a/rust/flexbuffers/src/lib.rs +++ b/rust/flexbuffers/src/lib.rs @@ -28,6 +28,10 @@ // Serializable structs are Pushable // Serde with maps - field names and type names. +// Until flat/flexbuffers is on Rust v1.42, we cannot use the previously unstable matches! macro. +#![allow(clippy::unknown_clippy_lints)] +#![allow(clippy::match_like_matches_macro)] + #[macro_use] extern crate bitflags; extern crate byteorder; diff --git a/samples/monster_generated.rs b/samples/monster_generated.rs index eb4f6c390..62a9c2d54 100644 --- a/samples/monster_generated.rs +++ b/samples/monster_generated.rs @@ -38,7 +38,7 @@ pub const ENUM_VALUES_COLOR: [Color; 3] = [ Color::Blue, ]; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[repr(transparent)] pub struct Color(pub i8); #[allow(non_upper_case_globals)] @@ -125,7 +125,7 @@ pub const ENUM_VALUES_EQUIPMENT: [Equipment; 2] = [ Equipment::Weapon, ]; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[repr(transparent)] pub struct Equipment(pub u8); #[allow(non_upper_case_globals)] @@ -157,7 +157,6 @@ impl std::fmt::Debug for Equipment { } } } -pub struct EquipmentUnionTableOffset {} impl<'a> flatbuffers::Follow<'a> for Equipment { type Inner = Self; #[inline] @@ -199,9 +198,57 @@ impl<'a> flatbuffers::Verifiable for Equipment { } impl flatbuffers::SimpleToVerifyInSlice for Equipment {} +pub struct EquipmentUnionTableOffset {} + +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq)] +pub enum EquipmentT { + NONE, + Weapon(Box), +} +impl Default for EquipmentT { + fn default() -> Self { + Self::NONE + } +} +impl EquipmentT { + fn equipment_type(&self) -> Equipment { + match self { + Self::NONE => Equipment::NONE, + Self::Weapon(_) => Equipment::Weapon, + } + } + pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder) -> Option> { + match self { + Self::NONE => None, + Self::Weapon(v) => Some(v.pack(fbb).as_union_value()), + } + } + /// If the union variant matches, return the owned WeaponT, setting the union to NONE. + pub fn take_weapon(&mut self) -> Option> { + if let Self::Weapon(_) = self { + let v = std::mem::replace(self, Self::NONE); + if let Self::Weapon(w) = v { + Some(w) + } else { + unreachable!() + } + } else { + None + } + } + /// If the union variant matches, return a reference to the WeaponT. + pub fn as_weapon(&self) -> Option<&WeaponT> { + if let Self::Weapon(v) = self { Some(v.as_ref()) } else { None } + } + /// If the union variant matches, return a mutable reference to the WeaponT. + pub fn as_weapon_mut(&mut self) -> Option<&mut WeaponT> { + if let Self::Weapon(v) = self { Some(v.as_mut()) } else { None } + } +} // struct Vec3, aligned to 4 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Default)] pub struct Vec3(pub [u8; 12]); impl std::fmt::Debug for Vec3 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -343,6 +390,29 @@ impl Vec3 { } } + pub fn unpack(&self) -> Vec3T { + Vec3T { + x: self.x(), + y: self.y(), + z: self.z(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct Vec3T { + pub x: f32, + pub y: f32, + pub z: f32, +} +impl Vec3T { + pub fn pack(&self) -> Vec3 { + Vec3::new( + self.x, + self.y, + self.z, + ) + } } pub enum MonsterOffset {} @@ -363,9 +433,7 @@ impl<'a> flatbuffers::Follow<'a> for Monster<'a> { impl<'a> Monster<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - Monster { - _tab: table, - } + Monster { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -385,6 +453,46 @@ impl<'a> Monster<'a> { builder.finish() } + pub fn unpack(&self) -> MonsterT { + let pos = self.pos().map(|x| { + x.unpack() + }); + let mana = self.mana(); + let hp = self.hp(); + let name = self.name().map(|x| { + x.to_string() + }); + let inventory = self.inventory().map(|x| { + x.to_vec() + }); + let color = self.color(); + let weapons = self.weapons().map(|x| { + x.iter().map(|t| t.unpack()).collect() + }); + let equipped = match self.equipped_type() { + Equipment::NONE => EquipmentT::NONE, + Equipment::Weapon => EquipmentT::Weapon(Box::new( + self.equipped_as_weapon() + .expect("Invalid union table, expected `Equipment::Weapon`.") + .unpack() + )), + _ => EquipmentT::NONE, + }; + let path = self.path().map(|x| { + x.iter().map(|t| t.unpack()).collect() + }); + MonsterT { + pos, + mana, + hp, + name, + inventory, + color, + weapons, + equipped, + path, + } + } pub const VT_POS: flatbuffers::VOffsetT = 4; pub const VT_MANA: flatbuffers::VOffsetT = 6; pub const VT_HP: flatbuffers::VOffsetT = 8; @@ -590,6 +698,57 @@ impl std::fmt::Debug for Monster<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct MonsterT { + pub pos: Option, + pub mana: i16, + pub hp: i16, + pub name: Option, + pub inventory: Option>, + pub color: Color, + pub weapons: Option>, + pub equipped: EquipmentT, + pub path: Option>, +} +impl MonsterT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let pos_tmp = self.pos.as_ref().map(|x| x.pack()); + let pos = pos_tmp.as_ref(); + let mana = self.mana; + let hp = self.hp; + let name = self.name.as_ref().map(|x|{ + _fbb.create_string(x) + }); + let inventory = self.inventory.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let color = self.color; + let weapons = self.weapons.as_ref().map(|x|{ + let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();_fbb.create_vector(&w) + }); + let equipped_type = self.equipped.equipment_type(); + let equipped = self.equipped.pack(_fbb); + let path = self.path.as_ref().map(|x|{ + let w: Vec<_> = x.iter().map(|t| t.pack()).collect();_fbb.create_vector(&w) + }); + Monster::create(_fbb, &MonsterArgs{ + pos, + mana, + hp, + name, + inventory, + color, + weapons, + equipped_type, + equipped, + path, + }) + } +} pub enum WeaponOffset {} #[derive(Copy, Clone, PartialEq)] @@ -608,9 +767,7 @@ impl<'a> flatbuffers::Follow<'a> for Weapon<'a> { impl<'a> Weapon<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - Weapon { - _tab: table, - } + Weapon { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -622,6 +779,16 @@ impl<'a> Weapon<'a> { builder.finish() } + pub fn unpack(&self) -> WeaponT { + let name = self.name().map(|x| { + x.to_string() + }); + let damage = self.damage(); + WeaponT { + name, + damage, + } + } pub const VT_NAME: flatbuffers::VOffsetT = 4; pub const VT_DAMAGE: flatbuffers::VOffsetT = 6; @@ -697,6 +864,27 @@ impl std::fmt::Debug for Weapon<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct WeaponT { + pub name: Option, + pub damage: i16, +} +impl WeaponT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let name = self.name.as_ref().map(|x|{ + _fbb.create_string(x) + }); + let damage = self.damage; + Weapon::create(_fbb, &WeaponArgs{ + name, + damage, + }) + } +} #[inline] #[deprecated(since="2.0.0", note="Deprecated in favor of `root_as...` methods.")] pub fn get_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> { diff --git a/samples/sample_binary.rs b/samples/sample_binary.rs index 649babf38..1b08f2050 100644 --- a/samples/sample_binary.rs +++ b/samples/sample_binary.rs @@ -19,6 +19,7 @@ extern crate flatbuffers; // import the generated code #[path = "./monster_generated.rs"] +#[allow(clippy::approx_constant)] // We use low precision PI as a default value. mod monster_generated; pub use monster_generated::my_game::sample::{Color, Equipment, Monster, MonsterArgs, @@ -27,7 +28,7 @@ pub use monster_generated::my_game::sample::{Color, Equipment, // Example how to use FlatBuffers to create and read binary buffers. - +#[allow(clippy::float_cmp)] fn main() { // Build up a serialized buffer algorithmically. // Initialize it with a capacity of 1024 bytes. diff --git a/samples/sample_flexbuffers.rs b/samples/sample_flexbuffers.rs index efe02c342..677bcacb5 100644 --- a/samples/sample_flexbuffers.rs +++ b/samples/sample_flexbuffers.rs @@ -31,6 +31,7 @@ use flexbuffers::{BitWidth, Builder, Reader, ReaderError}; // {"damage": 15, "name": "great axe"}, // {"damage": 5, "name": "hammer"}] // } +#[allow(clippy::float_cmp)] fn main() { // Create a new Flexbuffer builder. let mut builder = Builder::default(); diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp index 2f6f0b782..5fc3090ba 100644 --- a/src/idl_gen_rust.cpp +++ b/src/idl_gen_rust.cpp @@ -179,7 +179,7 @@ bool IsBitFlagsEnum(const EnumDef &enum_def) { return enum_def.attributes.Lookup("bit_flags") != nullptr; } bool IsBitFlagsEnum(const FieldDef &field) { - EnumDef* ed = field.value.type.enum_def; + EnumDef *ed = field.value.type.enum_def; return ed && IsBitFlagsEnum(*ed); } @@ -192,6 +192,7 @@ class RustGenerator : public BaseGenerator { : BaseGenerator(parser, path, file_name, "", "::", "rs"), cur_name_space_(nullptr) { const char *keywords[] = { + // clang-format off // list taken from: // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html // @@ -227,7 +228,7 @@ class RustGenerator : public BaseGenerator { // used by Enum constants "ENUM_MAX", "ENUM_MIN", "ENUM_VALUES", - }; + }; // clang-format on for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw); } @@ -257,8 +258,7 @@ class RustGenerator : public BaseGenerator { for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); ++it) { const auto &enum_def = **it; - if (enum_def.defined_namespace != ns) { continue; } - if (!enum_def.generated) { + if (enum_def.defined_namespace == ns && !enum_def.generated) { SetNameSpace(enum_def.defined_namespace); GenEnum(enum_def); } @@ -268,8 +268,8 @@ class RustGenerator : public BaseGenerator { for (auto it = parser_.structs_.vec.begin(); it != parser_.structs_.vec.end(); ++it) { const auto &struct_def = **it; - if (struct_def.defined_namespace != ns) { continue; } - if (struct_def.fixed && !struct_def.generated) { + if (struct_def.defined_namespace == ns && struct_def.fixed && + !struct_def.generated) { SetNameSpace(struct_def.defined_namespace); GenStruct(struct_def); } @@ -279,10 +279,13 @@ class RustGenerator : public BaseGenerator { for (auto it = parser_.structs_.vec.begin(); it != parser_.structs_.vec.end(); ++it) { const auto &struct_def = **it; - if (struct_def.defined_namespace != ns) { continue; } - if (!struct_def.fixed && !struct_def.generated) { + if (struct_def.defined_namespace == ns && !struct_def.fixed && + !struct_def.generated) { SetNameSpace(struct_def.defined_namespace); GenTable(struct_def); + if (parser_.opts.generate_object_based_api) { + GenTableObject(struct_def); + } } } @@ -347,6 +350,13 @@ class RustGenerator : public BaseGenerator { std::string EscapeKeyword(const std::string &name) const { return keywords_.find(name) == keywords_.end() ? name : name + "_"; } + std::string NamespacedNativeName(const Definition &def) { + return WrapInNameSpace(def.defined_namespace, NativeName(def)); + } + + std::string NativeName(const Definition &def) { + return parser_.opts.object_prefix + Name(def) + parser_.opts.object_suffix; + } std::string Name(const Definition &def) const { return EscapeKeyword(def.name); @@ -499,13 +509,13 @@ class RustGenerator : public BaseGenerator { } std::string GetEnumValue(const EnumDef &enum_def, - const EnumVal &enum_val) const { + const EnumVal &enum_val) const { return Name(enum_def) + "::" + Name(enum_val); } // 1 suffix since old C++ can't figure out the overload. void ForAllEnumValues1(const EnumDef &enum_def, - std::function cb) { + std::function cb) { for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { const auto &ev = **it; code_.SetValue("VARIANT", Name(ev)); @@ -514,11 +524,11 @@ class RustGenerator : public BaseGenerator { } } void ForAllEnumValues(const EnumDef &enum_def, std::function cb) { - std::function wrapped = [&](const EnumVal& unused) { - (void) unused; - cb(); - }; - ForAllEnumValues1(enum_def, wrapped); + std::function wrapped = [&](const EnumVal &unused) { + (void)unused; + cb(); + }; + ForAllEnumValues1(enum_def, wrapped); } // Generate an enum declaration, // an enum string lookup table, @@ -536,16 +546,17 @@ class RustGenerator : public BaseGenerator { code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv)); if (IsBitFlagsEnum(enum_def)) { - // Defer to the convenient and canonical bitflags crate. We declare it in a - // module to #allow camel case constants in a smaller scope. This matches - // Flatbuffers c-modeled enums where variants are associated constants but - // in camel case. + // Defer to the convenient and canonical bitflags crate. We declare it in + // a module to #allow camel case constants in a smaller scope. This + // matches Flatbuffers c-modeled enums where variants are associated + // constants but in camel case. code_ += "#[allow(non_upper_case_globals)]"; code_ += "mod bitflags_{{ENUM_NAME_SNAKE}} {"; code_ += " flatbuffers::bitflags::bitflags! {"; GenComment(enum_def.doc_comment, " "); + code_ += " #[derive(Default)]"; code_ += " pub struct {{ENUM_NAME}}: {{BASE_TYPE}} {"; - ForAllEnumValues1(enum_def, [&](const EnumVal &ev){ + ForAllEnumValues1(enum_def, [&](const EnumVal &ev) { this->GenComment(ev.doc_comment, " "); code_ += " const {{VARIANT}} = {{VALUE}};"; }); @@ -564,30 +575,36 @@ class RustGenerator : public BaseGenerator { "#[deprecated(since = \"2.0.0\", note = \"Use associated constants" " instead. This will no longer be generated in 2021.\")]"; code_ += deprecation_warning; - code_ += "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" - " = {{ENUM_MIN_BASE_VALUE}};"; + code_ += + "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" + " = {{ENUM_MIN_BASE_VALUE}};"; code_ += deprecation_warning; - code_ += "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" - " = {{ENUM_MAX_BASE_VALUE}};"; + code_ += + "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" + " = {{ENUM_MAX_BASE_VALUE}};"; auto num_fields = NumToString(enum_def.size()); code_ += deprecation_warning; code_ += "#[allow(non_camel_case_types)]"; code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " + num_fields + "] = ["; - ForAllEnumValues1(enum_def, [&](const EnumVal &ev){ + ForAllEnumValues1(enum_def, [&](const EnumVal &ev) { code_ += " " + GetEnumValue(enum_def, ev) + ","; }); code_ += "];"; code_ += ""; GenComment(enum_def.doc_comment); + // Derive Default to be 0. flatc enforces this when the enum + // is put into a struct, though this isn't documented behavior, it is + // needed to derive defaults in struct objects. code_ += - "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]"; + "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, " + "Default)]"; code_ += "#[repr(transparent)]"; code_ += "pub struct {{ENUM_NAME}}(pub {{BASE_TYPE}});"; code_ += "#[allow(non_upper_case_globals)]"; code_ += "impl {{ENUM_NAME}} {"; - ForAllEnumValues1(enum_def, [&](const EnumVal &ev){ + ForAllEnumValues1(enum_def, [&](const EnumVal &ev) { this->GenComment(ev.doc_comment, " "); code_ += " pub const {{VARIANT}}: Self = Self({{VALUE}});"; }); @@ -596,14 +613,12 @@ class RustGenerator : public BaseGenerator { code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};"; code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};"; code_ += " pub const ENUM_VALUES: &'static [Self] = &["; - ForAllEnumValues(enum_def, [&](){ - code_ += " Self::{{VARIANT}},"; - }); + ForAllEnumValues(enum_def, [&]() { code_ += " Self::{{VARIANT}},"; }); code_ += " ];"; code_ += " /// Returns the variant's name or \"\" if unknown."; code_ += " pub fn variant_name(self) -> Option<&'static str> {"; code_ += " match self {"; - ForAllEnumValues(enum_def, [&](){ + ForAllEnumValues(enum_def, [&]() { code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),"; }); code_ += " _ => None,"; @@ -613,8 +628,9 @@ class RustGenerator : public BaseGenerator { // Generate Debug. Unknown variants are printed like "". code_ += "impl std::fmt::Debug for {{ENUM_NAME}} {"; - code_ += " fn fmt(&self, f: &mut std::fmt::Formatter) ->" - " std::fmt::Result {"; + code_ += + " fn fmt(&self, f: &mut std::fmt::Formatter) ->" + " std::fmt::Result {"; code_ += " if let Some(name) = self.variant_name() {"; code_ += " f.write_str(name)"; code_ += " } else {"; @@ -623,13 +639,6 @@ class RustGenerator : public BaseGenerator { code_ += " }"; code_ += "}"; - if (enum_def.is_union) { - // Generate tyoesafe offset(s) for unions - code_.SetValue("NAME", Name(enum_def)); - code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset"); - code_ += "pub struct {{UNION_OFFSET_NAME}} {}"; - } - code_.SetValue("FROM_BASE", "Self(b)"); code_.SetValue("INTO_BASE", "self.0"); } @@ -639,8 +648,9 @@ class RustGenerator : public BaseGenerator { code_ += " type Inner = Self;"; code_ += " #[inline]"; code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; - code_ += " let b = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf," - " loc);"; + code_ += + " let b = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf," + " loc);"; code_ += " {{FROM_BASE}}"; code_ += " }"; code_ += "}"; @@ -649,8 +659,9 @@ class RustGenerator : public BaseGenerator { code_ += " type Output = {{ENUM_NAME}};"; code_ += " #[inline]"; code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; - code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>" - "(dst, {{INTO_BASE}});"; + code_ += + " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>" + "(dst, {{INTO_BASE}});"; code_ += " }"; code_ += "}"; code_ += ""; @@ -667,6 +678,7 @@ class RustGenerator : public BaseGenerator { code_ += " }"; code_ += "}"; code_ += ""; + // Generate verifier - deferring to the base type. code_ += "impl<'a> flatbuffers::Verifiable for {{ENUM_NAME}} {"; code_ += " #[inline]"; @@ -680,6 +692,126 @@ class RustGenerator : public BaseGenerator { code_ += ""; // Enums are basically integers. code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{ENUM_NAME}} {}"; + + if (enum_def.is_union) { + // Generate tyoesafe offset(s) for unions + code_.SetValue("NAME", Name(enum_def)); + code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset"); + code_ += "pub struct {{UNION_OFFSET_NAME}} {}"; + code_ += ""; + if (parser_.opts.generate_object_based_api) { GenUnionObject(enum_def); } + } + } + + // CASPER: dedup Object versions from non object versions. + void ForAllUnionObjectVariantsBesidesNone(const EnumDef &enum_def, + std::function cb) { + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &enum_val = **it; + if (enum_val.union_type.base_type == BASE_TYPE_NONE) continue; + code_.SetValue("VARIANT_NAME", Name(enum_val)); + code_.SetValue("NATIVE_VARIANT", MakeCamel(Name(enum_val))); + code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(enum_val))); + code_.SetValue("U_ELEMENT_TABLE_TYPE", + NamespacedNativeName(*enum_val.union_type.struct_def)); + cb(); + } + } + void GenUnionObject(const EnumDef &enum_def) { + code_.SetValue("ENUM_NAME", Name(enum_def)); + code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def))); + code_.SetValue("NATIVE_NAME", NativeName(enum_def)); + + // Generate native union. + code_ += "#[non_exhaustive]"; + code_ += "#[derive(Debug, Clone, PartialEq)]"; + code_ += "pub enum {{NATIVE_NAME}} {"; + code_ += " NONE,"; + ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { + code_ += " {{NATIVE_VARIANT}}(Box<{{U_ELEMENT_TABLE_TYPE}}>),"; + }); + code_ += "}"; + // Generate Default (NONE). + code_ += "impl Default for {{NATIVE_NAME}} {"; + code_ += " fn default() -> Self {"; + code_ += " Self::NONE"; + code_ += " }"; + code_ += "}"; + + // Generate native union methods. + code_ += "impl {{NATIVE_NAME}} {"; + + // Get flatbuffers union key. + // CASPER: add docstrings? + code_ += " fn {{ENUM_NAME_SNAKE}}_type(&self) -> {{ENUM_NAME}} {"; + code_ += " match self {"; + code_ += " Self::NONE => {{ENUM_NAME}}::NONE,"; + ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { + code_ += + " Self::{{NATIVE_VARIANT}}(_) => {{ENUM_NAME}}::" + "{{VARIANT_NAME}},"; + }); + code_ += " }"; + code_ += " }"; + // Pack flatbuffers union value + code_ += + " pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder)" + " -> Option>" + " {"; + code_ += " match self {"; + code_ += " Self::NONE => None,"; + ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { + code_ += + " Self::{{NATIVE_VARIANT}}(v) => " + "Some(v.pack(fbb).as_union_value()),"; + }); + code_ += " }"; + code_ += " }"; + + // Generate some accessors; + ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { + // Move accessor. + code_ += + " /// If the union variant matches, return the owned " + "{{U_ELEMENT_TABLE_TYPE}}, setting the union to NONE."; + code_ += + " pub fn take_{{U_ELEMENT_NAME}}(&mut self) -> " + "Option> {"; + code_ += " if let Self::{{NATIVE_VARIANT}}(_) = self {"; + code_ += " let v = std::mem::replace(self, Self::NONE);"; + code_ += " if let Self::{{NATIVE_VARIANT}}(w) = v {"; + code_ += " Some(w)"; + code_ += " } else {"; + code_ += " unreachable!()"; + code_ += " }"; + code_ += " } else {"; + code_ += " None"; + code_ += " }"; + code_ += " }"; + // Immutable reference accessor. + code_ += + " /// If the union variant matches, return a reference to the " + "{{U_ELEMENT_TABLE_TYPE}}."; + code_ += + " pub fn as_{{U_ELEMENT_NAME}}(&self) -> " + "Option<&{{U_ELEMENT_TABLE_TYPE}}> {"; + code_ += + " if let Self::{{NATIVE_VARIANT}}(v) = self " + "{ Some(v.as_ref()) } else { None }"; + code_ += " }"; + // Mutable reference accessor. + code_ += + " /// If the union variant matches, return a mutable reference" + " to the {{U_ELEMENT_TABLE_TYPE}}."; + code_ += + " pub fn as_{{U_ELEMENT_NAME}}_mut(&mut self) -> " + "Option<&mut {{U_ELEMENT_TABLE_TYPE}}> {"; + code_ += + " if let Self::{{NATIVE_VARIANT}}(v) = self " + "{ Some(v.as_mut()) } else { None }"; + code_ += " }"; + }); + code_ += "}"; // End union methods impl. } std::string GetFieldOffsetName(const FieldDef &field) { @@ -698,11 +830,9 @@ class RustGenerator : public BaseGenerator { } case ftUnionKey: case ftEnumKey: { - if (field.optional) { - return "None"; - } + if (field.optional) { return "None"; } auto ev = field.value.type.enum_def->FindByValue(field.value.constant); - assert(ev); + if (!ev) return "Default::default()"; // Bitflags enum. return WrapInNameSpace(field.value.type.enum_def->defined_namespace, GetEnumValue(*field.value.type.enum_def, *ev)); } @@ -797,6 +927,77 @@ class RustGenerator : public BaseGenerator { return "INVALID_CODE_GENERATION"; // for return analysis } + std::string ObjectFieldType(const FieldDef &field, bool in_a_table) { + const Type &type = field.value.type; + std::string ty; + switch (GetFullType(type)) { + case ftInteger: + case ftBool: + case ftFloat: { + ty = GetTypeBasic(type); + break; + } + case ftString: { + ty = "String"; + break; + } + case ftStruct: { + ty = NamespacedNativeName(*type.struct_def); + break; + } + case ftTable: { + // Since Tables can contain themselves, Box is required to avoid + // infinite types. + ty = "Box<" + NamespacedNativeName(*type.struct_def) + ">"; + break; + } + case ftUnionKey: { + // There is no native "UnionKey", natively, unions are rust enums with + // newtype-struct-variants. + return "INVALID_CODE_GENERATION"; + } + case ftUnionValue: { + ty = NamespacedNativeName(*type.enum_def); + break; + } + case ftEnumKey: { + ty = WrapInNameSpace(*type.enum_def); + break; + } + // Vectors are in tables and are optional + case ftVectorOfEnumKey: { + ty = "Vec<" + WrapInNameSpace(*type.VectorType().enum_def) + ">"; + break; + } + case ftVectorOfInteger: + case ftVectorOfBool: + case ftVectorOfFloat: { + ty = "Vec<" + GetTypeBasic(type.VectorType()) + ">"; + break; + } + case ftVectorOfString: { + ty = "Vec"; + break; + } + case ftVectorOfTable: + case ftVectorOfStruct: { + ty = NamespacedNativeName(*type.VectorType().struct_def); + ty = "Vec<" + ty + ">"; + break; + } + case ftVectorOfUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported"); + return "INVALID_CODE_GENERATION"; // OH NO! + } + } + if (in_a_table && !IsUnion(type) && + (IsScalar(type.base_type) ? field.optional : !field.required)) { + return "Option<" + ty + ">"; + } else { + return ty; + } + } + std::string TableBuilderArgsAddFuncType(const FieldDef &field, const std::string &lifetime) { const Type &type = field.value.type; @@ -834,7 +1035,8 @@ class RustGenerator : public BaseGenerator { ", flatbuffers::ForwardsUOffset>>"; } - case ftEnumKey: { + case ftEnumKey: + case ftUnionKey: { const auto typname = WrapInNameSpace(*type.enum_def); return typname; } @@ -854,10 +1056,6 @@ class RustGenerator : public BaseGenerator { case ftString: { return "flatbuffers::WIPOffset<&" + lifetime + " str>"; } - case ftUnionKey: { - const auto typname = WrapInNameSpace(*type.enum_def); - return typname; - } case ftUnionValue: { return "flatbuffers::WIPOffset"; } @@ -881,9 +1079,9 @@ class RustGenerator : public BaseGenerator { case ftEnumKey: case ftUnionKey: { const auto underlying_typname = GetTypeBasic(type); - return (field.optional ? - "self.fbb_.push_slot_always::<" : - "self.fbb_.push_slot::<") + underlying_typname + ">"; + return (field.optional ? "self.fbb_.push_slot_always::<" + : "self.fbb_.push_slot::<") + + underlying_typname + ">"; } case ftStruct: { @@ -1013,7 +1211,7 @@ class RustGenerator : public BaseGenerator { } case ftUnionKey: case ftEnumKey: { - return WrapInNameSpace(*type.enum_def); + return WrapInNameSpace(*type.enum_def); } case ftTable: { const auto typname = WrapInNameSpace(*type.struct_def); @@ -1034,7 +1232,6 @@ class RustGenerator : public BaseGenerator { case ftVectorOfEnumKey: { const auto typname = WrapInNameSpace(*type.VectorType().enum_def); return WrapForwardsUOffset(WrapVector(typname)); - } case ftVectorOfStruct: { const auto typname = WrapInNameSpace(*type.struct_def); @@ -1045,8 +1242,8 @@ class RustGenerator : public BaseGenerator { return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(typname))); } case ftVectorOfString: { - return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset( - "&" + lifetime + " str"))); + return WrapForwardsUOffset( + WrapVector(WrapForwardsUOffset("&" + lifetime + " str"))); } case ftVectorOfUnionValue: { FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported"); @@ -1061,21 +1258,25 @@ class RustGenerator : public BaseGenerator { const std::string vt_offset = GetFieldOffsetName(field); const std::string typname = FollowType(field.value.type, lifetime); // Default-y fields (scalars so far) are neither optional nor required. - const std::string default_value = !(field.optional || field.required) ? - "Some(" + GetDefaultScalarValue(field) + ")" : "None"; + const std::string default_value = + !(field.optional || field.required) + ? "Some(" + GetDefaultScalarValue(field) + ")" + : "None"; const std::string unwrap = field.optional ? "" : ".unwrap()"; const auto t = GetFullType(field.value.type); // TODO(caspern): Shouldn't 1byte VectorOfEnumKey be slice too? - const std::string safe_slice = ( - t == ftVectorOfStruct || - ((t == ftVectorOfBool || t == ftVectorOfFloat || t == ftVectorOfInteger) - && IsOneByte(field.value.type.VectorType().base_type)) - ) ? ".map(|v| v.safe_slice())" : ""; + const std::string safe_slice = + (t == ftVectorOfStruct || + ((t == ftVectorOfBool || t == ftVectorOfFloat || + t == ftVectorOfInteger) && + IsOneByte(field.value.type.VectorType().base_type))) + ? ".map(|v| v.safe_slice())" + : ""; - return "self._tab.get::<" + typname + ">({{STRUCT_NAME}}::" + - vt_offset + ", " + default_value + ")" + safe_slice + unwrap; + return "self._tab.get::<" + typname + ">({{STRUCT_NAME}}::" + vt_offset + + ", " + default_value + ")" + safe_slice + unwrap; } bool TableFieldReturnsOption(const FieldDef &field) { @@ -1101,19 +1302,18 @@ class RustGenerator : public BaseGenerator { } void ForAllUnionVariantsBesidesNone( - const EnumDef &def, - std::function cb - ) { + const EnumDef &def, std::function cb) { FLATBUFFERS_ASSERT(def.is_union); for (auto it = def.Vals().begin(); it != def.Vals().end(); ++it) { - const EnumVal & ev = **it; + const EnumVal &ev = **it; // TODO(cneo): Can variants be deprecated, should we skip them? if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; } code_.SetValue( "U_ELEMENT_ENUM_TYPE", WrapInNameSpace(def.defined_namespace, GetEnumValue(def, ev))); - code_.SetValue("U_ELEMENT_TABLE_TYPE", + code_.SetValue( + "U_ELEMENT_TABLE_TYPE", WrapInNameSpace(ev.union_type.struct_def->defined_namespace, ev.union_type.struct_def->name)); code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev))); @@ -1121,12 +1321,12 @@ class RustGenerator : public BaseGenerator { } } - void ForAllTableFields( - const StructDef &struct_def, - std::function cb, bool reversed=false) { + void ForAllTableFields(const StructDef &struct_def, + std::function cb, + bool reversed = false) { // TODO(cneo): Remove `reversed` overload. It's only here to minimize the // diff when refactoring to the `ForAllX` helper functions. - auto go = [&](const FieldDef& field) { + auto go = [&](const FieldDef &field) { if (field.deprecated) return; code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field)); code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset)); @@ -1178,9 +1378,7 @@ class RustGenerator : public BaseGenerator { code_ += " pub fn init_from_table(table: flatbuffers::Table<'a>) -> " "Self {"; - code_ += " {{STRUCT_NAME}} {"; - code_ += " _tab: table,"; - code_ += " }"; + code_ += " {{STRUCT_NAME}} { _tab: table }"; code_ += " }"; // Generate a convenient create* function that uses the above builder @@ -1200,27 +1398,140 @@ class RustGenerator : public BaseGenerator { code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);"; for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; size; size /= 2) { - ForAllTableFields(struct_def, [&](const FieldDef &field) { - if (struct_def.sortbysize && size != SizeOf(field.value.type.base_type)) - return; - if (TableFieldReturnsOption(field)) { - code_ += - " if let Some(x) = args.{{FIELD_NAME}} " - "{ builder.add_{{FIELD_NAME}}(x); }"; - } else { - code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});"; - } - }, /*reverse=*/true); + ForAllTableFields( + struct_def, + [&](const FieldDef &field) { + if (struct_def.sortbysize && + size != SizeOf(field.value.type.base_type)) + return; + if (TableFieldReturnsOption(field)) { + code_ += + " if let Some(x) = args.{{FIELD_NAME}} " + "{ builder.add_{{FIELD_NAME}}(x); }"; + } else { + code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});"; + } + }, + /*reverse=*/true); } code_ += " builder.finish()"; code_ += " }"; code_ += ""; + // Generate Object API Packer function. + if (parser_.opts.generate_object_based_api) { + // TODO(cneo): Replace more for loops with ForAllX stuff. + // TODO(cneo): Manage indentation with IncrementIdentLevel? + code_.SetValue("OBJECT_NAME", NativeName(struct_def)); + code_ += " pub fn unpack(&self) -> {{OBJECT_NAME}} {"; + ForAllObjectTableFields(struct_def, [&](const FieldDef &field) { + const Type &type = field.value.type; + switch (GetFullType(type)) { + case ftInteger: + case ftBool: + case ftFloat: + case ftEnumKey: { + code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}();"; + return; + } + case ftUnionKey: return; + case ftUnionValue: { + const auto &enum_def = *type.enum_def; + code_.SetValue("ENUM_NAME", Name(enum_def)); + code_.SetValue("NATIVE_ENUM_NAME", NativeName(enum_def)); + code_ += + " let {{FIELD_NAME}} = match " + "self.{{FIELD_NAME}}_type() {"; + code_ += + " {{ENUM_NAME}}::NONE =>" + " {{NATIVE_ENUM_NAME}}::NONE,"; + ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { + code_ += + " {{ENUM_NAME}}::{{VARIANT_NAME}} => " + "{{NATIVE_ENUM_NAME}}::{{NATIVE_VARIANT}}(Box::new("; + code_ += + " self.{{FIELD_NAME}}_as_" + "{{U_ELEMENT_NAME}}()"; + code_ += + " .expect(\"Invalid union table, " + "expected `{{ENUM_NAME}}::{{VARIANT_NAME}}`.\")"; + code_ += " .unpack()"; + code_ += " )),"; + }); + // Maybe we shouldn't throw away unknown discriminants? + code_ += " _ => {{NATIVE_ENUM_NAME}}::NONE,"; + code_ += " };"; + return; + } + // The rest of the types need special handling based on if the field + // is optional or not. + case ftString: { + code_.SetValue("EXPR", "x.to_string()"); + break; + } + case ftStruct: { + code_.SetValue("EXPR", "x.unpack()"); + break; + } + case ftTable: { + code_.SetValue("EXPR", "Box::new(x.unpack())"); + break; + } + case ftVectorOfInteger: + case ftVectorOfBool: { + if (IsOneByte(type.VectorType().base_type)) { + // 1 byte stuff is viewed w/ slice instead of flatbuffer::Vector + // and thus needs to be cloned out of the slice. + code_.SetValue("EXPR", "x.to_vec()"); + break; + } + code_.SetValue("EXPR", "x.into_iter().collect()"); + break; + } + case ftVectorOfFloat: + case ftVectorOfEnumKey: { + code_.SetValue("EXPR", "x.into_iter().collect()"); + break; + } + case ftVectorOfString: { + code_.SetValue("EXPR", "x.iter().map(|s| s.to_string()).collect()"); + break; + } + case ftVectorOfStruct: + case ftVectorOfTable: { + code_.SetValue("EXPR", "x.iter().map(|t| t.unpack()).collect()"); + break; + } + case ftVectorOfUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported"); + return; + } + } + if (field.optional) { + code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}().map(|x| {"; + code_ += " {{EXPR}}"; + code_ += " });"; + } else { + code_ += " let {{FIELD_NAME}} = {"; + code_ += " let x = self.{{FIELD_NAME}}();"; + code_ += " {{EXPR}}"; + code_ += " };"; + } + }); + code_ += " {{OBJECT_NAME}} {"; + ForAllObjectTableFields(struct_def, [&](const FieldDef &field) { + if (field.value.type.base_type == BASE_TYPE_UTYPE) return; + code_ += " {{FIELD_NAME}},"; + }); + code_ += " }"; + code_ += " }"; + } // Generate field id constants. - ForAllTableFields(struct_def, [&](const FieldDef &unused){ - (void) unused; - code_ += " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = " - "{{OFFSET_VALUE}};"; + ForAllTableFields(struct_def, [&](const FieldDef &unused) { + (void)unused; + code_ += + " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = " + "{{OFFSET_VALUE}};"; }); if (struct_def.fields.vec.size() > 0) code_ += ""; @@ -1261,20 +1572,21 @@ class RustGenerator : public BaseGenerator { FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser. code_.SetValue("NESTED", WrapInNameSpace(*nested_root)); - code_ += - " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> \\"; + code_ += " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> \\"; if (field.required) { code_ += "{{NESTED}}<'a> {"; code_ += " let data = self.{{FIELD_NAME}}();"; code_ += " use flatbuffers::Follow;"; - code_ += " >>" - "::follow(data, 0)"; + code_ += + " >>" + "::follow(data, 0)"; } else { code_ += "Option<{{NESTED}}<'a>> {"; code_ += " self.{{FIELD_NAME}}().map(|data| {"; code_ += " use flatbuffers::Follow;"; - code_ += " >>" - "::follow(data, 0)"; + code_ += + " >>" + "::follow(data, 0)"; code_ += " })"; } code_ += " }"; @@ -1286,45 +1598,45 @@ class RustGenerator : public BaseGenerator { if (field.value.type.base_type != BASE_TYPE_UNION) return; code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name); ForAllUnionVariantsBesidesNone( - *field.value.type.enum_def, [&](const EnumVal &unused){ - (void) unused; - code_ += " #[inline]"; - code_ += " #[allow(non_snake_case)]"; - code_ += - " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> " - "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {"; - // If the user defined schemas name a field that clashes with a - // language reserved word, flatc will try to escape the field name by - // appending an underscore. This works well for most cases, except - // one. When generating union accessors (and referring to them - // internally within the code generated here), an extra underscore - // will be appended to the name, causing build failures. - // - // This only happens when unions have members that overlap with - // language reserved words. - // - // To avoid this problem the type field name is used unescaped here: - code_ += - " if self.{{FIELD_TYPE_FIELD_NAME}}_type() == " - "{{U_ELEMENT_ENUM_TYPE}} {"; + *field.value.type.enum_def, [&](const EnumVal &unused) { + (void)unused; + code_ += " #[inline]"; + code_ += " #[allow(non_snake_case)]"; + code_ += + " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> " + "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {"; + // If the user defined schemas name a field that clashes with a + // language reserved word, flatc will try to escape the field name + // by appending an underscore. This works well for most cases, + // except one. When generating union accessors (and referring to + // them internally within the code generated here), an extra + // underscore will be appended to the name, causing build failures. + // + // This only happens when unions have members that overlap with + // language reserved words. + // + // To avoid this problem the type field name is used unescaped here: + code_ += + " if self.{{FIELD_TYPE_FIELD_NAME}}_type() == " + "{{U_ELEMENT_ENUM_TYPE}} {"; - // The following logic is not tested in the integration test, - // as of April 10, 2020 - if (field.required) { - code_ += " let u = self.{{FIELD_NAME}}();"; - code_ += " Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))"; - } else { - code_ += - " self.{{FIELD_NAME}}().map(" - "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)"; - } - code_ += " } else {"; - code_ += " None"; - code_ += " }"; - code_ += " }"; - code_ += ""; - - }); + // The following logic is not tested in the integration test, + // as of April 10, 2020 + if (field.required) { + code_ += " let u = self.{{FIELD_NAME}}();"; + code_ += + " Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))"; + } else { + code_ += + " self.{{FIELD_NAME}}().map(" + "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)"; + } + code_ += " } else {"; + code_ += " None"; + code_ += " }"; + code_ += " }"; + code_ += ""; + }); }); code_ += "}"; // End of table impl. code_ += ""; @@ -1346,23 +1658,26 @@ class RustGenerator : public BaseGenerator { if (GetFullType(field.value.type) != ftUnionValue) { // All types besides unions. code_.SetValue("TY", FollowType(field.value.type, "'_")); - code_ += "\n .visit_field::<{{TY}}>(&\"{{FIELD_NAME}}\", " - "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\"; - return; + code_ += + "\n .visit_field::<{{TY}}>(&\"{{FIELD_NAME}}\", " + "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\"; + return; } // Unions. EnumDef &union_def = *field.value.type.enum_def; code_.SetValue("UNION_TYPE", Name(union_def)); - code_ += "\n .visit_union::<{{UNION_TYPE}}, _>(" - "&\"{{FIELD_NAME}}_type\", Self::{{OFFSET_NAME}}_TYPE, " - "&\"{{FIELD_NAME}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, " - "|key, v, pos| {"; + code_ += + "\n .visit_union::<{{UNION_TYPE}}, _>(" + "&\"{{FIELD_NAME}}_type\", Self::{{OFFSET_NAME}}_TYPE, " + "&\"{{FIELD_NAME}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, " + "|key, v, pos| {"; code_ += " match key {"; ForAllUnionVariantsBesidesNone(union_def, [&](const EnumVal &unused) { - (void) unused; - code_ += " {{U_ELEMENT_ENUM_TYPE}} => v.verify_union_variant::" - ">(" - "\"{{U_ELEMENT_ENUM_TYPE}}\", pos),"; + (void)unused; + code_ += + " {{U_ELEMENT_ENUM_TYPE}} => v.verify_union_variant::" + ">(" + "\"{{U_ELEMENT_ENUM_TYPE}}\", pos),"; }); code_ += " _ => Ok(()),"; code_ += " }"; @@ -1424,8 +1739,9 @@ class RustGenerator : public BaseGenerator { code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b ")); code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field)); code_ += " #[inline]"; - code_ += " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: " - "{{FIELD_TYPE}}) {"; + code_ += + " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: " + "{{FIELD_TYPE}}) {"; if (is_scalar && !field.optional) { code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, " @@ -1468,30 +1784,35 @@ class RustGenerator : public BaseGenerator { code_ += ""; code_ += "impl std::fmt::Debug for {{STRUCT_NAME}}<'_> {"; - code_ += " fn fmt(&self, f: &mut std::fmt::Formatter<'_>" - ") -> std::fmt::Result {"; + code_ += + " fn fmt(&self, f: &mut std::fmt::Formatter<'_>" + ") -> std::fmt::Result {"; code_ += " let mut ds = f.debug_struct(\"{{STRUCT_NAME}}\");"; ForAllTableFields(struct_def, [&](const FieldDef &field) { if (GetFullType(field.value.type) == ftUnionValue) { // Generate a match statement to handle unions properly. code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, "")); code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name); - code_.SetValue("UNION_ERR", "&\"InvalidFlatbuffer: Union discriminant" - " does not match value.\""); + code_.SetValue("UNION_ERR", + "&\"InvalidFlatbuffer: Union discriminant" + " does not match value.\""); code_ += " match self.{{FIELD_NAME}}_type() {"; - ForAllUnionVariantsBesidesNone(*field.value.type.enum_def, - [&](const EnumVal &unused){ - (void) unused; - code_ += " {{U_ELEMENT_ENUM_TYPE}} => {"; - code_ += " if let Some(x) = self.{{FIELD_TYPE_FIELD_NAME}}_as_" - "{{U_ELEMENT_NAME}}() {"; - code_ += " ds.field(\"{{FIELD_NAME}}\", &x)"; - code_ += " } else {"; - code_ += " ds.field(\"{{FIELD_NAME}}\", {{UNION_ERR}})"; - code_ += " }"; - code_ += " },"; - }); + ForAllUnionVariantsBesidesNone( + *field.value.type.enum_def, [&](const EnumVal &unused) { + (void)unused; + code_ += " {{U_ELEMENT_ENUM_TYPE}} => {"; + code_ += + " if let Some(x) = " + "self.{{FIELD_TYPE_FIELD_NAME}}_as_" + "{{U_ELEMENT_NAME}}() {"; + code_ += " ds.field(\"{{FIELD_NAME}}\", &x)"; + code_ += " } else {"; + code_ += + " ds.field(\"{{FIELD_NAME}}\", {{UNION_ERR}})"; + code_ += " }"; + code_ += " },"; + }); code_ += " _ => { "; code_ += " let x: Option<()> = None;"; code_ += " ds.field(\"{{FIELD_NAME}}\", &x)"; @@ -1507,6 +1828,150 @@ class RustGenerator : public BaseGenerator { code_ += "}"; } + void GenTableObject(const StructDef &table) { + code_.SetValue("OBJECT_NAME", NativeName(table)); + code_.SetValue("STRUCT_NAME", Name(table)); + + // Generate the native object. + code_ += "#[non_exhaustive]"; + code_ += "#[derive(Debug, Clone, PartialEq, Default)]"; + code_ += "pub struct {{OBJECT_NAME}} {"; + ForAllObjectTableFields(table, [&](const FieldDef &field) { + // Union objects combine both the union discriminant and value, so we + // skip making a field for the discriminant. + if (field.value.type.base_type == BASE_TYPE_UTYPE) return; + code_ += " pub {{FIELD_NAME}}: {{FIELD_OBJECT_TYPE}},"; + }); + code_ += "}"; + + // TODO(cneo): Generate defaults for Native tables. However, since structs + // may be required, they, and therefore enums need defaults. + + // Generate pack function. + code_ += "impl {{OBJECT_NAME}} {"; + code_ += " pub fn pack<'b>("; + code_ += " &self,"; + code_ += " _fbb: &mut flatbuffers::FlatBufferBuilder<'b>"; + code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'b>> {"; + // First we generate variables for each field and then later assemble them + // using "StructArgs" to more easily manage ownership of the builder. + ForAllObjectTableFields(table, [&](const FieldDef &field) { + const Type &type = field.value.type; + switch (GetFullType(type)) { + case ftInteger: + case ftBool: + case ftFloat: + case ftEnumKey: { + code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}};"; + return; + } + case ftUnionKey: return; // Generate union type with union value. + case ftUnionValue: { + code_.SetValue("SNAKE_CASE_ENUM_NAME", + MakeSnakeCase(Name(*field.value.type.enum_def))); + code_ += + " let {{FIELD_NAME}}_type = " + "self.{{FIELD_NAME}}.{{SNAKE_CASE_ENUM_NAME}}_type();"; + code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}.pack(_fbb);"; + return; + } + // The rest of the types require special casing around optionalness + // due to "required" annotation. + case ftString: { + MapNativeTableField(field, "_fbb.create_string(x)"); + return; + } + case ftStruct: { + // Hold the struct in a variable so we can reference it. + if (field.required) { + code_ += + " let {{FIELD_NAME}}_tmp = " + "Some(self.{{FIELD_NAME}}.pack());"; + } else { + code_ += + " let {{FIELD_NAME}}_tmp = self.{{FIELD_NAME}}" + ".as_ref().map(|x| x.pack());"; + } + code_ += " let {{FIELD_NAME}} = {{FIELD_NAME}}_tmp.as_ref();"; + + return; + } + case ftTable: { + MapNativeTableField(field, "x.pack(_fbb)"); + return; + } + case ftVectorOfEnumKey: + case ftVectorOfInteger: + case ftVectorOfBool: + case ftVectorOfFloat: { + MapNativeTableField(field, "_fbb.create_vector(x)"); + return; + } + case ftVectorOfStruct: { + MapNativeTableField( + field, + "let w: Vec<_> = x.iter().map(|t| t.pack()).collect();" + "_fbb.create_vector(&w)"); + return; + } + case ftVectorOfString: { + // TODO(cneo): create_vector* should be more generic to avoid + // allocations. + + MapNativeTableField( + field, + "let w: Vec<_> = x.iter().map(|s| s.as_ref()).collect();" + "_fbb.create_vector_of_strings(&w)"); + return; + } + case ftVectorOfTable: { + MapNativeTableField( + field, + "let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();" + "_fbb.create_vector(&w)"); + return; + } + case ftVectorOfUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported"); + return; + } + } + }); + code_ += " {{STRUCT_NAME}}::create(_fbb, &{{STRUCT_NAME}}Args{"; + ForAllObjectTableFields(table, [&](const FieldDef &field) { + (void)field; // Unused. + code_ += " {{FIELD_NAME}},"; + }); + code_ += " })"; + code_ += " }"; + code_ += "}"; + } + void ForAllObjectTableFields(const StructDef &table, + std::function cb) { + const std::vector &v = table.fields.vec; + for (auto it = v.begin(); it != v.end(); it++) { + const FieldDef &field = **it; + if (field.deprecated) continue; + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("FIELD_OBJECT_TYPE", ObjectFieldType(field, true)); + cb(field); + } + } + void MapNativeTableField(const FieldDef &field, const std::string &expr) { + if (field.required) { + // For some reason Args has optional types for required fields. + // TODO(cneo): Fix this... but its a breaking change? + code_ += " let {{FIELD_NAME}} = Some({"; + code_ += " let x = &self.{{FIELD_NAME}};"; + code_ += " " + expr; + code_ += " });"; + } else { + code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}.as_ref().map(|x|{"; + code_ += " " + expr; + code_ += " });"; + } + } + // Generate functions to compare tables and structs by key. This function // must only be called if the field key is defined. void GenKeyFieldMethods(const FieldDef &field) { @@ -1542,19 +2007,22 @@ class RustGenerator : public BaseGenerator { // The root datatype accessors: code_ += "#[inline]"; - code_ += "#[deprecated(since=\"2.0.0\", " - "note=\"Deprecated in favor of `root_as...` methods.\")]"; + code_ += + "#[deprecated(since=\"2.0.0\", " + "note=\"Deprecated in favor of `root_as...` methods.\")]"; code_ += "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])" " -> {{STRUCT_NAME}}<'a> {"; - code_ += " unsafe { flatbuffers::root_unchecked::<{{STRUCT_NAME}}" - "<'a>>(buf) }"; + code_ += + " unsafe { flatbuffers::root_unchecked::<{{STRUCT_NAME}}" + "<'a>>(buf) }"; code_ += "}"; code_ += ""; code_ += "#[inline]"; - code_ += "#[deprecated(since=\"2.0.0\", " - "note=\"Deprecated in favor of `root_as...` methods.\")]"; + code_ += + "#[deprecated(since=\"2.0.0\", " + "note=\"Deprecated in favor of `root_as...` methods.\")]"; code_ += "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {"; @@ -1571,8 +2039,9 @@ class RustGenerator : public BaseGenerator { code_ += "/// catch every error, or be maximally performant. For the"; code_ += "/// previous, unchecked, behavior use"; code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`."; - code_ += "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}(buf: &[u8]) " - "-> Result<{{STRUCT_NAME}}, flatbuffers::InvalidFlatbuffer> {"; + code_ += + "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}(buf: &[u8]) " + "-> Result<{{STRUCT_NAME}}, flatbuffers::InvalidFlatbuffer> {"; code_ += " flatbuffers::root::<{{STRUCT_NAME}}>(buf)"; code_ += "}"; code_ += "#[inline]"; @@ -1582,9 +2051,10 @@ class RustGenerator : public BaseGenerator { code_ += "/// catch every error, or be maximally performant. For the"; code_ += "/// previous, unchecked, behavior use"; code_ += "/// `size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`."; - code_ += "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" - "(buf: &[u8]) -> Result<{{STRUCT_NAME}}, " - "flatbuffers::InvalidFlatbuffer> {"; + code_ += + "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" + "(buf: &[u8]) -> Result<{{STRUCT_NAME}}, " + "flatbuffers::InvalidFlatbuffer> {"; code_ += " flatbuffers::size_prefixed_root::<{{STRUCT_NAME}}>(buf)"; code_ += "}"; // Verifier with options root fns. @@ -1598,8 +2068,9 @@ class RustGenerator : public BaseGenerator { code_ += "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts<'b, 'o>("; code_ += " opts: &'o flatbuffers::VerifierOptions,"; code_ += " buf: &'b [u8],"; - code_ += ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>" - " {"; + code_ += + ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>" + " {"; code_ += " flatbuffers::root_with_opts::<{{STRUCT_NAME}}<'b>>(opts, buf)"; code_ += "}"; code_ += "#[inline]"; @@ -1609,39 +2080,48 @@ class RustGenerator : public BaseGenerator { code_ += "/// catch every error, or be maximally performant. For the"; code_ += "/// previous, unchecked, behavior use"; code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`."; - code_ += "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts" - "<'b, 'o>("; + code_ += + "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts" + "<'b, 'o>("; code_ += " opts: &'o flatbuffers::VerifierOptions,"; code_ += " buf: &'b [u8],"; - code_ += ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>" - " {"; - code_ += " flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_NAME}}" - "<'b>>(opts, buf)"; + code_ += + ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>" + " {"; + code_ += + " flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_NAME}}" + "<'b>>(opts, buf)"; code_ += "}"; // Unchecked root fns. code_ += "#[inline]"; - code_ += "/// Assumes, without verification, that a buffer of bytes " - "contains a {{STRUCT_NAME}} and returns it."; + code_ += + "/// Assumes, without verification, that a buffer of bytes " + "contains a {{STRUCT_NAME}} and returns it."; code_ += "/// # Safety"; - code_ += "/// Callers must trust the given bytes do indeed contain a valid" - " `{{STRUCT_NAME}}`."; - code_ += "pub unsafe fn root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked" - "(buf: &[u8]) -> {{STRUCT_NAME}} {"; + code_ += + "/// Callers must trust the given bytes do indeed contain a valid" + " `{{STRUCT_NAME}}`."; + code_ += + "pub unsafe fn root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked" + "(buf: &[u8]) -> {{STRUCT_NAME}} {"; code_ += " flatbuffers::root_unchecked::<{{STRUCT_NAME}}>(buf)"; code_ += "}"; code_ += "#[inline]"; - code_ += "/// Assumes, without verification, that a buffer of bytes " - "contains a size prefixed {{STRUCT_NAME}} and returns it."; + code_ += + "/// Assumes, without verification, that a buffer of bytes " + "contains a size prefixed {{STRUCT_NAME}} and returns it."; code_ += "/// # Safety"; - code_ += "/// Callers must trust the given bytes do indeed contain a valid" - " size prefixed `{{STRUCT_NAME}}`."; - code_ += "pub unsafe fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" - "_unchecked(buf: &[u8]) -> {{STRUCT_NAME}} {"; - code_ += " flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}>" - "(buf)"; + code_ += + "/// Callers must trust the given bytes do indeed contain a valid" + " size prefixed `{{STRUCT_NAME}}`."; + code_ += + "pub unsafe fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" + "_unchecked(buf: &[u8]) -> {{STRUCT_NAME}} {"; + code_ += + " flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}>" + "(buf)"; code_ += "}"; - if (parser_.file_identifier_.length()) { // Declare the identifier // (no lifetime needed as constants have static lifetimes by default) @@ -1725,15 +2205,14 @@ class RustGenerator : public BaseGenerator { *code_ptr += "padding" + NumToString((*id)++) + "__: 0,"; } - void ForAllStructFields( - const StructDef &struct_def, - std::function cb - ) { + void ForAllStructFields(const StructDef &struct_def, + std::function cb) { size_t offset_to_field = 0; for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type)); + code_.SetValue("FIELD_OBJECT_TYPE", ObjectFieldType(field, false)); code_.SetValue("FIELD_NAME", Name(field)); code_.SetValue("FIELD_OFFSET", NumToString(offset_to_field)); code_.SetValue("REF", IsStruct(field.value.type) ? "&" : ""); @@ -1759,16 +2238,17 @@ class RustGenerator : public BaseGenerator { // hold for PartialOrd/Ord. code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}"; code_ += "#[repr(transparent)]"; - code_ += "#[derive(Clone, Copy, PartialEq)]"; + code_ += "#[derive(Clone, Copy, PartialEq, Default)]"; code_ += "pub struct {{STRUCT_NAME}}(pub [u8; {{STRUCT_SIZE}}]);"; // Debug for structs. code_ += "impl std::fmt::Debug for {{STRUCT_NAME}} {"; - code_ += " fn fmt(&self, f: &mut std::fmt::Formatter" - ") -> std::fmt::Result {"; + code_ += + " fn fmt(&self, f: &mut std::fmt::Formatter" + ") -> std::fmt::Result {"; code_ += " f.debug_struct(\"{{STRUCT_NAME}}\")"; ForAllStructFields(struct_def, [&](const FieldDef &unused) { - (void) unused; + (void)unused; code_ += " .field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}())"; }); code_ += " .finish()"; @@ -1776,7 +2256,6 @@ class RustGenerator : public BaseGenerator { code_ += "}"; code_ += ""; - // Generate impls for SafeSliceAccess (because all structs are endian-safe), // Follow for the value type, Follow for the reference type, Push for the // value type, and Push for the reference type. @@ -1906,14 +2385,54 @@ class RustGenerator : public BaseGenerator { // Generate a comparison function for this field if it is a key. if (field.key) { GenKeyFieldMethods(field); } }); - code_ += "}"; + + // Generate Object API unpack method. + if (parser_.opts.generate_object_based_api) { + code_.SetValue("NATIVE_STRUCT_NAME", NativeName(struct_def)); + code_ += " pub fn unpack(&self) -> {{NATIVE_STRUCT_NAME}} {"; + code_ += " {{NATIVE_STRUCT_NAME}} {"; + ForAllStructFields(struct_def, [&](const FieldDef &field) { + std::string unpack = IsStruct(field.value.type) ? ".unpack()" : ""; + code_ += " {{FIELD_NAME}}: self.{{FIELD_NAME}}()" + unpack + ","; + }); + code_ += " }"; + code_ += " }"; + } + + code_ += "}"; // End impl Struct methods. code_ += ""; + + // Generate Struct Object. + if (parser_.opts.generate_object_based_api) { + // Struct declaration + code_ += "#[derive(Debug, Clone, PartialEq, Default)]"; + code_ += "pub struct {{NATIVE_STRUCT_NAME}} {"; + ForAllStructFields(struct_def, [&](const FieldDef &field) { + (void)field; // unused. + code_ += " pub {{FIELD_NAME}}: {{FIELD_OBJECT_TYPE}},"; + }); + code_ += "}"; + // The `pack` method that turns the native struct into its Flatbuffers + // counterpart. + code_ += "impl {{NATIVE_STRUCT_NAME}} {"; + code_ += " pub fn pack(&self) -> {{STRUCT_NAME}} {"; + code_ += " {{STRUCT_NAME}}::new("; + ForAllStructFields(struct_def, [&](const FieldDef &field) { + if (IsStruct(field.value.type)) { + code_ += " &self.{{FIELD_NAME}}.pack(),"; + } else { + code_ += " self.{{FIELD_NAME}},"; + } + }); + code_ += " )"; + code_ += " }"; + code_ += "}"; + code_ += ""; + } } void GenNamespaceImports(const int white_spaces) { - if (white_spaces == 0) { - code_ += "#![allow(unused_imports, dead_code)]"; - } + if (white_spaces == 0) { code_ += "#![allow(unused_imports, dead_code)]"; } std::string indent = std::string(white_spaces, ' '); code_ += ""; if (!parser_.opts.generate_all) { @@ -1935,7 +2454,6 @@ class RustGenerator : public BaseGenerator { } } } - code_ += indent + "use std::mem;"; code_ += indent + "use std::cmp::Ordering;"; code_ += ""; diff --git a/tests/RustTest.sh b/tests/RustTest.sh index a74690af4..7fa649266 100755 --- a/tests/RustTest.sh +++ b/tests/RustTest.sh @@ -21,33 +21,30 @@ if [[ "$1" == "mips-unknown-linux-gnu" ]]; then export CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER="qemu-mips -L /usr/mips-linux-gnu" fi + +function check_test_result() { + if [[ $? == 0 ]]; then + echo OK: $1 passed. + else + echo KO: $1 failed. + exit 1 + fi +} + cd ./rust_usage_test cargo test $TARGET_FLAG -- --quiet -TEST_RESULT=$? -if [[ $TEST_RESULT == 0 ]]; then - echo "OK: Rust tests passed." -else - echo "KO: Rust tests failed." - exit 1 -fi +check_test_result "Rust tests" + cargo run $TARGET_FLAG --bin=flatbuffers_alloc_check -TEST_RESULT=$? -if [[ $TEST_RESULT == 0 ]]; then - echo "OK: Rust heap alloc test passed." -else - echo "KO: Rust heap alloc test failed." - exit 1 -fi +check_test_result "Rust flatbuffers heap alloc test" cargo run $TARGET_FLAG --bin=flexbuffers_alloc_check -TEST_RESULT=$? -if [[ $TEST_RESULT == 0 ]]; then - echo "OK: Rust heap alloc test passed." -else - echo "KO: Rust heap alloc test failed." - exit 1 -fi +check_test_result "Rust flexbuffers heap alloc test" + +rustup component add clippy +cargo clippy $TARGET_FLAG +check_test_result "No Cargo clippy lints test" cargo bench $TARGET_FLAG diff --git a/tests/generate_code.bat b/tests/generate_code.bat index 045e68833..7972d1c78 100644 --- a/tests/generate_code.bat +++ b/tests/generate_code.bat @@ -55,8 +55,8 @@ set TEST_NOINCL_FLAGS=%TEST_BASE_FLAGS% --no-includes ..\%buildtype%\flatc.exe --cpp %TEST_BASE_FLAGS% --cpp-ptr-type flatbuffers::unique_ptr native_type_test.fbs || goto FAIL @rem Generate the optional scalar code for tests. -..\%buildtype%\flatc.exe --java --kotlin --rust --lobster --ts optional_scalars.fbs || goto FAIL -..\%buildtype%\flatc.exe --csharp --gen-object-api optional_scalars.fbs || goto FAIL +..\%buildtype%\flatc.exe --java --kotlin --lobster --ts optional_scalars.fbs || goto FAIL +..\%buildtype%\flatc.exe --csharp --rust --gen-object-api optional_scalars.fbs || goto FAIL ..\%buildtype%\flatc.exe %TEST_NOINCL_FLAGS% %TEST_CPP_FLAGS% --cpp optional_scalars.fbs || goto FAIL @rem Generate the schema evolution tests diff --git a/tests/generate_code.sh b/tests/generate_code.sh index e07446233..f8229c497 100755 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -53,8 +53,8 @@ $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS $TEST_JS_TS_FLAGS -o namespace ../flatc --dart monster_extra.fbs # Generate optional scalar code for tests. -../flatc --java --kotlin --rust --lobster --ts optional_scalars.fbs -../flatc --csharp --gen-object-api optional_scalars.fbs +../flatc --java --kotlin --lobster --ts optional_scalars.fbs +../flatc --csharp --rust --gen-object-api optional_scalars.fbs ../flatc $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS --cpp optional_scalars.fbs # Generate the schema evolution tests diff --git a/tests/include_test/include_test1_generated.rs b/tests/include_test/include_test1_generated.rs index 23c0d3f44..4015a3c8f 100644 --- a/tests/include_test/include_test1_generated.rs +++ b/tests/include_test/include_test1_generated.rs @@ -28,9 +28,7 @@ impl<'a> flatbuffers::Follow<'a> for TableA<'a> { impl<'a> TableA<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - TableA { - _tab: table, - } + TableA { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( diff --git a/tests/include_test/sub/include_test2_generated.rs b/tests/include_test/sub/include_test2_generated.rs index a0137b9c8..9b3c7ee67 100644 --- a/tests/include_test/sub/include_test2_generated.rs +++ b/tests/include_test/sub/include_test2_generated.rs @@ -39,7 +39,7 @@ pub const ENUM_VALUES_FROM_INCLUDE: [FromInclude; 1] = [ FromInclude::IncludeVal, ]; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[repr(transparent)] pub struct FromInclude(pub i64); #[allow(non_upper_case_globals)] @@ -111,7 +111,7 @@ impl<'a> flatbuffers::Verifiable for FromInclude { impl flatbuffers::SimpleToVerifyInSlice for FromInclude {} // struct Unused, aligned to 4 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Default)] pub struct Unused(pub [u8; 4]); impl std::fmt::Debug for Unused { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -221,9 +221,7 @@ impl<'a> flatbuffers::Follow<'a> for TableB<'a> { impl<'a> TableB<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - TableB { - _tab: table, - } + TableB { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( diff --git a/tests/monster_test_generated.rs b/tests/monster_test_generated.rs index 59c8f1425..3f8714ba7 100644 --- a/tests/monster_test_generated.rs +++ b/tests/monster_test_generated.rs @@ -44,9 +44,7 @@ impl<'a> InParentNamespace<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - InParentNamespace { - _tab: table, - } + InParentNamespace { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -56,6 +54,10 @@ impl<'a> InParentNamespace<'a> { builder.finish() } + pub fn unpack(&self) -> InParentNamespaceT { + InParentNamespaceT { + } + } } impl flatbuffers::Verifiable for InParentNamespace<'_> { @@ -104,6 +106,19 @@ impl std::fmt::Debug for InParentNamespace<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct InParentNamespaceT { +} +impl InParentNamespaceT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + InParentNamespace::create(_fbb, &InParentNamespaceArgs{ + }) + } +} #[allow(unused_imports, dead_code)] pub mod example_2 { @@ -137,9 +152,7 @@ impl<'a> Monster<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - Monster { - _tab: table, - } + Monster { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -149,6 +162,10 @@ impl<'a> Monster<'a> { builder.finish() } + pub fn unpack(&self) -> MonsterT { + MonsterT { + } + } } impl flatbuffers::Verifiable for Monster<'_> { @@ -197,6 +214,19 @@ impl std::fmt::Debug for Monster<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct MonsterT { +} +impl MonsterT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + Monster::create(_fbb, &MonsterArgs{ + }) + } +} } // pub mod Example2 #[allow(unused_imports, dead_code)] @@ -214,6 +244,7 @@ pub mod example { mod bitflags_color { flatbuffers::bitflags::bitflags! { /// Composite components of Monster color. + #[derive(Default)] pub struct Color: u8 { const Red = 1; /// \brief color Green @@ -280,7 +311,7 @@ pub const ENUM_VALUES_RACE: [Race; 4] = [ Race::Elf, ]; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[repr(transparent)] pub struct Race(pub i8); #[allow(non_upper_case_globals)] @@ -372,7 +403,7 @@ pub const ENUM_VALUES_ANY: [Any; 4] = [ Any::MyGame_Example2_Monster, ]; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[repr(transparent)] pub struct Any(pub u8); #[allow(non_upper_case_globals)] @@ -410,7 +441,6 @@ impl std::fmt::Debug for Any { } } } -pub struct AnyUnionTableOffset {} impl<'a> flatbuffers::Follow<'a> for Any { type Inner = Self; #[inline] @@ -452,6 +482,102 @@ impl<'a> flatbuffers::Verifiable for Any { } impl flatbuffers::SimpleToVerifyInSlice for Any {} +pub struct AnyUnionTableOffset {} + +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq)] +pub enum AnyT { + NONE, + Monster(Box), + TestSimpleTableWithEnum(Box), + MyGameExample2Monster(Box), +} +impl Default for AnyT { + fn default() -> Self { + Self::NONE + } +} +impl AnyT { + fn any_type(&self) -> Any { + match self { + Self::NONE => Any::NONE, + Self::Monster(_) => Any::Monster, + Self::TestSimpleTableWithEnum(_) => Any::TestSimpleTableWithEnum, + Self::MyGameExample2Monster(_) => Any::MyGame_Example2_Monster, + } + } + pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder) -> Option> { + match self { + Self::NONE => None, + Self::Monster(v) => Some(v.pack(fbb).as_union_value()), + Self::TestSimpleTableWithEnum(v) => Some(v.pack(fbb).as_union_value()), + Self::MyGameExample2Monster(v) => Some(v.pack(fbb).as_union_value()), + } + } + /// If the union variant matches, return the owned MonsterT, setting the union to NONE. + pub fn take_monster(&mut self) -> Option> { + if let Self::Monster(_) = self { + let v = std::mem::replace(self, Self::NONE); + if let Self::Monster(w) = v { + Some(w) + } else { + unreachable!() + } + } else { + None + } + } + /// If the union variant matches, return a reference to the MonsterT. + pub fn as_monster(&self) -> Option<&MonsterT> { + if let Self::Monster(v) = self { Some(v.as_ref()) } else { None } + } + /// If the union variant matches, return a mutable reference to the MonsterT. + pub fn as_monster_mut(&mut self) -> Option<&mut MonsterT> { + if let Self::Monster(v) = self { Some(v.as_mut()) } else { None } + } + /// If the union variant matches, return the owned TestSimpleTableWithEnumT, setting the union to NONE. + pub fn take_test_simple_table_with_enum(&mut self) -> Option> { + if let Self::TestSimpleTableWithEnum(_) = self { + let v = std::mem::replace(self, Self::NONE); + if let Self::TestSimpleTableWithEnum(w) = v { + Some(w) + } else { + unreachable!() + } + } else { + None + } + } + /// If the union variant matches, return a reference to the TestSimpleTableWithEnumT. + pub fn as_test_simple_table_with_enum(&self) -> Option<&TestSimpleTableWithEnumT> { + if let Self::TestSimpleTableWithEnum(v) = self { Some(v.as_ref()) } else { None } + } + /// If the union variant matches, return a mutable reference to the TestSimpleTableWithEnumT. + pub fn as_test_simple_table_with_enum_mut(&mut self) -> Option<&mut TestSimpleTableWithEnumT> { + if let Self::TestSimpleTableWithEnum(v) = self { Some(v.as_mut()) } else { None } + } + /// If the union variant matches, return the owned super::example_2::MonsterT, setting the union to NONE. + pub fn take_my_game_example_2_monster(&mut self) -> Option> { + if let Self::MyGameExample2Monster(_) = self { + let v = std::mem::replace(self, Self::NONE); + if let Self::MyGameExample2Monster(w) = v { + Some(w) + } else { + unreachable!() + } + } else { + None + } + } + /// If the union variant matches, return a reference to the super::example_2::MonsterT. + pub fn as_my_game_example_2_monster(&self) -> Option<&super::example_2::MonsterT> { + if let Self::MyGameExample2Monster(v) = self { Some(v.as_ref()) } else { None } + } + /// If the union variant matches, return a mutable reference to the super::example_2::MonsterT. + pub fn as_my_game_example_2_monster_mut(&mut self) -> Option<&mut super::example_2::MonsterT> { + if let Self::MyGameExample2Monster(v) = self { Some(v.as_mut()) } else { None } + } +} #[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] pub const ENUM_MIN_ANY_UNIQUE_ALIASES: u8 = 0; #[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] @@ -465,7 +591,7 @@ pub const ENUM_VALUES_ANY_UNIQUE_ALIASES: [AnyUniqueAliases; 4] = [ AnyUniqueAliases::M2, ]; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[repr(transparent)] pub struct AnyUniqueAliases(pub u8); #[allow(non_upper_case_globals)] @@ -503,7 +629,6 @@ impl std::fmt::Debug for AnyUniqueAliases { } } } -pub struct AnyUniqueAliasesUnionTableOffset {} impl<'a> flatbuffers::Follow<'a> for AnyUniqueAliases { type Inner = Self; #[inline] @@ -545,6 +670,102 @@ impl<'a> flatbuffers::Verifiable for AnyUniqueAliases { } impl flatbuffers::SimpleToVerifyInSlice for AnyUniqueAliases {} +pub struct AnyUniqueAliasesUnionTableOffset {} + +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq)] +pub enum AnyUniqueAliasesT { + NONE, + M(Box), + TS(Box), + M2(Box), +} +impl Default for AnyUniqueAliasesT { + fn default() -> Self { + Self::NONE + } +} +impl AnyUniqueAliasesT { + fn any_unique_aliases_type(&self) -> AnyUniqueAliases { + match self { + Self::NONE => AnyUniqueAliases::NONE, + Self::M(_) => AnyUniqueAliases::M, + Self::TS(_) => AnyUniqueAliases::TS, + Self::M2(_) => AnyUniqueAliases::M2, + } + } + pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder) -> Option> { + match self { + Self::NONE => None, + Self::M(v) => Some(v.pack(fbb).as_union_value()), + Self::TS(v) => Some(v.pack(fbb).as_union_value()), + Self::M2(v) => Some(v.pack(fbb).as_union_value()), + } + } + /// If the union variant matches, return the owned MonsterT, setting the union to NONE. + pub fn take_m(&mut self) -> Option> { + if let Self::M(_) = self { + let v = std::mem::replace(self, Self::NONE); + if let Self::M(w) = v { + Some(w) + } else { + unreachable!() + } + } else { + None + } + } + /// If the union variant matches, return a reference to the MonsterT. + pub fn as_m(&self) -> Option<&MonsterT> { + if let Self::M(v) = self { Some(v.as_ref()) } else { None } + } + /// If the union variant matches, return a mutable reference to the MonsterT. + pub fn as_m_mut(&mut self) -> Option<&mut MonsterT> { + if let Self::M(v) = self { Some(v.as_mut()) } else { None } + } + /// If the union variant matches, return the owned TestSimpleTableWithEnumT, setting the union to NONE. + pub fn take_ts(&mut self) -> Option> { + if let Self::TS(_) = self { + let v = std::mem::replace(self, Self::NONE); + if let Self::TS(w) = v { + Some(w) + } else { + unreachable!() + } + } else { + None + } + } + /// If the union variant matches, return a reference to the TestSimpleTableWithEnumT. + pub fn as_ts(&self) -> Option<&TestSimpleTableWithEnumT> { + if let Self::TS(v) = self { Some(v.as_ref()) } else { None } + } + /// If the union variant matches, return a mutable reference to the TestSimpleTableWithEnumT. + pub fn as_ts_mut(&mut self) -> Option<&mut TestSimpleTableWithEnumT> { + if let Self::TS(v) = self { Some(v.as_mut()) } else { None } + } + /// If the union variant matches, return the owned super::example_2::MonsterT, setting the union to NONE. + pub fn take_m2(&mut self) -> Option> { + if let Self::M2(_) = self { + let v = std::mem::replace(self, Self::NONE); + if let Self::M2(w) = v { + Some(w) + } else { + unreachable!() + } + } else { + None + } + } + /// If the union variant matches, return a reference to the super::example_2::MonsterT. + pub fn as_m2(&self) -> Option<&super::example_2::MonsterT> { + if let Self::M2(v) = self { Some(v.as_ref()) } else { None } + } + /// If the union variant matches, return a mutable reference to the super::example_2::MonsterT. + pub fn as_m2_mut(&mut self) -> Option<&mut super::example_2::MonsterT> { + if let Self::M2(v) = self { Some(v.as_mut()) } else { None } + } +} #[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] pub const ENUM_MIN_ANY_AMBIGUOUS_ALIASES: u8 = 0; #[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")] @@ -558,7 +779,7 @@ pub const ENUM_VALUES_ANY_AMBIGUOUS_ALIASES: [AnyAmbiguousAliases; 4] = [ AnyAmbiguousAliases::M3, ]; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[repr(transparent)] pub struct AnyAmbiguousAliases(pub u8); #[allow(non_upper_case_globals)] @@ -596,7 +817,6 @@ impl std::fmt::Debug for AnyAmbiguousAliases { } } } -pub struct AnyAmbiguousAliasesUnionTableOffset {} impl<'a> flatbuffers::Follow<'a> for AnyAmbiguousAliases { type Inner = Self; #[inline] @@ -638,9 +858,105 @@ impl<'a> flatbuffers::Verifiable for AnyAmbiguousAliases { } impl flatbuffers::SimpleToVerifyInSlice for AnyAmbiguousAliases {} +pub struct AnyAmbiguousAliasesUnionTableOffset {} + +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq)] +pub enum AnyAmbiguousAliasesT { + NONE, + M1(Box), + M2(Box), + M3(Box), +} +impl Default for AnyAmbiguousAliasesT { + fn default() -> Self { + Self::NONE + } +} +impl AnyAmbiguousAliasesT { + fn any_ambiguous_aliases_type(&self) -> AnyAmbiguousAliases { + match self { + Self::NONE => AnyAmbiguousAliases::NONE, + Self::M1(_) => AnyAmbiguousAliases::M1, + Self::M2(_) => AnyAmbiguousAliases::M2, + Self::M3(_) => AnyAmbiguousAliases::M3, + } + } + pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder) -> Option> { + match self { + Self::NONE => None, + Self::M1(v) => Some(v.pack(fbb).as_union_value()), + Self::M2(v) => Some(v.pack(fbb).as_union_value()), + Self::M3(v) => Some(v.pack(fbb).as_union_value()), + } + } + /// If the union variant matches, return the owned MonsterT, setting the union to NONE. + pub fn take_m1(&mut self) -> Option> { + if let Self::M1(_) = self { + let v = std::mem::replace(self, Self::NONE); + if let Self::M1(w) = v { + Some(w) + } else { + unreachable!() + } + } else { + None + } + } + /// If the union variant matches, return a reference to the MonsterT. + pub fn as_m1(&self) -> Option<&MonsterT> { + if let Self::M1(v) = self { Some(v.as_ref()) } else { None } + } + /// If the union variant matches, return a mutable reference to the MonsterT. + pub fn as_m1_mut(&mut self) -> Option<&mut MonsterT> { + if let Self::M1(v) = self { Some(v.as_mut()) } else { None } + } + /// If the union variant matches, return the owned MonsterT, setting the union to NONE. + pub fn take_m2(&mut self) -> Option> { + if let Self::M2(_) = self { + let v = std::mem::replace(self, Self::NONE); + if let Self::M2(w) = v { + Some(w) + } else { + unreachable!() + } + } else { + None + } + } + /// If the union variant matches, return a reference to the MonsterT. + pub fn as_m2(&self) -> Option<&MonsterT> { + if let Self::M2(v) = self { Some(v.as_ref()) } else { None } + } + /// If the union variant matches, return a mutable reference to the MonsterT. + pub fn as_m2_mut(&mut self) -> Option<&mut MonsterT> { + if let Self::M2(v) = self { Some(v.as_mut()) } else { None } + } + /// If the union variant matches, return the owned MonsterT, setting the union to NONE. + pub fn take_m3(&mut self) -> Option> { + if let Self::M3(_) = self { + let v = std::mem::replace(self, Self::NONE); + if let Self::M3(w) = v { + Some(w) + } else { + unreachable!() + } + } else { + None + } + } + /// If the union variant matches, return a reference to the MonsterT. + pub fn as_m3(&self) -> Option<&MonsterT> { + if let Self::M3(v) = self { Some(v.as_ref()) } else { None } + } + /// If the union variant matches, return a mutable reference to the MonsterT. + pub fn as_m3_mut(&mut self) -> Option<&mut MonsterT> { + if let Self::M3(v) = self { Some(v.as_mut()) } else { None } + } +} // struct Test, aligned to 2 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Default)] pub struct Test(pub [u8; 4]); impl std::fmt::Debug for Test { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -760,11 +1076,31 @@ impl Test { } } + pub fn unpack(&self) -> TestT { + TestT { + a: self.a(), + b: self.b(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct TestT { + pub a: i16, + pub b: i8, +} +impl TestT { + pub fn pack(&self) -> Test { + Test::new( + self.a, + self.b, + ) + } } // struct Vec3, aligned to 8 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Default)] pub struct Vec3(pub [u8; 32]); impl std::fmt::Debug for Vec3 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -973,11 +1309,43 @@ impl Vec3 { self.0[26..26+4].copy_from_slice(&x.0) } + pub fn unpack(&self) -> Vec3T { + Vec3T { + x: self.x(), + y: self.y(), + z: self.z(), + test1: self.test1(), + test2: self.test2(), + test3: self.test3().unpack(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct Vec3T { + pub x: f32, + pub y: f32, + pub z: f32, + pub test1: f64, + pub test2: Color, + pub test3: TestT, +} +impl Vec3T { + pub fn pack(&self) -> Vec3 { + Vec3::new( + self.x, + self.y, + self.z, + self.test1, + self.test2, + &self.test3.pack(), + ) + } } // struct Ability, aligned to 4 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Default)] pub struct Ability(pub [u8; 8]); impl std::fmt::Debug for Ability { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -1107,6 +1475,26 @@ impl Ability { } } + pub fn unpack(&self) -> AbilityT { + AbilityT { + id: self.id(), + distance: self.distance(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct AbilityT { + pub id: u32, + pub distance: u32, +} +impl AbilityT { + pub fn pack(&self) -> Ability { + Ability::new( + self.id, + self.distance, + ) + } } pub enum TestSimpleTableWithEnumOffset {} @@ -1131,9 +1519,7 @@ impl<'a> TestSimpleTableWithEnum<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - TestSimpleTableWithEnum { - _tab: table, - } + TestSimpleTableWithEnum { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -1144,6 +1530,12 @@ impl<'a> TestSimpleTableWithEnum<'a> { builder.finish() } + pub fn unpack(&self) -> TestSimpleTableWithEnumT { + let color = self.color(); + TestSimpleTableWithEnumT { + color, + } + } pub const VT_COLOR: flatbuffers::VOffsetT = 4; #[inline] @@ -1206,6 +1598,22 @@ impl std::fmt::Debug for TestSimpleTableWithEnum<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct TestSimpleTableWithEnumT { + pub color: Color, +} +impl TestSimpleTableWithEnumT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let color = self.color; + TestSimpleTableWithEnum::create(_fbb, &TestSimpleTableWithEnumArgs{ + color, + }) + } +} pub enum StatOffset {} #[derive(Copy, Clone, PartialEq)] @@ -1228,9 +1636,7 @@ impl<'a> Stat<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - Stat { - _tab: table, - } + Stat { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -1243,6 +1649,18 @@ impl<'a> Stat<'a> { builder.finish() } + pub fn unpack(&self) -> StatT { + let id = self.id().map(|x| { + x.to_string() + }); + let val = self.val(); + let count = self.count(); + StatT { + id, + val, + count, + } + } pub const VT_ID: flatbuffers::VOffsetT = 4; pub const VT_VAL: flatbuffers::VOffsetT = 6; pub const VT_COUNT: flatbuffers::VOffsetT = 8; @@ -1341,6 +1759,30 @@ impl std::fmt::Debug for Stat<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct StatT { + pub id: Option, + pub val: i64, + pub count: u16, +} +impl StatT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let id = self.id.as_ref().map(|x|{ + _fbb.create_string(x) + }); + let val = self.val; + let count = self.count; + Stat::create(_fbb, &StatArgs{ + id, + val, + count, + }) + } +} pub enum ReferrableOffset {} #[derive(Copy, Clone, PartialEq)] @@ -1363,9 +1805,7 @@ impl<'a> Referrable<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - Referrable { - _tab: table, - } + Referrable { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -1376,6 +1816,12 @@ impl<'a> Referrable<'a> { builder.finish() } + pub fn unpack(&self) -> ReferrableT { + let id = self.id(); + ReferrableT { + id, + } + } pub const VT_ID: flatbuffers::VOffsetT = 4; #[inline] @@ -1448,6 +1894,22 @@ impl std::fmt::Debug for Referrable<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct ReferrableT { + pub id: u64, +} +impl ReferrableT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let id = self.id; + Referrable::create(_fbb, &ReferrableArgs{ + id, + }) + } +} pub enum MonsterOffset {} #[derive(Copy, Clone, PartialEq)] @@ -1471,9 +1933,7 @@ impl<'a> Monster<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - Monster { - _tab: table, - } + Monster { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -1533,6 +1993,209 @@ impl<'a> Monster<'a> { builder.finish() } + pub fn unpack(&self) -> MonsterT { + let pos = self.pos().map(|x| { + x.unpack() + }); + let mana = self.mana(); + let hp = self.hp(); + let name = { + let x = self.name(); + x.to_string() + }; + let inventory = self.inventory().map(|x| { + x.to_vec() + }); + let color = self.color(); + let test = match self.test_type() { + Any::NONE => AnyT::NONE, + Any::Monster => AnyT::Monster(Box::new( + self.test_as_monster() + .expect("Invalid union table, expected `Any::Monster`.") + .unpack() + )), + Any::TestSimpleTableWithEnum => AnyT::TestSimpleTableWithEnum(Box::new( + self.test_as_test_simple_table_with_enum() + .expect("Invalid union table, expected `Any::TestSimpleTableWithEnum`.") + .unpack() + )), + Any::MyGame_Example2_Monster => AnyT::MyGameExample2Monster(Box::new( + self.test_as_my_game_example_2_monster() + .expect("Invalid union table, expected `Any::MyGame_Example2_Monster`.") + .unpack() + )), + _ => AnyT::NONE, + }; + let test4 = self.test4().map(|x| { + x.iter().map(|t| t.unpack()).collect() + }); + let testarrayofstring = self.testarrayofstring().map(|x| { + x.iter().map(|s| s.to_string()).collect() + }); + let testarrayoftables = self.testarrayoftables().map(|x| { + x.iter().map(|t| t.unpack()).collect() + }); + let enemy = self.enemy().map(|x| { + Box::new(x.unpack()) + }); + let testnestedflatbuffer = self.testnestedflatbuffer().map(|x| { + x.to_vec() + }); + let testempty = self.testempty().map(|x| { + Box::new(x.unpack()) + }); + let testbool = self.testbool(); + let testhashs32_fnv1 = self.testhashs32_fnv1(); + let testhashu32_fnv1 = self.testhashu32_fnv1(); + let testhashs64_fnv1 = self.testhashs64_fnv1(); + let testhashu64_fnv1 = self.testhashu64_fnv1(); + let testhashs32_fnv1a = self.testhashs32_fnv1a(); + let testhashu32_fnv1a = self.testhashu32_fnv1a(); + let testhashs64_fnv1a = self.testhashs64_fnv1a(); + let testhashu64_fnv1a = self.testhashu64_fnv1a(); + let testarrayofbools = self.testarrayofbools().map(|x| { + x.to_vec() + }); + let testf = self.testf(); + let testf2 = self.testf2(); + let testf3 = self.testf3(); + let testarrayofstring2 = self.testarrayofstring2().map(|x| { + x.iter().map(|s| s.to_string()).collect() + }); + let testarrayofsortedstruct = self.testarrayofsortedstruct().map(|x| { + x.iter().map(|t| t.unpack()).collect() + }); + let flex = self.flex().map(|x| { + x.to_vec() + }); + let test5 = self.test5().map(|x| { + x.iter().map(|t| t.unpack()).collect() + }); + let vector_of_longs = self.vector_of_longs().map(|x| { + x.into_iter().collect() + }); + let vector_of_doubles = self.vector_of_doubles().map(|x| { + x.into_iter().collect() + }); + let parent_namespace_test = self.parent_namespace_test().map(|x| { + Box::new(x.unpack()) + }); + let vector_of_referrables = self.vector_of_referrables().map(|x| { + x.iter().map(|t| t.unpack()).collect() + }); + let single_weak_reference = self.single_weak_reference(); + let vector_of_weak_references = self.vector_of_weak_references().map(|x| { + x.into_iter().collect() + }); + let vector_of_strong_referrables = self.vector_of_strong_referrables().map(|x| { + x.iter().map(|t| t.unpack()).collect() + }); + let co_owning_reference = self.co_owning_reference(); + let vector_of_co_owning_references = self.vector_of_co_owning_references().map(|x| { + x.into_iter().collect() + }); + let non_owning_reference = self.non_owning_reference(); + let vector_of_non_owning_references = self.vector_of_non_owning_references().map(|x| { + x.into_iter().collect() + }); + let any_unique = match self.any_unique_type() { + AnyUniqueAliases::NONE => AnyUniqueAliasesT::NONE, + AnyUniqueAliases::M => AnyUniqueAliasesT::M(Box::new( + self.any_unique_as_m() + .expect("Invalid union table, expected `AnyUniqueAliases::M`.") + .unpack() + )), + AnyUniqueAliases::TS => AnyUniqueAliasesT::TS(Box::new( + self.any_unique_as_ts() + .expect("Invalid union table, expected `AnyUniqueAliases::TS`.") + .unpack() + )), + AnyUniqueAliases::M2 => AnyUniqueAliasesT::M2(Box::new( + self.any_unique_as_m2() + .expect("Invalid union table, expected `AnyUniqueAliases::M2`.") + .unpack() + )), + _ => AnyUniqueAliasesT::NONE, + }; + let any_ambiguous = match self.any_ambiguous_type() { + AnyAmbiguousAliases::NONE => AnyAmbiguousAliasesT::NONE, + AnyAmbiguousAliases::M1 => AnyAmbiguousAliasesT::M1(Box::new( + self.any_ambiguous_as_m1() + .expect("Invalid union table, expected `AnyAmbiguousAliases::M1`.") + .unpack() + )), + AnyAmbiguousAliases::M2 => AnyAmbiguousAliasesT::M2(Box::new( + self.any_ambiguous_as_m2() + .expect("Invalid union table, expected `AnyAmbiguousAliases::M2`.") + .unpack() + )), + AnyAmbiguousAliases::M3 => AnyAmbiguousAliasesT::M3(Box::new( + self.any_ambiguous_as_m3() + .expect("Invalid union table, expected `AnyAmbiguousAliases::M3`.") + .unpack() + )), + _ => AnyAmbiguousAliasesT::NONE, + }; + let vector_of_enums = self.vector_of_enums().map(|x| { + x.into_iter().collect() + }); + let signed_enum = self.signed_enum(); + let testrequirednestedflatbuffer = self.testrequirednestedflatbuffer().map(|x| { + x.to_vec() + }); + let scalar_key_sorted_tables = self.scalar_key_sorted_tables().map(|x| { + x.iter().map(|t| t.unpack()).collect() + }); + MonsterT { + pos, + mana, + hp, + name, + inventory, + color, + test, + test4, + testarrayofstring, + testarrayoftables, + enemy, + testnestedflatbuffer, + testempty, + testbool, + testhashs32_fnv1, + testhashu32_fnv1, + testhashs64_fnv1, + testhashu64_fnv1, + testhashs32_fnv1a, + testhashu32_fnv1a, + testhashs64_fnv1a, + testhashu64_fnv1a, + testarrayofbools, + testf, + testf2, + testf3, + testarrayofstring2, + testarrayofsortedstruct, + flex, + test5, + vector_of_longs, + vector_of_doubles, + parent_namespace_test, + vector_of_referrables, + single_weak_reference, + vector_of_weak_references, + vector_of_strong_referrables, + co_owning_reference, + vector_of_co_owning_references, + non_owning_reference, + vector_of_non_owning_references, + any_unique, + any_ambiguous, + vector_of_enums, + signed_enum, + testrequirednestedflatbuffer, + scalar_key_sorted_tables, + } + } pub const VT_POS: flatbuffers::VOffsetT = 4; pub const VT_MANA: flatbuffers::VOffsetT = 6; pub const VT_HP: flatbuffers::VOffsetT = 8; @@ -2443,6 +3106,216 @@ impl std::fmt::Debug for Monster<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct MonsterT { + pub pos: Option, + pub mana: i16, + pub hp: i16, + pub name: String, + pub inventory: Option>, + pub color: Color, + pub test: AnyT, + pub test4: Option>, + pub testarrayofstring: Option>, + pub testarrayoftables: Option>, + pub enemy: Option>, + pub testnestedflatbuffer: Option>, + pub testempty: Option>, + pub testbool: bool, + pub testhashs32_fnv1: i32, + pub testhashu32_fnv1: u32, + pub testhashs64_fnv1: i64, + pub testhashu64_fnv1: u64, + pub testhashs32_fnv1a: i32, + pub testhashu32_fnv1a: u32, + pub testhashs64_fnv1a: i64, + pub testhashu64_fnv1a: u64, + pub testarrayofbools: Option>, + pub testf: f32, + pub testf2: f32, + pub testf3: f32, + pub testarrayofstring2: Option>, + pub testarrayofsortedstruct: Option>, + pub flex: Option>, + pub test5: Option>, + pub vector_of_longs: Option>, + pub vector_of_doubles: Option>, + pub parent_namespace_test: Option>, + pub vector_of_referrables: Option>, + pub single_weak_reference: u64, + pub vector_of_weak_references: Option>, + pub vector_of_strong_referrables: Option>, + pub co_owning_reference: u64, + pub vector_of_co_owning_references: Option>, + pub non_owning_reference: u64, + pub vector_of_non_owning_references: Option>, + pub any_unique: AnyUniqueAliasesT, + pub any_ambiguous: AnyAmbiguousAliasesT, + pub vector_of_enums: Option>, + pub signed_enum: Race, + pub testrequirednestedflatbuffer: Option>, + pub scalar_key_sorted_tables: Option>, +} +impl MonsterT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let pos_tmp = self.pos.as_ref().map(|x| x.pack()); + let pos = pos_tmp.as_ref(); + let mana = self.mana; + let hp = self.hp; + let name = Some({ + let x = &self.name; + _fbb.create_string(x) + }); + let inventory = self.inventory.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let color = self.color; + let test_type = self.test.any_type(); + let test = self.test.pack(_fbb); + let test4 = self.test4.as_ref().map(|x|{ + let w: Vec<_> = x.iter().map(|t| t.pack()).collect();_fbb.create_vector(&w) + }); + let testarrayofstring = self.testarrayofstring.as_ref().map(|x|{ + let w: Vec<_> = x.iter().map(|s| s.as_ref()).collect();_fbb.create_vector_of_strings(&w) + }); + let testarrayoftables = self.testarrayoftables.as_ref().map(|x|{ + let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();_fbb.create_vector(&w) + }); + let enemy = self.enemy.as_ref().map(|x|{ + x.pack(_fbb) + }); + let testnestedflatbuffer = self.testnestedflatbuffer.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let testempty = self.testempty.as_ref().map(|x|{ + x.pack(_fbb) + }); + let testbool = self.testbool; + let testhashs32_fnv1 = self.testhashs32_fnv1; + let testhashu32_fnv1 = self.testhashu32_fnv1; + let testhashs64_fnv1 = self.testhashs64_fnv1; + let testhashu64_fnv1 = self.testhashu64_fnv1; + let testhashs32_fnv1a = self.testhashs32_fnv1a; + let testhashu32_fnv1a = self.testhashu32_fnv1a; + let testhashs64_fnv1a = self.testhashs64_fnv1a; + let testhashu64_fnv1a = self.testhashu64_fnv1a; + let testarrayofbools = self.testarrayofbools.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let testf = self.testf; + let testf2 = self.testf2; + let testf3 = self.testf3; + let testarrayofstring2 = self.testarrayofstring2.as_ref().map(|x|{ + let w: Vec<_> = x.iter().map(|s| s.as_ref()).collect();_fbb.create_vector_of_strings(&w) + }); + let testarrayofsortedstruct = self.testarrayofsortedstruct.as_ref().map(|x|{ + let w: Vec<_> = x.iter().map(|t| t.pack()).collect();_fbb.create_vector(&w) + }); + let flex = self.flex.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let test5 = self.test5.as_ref().map(|x|{ + let w: Vec<_> = x.iter().map(|t| t.pack()).collect();_fbb.create_vector(&w) + }); + let vector_of_longs = self.vector_of_longs.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let vector_of_doubles = self.vector_of_doubles.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let parent_namespace_test = self.parent_namespace_test.as_ref().map(|x|{ + x.pack(_fbb) + }); + let vector_of_referrables = self.vector_of_referrables.as_ref().map(|x|{ + let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();_fbb.create_vector(&w) + }); + let single_weak_reference = self.single_weak_reference; + let vector_of_weak_references = self.vector_of_weak_references.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let vector_of_strong_referrables = self.vector_of_strong_referrables.as_ref().map(|x|{ + let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();_fbb.create_vector(&w) + }); + let co_owning_reference = self.co_owning_reference; + let vector_of_co_owning_references = self.vector_of_co_owning_references.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let non_owning_reference = self.non_owning_reference; + let vector_of_non_owning_references = self.vector_of_non_owning_references.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let any_unique_type = self.any_unique.any_unique_aliases_type(); + let any_unique = self.any_unique.pack(_fbb); + let any_ambiguous_type = self.any_ambiguous.any_ambiguous_aliases_type(); + let any_ambiguous = self.any_ambiguous.pack(_fbb); + let vector_of_enums = self.vector_of_enums.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let signed_enum = self.signed_enum; + let testrequirednestedflatbuffer = self.testrequirednestedflatbuffer.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let scalar_key_sorted_tables = self.scalar_key_sorted_tables.as_ref().map(|x|{ + let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();_fbb.create_vector(&w) + }); + Monster::create(_fbb, &MonsterArgs{ + pos, + mana, + hp, + name, + inventory, + color, + test_type, + test, + test4, + testarrayofstring, + testarrayoftables, + enemy, + testnestedflatbuffer, + testempty, + testbool, + testhashs32_fnv1, + testhashu32_fnv1, + testhashs64_fnv1, + testhashu64_fnv1, + testhashs32_fnv1a, + testhashu32_fnv1a, + testhashs64_fnv1a, + testhashu64_fnv1a, + testarrayofbools, + testf, + testf2, + testf3, + testarrayofstring2, + testarrayofsortedstruct, + flex, + test5, + vector_of_longs, + vector_of_doubles, + parent_namespace_test, + vector_of_referrables, + single_weak_reference, + vector_of_weak_references, + vector_of_strong_referrables, + co_owning_reference, + vector_of_co_owning_references, + non_owning_reference, + vector_of_non_owning_references, + any_unique_type, + any_unique, + any_ambiguous_type, + any_ambiguous, + vector_of_enums, + signed_enum, + testrequirednestedflatbuffer, + scalar_key_sorted_tables, + }) + } +} pub enum TypeAliasesOffset {} #[derive(Copy, Clone, PartialEq)] @@ -2465,9 +3338,7 @@ impl<'a> TypeAliases<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - TypeAliases { - _tab: table, - } + TypeAliases { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -2489,6 +3360,38 @@ impl<'a> TypeAliases<'a> { builder.finish() } + pub fn unpack(&self) -> TypeAliasesT { + let i8_ = self.i8_(); + let u8_ = self.u8_(); + let i16_ = self.i16_(); + let u16_ = self.u16_(); + let i32_ = self.i32_(); + let u32_ = self.u32_(); + let i64_ = self.i64_(); + let u64_ = self.u64_(); + let f32_ = self.f32_(); + let f64_ = self.f64_(); + let v8 = self.v8().map(|x| { + x.to_vec() + }); + let vf64 = self.vf64().map(|x| { + x.into_iter().collect() + }); + TypeAliasesT { + i8_, + u8_, + i16_, + u16_, + i32_, + u32_, + i64_, + u64_, + f32_, + f64_, + v8, + vf64, + } + } pub const VT_I8_: flatbuffers::VOffsetT = 4; pub const VT_U8_: flatbuffers::VOffsetT = 6; pub const VT_I16_: flatbuffers::VOffsetT = 8; @@ -2694,6 +3597,59 @@ impl std::fmt::Debug for TypeAliases<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct TypeAliasesT { + pub i8_: i8, + pub u8_: u8, + pub i16_: i16, + pub u16_: u16, + pub i32_: i32, + pub u32_: u32, + pub i64_: i64, + pub u64_: u64, + pub f32_: f32, + pub f64_: f64, + pub v8: Option>, + pub vf64: Option>, +} +impl TypeAliasesT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let i8_ = self.i8_; + let u8_ = self.u8_; + let i16_ = self.i16_; + let u16_ = self.u16_; + let i32_ = self.i32_; + let u32_ = self.u32_; + let i64_ = self.i64_; + let u64_ = self.u64_; + let f32_ = self.f32_; + let f64_ = self.f64_; + let v8 = self.v8.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + let vf64 = self.vf64.as_ref().map(|x|{ + _fbb.create_vector(x) + }); + TypeAliases::create(_fbb, &TypeAliasesArgs{ + i8_, + u8_, + i16_, + u16_, + i32_, + u32_, + i64_, + u64_, + f32_, + f64_, + v8, + vf64, + }) + } +} #[inline] #[deprecated(since="2.0.0", note="Deprecated in favor of `root_as...` methods.")] pub fn get_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> { diff --git a/tests/namespace_test/namespace_test1_generated.rs b/tests/namespace_test/namespace_test1_generated.rs index e3a58b619..516c9b88b 100644 --- a/tests/namespace_test/namespace_test1_generated.rs +++ b/tests/namespace_test/namespace_test1_generated.rs @@ -38,7 +38,7 @@ pub const ENUM_VALUES_ENUM_IN_NESTED_NS: [EnumInNestedNS; 3] = [ EnumInNestedNS::C, ]; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[repr(transparent)] pub struct EnumInNestedNS(pub i8); #[allow(non_upper_case_globals)] @@ -116,7 +116,7 @@ impl<'a> flatbuffers::Verifiable for EnumInNestedNS { impl flatbuffers::SimpleToVerifyInSlice for EnumInNestedNS {} // struct StructInNestedNS, aligned to 4 #[repr(transparent)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Default)] pub struct StructInNestedNS(pub [u8; 8]); impl std::fmt::Debug for StructInNestedNS { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -236,6 +236,26 @@ impl StructInNestedNS { } } + pub fn unpack(&self) -> StructInNestedNST { + StructInNestedNST { + a: self.a(), + b: self.b(), + } + } +} + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct StructInNestedNST { + pub a: i32, + pub b: i32, +} +impl StructInNestedNST { + pub fn pack(&self) -> StructInNestedNS { + StructInNestedNS::new( + self.a, + self.b, + ) + } } pub enum TableInNestedNSOffset {} @@ -260,9 +280,7 @@ impl<'a> TableInNestedNS<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - TableInNestedNS { - _tab: table, - } + TableInNestedNS { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -273,6 +291,12 @@ impl<'a> TableInNestedNS<'a> { builder.finish() } + pub fn unpack(&self) -> TableInNestedNST { + let foo = self.foo(); + TableInNestedNST { + foo, + } + } pub const VT_FOO: flatbuffers::VOffsetT = 4; #[inline] @@ -335,6 +359,22 @@ impl std::fmt::Debug for TableInNestedNS<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct TableInNestedNST { + pub foo: i32, +} +impl TableInNestedNST { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let foo = self.foo; + TableInNestedNS::create(_fbb, &TableInNestedNSArgs{ + foo, + }) + } +} } // pub mod NamespaceB } // pub mod NamespaceA diff --git a/tests/namespace_test/namespace_test2_generated.rs b/tests/namespace_test/namespace_test2_generated.rs index 490dd6b9b..a774dbfc8 100644 --- a/tests/namespace_test/namespace_test2_generated.rs +++ b/tests/namespace_test/namespace_test2_generated.rs @@ -42,9 +42,7 @@ impl<'a> TableInFirstNS<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - TableInFirstNS { - _tab: table, - } + TableInFirstNS { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -57,6 +55,20 @@ impl<'a> TableInFirstNS<'a> { builder.finish() } + pub fn unpack(&self) -> TableInFirstNST { + let foo_table = self.foo_table().map(|x| { + Box::new(x.unpack()) + }); + let foo_enum = self.foo_enum(); + let foo_struct = self.foo_struct().map(|x| { + x.unpack() + }); + TableInFirstNST { + foo_table, + foo_enum, + foo_struct, + } + } pub const VT_FOO_TABLE: flatbuffers::VOffsetT = 4; pub const VT_FOO_ENUM: flatbuffers::VOffsetT = 6; pub const VT_FOO_STRUCT: flatbuffers::VOffsetT = 8; @@ -145,6 +157,31 @@ impl std::fmt::Debug for TableInFirstNS<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct TableInFirstNST { + pub foo_table: Option>, + pub foo_enum: namespace_b::EnumInNestedNS, + pub foo_struct: Option, +} +impl TableInFirstNST { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let foo_table = self.foo_table.as_ref().map(|x|{ + x.pack(_fbb) + }); + let foo_enum = self.foo_enum; + let foo_struct_tmp = self.foo_struct.as_ref().map(|x| x.pack()); + let foo_struct = foo_struct_tmp.as_ref(); + TableInFirstNS::create(_fbb, &TableInFirstNSArgs{ + foo_table, + foo_enum, + foo_struct, + }) + } +} pub enum SecondTableInAOffset {} #[derive(Copy, Clone, PartialEq)] @@ -167,9 +204,7 @@ impl<'a> SecondTableInA<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - SecondTableInA { - _tab: table, - } + SecondTableInA { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -180,6 +215,14 @@ impl<'a> SecondTableInA<'a> { builder.finish() } + pub fn unpack(&self) -> SecondTableInAT { + let refer_to_c = self.refer_to_c().map(|x| { + Box::new(x.unpack()) + }); + SecondTableInAT { + refer_to_c, + } + } pub const VT_REFER_TO_C: flatbuffers::VOffsetT = 4; #[inline] @@ -242,6 +285,24 @@ impl std::fmt::Debug for SecondTableInA<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct SecondTableInAT { + pub refer_to_c: Option>, +} +impl SecondTableInAT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let refer_to_c = self.refer_to_c.as_ref().map(|x|{ + x.pack(_fbb) + }); + SecondTableInA::create(_fbb, &SecondTableInAArgs{ + refer_to_c, + }) + } +} } // pub mod NamespaceA #[allow(unused_imports, dead_code)] @@ -276,9 +337,7 @@ impl<'a> TableInC<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - TableInC { - _tab: table, - } + TableInC { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -290,6 +349,18 @@ impl<'a> TableInC<'a> { builder.finish() } + pub fn unpack(&self) -> TableInCT { + let refer_to_a1 = self.refer_to_a1().map(|x| { + Box::new(x.unpack()) + }); + let refer_to_a2 = self.refer_to_a2().map(|x| { + Box::new(x.unpack()) + }); + TableInCT { + refer_to_a1, + refer_to_a2, + } + } pub const VT_REFER_TO_A1: flatbuffers::VOffsetT = 4; pub const VT_REFER_TO_A2: flatbuffers::VOffsetT = 6; @@ -365,5 +436,28 @@ impl std::fmt::Debug for TableInC<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct TableInCT { + pub refer_to_a1: Option>, + pub refer_to_a2: Option>, +} +impl TableInCT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let refer_to_a1 = self.refer_to_a1.as_ref().map(|x|{ + x.pack(_fbb) + }); + let refer_to_a2 = self.refer_to_a2.as_ref().map(|x|{ + x.pack(_fbb) + }); + TableInC::create(_fbb, &TableInCArgs{ + refer_to_a1, + refer_to_a2, + }) + } +} } // pub mod NamespaceC diff --git a/tests/optional_scalars_generated.rs b/tests/optional_scalars_generated.rs index 702df823f..73ebee301 100644 --- a/tests/optional_scalars_generated.rs +++ b/tests/optional_scalars_generated.rs @@ -30,7 +30,7 @@ pub const ENUM_VALUES_OPTIONAL_BYTE: [OptionalByte; 3] = [ OptionalByte::Two, ]; -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[repr(transparent)] pub struct OptionalByte(pub i8); #[allow(non_upper_case_globals)] @@ -124,9 +124,7 @@ impl<'a> flatbuffers::Follow<'a> for ScalarStuff<'a> { impl<'a> ScalarStuff<'a> { #[inline] pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - ScalarStuff { - _tab: table, - } + ScalarStuff { _tab: table } } #[allow(unused_mut)] pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( @@ -172,6 +170,82 @@ impl<'a> ScalarStuff<'a> { builder.finish() } + pub fn unpack(&self) -> ScalarStuffT { + let just_i8 = self.just_i8(); + let maybe_i8 = self.maybe_i8(); + let default_i8 = self.default_i8(); + let just_u8 = self.just_u8(); + let maybe_u8 = self.maybe_u8(); + let default_u8 = self.default_u8(); + let just_i16 = self.just_i16(); + let maybe_i16 = self.maybe_i16(); + let default_i16 = self.default_i16(); + let just_u16 = self.just_u16(); + let maybe_u16 = self.maybe_u16(); + let default_u16 = self.default_u16(); + let just_i32 = self.just_i32(); + let maybe_i32 = self.maybe_i32(); + let default_i32 = self.default_i32(); + let just_u32 = self.just_u32(); + let maybe_u32 = self.maybe_u32(); + let default_u32 = self.default_u32(); + let just_i64 = self.just_i64(); + let maybe_i64 = self.maybe_i64(); + let default_i64 = self.default_i64(); + let just_u64 = self.just_u64(); + let maybe_u64 = self.maybe_u64(); + let default_u64 = self.default_u64(); + let just_f32 = self.just_f32(); + let maybe_f32 = self.maybe_f32(); + let default_f32 = self.default_f32(); + let just_f64 = self.just_f64(); + let maybe_f64 = self.maybe_f64(); + let default_f64 = self.default_f64(); + let just_bool = self.just_bool(); + let maybe_bool = self.maybe_bool(); + let default_bool = self.default_bool(); + let just_enum = self.just_enum(); + let maybe_enum = self.maybe_enum(); + let default_enum = self.default_enum(); + ScalarStuffT { + just_i8, + maybe_i8, + default_i8, + just_u8, + maybe_u8, + default_u8, + just_i16, + maybe_i16, + default_i16, + just_u16, + maybe_u16, + default_u16, + just_i32, + maybe_i32, + default_i32, + just_u32, + maybe_u32, + default_u32, + just_i64, + maybe_i64, + default_i64, + just_u64, + maybe_u64, + default_u64, + just_f32, + maybe_f32, + default_f32, + just_f64, + maybe_f64, + default_f64, + just_bool, + maybe_bool, + default_bool, + just_enum, + maybe_enum, + default_enum, + } + } pub const VT_JUST_I8: flatbuffers::VOffsetT = 4; pub const VT_MAYBE_I8: flatbuffers::VOffsetT = 6; pub const VT_DEFAULT_I8: flatbuffers::VOffsetT = 8; @@ -689,6 +763,127 @@ impl std::fmt::Debug for ScalarStuff<'_> { ds.finish() } } +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct ScalarStuffT { + pub just_i8: i8, + pub maybe_i8: Option, + pub default_i8: i8, + pub just_u8: u8, + pub maybe_u8: Option, + pub default_u8: u8, + pub just_i16: i16, + pub maybe_i16: Option, + pub default_i16: i16, + pub just_u16: u16, + pub maybe_u16: Option, + pub default_u16: u16, + pub just_i32: i32, + pub maybe_i32: Option, + pub default_i32: i32, + pub just_u32: u32, + pub maybe_u32: Option, + pub default_u32: u32, + pub just_i64: i64, + pub maybe_i64: Option, + pub default_i64: i64, + pub just_u64: u64, + pub maybe_u64: Option, + pub default_u64: u64, + pub just_f32: f32, + pub maybe_f32: Option, + pub default_f32: f32, + pub just_f64: f64, + pub maybe_f64: Option, + pub default_f64: f64, + pub just_bool: bool, + pub maybe_bool: Option, + pub default_bool: bool, + pub just_enum: OptionalByte, + pub maybe_enum: Option, + pub default_enum: OptionalByte, +} +impl ScalarStuffT { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let just_i8 = self.just_i8; + let maybe_i8 = self.maybe_i8; + let default_i8 = self.default_i8; + let just_u8 = self.just_u8; + let maybe_u8 = self.maybe_u8; + let default_u8 = self.default_u8; + let just_i16 = self.just_i16; + let maybe_i16 = self.maybe_i16; + let default_i16 = self.default_i16; + let just_u16 = self.just_u16; + let maybe_u16 = self.maybe_u16; + let default_u16 = self.default_u16; + let just_i32 = self.just_i32; + let maybe_i32 = self.maybe_i32; + let default_i32 = self.default_i32; + let just_u32 = self.just_u32; + let maybe_u32 = self.maybe_u32; + let default_u32 = self.default_u32; + let just_i64 = self.just_i64; + let maybe_i64 = self.maybe_i64; + let default_i64 = self.default_i64; + let just_u64 = self.just_u64; + let maybe_u64 = self.maybe_u64; + let default_u64 = self.default_u64; + let just_f32 = self.just_f32; + let maybe_f32 = self.maybe_f32; + let default_f32 = self.default_f32; + let just_f64 = self.just_f64; + let maybe_f64 = self.maybe_f64; + let default_f64 = self.default_f64; + let just_bool = self.just_bool; + let maybe_bool = self.maybe_bool; + let default_bool = self.default_bool; + let just_enum = self.just_enum; + let maybe_enum = self.maybe_enum; + let default_enum = self.default_enum; + ScalarStuff::create(_fbb, &ScalarStuffArgs{ + just_i8, + maybe_i8, + default_i8, + just_u8, + maybe_u8, + default_u8, + just_i16, + maybe_i16, + default_i16, + just_u16, + maybe_u16, + default_u16, + just_i32, + maybe_i32, + default_i32, + just_u32, + maybe_u32, + default_u32, + just_i64, + maybe_i64, + default_i64, + just_u64, + maybe_u64, + default_u64, + just_f32, + maybe_f32, + default_f32, + just_f64, + maybe_f64, + default_f64, + just_bool, + maybe_bool, + default_bool, + just_enum, + maybe_enum, + default_enum, + }) + } +} #[inline] #[deprecated(since="2.0.0", note="Deprecated in favor of `root_as...` methods.")] pub fn get_root_as_scalar_stuff<'a>(buf: &'a [u8]) -> ScalarStuff<'a> { diff --git a/tests/rust_usage_test/bin/flatbuffers_alloc_check.rs b/tests/rust_usage_test/bin/flatbuffers_alloc_check.rs index 7cf2db5cf..84abd1e0d 100644 --- a/tests/rust_usage_test/bin/flatbuffers_alloc_check.rs +++ b/tests/rust_usage_test/bin/flatbuffers_alloc_check.rs @@ -36,7 +36,7 @@ pub mod include_test1_generated; #[path = "../../include_test/sub/include_test2_generated.rs"] pub mod include_test2_generated; -#[allow(dead_code, unused_imports)] +#[allow(dead_code, unused_imports, clippy::approx_constant)] #[path = "../../monster_test_generated.rs"] mod monster_test_generated; pub use monster_test_generated::my_game; diff --git a/tests/rust_usage_test/bin/monster_example.rs b/tests/rust_usage_test/bin/monster_example.rs index a3c4300d5..2e3c7ac60 100644 --- a/tests/rust_usage_test/bin/monster_example.rs +++ b/tests/rust_usage_test/bin/monster_example.rs @@ -8,7 +8,7 @@ pub mod include_test1_generated; #[path = "../../include_test/sub/include_test2_generated.rs"] pub mod include_test2_generated; -#[allow(dead_code, unused_imports)] +#[allow(dead_code, unused_imports, clippy::approx_constant)] #[path = "../../monster_test_generated.rs"] mod monster_test_generated; pub use monster_test_generated::my_game; diff --git a/tests/rust_usage_test/tests/integration_test.rs b/tests/rust_usage_test/tests/integration_test.rs index a30712800..c5a0a56dc 100644 --- a/tests/rust_usage_test/tests/integration_test.rs +++ b/tests/rust_usage_test/tests/integration_test.rs @@ -227,6 +227,50 @@ fn serialized_example_is_accessible_and_correct(bytes: &[u8], identifier_require Ok(()) } +#[test] +fn test_object_api_reads_correctly() -> Result<(), &'static str>{ + let mut fbb = flatbuffers::FlatBufferBuilder::new(); + create_serialized_example_with_library_code(&mut fbb); + + let m = my_game::example::root_as_monster(fbb.finished_data()).unwrap().unpack(); + + check_eq!(m.hp, 80)?; + check_eq!(m.mana, 150)?; + check_eq!(m.name, "MyMonster")?; + + let pos = m.pos.as_ref().unwrap(); + check_eq!(pos.x, 1.0f32)?; + check_eq!(pos.y, 2.0f32)?; + check_eq!(pos.z, 3.0f32)?; + check_eq!(pos.test1, 3.0f64)?; + check_eq!(pos.test2, my_game::example::Color::Green)?; + + let pos_test3 = &pos.test3; + check_eq!(pos_test3.a, 5i16)?; + check_eq!(pos_test3.b, 6i8)?; + + let monster2 = m.test.as_monster().unwrap(); + check_eq!(monster2.name, "Fred")?; + + let inv = m.inventory.as_ref().unwrap(); + check_eq!(inv.len(), 5)?; + check_eq!(inv.iter().sum::(), 10u8)?; + check_eq!(inv.iter().rev().sum::(), 10u8)?; + + let test4 = m.test4.as_ref().unwrap(); + check_eq!(test4.len(), 2)?; + check_eq!(test4[0].a as i32 + test4[0].b as i32 + + test4[1].a as i32 + test4[1].b as i32, 100)?; + + let testarrayofstring = m.testarrayofstring.as_ref().unwrap(); + check_eq!(testarrayofstring.len(), 2)?; + check_eq!(testarrayofstring[0], "test1")?; + check_eq!(testarrayofstring[1], "test2")?; + Ok(()) +} + + + // Disabled due to Windows CI limitations. // #[test] // fn builder_initializes_with_maximum_buffer_size() { diff --git a/tests/rust_usage_test/tests/optional_scalars_test.rs b/tests/rust_usage_test/tests/optional_scalars_test.rs index 5a662414d..32e93725f 100644 --- a/tests/rust_usage_test/tests/optional_scalars_test.rs +++ b/tests/rust_usage_test/tests/optional_scalars_test.rs @@ -37,6 +37,16 @@ macro_rules! make_test { assert_eq!(s.$just(), $zero); assert_eq!(s.$default(), $fortytwo); assert_eq!(s.$maybe(), None); + + // Same for object API + let s = flatbuffers::root::(builder.finished_data()).unwrap().unpack(); + assert_eq!(s.$just, $five); + assert_eq!(s.$default, $five); + assert_eq!(s.$maybe, Some($five)); + let s = flatbuffers::root::(&[0; 8]).unwrap().unpack(); + assert_eq!(s.$just, $zero); + assert_eq!(s.$default, $fortytwo); + assert_eq!(s.$maybe, None); } }; }