diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp index 90cb57186..1e7502ae0 100644 --- a/src/idl_gen_rust.cpp +++ b/src/idl_gen_rust.cpp @@ -673,6 +673,9 @@ class RustGenerator : public BaseGenerator { } case ftUnionKey: case ftEnumKey: { + if (field.optional) { + return "None"; + } auto ev = field.value.type.enum_def->FindByValue(field.value.constant); assert(ev); return WrapInNameSpace(field.value.type.enum_def->defined_namespace, @@ -724,7 +727,7 @@ class RustGenerator : public BaseGenerator { case ftEnumKey: case ftUnionKey: { const auto typname = WrapInNameSpace(*type.enum_def); - return typname; + return field.optional ? "Option<" + typname + ">" : typname; } case ftUnionValue: { return "Option>"; @@ -872,7 +875,9 @@ class RustGenerator : public BaseGenerator { case ftEnumKey: case ftUnionKey: { const auto underlying_typname = GetTypeBasic(type); - return "self.fbb_.push_slot::<" + underlying_typname + ">"; + return (field.optional ? + "self.fbb_.push_slot_always::<" : + "self.fbb_.push_slot::<") + underlying_typname + ">"; } case ftStruct: { @@ -925,7 +930,7 @@ class RustGenerator : public BaseGenerator { case ftEnumKey: case ftUnionKey: { const auto typname = WrapInNameSpace(*type.enum_def); - return typname; + return field.optional ? "Option<" + typname + ">" : typname; } case ftUnionValue: { @@ -1027,8 +1032,12 @@ class RustGenerator : public BaseGenerator { const auto underlying_typname = GetTypeBasic(type); //<- never used const auto typname = WrapInNameSpace(*type.enum_def); const auto default_value = GetDefaultScalarValue(field); - return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + - default_value + ")).unwrap()"; + if (field.optional) { + return "self._tab.get::<" + typname + ">(" + offset_name + ", None)"; + } else { + return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + + default_value + ")).unwrap()"; + } } case ftString: { return AddUnwrapIfRequired( diff --git a/tests/generate_code.sh b/tests/generate_code.sh index 4dbf7aa21..9dce7bd4d 100755 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -53,7 +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 --kotlin --rust --lobster optional_scalars.fbs +../flatc --kotlin --lobster optional_scalars.fbs # These ones have not added optional enum support. +../flatc --rust optional_scalars2.fbs ../flatc $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS --cpp optional_scalars.fbs # Generate the schema evolution tests diff --git a/tests/optional_scalars2.fbs b/tests/optional_scalars2.fbs new file mode 100644 index 000000000..260d4432b --- /dev/null +++ b/tests/optional_scalars2.fbs @@ -0,0 +1,59 @@ +namespace optional_scalars; + +enum OptionalByte: byte { + None = 0, + One = 1, + Two = 2, +} + +// This table tests optional scalars in tables. It should be integrated with +// the main monster test once most languages support optional scalars. +table ScalarStuff { + just_i8: int8; + maybe_i8: int8 = null; + default_i8: int8 = 42; + just_u8: uint8; + maybe_u8: uint8 = null; + default_u8: uint8 = 42; + + just_i16: int16; + maybe_i16: int16 = null; + default_i16: int16 = 42; + just_u16: uint16; + maybe_u16: uint16 = null; + default_u16: uint16 = 42; + + just_i32: int32; + maybe_i32: int32 = null; + default_i32: int32 = 42; + just_u32: uint32; + maybe_u32: uint32 = null; + default_u32: uint32 = 42; + + just_i64: int64; + maybe_i64: int64 = null; + default_i64: int64 = 42; + just_u64: uint64; + maybe_u64: uint64 = null; + default_u64: uint64 = 42; + + just_f32: float32; + maybe_f32: float32 = null; + default_f32: float32 = 42; + just_f64: float64; + maybe_f64: float64 = null; + default_f64: float64 = 42; + + just_bool: bool; + maybe_bool: bool = null; + default_bool: bool = true; + + just_enum: OptionalByte; + maybe_enum: OptionalByte = null; + default_enum: OptionalByte = One; +} + +root_type ScalarStuff; + +file_identifier "NULL"; +file_extension "mon"; diff --git a/tests/optional_scalars_generated.rs b/tests/optional_scalars2_generated.rs similarity index 96% rename from tests/optional_scalars_generated.rs rename to tests/optional_scalars2_generated.rs index 39625a457..8e10527f5 100644 --- a/tests/optional_scalars_generated.rs +++ b/tests/optional_scalars2_generated.rs @@ -23,11 +23,12 @@ pub mod optional_scalars { pub enum OptionalByte { None = 0, One = 1, + Two = 2, } pub const ENUM_MIN_OPTIONAL_BYTE: i8 = 0; -pub const ENUM_MAX_OPTIONAL_BYTE: i8 = 1; +pub const ENUM_MAX_OPTIONAL_BYTE: i8 = 2; impl<'a> flatbuffers::Follow<'a> for OptionalByte { type Inner = Self; @@ -61,15 +62,17 @@ impl flatbuffers::Push for OptionalByte { } #[allow(non_camel_case_types)] -pub const ENUM_VALUES_OPTIONAL_BYTE: [OptionalByte; 2] = [ +pub const ENUM_VALUES_OPTIONAL_BYTE: [OptionalByte; 3] = [ OptionalByte::None, - OptionalByte::One + OptionalByte::One, + OptionalByte::Two ]; #[allow(non_camel_case_types)] -pub const ENUM_NAMES_OPTIONAL_BYTE: [&str; 2] = [ +pub const ENUM_NAMES_OPTIONAL_BYTE: [&str; 3] = [ "None", - "One" + "One", + "Two" ]; pub fn enum_name_optional_byte(e: OptionalByte) -> &'static str { @@ -129,6 +132,7 @@ impl<'a> ScalarStuff<'a> { if let Some(x) = args.maybe_i16 { builder.add_maybe_i16(x); } builder.add_just_i16(args.just_i16); builder.add_default_enum(args.default_enum); + if let Some(x) = args.maybe_enum { builder.add_maybe_enum(x); } builder.add_just_enum(args.just_enum); builder.add_default_bool(args.default_bool); if let Some(x) = args.maybe_bool { builder.add_maybe_bool(x); } @@ -176,7 +180,8 @@ impl<'a> ScalarStuff<'a> { pub const VT_MAYBE_BOOL: flatbuffers::VOffsetT = 66; pub const VT_DEFAULT_BOOL: flatbuffers::VOffsetT = 68; pub const VT_JUST_ENUM: flatbuffers::VOffsetT = 70; - pub const VT_DEFAULT_ENUM: flatbuffers::VOffsetT = 72; + pub const VT_MAYBE_ENUM: flatbuffers::VOffsetT = 72; + pub const VT_DEFAULT_ENUM: flatbuffers::VOffsetT = 74; #[inline] pub fn just_i8(&self) -> i8 { @@ -315,6 +320,10 @@ impl<'a> ScalarStuff<'a> { self._tab.get::(ScalarStuff::VT_JUST_ENUM, Some(OptionalByte::None)).unwrap() } #[inline] + pub fn maybe_enum(&self) -> Option { + self._tab.get::(ScalarStuff::VT_MAYBE_ENUM, None) + } + #[inline] pub fn default_enum(&self) -> OptionalByte { self._tab.get::(ScalarStuff::VT_DEFAULT_ENUM, Some(OptionalByte::One)).unwrap() } @@ -355,6 +364,7 @@ pub struct ScalarStuffArgs { pub maybe_bool: Option, pub default_bool: bool, pub just_enum: OptionalByte, + pub maybe_enum: Option, pub default_enum: OptionalByte, } impl<'a> Default for ScalarStuffArgs { @@ -395,6 +405,7 @@ impl<'a> Default for ScalarStuffArgs { maybe_bool: None, default_bool: true, just_enum: OptionalByte::None, + maybe_enum: None, default_enum: OptionalByte::One, } } @@ -541,6 +552,10 @@ impl<'a: 'b, 'b> ScalarStuffBuilder<'a, 'b> { self.fbb_.push_slot::(ScalarStuff::VT_JUST_ENUM, just_enum, OptionalByte::None); } #[inline] + pub fn add_maybe_enum(&mut self, maybe_enum: OptionalByte) { + self.fbb_.push_slot_always::(ScalarStuff::VT_MAYBE_ENUM, maybe_enum); + } + #[inline] pub fn add_default_enum(&mut self, default_enum: OptionalByte) { self.fbb_.push_slot::(ScalarStuff::VT_DEFAULT_ENUM, default_enum, OptionalByte::One); } diff --git a/tests/rust_usage_test/tests/integration_test.rs b/tests/rust_usage_test/tests/integration_test.rs index b861cf034..58a673fc7 100644 --- a/tests/rust_usage_test/tests/integration_test.rs +++ b/tests/rust_usage_test/tests/integration_test.rs @@ -43,7 +43,7 @@ mod monster_test_generated; pub use monster_test_generated::my_game; #[allow(dead_code, unused_imports)] -#[path = "../../optional_scalars_generated.rs"] +#[path = "../../optional_scalars2_generated.rs"] mod optional_scalars_generated; #[rustfmt::skip] // TODO: Use standard rust formatting and remove dead code. diff --git a/tests/rust_usage_test/tests/optional_scalars_test.rs b/tests/rust_usage_test/tests/optional_scalars_test.rs index 4b63de2e7..34a94dbcf 100644 --- a/tests/rust_usage_test/tests/optional_scalars_test.rs +++ b/tests/rust_usage_test/tests/optional_scalars_test.rs @@ -1,5 +1,5 @@ #[allow(dead_code, unused_imports)] -#[path = "../../optional_scalars_generated.rs"] +#[path = "../../optional_scalars2_generated.rs"] mod optional_scalars_generated; use crate::optional_scalars_generated::optional_scalars::*; @@ -16,12 +16,15 @@ macro_rules! make_test { fn $test_name() { let mut builder = flatbuffers::FlatBufferBuilder::new(); // Test five makes sense when specified. - let ss = ScalarStuff::create(&mut builder, &ScalarStuffArgs { - $just: $five, - $default: $five, - $maybe: Some($five), - ..Default::default() - }); + let ss = ScalarStuff::create( + &mut builder, + &ScalarStuffArgs { + $just: $five, + $default: $five, + $maybe: Some($five), + ..Default::default() + }, + ); builder.finish(ss, None); let s = flatbuffers::get_root::(builder.finished_data()); @@ -35,7 +38,6 @@ macro_rules! make_test { assert_eq!(s.$default(), $fortytwo); assert_eq!(s.$maybe(), None); } - }; } @@ -47,6 +49,39 @@ make_test!(optional_i32, just_i32, default_i32, maybe_i32, 5, 0, 42); make_test!(optional_u32, just_u32, default_u32, maybe_u32, 5, 0, 42); make_test!(optional_i64, just_i64, default_i64, maybe_i64, 5, 0, 42); make_test!(optional_u64, just_u64, default_u64, maybe_u64, 5, 0, 42); -make_test!(optional_f32, just_f32, default_f32, maybe_f32, 5.0, 0.0, 42.0); -make_test!(optional_f64, just_f64, default_f64, maybe_f64, 5.0, 0.0, 42.0); -make_test!(optional_bool, just_bool, default_bool, maybe_bool, true, false, true); +make_test!( + optional_f32, + just_f32, + default_f32, + maybe_f32, + 5.0, + 0.0, + 42.0 +); +make_test!( + optional_f64, + just_f64, + default_f64, + maybe_f64, + 5.0, + 0.0, + 42.0 +); +make_test!( + optional_bool, + just_bool, + default_bool, + maybe_bool, + true, + false, + true +); +make_test!( + optional_enum, + just_enum, + default_enum, + maybe_enum, + OptionalByte::Two, + OptionalByte::None, + OptionalByte::One +);