diff --git a/dart/test/keyword_test_keyword_test_generated.dart b/dart/test/keyword_test_keyword_test_generated.dart index 6cfc2337c4e..3dd5bea3944 100644 --- a/dart/test/keyword_test_keyword_test_generated.dart +++ b/dart/test/keyword_test_keyword_test_generated.dart @@ -278,3 +278,122 @@ class KeywordsInTableObjectBuilder extends fb.ObjectBuilder { return fbBuilder.buffer; } } +class Table2 { + Table2._(this._bc, this._bcOffset); + factory Table2(List bytes) { + final rootRef = fb.BufferContext.fromBytes(bytes); + return reader.read(rootRef, 0); + } + + static const fb.Reader reader = _Table2Reader(); + + final fb.BufferContext _bc; + final int _bcOffset; + + KeywordsInUnionTypeId? get typeType => KeywordsInUnionTypeId._createOrNull(const fb.Uint8Reader().vTableGetNullable(_bc, _bcOffset, 4)); + dynamic get type { + switch (typeType?.value) { + case 1: return KeywordsInTable.reader.vTableGetNullable(_bc, _bcOffset, 6); + case 2: return KeywordsInTable.reader.vTableGetNullable(_bc, _bcOffset, 6); + default: return null; + } + } + + @override + String toString() { + return 'Table2{typeType: ${typeType}, type: ${type}}'; + } + + Table2T unpack() => Table2T( + typeType: typeType, + type: type); + + static int pack(fb.Builder fbBuilder, Table2T? object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class Table2T implements fb.Packable { + KeywordsInUnionTypeId? typeType; + dynamic type; + + Table2T({ + this.typeType, + this.type}); + + @override + int pack(fb.Builder fbBuilder) { + final int? typeOffset = type?.pack(fbBuilder); + fbBuilder.startTable(2); + fbBuilder.addUint8(0, typeType?.value); + fbBuilder.addOffset(1, typeOffset); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'Table2T{typeType: ${typeType}, type: ${type}}'; + } +} + +class _Table2Reader extends fb.TableReader { + const _Table2Reader(); + + @override + Table2 createObject(fb.BufferContext bc, int offset) => + Table2._(bc, offset); +} + +class Table2Builder { + Table2Builder(this.fbBuilder); + + final fb.Builder fbBuilder; + + void begin() { + fbBuilder.startTable(2); + } + + int addTypeType(KeywordsInUnionTypeId? typeType) { + fbBuilder.addUint8(0, typeType?.value); + return fbBuilder.offset; + } + int addTypeOffset(int? offset) { + fbBuilder.addOffset(1, offset); + return fbBuilder.offset; + } + + int finish() { + return fbBuilder.endTable(); + } +} + +class Table2ObjectBuilder extends fb.ObjectBuilder { + final KeywordsInUnionTypeId? _typeType; + final dynamic _type; + + Table2ObjectBuilder({ + KeywordsInUnionTypeId? typeType, + dynamic type, + }) + : _typeType = typeType, + _type = type; + + /// Finish building, and store into the [fbBuilder]. + @override + int finish(fb.Builder fbBuilder) { + final int? typeOffset = _type?.getOrCreateOffset(fbBuilder); + fbBuilder.startTable(2); + fbBuilder.addUint8(0, _typeType?.value); + fbBuilder.addOffset(1, typeOffset); + return fbBuilder.endTable(); + } + + /// Convenience method to serialize to byte list. + @override + Uint8List toBytes([String? fileIdentifier]) { + final fbBuilder = fb.Builder(deduplicateTables: false); + fbBuilder.finish(finish(fbBuilder), fileIdentifier); + return fbBuilder.buffer; + } +} diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp index c01410a6498..4ea9122ee81 100644 --- a/src/idl_gen_rust.cpp +++ b/src/idl_gen_rust.cpp @@ -1629,7 +1629,7 @@ class RustGenerator : public BaseGenerator { code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset)); code_.SetValue("FIELD", namer_.Field(field)); code_.SetValue("BLDR_DEF_VAL", GetDefaultValue(field, kBuilder)); - code_.SetValue("DISCRIMINANT", namer_.Field(field) + "_type"); + code_.SetValue("DISCRIMINANT", namer_.LegacyRustUnionTypeMethod(field)); code_.IncrementIdentLevel(); cb(field); code_.DecrementIdentLevel(); @@ -1747,7 +1747,10 @@ class RustGenerator : public BaseGenerator { const auto &enum_def = *type.enum_def; code_.SetValue("ENUM_TY", WrapInNameSpace(enum_def)); code_.SetValue("NATIVE_ENUM_NAME", NamespacedNativeName(enum_def)); - code_ += " let {{FIELD}} = match self.{{FIELD}}_type() {"; + code_.SetValue("UNION_TYPE_METHOD", + namer_.LegacyRustUnionTypeMethod(field)); + + code_ += " let {{FIELD}} = match self.{{UNION_TYPE_METHOD}}() {"; code_ += " {{ENUM_TY}}::NONE => {{NATIVE_ENUM_NAME}}::NONE,"; ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { code_ += @@ -1973,10 +1976,12 @@ class RustGenerator : public BaseGenerator { const EnumDef &union_def = *field.value.type.enum_def; code_.SetValue("UNION_TYPE", WrapInNameSpace(union_def)); code_.SetValue("UNION_TYPE_OFFSET_NAME", - namer_.LegacyRustFieldOffsetName(field) + "_TYPE"); + namer_.LegacyRustUnionTypeOffsetName(field)); + code_.SetValue("UNION_TYPE_METHOD", + namer_.LegacyRustUnionTypeMethod(field)); code_ += "\n .visit_union::<{{UNION_TYPE}}, _>(" - "\"{{FIELD}}_type\", Self::{{UNION_TYPE_OFFSET_NAME}}, " + "\"{{UNION_TYPE_METHOD}}\", Self::{{UNION_TYPE_OFFSET_NAME}}, " "\"{{FIELD}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, " "|key, v, pos| {"; code_ += " match key {"; @@ -2045,8 +2050,10 @@ class RustGenerator : public BaseGenerator { const auto &enum_def = *type.enum_def; code_.SetValue("ENUM_TY", WrapInNameSpace(enum_def)); code_.SetValue("FIELD", namer_.Field(field)); + code_.SetValue("UNION_TYPE_METHOD", + namer_.LegacyRustUnionTypeMethod(field)); - code_ += " match self.{{FIELD}}_type() {"; + code_ += " match self.{{UNION_TYPE_METHOD}}() {"; code_ += " {{ENUM_TY}}::NONE => (),"; ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { code_.SetValue("FIELD", namer_.Field(field)); @@ -2255,8 +2262,9 @@ class RustGenerator : public BaseGenerator { case ftUnionValue: { code_.SetValue("ENUM_METHOD", namer_.Method(*field.value.type.enum_def)); + code_.SetValue("DISCRIMINANT", namer_.LegacyRustUnionTypeMethod(field)); code_ += - " let {{FIELD}}_type = " + " let {{DISCRIMINANT}} = " "self.{{FIELD}}.{{ENUM_METHOD}}_type();"; code_ += " let {{FIELD}} = self.{{FIELD}}.pack(_fbb);"; return; diff --git a/src/idl_namer.h b/src/idl_namer.h index f60e30c3f51..7f89433da65 100644 --- a/src/idl_namer.h +++ b/src/idl_namer.h @@ -102,6 +102,10 @@ class IdlNamer : public Namer { std::string LegacyRustFieldOffsetName(const FieldDef &field) const { return "VT_" + ConvertCase(EscapeKeyword(field.name), Case::kAllUpper); } + std::string LegacyRustUnionTypeOffsetName(const FieldDef &field) const { + return "VT_" + ConvertCase(EscapeKeyword(field.name + "_type"), Case::kAllUpper); + } + std::string LegacySwiftVariant(const EnumVal &ev) const { auto name = ev.name; @@ -140,6 +144,11 @@ class IdlNamer : public Namer { return "mutate_" + d.name; } + std::string LegacyRustUnionTypeMethod(const FieldDef &d) { + // assert d is a union + return Method(d.name + "_type"); + } + private: std::string NamespacedString(const struct Namespace *ns, const std::string &str) const { diff --git a/tests/KeywordTest/Table2.cs b/tests/KeywordTest/Table2.cs new file mode 100644 index 00000000000..4e162746448 --- /dev/null +++ b/tests/KeywordTest/Table2.cs @@ -0,0 +1,94 @@ +// +// automatically generated by the FlatBuffers compiler, do not modify +// + +namespace KeywordTest +{ + +using global::System; +using global::System.Collections.Generic; +using global::Google.FlatBuffers; + +public struct Table2 : IFlatbufferObject +{ + private Table __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_22_12_06(); } + public static Table2 GetRootAsTable2(ByteBuffer _bb) { return GetRootAsTable2(_bb, new Table2()); } + public static Table2 GetRootAsTable2(ByteBuffer _bb, Table2 obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } + public Table2 __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public KeywordTest.KeywordsInUnion TypeType { get { int o = __p.__offset(4); return o != 0 ? (KeywordTest.KeywordsInUnion)__p.bb.Get(o + __p.bb_pos) : KeywordTest.KeywordsInUnion.NONE; } } + public TTable? Type() where TTable : struct, IFlatbufferObject { int o = __p.__offset(6); return o != 0 ? (TTable?)__p.__union(o + __p.bb_pos) : null; } + public KeywordTest.KeywordsInTable TypeAsstatic() { return Type().Value; } + public KeywordTest.KeywordsInTable TypeAsinternal() { return Type().Value; } + + public static Offset CreateTable2(FlatBufferBuilder builder, + KeywordTest.KeywordsInUnion type_type = KeywordTest.KeywordsInUnion.NONE, + int typeOffset = 0) { + builder.StartTable(2); + Table2.AddType(builder, typeOffset); + Table2.AddTypeType(builder, type_type); + return Table2.EndTable2(builder); + } + + public static void StartTable2(FlatBufferBuilder builder) { builder.StartTable(2); } + public static void AddTypeType(FlatBufferBuilder builder, KeywordTest.KeywordsInUnion typeType) { builder.AddByte(0, (byte)typeType, 0); } + public static void AddType(FlatBufferBuilder builder, int typeOffset) { builder.AddOffset(1, typeOffset, 0); } + public static Offset EndTable2(FlatBufferBuilder builder) { + int o = builder.EndTable(); + return new Offset(o); + } + public Table2T UnPack() { + var _o = new Table2T(); + this.UnPackTo(_o); + return _o; + } + public void UnPackTo(Table2T _o) { + _o.Type = new KeywordTest.KeywordsInUnionUnion(); + _o.Type.Type = this.TypeType; + switch (this.TypeType) { + default: break; + case KeywordTest.KeywordsInUnion.static: + _o.Type.Value = this.Type().HasValue ? this.Type().Value.UnPack() : null; + break; + case KeywordTest.KeywordsInUnion.internal: + _o.Type.Value = this.Type().HasValue ? this.Type().Value.UnPack() : null; + break; + } + } + public static Offset Pack(FlatBufferBuilder builder, Table2T _o) { + if (_o == null) return default(Offset); + var _type_type = _o.Type == null ? KeywordTest.KeywordsInUnion.NONE : _o.Type.Type; + var _type = _o.Type == null ? 0 : KeywordTest.KeywordsInUnionUnion.Pack(builder, _o.Type); + return CreateTable2( + builder, + _type_type, + _type); + } +} + +public class Table2T +{ + [Newtonsoft.Json.JsonProperty("type_type")] + private KeywordTest.KeywordsInUnion TypeType { + get { + return this.Type != null ? this.Type.Type : KeywordTest.KeywordsInUnion.NONE; + } + set { + this.Type = new KeywordTest.KeywordsInUnionUnion(); + this.Type.Type = value; + } + } + [Newtonsoft.Json.JsonProperty("type")] + [Newtonsoft.Json.JsonConverter(typeof(KeywordTest.KeywordsInUnionUnion_JsonConverter))] + public KeywordTest.KeywordsInUnionUnion Type { get; set; } + + public Table2T() { + this.Type = null; + } +} + + +} diff --git a/tests/keyword_test.fbs b/tests/keyword_test.fbs index 77fc42bccf9..b5955cbfd20 100644 --- a/tests/keyword_test.fbs +++ b/tests/keyword_test.fbs @@ -15,3 +15,7 @@ union KeywordsInUnion { static: KeywordsInTable, internal: KeywordsInTable, } + +table Table2 { + type: KeywordsInUnion; +} diff --git a/tests/keyword_test/keyword_test/table_2_generated.rs b/tests/keyword_test/keyword_test/table_2_generated.rs new file mode 100644 index 00000000000..65c5541e696 --- /dev/null +++ b/tests/keyword_test/keyword_test/table_2_generated.rs @@ -0,0 +1,227 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// @generated +extern crate alloc; +extern crate flatbuffers; +use alloc::boxed::Box; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; +use core::mem; +use core::cmp::Ordering; +use self::flatbuffers::{EndianScalar, Follow}; +use super::*; +pub enum Table2Offset {} +#[derive(Copy, Clone, PartialEq)] + +pub struct Table2<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for Table2<'a> { + type Inner = Table2<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> Table2<'a> { + pub const VT_TYPE_TYPE: flatbuffers::VOffsetT = 4; + pub const VT_TYPE_: flatbuffers::VOffsetT = 6; + + pub const fn get_fully_qualified_name() -> &'static str { + "KeywordTest.Table2" + } + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + Table2 { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>, + args: &'args Table2Args + ) -> flatbuffers::WIPOffset> { + let mut builder = Table2Builder::new(_fbb); + if let Some(x) = args.type_ { builder.add_type_(x); } + builder.add_type_type(args.type_type); + builder.finish() + } + + pub fn unpack(&self) -> Table2T { + let type_ = match self.type_type() { + KeywordsInUnion::NONE => KeywordsInUnionT::NONE, + KeywordsInUnion::static_ => KeywordsInUnionT::Static_(Box::new( + self.type__as_static_() + .expect("Invalid union table, expected `KeywordsInUnion::static_`.") + .unpack() + )), + KeywordsInUnion::internal => KeywordsInUnionT::Internal(Box::new( + self.type__as_internal() + .expect("Invalid union table, expected `KeywordsInUnion::internal`.") + .unpack() + )), + _ => KeywordsInUnionT::NONE, + }; + Table2T { + type_, + } + } + + #[inline] + pub fn type_type(&self) -> KeywordsInUnion { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::(Table2::VT_TYPE_TYPE, Some(KeywordsInUnion::NONE)).unwrap()} + } + #[inline] + pub fn type_(&self) -> Option> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>>(Table2::VT_TYPE_, None)} + } + #[inline] + #[allow(non_snake_case)] + pub fn type__as_static_(&self) -> Option> { + if self.type_type() == KeywordsInUnion::static_ { + self.type_().map(|t| { + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + unsafe { KeywordsInTable::init_from_table(t) } + }) + } else { + None + } + } + + #[inline] + #[allow(non_snake_case)] + pub fn type__as_internal(&self) -> Option> { + if self.type_type() == KeywordsInUnion::internal { + self.type_().map(|t| { + // Safety: + // Created from a valid Table for this object + // Which contains a valid union in this slot + unsafe { KeywordsInTable::init_from_table(t) } + }) + } else { + None + } + } + +} + +impl flatbuffers::Verifiable for Table2<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_union::("type_type", Self::VT_TYPE_TYPE, "type_", Self::VT_TYPE_, false, |key, v, pos| { + match key { + KeywordsInUnion::static_ => v.verify_union_variant::>("KeywordsInUnion::static_", pos), + KeywordsInUnion::internal => v.verify_union_variant::>("KeywordsInUnion::internal", pos), + _ => Ok(()), + } + })? + .finish(); + Ok(()) + } +} +pub struct Table2Args { + pub type_type: KeywordsInUnion, + pub type_: Option>, +} +impl<'a> Default for Table2Args { + #[inline] + fn default() -> Self { + Table2Args { + type_type: KeywordsInUnion::NONE, + type_: None, + } + } +} + +pub struct Table2Builder<'a: 'b, 'b> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b> Table2Builder<'a, 'b> { + #[inline] + pub fn add_type_type(&mut self, type_type: KeywordsInUnion) { + self.fbb_.push_slot::(Table2::VT_TYPE_TYPE, type_type, KeywordsInUnion::NONE); + } + #[inline] + pub fn add_type_(&mut self, type_: flatbuffers::WIPOffset) { + self.fbb_.push_slot_always::>(Table2::VT_TYPE_, type_); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> Table2Builder<'a, 'b> { + let start = _fbb.start_table(); + Table2Builder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} + +impl core::fmt::Debug for Table2<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("Table2"); + ds.field("type_type", &self.type_type()); + match self.type_type() { + KeywordsInUnion::static_ => { + if let Some(x) = self.type__as_static_() { + ds.field("type_", &x) + } else { + ds.field("type_", &"InvalidFlatbuffer: Union discriminant does not match value.") + } + }, + KeywordsInUnion::internal => { + if let Some(x) = self.type__as_internal() { + ds.field("type_", &x) + } else { + ds.field("type_", &"InvalidFlatbuffer: Union discriminant does not match value.") + } + }, + _ => { + let x: Option<()> = None; + ds.field("type_", &x) + }, + }; + ds.finish() + } +} +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq)] +pub struct Table2T { + pub type_: KeywordsInUnionT, +} +impl Default for Table2T { + fn default() -> Self { + Self { + type_: KeywordsInUnionT::NONE, + } + } +} +impl Table2T { + pub fn pack<'b>( + &self, + _fbb: &mut flatbuffers::FlatBufferBuilder<'b> + ) -> flatbuffers::WIPOffset> { + let type_type = self.type_.keywords_in_union_type(); + let type_ = self.type_.pack(_fbb); + Table2::create(_fbb, &Table2Args{ + type_type, + type_, + }) + } +} diff --git a/tests/keyword_test/mod.rs b/tests/keyword_test/mod.rs index d87e5d1c767..56f68c40d53 100644 --- a/tests/keyword_test/mod.rs +++ b/tests/keyword_test/mod.rs @@ -10,4 +10,6 @@ pub mod keyword_test { pub use self::keywords_in_union_generated::*; mod keywords_in_table_generated; pub use self::keywords_in_table_generated::*; + mod table_2_generated; + pub use self::table_2_generated::*; } // keyword_test