From: Casper Date: Sun, 7 Feb 2021 21:51:33 +0000 (-0500) Subject: Implement Rust object API defaults (#6444) X-Git-Tag: v2.0.0~88 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6f3e45eca1fde7a68cb72fd4499a3647f719c9db;p=platform%2Fupstream%2Fflatbuffers.git Implement Rust object API defaults (#6444) * Implment Rust object API defaults * satisfy return analysis * git clang format Co-authored-by: Casper Neo --- diff --git a/samples/monster_generated.rs b/samples/monster_generated.rs index cc2051e..aae5c6c 100644 --- a/samples/monster_generated.rs +++ b/samples/monster_generated.rs @@ -698,7 +698,7 @@ impl std::fmt::Debug for Monster<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct MonsterT { pub pos: Option, pub mana: i16, @@ -710,6 +710,21 @@ pub struct MonsterT { pub equipped: EquipmentT, pub path: Option>, } +impl Default for MonsterT { + fn default() -> Self { + Self { + pos: None, + mana: 150, + hp: 100, + name: None, + inventory: None, + color: Color::Blue, + weapons: None, + equipped: EquipmentT::NONE, + path: None, + } + } +} impl MonsterT { pub fn pack<'b>( &self, @@ -864,11 +879,19 @@ impl std::fmt::Debug for Weapon<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct WeaponT { pub name: Option, pub damage: i16, } +impl Default for WeaponT { + fn default() -> Self { + Self { + name: None, + damage: 0, + } + } +} impl WeaponT { pub fn pack<'b>( &self, diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp index 424112c..5236649 100644 --- a/src/idl_gen_rust.cpp +++ b/src/idl_gen_rust.cpp @@ -883,31 +883,60 @@ class RustGenerator : public BaseGenerator { return "VT_" + MakeUpper(Name(field)); } - std::string GetDefaultScalarValue(const FieldDef &field) { + std::string GetDefaultValue(const FieldDef &field, bool for_builder) { + if (for_builder) { + // Builders and Args structs model nonscalars "optional" even if they're + // required or have defaults according to the schema. I guess its because + // WIPOffset is not nullable. + if (!IsScalar(field.value.type.base_type) || field.IsOptional()) { + return "None"; + } + } else { + // This for defaults in objects. + // Unions have a NONE variant instead of using Rust's None. + if (field.IsOptional() && !IsUnion(field.value.type)) { return "None"; } + } switch (GetFullType(field.value.type)) { case ftInteger: case ftFloat: { - return field.IsOptional() ? "None" : field.value.constant; + return field.value.constant; } case ftBool: { - return field.IsOptional() ? "None" - : field.value.constant == "0" ? "false" : "true"; + return field.value.constant == "0" ? "false" : "true"; } case ftUnionKey: case ftEnumKey: { - if (field.IsOptional()) { return "None"; } auto ev = field.value.type.enum_def->FindByValue(field.value.constant); if (!ev) return "Default::default()"; // Bitflags enum. return WrapInNameSpace(field.value.type.enum_def->defined_namespace, GetEnumValue(*field.value.type.enum_def, *ev)); } - - // All pointer-ish types have a default value of None, because they are - // wrapped in Option. - default: { - return "None"; + case ftUnionValue: { + return ObjectFieldType(field, true) + "::NONE"; + } + case ftString: { + // Required strings. + return "String::new()"; // No default strings yet. + } + case ftVectorOfBool: + case ftVectorOfFloat: + case ftVectorOfInteger: + case ftVectorOfString: + case ftVectorOfStruct: + case ftVectorOfTable: + case ftVectorOfEnumKey: + case ftVectorOfUnionValue: { + // Required vectors. + return "Vec::new()"; // No default strings yet. + } + case ftStruct: + case ftTable: { + // Required struct/tables. + return "Default::default()"; // punt. } } + FLATBUFFERS_ASSERT("Unreachable."); + return "INVALID_CODE_GENERATION"; } // Create the return type for fields in the *BuilderArgs structs that are @@ -1138,14 +1167,14 @@ class RustGenerator : public BaseGenerator { case ftFloat: { const auto typname = GetTypeBasic(field.value.type); return (field.IsOptional() ? "self.fbb_.push_slot_always::<" - : "self.fbb_.push_slot::<") + + : "self.fbb_.push_slot::<") + typname + ">"; } case ftEnumKey: case ftUnionKey: { const auto underlying_typname = GetTypeBasic(type); return (field.IsOptional() ? "self.fbb_.push_slot_always::<" - : "self.fbb_.push_slot::<") + + : "self.fbb_.push_slot::<") + underlying_typname + ">"; } @@ -1325,7 +1354,7 @@ class RustGenerator : public BaseGenerator { // Default-y fields (scalars so far) are neither optional nor required. const std::string default_value = !(field.IsOptional() || field.IsRequired()) - ? "Some(" + GetDefaultScalarValue(field) + ")" + ? "Some(" + GetDefaultValue(field, /*builder=*/true) + ")" : "None"; const std::string unwrap = field.IsOptional() ? "" : ".unwrap()"; @@ -1396,7 +1425,7 @@ class RustGenerator : public BaseGenerator { code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field)); code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset)); code_.SetValue("FIELD_NAME", Name(field)); - code_.SetValue("DEFAULT_VALUE", GetDefaultScalarValue(field)); + code_.SetValue("BLDR_DEF_VAL", GetDefaultValue(field, /*builder=*/true)); cb(field); }; const auto &fields = struct_def.fields.vec; @@ -1769,7 +1798,7 @@ class RustGenerator : public BaseGenerator { code_ += " fn default() -> Self {"; code_ += " {{STRUCT_NAME}}Args {"; ForAllTableFields(struct_def, [&](const FieldDef &field) { - code_ += " {{FIELD_NAME}}: {{DEFAULT_VALUE}},\\"; + code_ += " {{FIELD_NAME}}: {{BLDR_DEF_VAL}},\\"; code_ += field.IsRequired() ? " // required field" : ""; }); code_ += " }"; @@ -1810,7 +1839,7 @@ class RustGenerator : public BaseGenerator { if (is_scalar && !field.IsOptional()) { code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, " - "{{DEFAULT_VALUE}});"; + "{{BLDR_DEF_VAL}});"; } else { code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});"; } @@ -1899,7 +1928,7 @@ class RustGenerator : public BaseGenerator { // Generate the native object. code_ += "#[non_exhaustive]"; - code_ += "#[derive(Debug, Clone, PartialEq, Default)]"; + code_ += "#[derive(Debug, Clone, PartialEq)]"; code_ += "pub struct {{OBJECT_NAME}} {"; ForAllObjectTableFields(table, [&](const FieldDef &field) { // Union objects combine both the union discriminant and value, so we @@ -1909,6 +1938,18 @@ class RustGenerator : public BaseGenerator { }); code_ += "}"; + code_ += "impl Default for {{OBJECT_NAME}} {"; + code_ += " fn default() -> Self {"; + code_ += " Self {"; + ForAllObjectTableFields(table, [&](const FieldDef &field) { + if (field.value.type.base_type == BASE_TYPE_UTYPE) return; + std::string default_value = GetDefaultValue(field, /*builder=*/false); + code_ += " {{FIELD_NAME}}: " + default_value + ","; + }); + code_ += " }"; + code_ += " }"; + code_ += "}"; + // TODO(cneo): Generate defaults for Native tables. However, since structs // may be required, they, and therefore enums need defaults. diff --git a/tests/monster_test_generated.rs b/tests/monster_test_generated.rs index a514c7a..2e4b840 100644 --- a/tests/monster_test_generated.rs +++ b/tests/monster_test_generated.rs @@ -106,9 +106,15 @@ impl std::fmt::Debug for InParentNamespace<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct InParentNamespaceT { } +impl Default for InParentNamespaceT { + fn default() -> Self { + Self { + } + } +} impl InParentNamespaceT { pub fn pack<'b>( &self, @@ -214,9 +220,15 @@ impl std::fmt::Debug for Monster<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct MonsterT { } +impl Default for MonsterT { + fn default() -> Self { + Self { + } + } +} impl MonsterT { pub fn pack<'b>( &self, @@ -1598,10 +1610,17 @@ impl std::fmt::Debug for TestSimpleTableWithEnum<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct TestSimpleTableWithEnumT { pub color: Color, } +impl Default for TestSimpleTableWithEnumT { + fn default() -> Self { + Self { + color: Color::Green, + } + } +} impl TestSimpleTableWithEnumT { pub fn pack<'b>( &self, @@ -1759,12 +1778,21 @@ impl std::fmt::Debug for Stat<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct StatT { pub id: Option, pub val: i64, pub count: u16, } +impl Default for StatT { + fn default() -> Self { + Self { + id: None, + val: 0, + count: 0, + } + } +} impl StatT { pub fn pack<'b>( &self, @@ -1894,10 +1922,17 @@ impl std::fmt::Debug for Referrable<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct ReferrableT { pub id: u64, } +impl Default for ReferrableT { + fn default() -> Self { + Self { + id: 0, + } + } +} impl ReferrableT { pub fn pack<'b>( &self, @@ -3106,7 +3141,7 @@ impl std::fmt::Debug for Monster<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct MonsterT { pub pos: Option, pub mana: i16, @@ -3156,6 +3191,59 @@ pub struct MonsterT { pub testrequirednestedflatbuffer: Option>, pub scalar_key_sorted_tables: Option>, } +impl Default for MonsterT { + fn default() -> Self { + Self { + pos: None, + mana: 150, + hp: 100, + name: String::new(), + inventory: None, + color: Color::Blue, + test: AnyT::NONE, + test4: None, + testarrayofstring: None, + testarrayoftables: None, + enemy: None, + testnestedflatbuffer: None, + testempty: None, + testbool: false, + testhashs32_fnv1: 0, + testhashu32_fnv1: 0, + testhashs64_fnv1: 0, + testhashu64_fnv1: 0, + testhashs32_fnv1a: 0, + testhashu32_fnv1a: 0, + testhashs64_fnv1a: 0, + testhashu64_fnv1a: 0, + testarrayofbools: None, + testf: 3.14159, + testf2: 3.0, + testf3: 0.0, + testarrayofstring2: None, + testarrayofsortedstruct: None, + flex: None, + test5: None, + vector_of_longs: None, + vector_of_doubles: None, + parent_namespace_test: None, + vector_of_referrables: None, + single_weak_reference: 0, + vector_of_weak_references: None, + vector_of_strong_referrables: None, + co_owning_reference: 0, + vector_of_co_owning_references: None, + non_owning_reference: 0, + vector_of_non_owning_references: None, + any_unique: AnyUniqueAliasesT::NONE, + any_ambiguous: AnyAmbiguousAliasesT::NONE, + vector_of_enums: None, + signed_enum: Race::None, + testrequirednestedflatbuffer: None, + scalar_key_sorted_tables: None, + } + } +} impl MonsterT { pub fn pack<'b>( &self, @@ -3597,7 +3685,7 @@ impl std::fmt::Debug for TypeAliases<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct TypeAliasesT { pub i8_: i8, pub u8_: u8, @@ -3612,6 +3700,24 @@ pub struct TypeAliasesT { pub v8: Option>, pub vf64: Option>, } +impl Default for TypeAliasesT { + fn default() -> Self { + Self { + i8_: 0, + u8_: 0, + i16_: 0, + u16_: 0, + i32_: 0, + u32_: 0, + i64_: 0, + u64_: 0, + f32_: 0.0, + f64_: 0.0, + v8: None, + vf64: None, + } + } +} impl TypeAliasesT { pub fn pack<'b>( &self, diff --git a/tests/namespace_test/namespace_test1_generated.rs b/tests/namespace_test/namespace_test1_generated.rs index aa4dde6..183d904 100644 --- a/tests/namespace_test/namespace_test1_generated.rs +++ b/tests/namespace_test/namespace_test1_generated.rs @@ -491,10 +491,17 @@ impl std::fmt::Debug for TableInNestedNS<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct TableInNestedNST { pub foo: i32, } +impl Default for TableInNestedNST { + fn default() -> Self { + Self { + foo: 0, + } + } +} impl TableInNestedNST { pub fn pack<'b>( &self, diff --git a/tests/namespace_test/namespace_test2_generated.rs b/tests/namespace_test/namespace_test2_generated.rs index e0ecd72..815d9f4 100644 --- a/tests/namespace_test/namespace_test2_generated.rs +++ b/tests/namespace_test/namespace_test2_generated.rs @@ -491,10 +491,17 @@ impl std::fmt::Debug for TableInNestedNS<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct TableInNestedNST { pub foo: i32, } +impl Default for TableInNestedNST { + fn default() -> Self { + Self { + foo: 0, + } + } +} impl TableInNestedNST { pub fn pack<'b>( &self, @@ -710,13 +717,23 @@ impl std::fmt::Debug for TableInFirstNS<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct TableInFirstNST { pub foo_table: Option>, pub foo_enum: namespace_b::EnumInNestedNS, pub foo_union: namespace_b::UnionInNestedNST, pub foo_struct: Option, } +impl Default for TableInFirstNST { + fn default() -> Self { + Self { + foo_table: None, + foo_enum: namespace_b::EnumInNestedNS::A, + foo_union: namespace_b::UnionInNestedNST::NONE, + foo_struct: None, + } + } +} impl TableInFirstNST { pub fn pack<'b>( &self, @@ -843,10 +860,17 @@ impl std::fmt::Debug for SecondTableInA<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct SecondTableInAT { pub refer_to_c: Option>, } +impl Default for SecondTableInAT { + fn default() -> Self { + Self { + refer_to_c: None, + } + } +} impl SecondTableInAT { pub fn pack<'b>( &self, @@ -993,11 +1017,19 @@ impl std::fmt::Debug for TableInC<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct TableInCT { pub refer_to_a1: Option>, pub refer_to_a2: Option>, } +impl Default for TableInCT { + fn default() -> Self { + Self { + refer_to_a1: None, + refer_to_a2: None, + } + } +} impl TableInCT { pub fn pack<'b>( &self, diff --git a/tests/optional_scalars_generated.rs b/tests/optional_scalars_generated.rs index 81483b5..f27ecf4 100644 --- a/tests/optional_scalars_generated.rs +++ b/tests/optional_scalars_generated.rs @@ -763,7 +763,7 @@ impl std::fmt::Debug for ScalarStuff<'_> { } } #[non_exhaustive] -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq)] pub struct ScalarStuffT { pub just_i8: i8, pub maybe_i8: Option, @@ -802,6 +802,48 @@ pub struct ScalarStuffT { pub maybe_enum: Option, pub default_enum: OptionalByte, } +impl Default for ScalarStuffT { + fn default() -> Self { + Self { + just_i8: 0, + maybe_i8: None, + default_i8: 42, + just_u8: 0, + maybe_u8: None, + default_u8: 42, + just_i16: 0, + maybe_i16: None, + default_i16: 42, + just_u16: 0, + maybe_u16: None, + default_u16: 42, + just_i32: 0, + maybe_i32: None, + default_i32: 42, + just_u32: 0, + maybe_u32: None, + default_u32: 42, + just_i64: 0, + maybe_i64: None, + default_i64: 42, + just_u64: 0, + maybe_u64: None, + default_u64: 42, + just_f32: 0.0, + maybe_f32: None, + default_f32: 42.0, + just_f64: 0.0, + maybe_f64: None, + default_f64: 42.0, + just_bool: false, + maybe_bool: None, + default_bool: true, + just_enum: OptionalByte::None, + maybe_enum: None, + default_enum: OptionalByte::One, + } + } +} impl ScalarStuffT { pub fn pack<'b>( &self, diff --git a/tests/rust_usage_test/tests/integration_test.rs b/tests/rust_usage_test/tests/integration_test.rs index fa68647..9bbbe88 100644 --- a/tests/rust_usage_test/tests/integration_test.rs +++ b/tests/rust_usage_test/tests/integration_test.rs @@ -115,6 +115,74 @@ fn macro_check_is_some() { assert!(check_is_some!(none).is_err()); } +#[test] +fn object_api_defaults() { + use my_game::example::*; + assert_eq!( + Vec3T::default(), Vec3T { + x: 0.0, + y: 0.0, + z: 0.0, + test1: 0.0, + test2: Color::empty(), + test3: TestT { + a: 0, + b: 0 + } + }); + assert_eq!( + MonsterT::default(), + MonsterT { + pos: None, + hp: 100, + mana: 150, + name: String::new(), // required string => default is empty string. + color: Color::Blue, + inventory: None, + testarrayoftables: None, + testarrayofstring: None, + testarrayofstring2: None, + testarrayofbools: None, + testarrayofsortedstruct: None, + enemy: None, + test: AnyT::NONE, + test4: None, + test5: None, + testnestedflatbuffer: None, + testempty: None, + testbool: false, + testhashs32_fnv1: 0, + testhashu32_fnv1: 0, + testhashs64_fnv1: 0, + testhashu64_fnv1: 0, + testhashs32_fnv1a: 0, + testhashu32_fnv1a: 0, + testhashs64_fnv1a: 0, + testhashu64_fnv1a: 0, + testf: 3.14159, + testf2: 3.0, + testf3: 0.0, + flex: None, + vector_of_longs: None, + vector_of_doubles: None, + parent_namespace_test: None, + vector_of_referrables: None, + single_weak_reference: 0, + vector_of_weak_references: None, + vector_of_strong_referrables: None, + co_owning_reference: 0, + vector_of_co_owning_references: None, + non_owning_reference: 0, + vector_of_non_owning_references: None, + any_unique: AnyUniqueAliasesT::NONE, + any_ambiguous: AnyAmbiguousAliasesT::NONE, + vector_of_enums: None, + signed_enum: Race::None, + testrequirednestedflatbuffer: None, // despite the name, it is not required. + scalar_key_sorted_tables: None, + } + ); +} fn create_serialized_example_with_generated_code(builder: &mut flatbuffers::FlatBufferBuilder) { let mon = { diff --git a/tests/rust_usage_test/tests/optional_scalars_test.rs b/tests/rust_usage_test/tests/optional_scalars_test.rs index 32e9372..d6c8422 100644 --- a/tests/rust_usage_test/tests/optional_scalars_test.rs +++ b/tests/rust_usage_test/tests/optional_scalars_test.rs @@ -95,3 +95,55 @@ make_test!( OptionalByte::None, OptionalByte::One ); + +#[test] +fn object_api_defaults() { + assert_eq!( + ScalarStuffT::default(), + ScalarStuffT { + just_i8: 0, + maybe_i8: None, + default_i8: 42, + just_u8: 0, + maybe_u8: None, + default_u8: 42, + + just_i16: 0, + maybe_i16: None, + default_i16: 42, + just_u16: 0, + maybe_u16: None, + default_u16: 42, + + just_i32: 0, + maybe_i32: None, + default_i32: 42, + just_u32: 0, + maybe_u32: None, + default_u32: 42, + + just_i64: 0, + maybe_i64: None, + default_i64: 42, + just_u64: 0, + maybe_u64: None, + default_u64: 42, + + just_f32: 0.0, + maybe_f32: None, + default_f32: 42.0, + just_f64: 0.0, + maybe_f64: None, + default_f64: 42.0, + + just_bool: false, + maybe_bool: None, + default_bool: true, + + just_enum: OptionalByte::None, + maybe_enum: None, + default_enum: OptionalByte::One, + + } + ); +}