From 9fa1d27059a69149856c6e003da8c9723fec7506 Mon Sep 17 00:00:00 2001 From: Casper Date: Mon, 19 Oct 2020 11:40:03 -0700 Subject: [PATCH] Rework enums in rust. (#6098) * Rework enums in rust. They're now a unit struct, rather than an enum. This is a backwards incompatible change but the previous version had UB and was also backwards incompatible so... * Update and test sample rust flatbuffers * Use bitflags crate to properly support rust enums. Previously, the bitflags attribute was just ignored. This is a breaking change as the bitflgs API is not like a normal rust enum (duh). * variant_name() -> Option<_> * repr transparent * Reexport bitflags from flatbuffers * Make bitflags constants CamelCase, matching normal enums * Deprecate c-style associated enum constants Co-authored-by: Casper Neo --- rust/flatbuffers/Cargo.toml | 1 + rust/flatbuffers/src/lib.rs | 1 + samples/monster_generated.rs | 160 +++--- samples/sample_binary.rs | 6 + src/idl_gen_rust.cpp | 278 ++++++---- tests/include_test/include_test1_generated.rs | 1 + .../sub/include_test2_generated.rs | 86 +-- tests/monster_test_generated.rs | 499 +++++++++--------- .../namespace_test1_generated.rs | 100 ++-- .../namespace_test2_generated.rs | 1 + tests/optional_scalars2_generated.rs | 100 ++-- tests/rust_usage_test/Cargo.toml | 5 + .../rust_usage_test/tests/integration_test.rs | 94 +--- 13 files changed, 714 insertions(+), 618 deletions(-) diff --git a/rust/flatbuffers/Cargo.toml b/rust/flatbuffers/Cargo.toml index 845df68edf8..2afb31c70a8 100644 --- a/rust/flatbuffers/Cargo.toml +++ b/rust/flatbuffers/Cargo.toml @@ -12,3 +12,4 @@ categories = ["encoding", "data-structures", "memory-management"] [dependencies] smallvec = "1.0" +bitflags = "1.2" diff --git a/rust/flatbuffers/src/lib.rs b/rust/flatbuffers/src/lib.rs index 95e79c57691..3abd33b4a4e 100644 --- a/rust/flatbuffers/src/lib.rs +++ b/rust/flatbuffers/src/lib.rs @@ -38,6 +38,7 @@ mod vector; mod vtable; mod vtable_writer; +pub use bitflags; pub use crate::builder::FlatBufferBuilder; pub use crate::endian_scalar::{ byte_swap_f32, byte_swap_f64, emplace_scalar, read_scalar, read_scalar_at, EndianScalar, diff --git a/samples/monster_generated.rs b/samples/monster_generated.rs index f793f85241a..0d37eb4bc25 100644 --- a/samples/monster_generated.rs +++ b/samples/monster_generated.rs @@ -1,6 +1,7 @@ // automatically generated by the FlatBuffers compiler, do not modify +#![allow(unused_imports, dead_code)] use std::mem; use std::cmp::Ordering; @@ -25,50 +26,67 @@ pub mod sample { extern crate flatbuffers; use self::flatbuffers::EndianScalar; -#[allow(non_camel_case_types)] -#[repr(i8)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum Color { - Red = 0, - Green = 1, - Blue = 2, - +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Color(pub i8); +#[allow(non_upper_case_globals)] +impl Color { + pub const ENUM_MIN: i8 = 0; + pub const ENUM_MAX: i8 = 2; + pub const Red: Self = Self(0); + pub const Green: Self = Self(1); + pub const Blue: Self = Self(2); + pub const ENUM_VALUES: &'static [Self] = &[ + Self::Red, + Self::Green, + Self::Blue, + ]; + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> &'static str { + match self { + Self::Red => "Red", + Self::Green => "Green", + Self::Blue => "Blue", + _ => "", + } + } +} +impl std::fmt::Debug for Color { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let name = self.variant_name(); + if name.is_empty() { + f.write_fmt(format_args!("", self.0)) + } else { + f.write_str(name) + } + } } - -pub const ENUM_MIN_COLOR: i8 = 0; -pub const ENUM_MAX_COLOR: i8 = 2; - impl<'a> flatbuffers::Follow<'a> for Color { type Inner = Self; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - flatbuffers::read_scalar_at::(buf, loc) + Self(flatbuffers::read_scalar_at::(buf, loc)) } } +impl flatbuffers::Push for Color { + type Output = Color; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + flatbuffers::emplace_scalar::(dst, self.0); + } +} + impl flatbuffers::EndianScalar for Color { #[inline] fn to_little_endian(self) -> Self { - let n = i8::to_le(self as i8); - let p = &n as *const i8 as *const Color; - unsafe { *p } + Self(i8::to_le(self.0)) } #[inline] fn from_little_endian(self) -> Self { - let n = i8::from_le(self as i8); - let p = &n as *const i8 as *const Color; - unsafe { *p } + Self(i8::from_le(self.0)) } } -impl flatbuffers::Push for Color { - type Output = Color; - #[inline] - fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, *self); - } -} - #[allow(non_camel_case_types)] pub const ENUM_VALUES_COLOR: [Color; 3] = [ Color::Red, @@ -76,78 +94,70 @@ pub const ENUM_VALUES_COLOR: [Color; 3] = [ Color::Blue ]; -#[allow(non_camel_case_types)] -pub const ENUM_NAMES_COLOR: [&str; 3] = [ - "Red", - "Green", - "Blue" -]; - -pub fn enum_name_color(e: Color) -> &'static str { - let index = e as i8; - ENUM_NAMES_COLOR[index as usize] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Equipment(pub u8); +#[allow(non_upper_case_globals)] +impl Equipment { + pub const ENUM_MIN: u8 = 0; + pub const ENUM_MAX: u8 = 1; + pub const NONE: Self = Self(0); + pub const Weapon: Self = Self(1); + pub const ENUM_VALUES: &'static [Self] = &[ + Self::NONE, + Self::Weapon, + ]; + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> &'static str { + match self { + Self::NONE => "NONE", + Self::Weapon => "Weapon", + _ => "", + } + } } - -#[allow(non_camel_case_types)] -#[repr(u8)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum Equipment { - NONE = 0, - Weapon = 1, - +impl std::fmt::Debug for Equipment { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let name = self.variant_name(); + if name.is_empty() { + f.write_fmt(format_args!("", self.0)) + } else { + f.write_str(name) + } + } } - -pub const ENUM_MIN_EQUIPMENT: u8 = 0; -pub const ENUM_MAX_EQUIPMENT: u8 = 1; - impl<'a> flatbuffers::Follow<'a> for Equipment { type Inner = Self; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - flatbuffers::read_scalar_at::(buf, loc) + Self(flatbuffers::read_scalar_at::(buf, loc)) } } +impl flatbuffers::Push for Equipment { + type Output = Equipment; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + flatbuffers::emplace_scalar::(dst, self.0); + } +} + impl flatbuffers::EndianScalar for Equipment { #[inline] fn to_little_endian(self) -> Self { - let n = u8::to_le(self as u8); - let p = &n as *const u8 as *const Equipment; - unsafe { *p } + Self(u8::to_le(self.0)) } #[inline] fn from_little_endian(self) -> Self { - let n = u8::from_le(self as u8); - let p = &n as *const u8 as *const Equipment; - unsafe { *p } + Self(u8::from_le(self.0)) } } -impl flatbuffers::Push for Equipment { - type Output = Equipment; - #[inline] - fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, *self); - } -} - #[allow(non_camel_case_types)] pub const ENUM_VALUES_EQUIPMENT: [Equipment; 2] = [ Equipment::NONE, Equipment::Weapon ]; -#[allow(non_camel_case_types)] -pub const ENUM_NAMES_EQUIPMENT: [&str; 2] = [ - "NONE", - "Weapon" -]; - -pub fn enum_name_equipment(e: Equipment) -> &'static str { - let index = e as u8; - ENUM_NAMES_EQUIPMENT[index as usize] -} - pub struct EquipmentUnionTableOffset {} // struct Vec3, aligned to 4 #[repr(C, align(4))] diff --git a/samples/sample_binary.rs b/samples/sample_binary.rs index 7a4c2ae0c7a..b42e8c8e65c 100644 --- a/samples/sample_binary.rs +++ b/samples/sample_binary.rs @@ -153,3 +153,9 @@ fn main() { println!("The FlatBuffer was successfully created and accessed!"); } + +#[cfg(test)] +#[test] +fn test_main() { + main() +} diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp index 4e157827e6d..ad46bac67fc 100644 --- a/src/idl_gen_rust.cpp +++ b/src/idl_gen_rust.cpp @@ -175,6 +175,14 @@ std::string AddUnwrapIfRequired(std::string s, bool required) { } } +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; + return ed && IsBitFlagsEnum(*ed); +} + namespace rust { class RustGenerator : public BaseGenerator { @@ -215,7 +223,10 @@ class RustGenerator : public BaseGenerator { // the future. as a result, we proactively block these out as reserved // words. "follow", "push", "size", "alignment", "to_little_endian", - "from_little_endian", nullptr + "from_little_endian", nullptr, + + // used by Enum constants + "ENUM_MAX", "ENUM_MIN", "ENUM_VALUES", }; for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw); } @@ -508,11 +519,28 @@ class RustGenerator : public BaseGenerator { } } - std::string GetEnumValUse(const EnumDef &enum_def, + std::string GetEnumValue(const EnumDef &enum_def, 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) { + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + const auto &ev = **it; + code_.SetValue("VARIANT", Name(ev)); + code_.SetValue("VALUE", enum_def.ToString(ev)); + cb(ev); + } + } + void ForAllEnumValues(const EnumDef &enum_def, std::function cb) { + std::function wrapped = [&](const EnumVal& unused) { + (void) unused; + cb(); + }; + ForAllEnumValues1(enum_def, wrapped); + } // Generate an enum declaration, // an enum string lookup table, // an enum match function, @@ -520,132 +548,162 @@ class RustGenerator : public BaseGenerator { void GenEnum(const EnumDef &enum_def) { code_.SetValue("ENUM_NAME", Name(enum_def)); code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type)); - - GenComment(enum_def.doc_comment); - code_ += "#[allow(non_camel_case_types)]"; - code_ += "#[repr({{BASE_TYPE}})]"; - code_ += - "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]"; - code_ += "pub enum " + Name(enum_def) + " {"; - - for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { - const auto &ev = **it; - - GenComment(ev.doc_comment, " "); - code_.SetValue("KEY", Name(ev)); - code_.SetValue("VALUE", enum_def.ToString(ev)); - code_ += " {{KEY}} = {{VALUE}},"; - } + code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def))); + code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def)))); const EnumVal *minv = enum_def.MinValue(); const EnumVal *maxv = enum_def.MaxValue(); FLATBUFFERS_ASSERT(minv && maxv); + code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv)); + 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. + code_ += "#[allow(non_upper_case_globals)]"; + code_ += "mod bitflags_{{ENUM_NAME_SNAKE}} {"; + code_ += " flatbuffers::bitflags::bitflags! {"; + GenComment(enum_def.doc_comment, " "); + code_ += " pub struct {{ENUM_NAME}}: {{BASE_TYPE}} {"; + ForAllEnumValues1(enum_def, [&](const EnumVal &ev){ + this->GenComment(ev.doc_comment, " "); + code_ += " const {{VARIANT}} = {{VALUE}};"; + }); + code_ += " }"; + code_ += " }"; + code_ += "}"; + code_ += "pub use self::bitflags_{{ENUM_NAME_SNAKE}}::{{ENUM_NAME}};"; + code_ += ""; + + // Generate Follow and Push so we can serialize and stuff. + code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {"; + code_ += " type Inner = Self;"; + code_ += " #[inline]"; + code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; + code_ += " let bits = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc);"; + code_ += " unsafe { Self::from_bits_unchecked(bits) }"; + code_ += " }"; + code_ += "}"; + code_ += ""; + code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {"; + code_ += " type Output = {{ENUM_NAME}};"; + code_ += " #[inline]"; + code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; + code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>" + "(dst, self.bits());"; + code_ += " }"; + code_ += "}"; + code_ += ""; + code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {"; + code_ += " #[inline]"; + code_ += " fn to_little_endian(self) -> Self {"; + code_ += " let bits = {{BASE_TYPE}}::to_le(self.bits());"; + code_ += " unsafe { Self::from_bits_unchecked(bits) }"; + code_ += " }"; + code_ += " #[inline]"; + code_ += " fn from_little_endian(self) -> Self {"; + code_ += " let bits = {{BASE_TYPE}}::from_le(self.bits());"; + code_ += " unsafe { Self::from_bits_unchecked(bits) }"; + code_ += " }"; + code_ += "}"; + code_ += ""; + return; + } + // Deprecated associated constants; + code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants" + " instead. This will no longer be generated in 2021.\")]"; + code_ += "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" + " = {{ENUM_MIN_BASE_VALUE}};"; + code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants" + " instead. This will no longer be generated in 2021.\")]"; + code_ += "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" + " = {{ENUM_MAX_BASE_VALUE}};"; + auto num_fields = NumToString(enum_def.size()); + code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants" + " instead. This will no longer be generated in 2021.\")]"; + code_ += "#[allow(non_camel_case_types)]"; + code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " + + num_fields + "] = ["; + ForAllEnumValues1(enum_def, [&](const EnumVal &ev){ + code_ += " " + GetEnumValue(enum_def, ev) + ","; + }); + code_ += "];"; code_ += ""; - code_ += "}"; + + GenComment(enum_def.doc_comment); + code_ += + "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]"; + 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){ + this->GenComment(ev.doc_comment, " "); + code_ += " pub const {{VARIANT}}: Self = Self({{VALUE}});"; + }); code_ += ""; + // Generate Associated constants + 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}},"; + }); + 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, [&](){ + code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),"; + }); + code_ += " _ => None,"; + code_ += " }"; + code_ += " }"; + code_ += "}"; - code_.SetValue("ENUM_NAME", Name(enum_def)); - code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def))); - code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def)))); - code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv)); - code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv)); + // 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_ += " if let Some(name) = self.variant_name() {"; + code_ += " f.write_str(name)"; + code_ += " } else {"; + code_ += " f.write_fmt(format_args!(\"\", self.0))"; + code_ += " }"; + code_ += " }"; + code_ += "}"; - // Generate enum constants, and impls for Follow, EndianScalar, and Push. - code_ += "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\"; - code_ += "{{ENUM_MIN_BASE_VALUE}};"; - code_ += "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\"; - code_ += "{{ENUM_MAX_BASE_VALUE}};"; - code_ += ""; + // Generate Follow and Push so we can serialize and stuff. code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {"; code_ += " type Inner = Self;"; code_ += " #[inline]"; code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; - code_ += " flatbuffers::read_scalar_at::(buf, loc)"; + code_ += " Self(flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc))"; code_ += " }"; code_ += "}"; code_ += ""; + code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {"; + code_ += " type Output = {{ENUM_NAME}};"; + code_ += " #[inline]"; + code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; + code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>" + "(dst, self.0);"; + code_ += " }"; + code_ += "}"; + code_ += ""; code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {"; code_ += " #[inline]"; code_ += " fn to_little_endian(self) -> Self {"; - code_ += " let n = {{BASE_TYPE}}::to_le(self as {{BASE_TYPE}});"; - code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};"; - code_ += " unsafe { *p }"; + code_ += " Self({{BASE_TYPE}}::to_le(self.0))"; code_ += " }"; code_ += " #[inline]"; code_ += " fn from_little_endian(self) -> Self {"; - code_ += " let n = {{BASE_TYPE}}::from_le(self as {{BASE_TYPE}});"; - code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};"; - code_ += " unsafe { *p }"; + code_ += " Self({{BASE_TYPE}}::from_le(self.0))"; code_ += " }"; code_ += "}"; code_ += ""; - code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {"; - code_ += " type Output = {{ENUM_NAME}};"; - code_ += " #[inline]"; - code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; - code_ += - " flatbuffers::emplace_scalar::<{{ENUM_NAME}}>" - "(dst, *self);"; - code_ += " }"; - code_ += "}"; - code_ += ""; - - // Generate an array of all enumeration values. - auto num_fields = NumToString(enum_def.size()); - code_ += "#[allow(non_camel_case_types)]"; - code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " + - num_fields + "] = ["; - for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { - const auto &ev = **it; - auto value = GetEnumValUse(enum_def, ev); - auto suffix = *it != enum_def.Vals().back() ? "," : ""; - code_ += " " + value + suffix; - } - code_ += "];"; - code_ += ""; - - // Generate a string table for enum values. - // Problem is, if values are very sparse that could generate really big - // tables. Ideally in that case we generate a map lookup instead, but for - // the moment we simply don't output a table at all. - auto range = enum_def.Distance(); - // Average distance between values above which we consider a table - // "too sparse". Change at will. - static const uint64_t kMaxSparseness = 5; - if (range / static_cast(enum_def.size()) < kMaxSparseness) { - code_ += "#[allow(non_camel_case_types)]"; - code_ += "pub const ENUM_NAMES_{{ENUM_NAME_CAPS}}: [&str; " + - NumToString(range + 1) + "] = ["; - - auto val = enum_def.Vals().front(); - for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); - ++it) { - auto ev = *it; - for (auto k = enum_def.Distance(val, ev); k > 1; --k) { - code_ += " \"\","; - } - val = ev; - auto suffix = *it != enum_def.Vals().back() ? "," : ""; - code_ += " \"" + Name(*ev) + "\"" + suffix; - } - code_ += "];"; - code_ += ""; - - code_ += - "pub fn enum_name_{{ENUM_NAME_SNAKE}}(e: {{ENUM_NAME}}) -> " - "&'static str {"; - - code_ += " let index = e as {{BASE_TYPE}}\\"; - if (enum_def.MinValue()->IsNonZero()) { - auto vals = GetEnumValUse(enum_def, *enum_def.MinValue()); - code_ += " - " + vals + " as {{BASE_TYPE}}\\"; - } - code_ += ";"; - - code_ += " ENUM_NAMES_{{ENUM_NAME_CAPS}}[index as usize]"; - code_ += "}"; - code_ += ""; - } if (enum_def.is_union) { // Generate tyoesafe offset(s) for unions @@ -677,7 +735,7 @@ class RustGenerator : public BaseGenerator { auto ev = field.value.type.enum_def->FindByValue(field.value.constant); assert(ev); return WrapInNameSpace(field.value.type.enum_def->defined_namespace, - GetEnumValUse(*field.value.type.enum_def, *ev)); + GetEnumValue(*field.value.type.enum_def, *ev)); } // All pointer-ish types have a default value of None, because they are @@ -1027,9 +1085,8 @@ class RustGenerator : public BaseGenerator { } case ftUnionKey: case ftEnumKey: { - const auto underlying_typname = GetTypeBasic(type); //<- never used - const auto typname = WrapInNameSpace(*type.enum_def); - const auto default_value = GetDefaultScalarValue(field); + const std::string typname = WrapInNameSpace(*type.enum_def); + const std::string default_value = GetDefaultScalarValue(field); if (field.optional) { return "self._tab.get::<" + typname + ">(" + offset_name + ", None)"; } else { @@ -1302,7 +1359,7 @@ class RustGenerator : public BaseGenerator { code_.SetValue( "U_ELEMENT_ENUM_TYPE", - WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev))); + WrapInNameSpace(u->defined_namespace, GetEnumValue(*u, ev))); code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type); code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev))); @@ -1763,6 +1820,9 @@ class RustGenerator : public BaseGenerator { } void GenNamespaceImports(const int white_spaces) { + if (white_spaces == 0) { + code_ += "#![allow(unused_imports, dead_code)]"; + } std::string indent = std::string(white_spaces, ' '); code_ += ""; if (!parser_.opts.generate_all) { diff --git a/tests/include_test/include_test1_generated.rs b/tests/include_test/include_test1_generated.rs index 3c549e01143..12b8b08b9de 100644 --- a/tests/include_test/include_test1_generated.rs +++ b/tests/include_test/include_test1_generated.rs @@ -1,6 +1,7 @@ // automatically generated by the FlatBuffers compiler, do not modify +#![allow(unused_imports, dead_code)] use crate::include_test2_generated::*; use std::mem; diff --git a/tests/include_test/sub/include_test2_generated.rs b/tests/include_test/sub/include_test2_generated.rs index a3500c97414..6cfebf2bb10 100644 --- a/tests/include_test/sub/include_test2_generated.rs +++ b/tests/include_test/sub/include_test2_generated.rs @@ -1,6 +1,7 @@ // automatically generated by the FlatBuffers compiler, do not modify +#![allow(unused_imports, dead_code)] use crate::include_test1_generated::*; use std::mem; @@ -28,37 +29,50 @@ pub mod other_name_space { extern crate flatbuffers; use self::flatbuffers::EndianScalar; -#[allow(non_camel_case_types)] -#[repr(i64)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum FromInclude { - IncludeVal = 0, - -} - +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] pub const ENUM_MIN_FROM_INCLUDE: i64 = 0; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] pub const ENUM_MAX_FROM_INCLUDE: i64 = 0; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] +#[allow(non_camel_case_types)] +pub const ENUM_VALUES_FROM_INCLUDE: [FromInclude; 1] = [ + FromInclude::IncludeVal, +]; -impl<'a> flatbuffers::Follow<'a> for FromInclude { - type Inner = Self; - #[inline] - fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - flatbuffers::read_scalar_at::(buf, loc) +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct FromInclude(pub i64); +#[allow(non_upper_case_globals)] +impl FromInclude { + pub const IncludeVal: Self = Self(0); + + pub const ENUM_MIN: i64 = 0; + pub const ENUM_MAX: i64 = 0; + pub const ENUM_VALUES: &'static [Self] = &[ + Self::IncludeVal, + ]; + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> Option<&'static str> { + match self { + Self::IncludeVal => Some("IncludeVal"), + _ => None, + } } } - -impl flatbuffers::EndianScalar for FromInclude { - #[inline] - fn to_little_endian(self) -> Self { - let n = i64::to_le(self as i64); - let p = &n as *const i64 as *const FromInclude; - unsafe { *p } +impl std::fmt::Debug for FromInclude { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(name) = self.variant_name() { + f.write_str(name) + } else { + f.write_fmt(format_args!("", self.0)) + } } +} +impl<'a> flatbuffers::Follow<'a> for FromInclude { + type Inner = Self; #[inline] - fn from_little_endian(self) -> Self { - let n = i64::from_le(self as i64); - let p = &n as *const i64 as *const FromInclude; - unsafe { *p } + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self(flatbuffers::read_scalar_at::(buf, loc)) } } @@ -66,23 +80,19 @@ impl flatbuffers::Push for FromInclude { type Output = FromInclude; #[inline] fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, *self); + flatbuffers::emplace_scalar::(dst, self.0); } } -#[allow(non_camel_case_types)] -pub const ENUM_VALUES_FROM_INCLUDE: [FromInclude; 1] = [ - FromInclude::IncludeVal -]; - -#[allow(non_camel_case_types)] -pub const ENUM_NAMES_FROM_INCLUDE: [&str; 1] = [ - "IncludeVal" -]; - -pub fn enum_name_from_include(e: FromInclude) -> &'static str { - let index = e as i64; - ENUM_NAMES_FROM_INCLUDE[index as usize] +impl flatbuffers::EndianScalar for FromInclude { + #[inline] + fn to_little_endian(self) -> Self { + Self(i64::to_le(self.0)) + } + #[inline] + fn from_little_endian(self) -> Self { + Self(i64::from_le(self.0)) + } } // struct Unused, aligned to 4 diff --git a/tests/monster_test_generated.rs b/tests/monster_test_generated.rs index 47afea1cf42..809e67a6167 100644 --- a/tests/monster_test_generated.rs +++ b/tests/monster_test_generated.rs @@ -1,6 +1,7 @@ // automatically generated by the FlatBuffers compiler, do not modify +#![allow(unused_imports, dead_code)] use crate::include_test1_generated::*; use crate::include_test2_generated::*; @@ -175,43 +176,28 @@ pub mod example { extern crate flatbuffers; use self::flatbuffers::EndianScalar; -/// Composite components of Monster color. -#[allow(non_camel_case_types)] -#[repr(u8)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum Color { - Red = 1, - /// \brief color Green - /// Green is bit_flag with value (1u << 1) - Green = 2, - /// \brief color Blue (1u << 3) - Blue = 8, - +#[allow(non_upper_case_globals)] +mod bitflags_color { + flatbuffers::bitflags::bitflags! { + /// Composite components of Monster color. + pub struct Color: u8 { + const Red = 1; + /// \brief color Green + /// Green is bit_flag with value (1u << 1) + const Green = 2; + /// \brief color Blue (1u << 3) + const Blue = 8; + } + } } - -pub const ENUM_MIN_COLOR: u8 = 1; -pub const ENUM_MAX_COLOR: u8 = 8; +pub use self::bitflags_color::Color; impl<'a> flatbuffers::Follow<'a> for Color { type Inner = Self; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - flatbuffers::read_scalar_at::(buf, loc) - } -} - -impl flatbuffers::EndianScalar for Color { - #[inline] - fn to_little_endian(self) -> Self { - let n = u8::to_le(self as u8); - let p = &n as *const u8 as *const Color; - unsafe { *p } - } - #[inline] - fn from_little_endian(self) -> Self { - let n = u8::from_le(self as u8); - let p = &n as *const u8 as *const Color; - unsafe { *p } + let bits = flatbuffers::read_scalar_at::(buf, loc); + unsafe { Self::from_bits_unchecked(bits) } } } @@ -219,298 +205,335 @@ impl flatbuffers::Push for Color { type Output = Color; #[inline] fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, *self); + flatbuffers::emplace_scalar::(dst, self.bits()); } } -#[allow(non_camel_case_types)] -pub const ENUM_VALUES_COLOR: [Color; 3] = [ - Color::Red, - Color::Green, - Color::Blue -]; - -#[allow(non_camel_case_types)] -pub const ENUM_NAMES_COLOR: [&str; 8] = [ - "Red", - "Green", - "", - "", - "", - "", - "", - "Blue" -]; - -pub fn enum_name_color(e: Color) -> &'static str { - let index = e as u8 - Color::Red as u8; - ENUM_NAMES_COLOR[index as usize] -} - -#[allow(non_camel_case_types)] -#[repr(i8)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum Race { - None = -1, - Human = 0, - Dwarf = 1, - Elf = 2, - -} - -pub const ENUM_MIN_RACE: i8 = -1; -pub const ENUM_MAX_RACE: i8 = 2; - -impl<'a> flatbuffers::Follow<'a> for Race { - type Inner = Self; - #[inline] - fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - flatbuffers::read_scalar_at::(buf, loc) - } -} - -impl flatbuffers::EndianScalar for Race { +impl flatbuffers::EndianScalar for Color { #[inline] fn to_little_endian(self) -> Self { - let n = i8::to_le(self as i8); - let p = &n as *const i8 as *const Race; - unsafe { *p } + let bits = u8::to_le(self.bits()); + unsafe { Self::from_bits_unchecked(bits) } } #[inline] fn from_little_endian(self) -> Self { - let n = i8::from_le(self as i8); - let p = &n as *const i8 as *const Race; - unsafe { *p } + let bits = u8::from_le(self.bits()); + unsafe { Self::from_bits_unchecked(bits) } } } -impl flatbuffers::Push for Race { - type Output = Race; - #[inline] - fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, *self); - } -} - +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MIN_RACE: i8 = -1; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MAX_RACE: i8 = 2; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] #[allow(non_camel_case_types)] pub const ENUM_VALUES_RACE: [Race; 4] = [ Race::None, Race::Human, Race::Dwarf, - Race::Elf -]; - -#[allow(non_camel_case_types)] -pub const ENUM_NAMES_RACE: [&str; 4] = [ - "None", - "Human", - "Dwarf", - "Elf" + Race::Elf, ]; -pub fn enum_name_race(e: Race) -> &'static str { - let index = e as i8 - Race::None as i8; - ENUM_NAMES_RACE[index as usize] -} - -#[allow(non_camel_case_types)] -#[repr(u8)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum Any { - NONE = 0, - Monster = 1, - TestSimpleTableWithEnum = 2, - MyGame_Example2_Monster = 3, - +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct Race(pub i8); +#[allow(non_upper_case_globals)] +impl Race { + pub const None: Self = Self(-1); + pub const Human: Self = Self(0); + pub const Dwarf: Self = Self(1); + pub const Elf: Self = Self(2); + + pub const ENUM_MIN: i8 = -1; + pub const ENUM_MAX: i8 = 2; + pub const ENUM_VALUES: &'static [Self] = &[ + Self::None, + Self::Human, + Self::Dwarf, + Self::Elf, + ]; + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> Option<&'static str> { + match self { + Self::None => Some("None"), + Self::Human => Some("Human"), + Self::Dwarf => Some("Dwarf"), + Self::Elf => Some("Elf"), + _ => None, + } + } +} +impl std::fmt::Debug for Race { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(name) = self.variant_name() { + f.write_str(name) + } else { + f.write_fmt(format_args!("", self.0)) + } + } } - -pub const ENUM_MIN_ANY: u8 = 0; -pub const ENUM_MAX_ANY: u8 = 3; - -impl<'a> flatbuffers::Follow<'a> for Any { +impl<'a> flatbuffers::Follow<'a> for Race { type Inner = Self; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - flatbuffers::read_scalar_at::(buf, loc) + Self(flatbuffers::read_scalar_at::(buf, loc)) } } -impl flatbuffers::EndianScalar for Any { +impl flatbuffers::Push for Race { + type Output = Race; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + flatbuffers::emplace_scalar::(dst, self.0); + } +} + +impl flatbuffers::EndianScalar for Race { #[inline] fn to_little_endian(self) -> Self { - let n = u8::to_le(self as u8); - let p = &n as *const u8 as *const Any; - unsafe { *p } + Self(i8::to_le(self.0)) } #[inline] fn from_little_endian(self) -> Self { - let n = u8::from_le(self as u8); - let p = &n as *const u8 as *const Any; - unsafe { *p } + Self(i8::from_le(self.0)) } } -impl flatbuffers::Push for Any { - type Output = Any; - #[inline] - fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, *self); - } -} - +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MIN_ANY: u8 = 0; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MAX_ANY: u8 = 3; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] #[allow(non_camel_case_types)] pub const ENUM_VALUES_ANY: [Any; 4] = [ Any::NONE, Any::Monster, Any::TestSimpleTableWithEnum, - Any::MyGame_Example2_Monster -]; - -#[allow(non_camel_case_types)] -pub const ENUM_NAMES_ANY: [&str; 4] = [ - "NONE", - "Monster", - "TestSimpleTableWithEnum", - "MyGame_Example2_Monster" + Any::MyGame_Example2_Monster, ]; -pub fn enum_name_any(e: Any) -> &'static str { - let index = e as u8; - ENUM_NAMES_ANY[index as usize] -} - -pub struct AnyUnionTableOffset {} -#[allow(non_camel_case_types)] -#[repr(u8)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum AnyUniqueAliases { - NONE = 0, - M = 1, - TS = 2, - M2 = 3, - +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct Any(pub u8); +#[allow(non_upper_case_globals)] +impl Any { + pub const NONE: Self = Self(0); + pub const Monster: Self = Self(1); + pub const TestSimpleTableWithEnum: Self = Self(2); + pub const MyGame_Example2_Monster: Self = Self(3); + + pub const ENUM_MIN: u8 = 0; + pub const ENUM_MAX: u8 = 3; + pub const ENUM_VALUES: &'static [Self] = &[ + Self::NONE, + Self::Monster, + Self::TestSimpleTableWithEnum, + Self::MyGame_Example2_Monster, + ]; + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> Option<&'static str> { + match self { + Self::NONE => Some("NONE"), + Self::Monster => Some("Monster"), + Self::TestSimpleTableWithEnum => Some("TestSimpleTableWithEnum"), + Self::MyGame_Example2_Monster => Some("MyGame_Example2_Monster"), + _ => None, + } + } +} +impl std::fmt::Debug for Any { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(name) = self.variant_name() { + f.write_str(name) + } else { + f.write_fmt(format_args!("", self.0)) + } + } } - -pub const ENUM_MIN_ANY_UNIQUE_ALIASES: u8 = 0; -pub const ENUM_MAX_ANY_UNIQUE_ALIASES: u8 = 3; - -impl<'a> flatbuffers::Follow<'a> for AnyUniqueAliases { +impl<'a> flatbuffers::Follow<'a> for Any { type Inner = Self; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - flatbuffers::read_scalar_at::(buf, loc) + Self(flatbuffers::read_scalar_at::(buf, loc)) } } -impl flatbuffers::EndianScalar for AnyUniqueAliases { +impl flatbuffers::Push for Any { + type Output = Any; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + flatbuffers::emplace_scalar::(dst, self.0); + } +} + +impl flatbuffers::EndianScalar for Any { #[inline] fn to_little_endian(self) -> Self { - let n = u8::to_le(self as u8); - let p = &n as *const u8 as *const AnyUniqueAliases; - unsafe { *p } + Self(u8::to_le(self.0)) } #[inline] fn from_little_endian(self) -> Self { - let n = u8::from_le(self as u8); - let p = &n as *const u8 as *const AnyUniqueAliases; - unsafe { *p } + Self(u8::from_le(self.0)) } } -impl flatbuffers::Push for AnyUniqueAliases { - type Output = AnyUniqueAliases; - #[inline] - fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, *self); - } -} - +pub struct AnyUnionTableOffset {} +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MIN_ANY_UNIQUE_ALIASES: u8 = 0; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MAX_ANY_UNIQUE_ALIASES: u8 = 3; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] #[allow(non_camel_case_types)] pub const ENUM_VALUES_ANY_UNIQUE_ALIASES: [AnyUniqueAliases; 4] = [ AnyUniqueAliases::NONE, AnyUniqueAliases::M, AnyUniqueAliases::TS, - AnyUniqueAliases::M2 + AnyUniqueAliases::M2, ]; -#[allow(non_camel_case_types)] -pub const ENUM_NAMES_ANY_UNIQUE_ALIASES: [&str; 4] = [ - "NONE", - "M", - "TS", - "M2" -]; - -pub fn enum_name_any_unique_aliases(e: AnyUniqueAliases) -> &'static str { - let index = e as u8; - ENUM_NAMES_ANY_UNIQUE_ALIASES[index as usize] -} - -pub struct AnyUniqueAliasesUnionTableOffset {} -#[allow(non_camel_case_types)] -#[repr(u8)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum AnyAmbiguousAliases { - NONE = 0, - M1 = 1, - M2 = 2, - M3 = 3, - +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct AnyUniqueAliases(pub u8); +#[allow(non_upper_case_globals)] +impl AnyUniqueAliases { + pub const NONE: Self = Self(0); + pub const M: Self = Self(1); + pub const TS: Self = Self(2); + pub const M2: Self = Self(3); + + pub const ENUM_MIN: u8 = 0; + pub const ENUM_MAX: u8 = 3; + pub const ENUM_VALUES: &'static [Self] = &[ + Self::NONE, + Self::M, + Self::TS, + Self::M2, + ]; + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> Option<&'static str> { + match self { + Self::NONE => Some("NONE"), + Self::M => Some("M"), + Self::TS => Some("TS"), + Self::M2 => Some("M2"), + _ => None, + } + } +} +impl std::fmt::Debug for AnyUniqueAliases { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(name) = self.variant_name() { + f.write_str(name) + } else { + f.write_fmt(format_args!("", self.0)) + } + } } - -pub const ENUM_MIN_ANY_AMBIGUOUS_ALIASES: u8 = 0; -pub const ENUM_MAX_ANY_AMBIGUOUS_ALIASES: u8 = 3; - -impl<'a> flatbuffers::Follow<'a> for AnyAmbiguousAliases { +impl<'a> flatbuffers::Follow<'a> for AnyUniqueAliases { type Inner = Self; #[inline] fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - flatbuffers::read_scalar_at::(buf, loc) + Self(flatbuffers::read_scalar_at::(buf, loc)) } } -impl flatbuffers::EndianScalar for AnyAmbiguousAliases { +impl flatbuffers::Push for AnyUniqueAliases { + type Output = AnyUniqueAliases; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + flatbuffers::emplace_scalar::(dst, self.0); + } +} + +impl flatbuffers::EndianScalar for AnyUniqueAliases { #[inline] fn to_little_endian(self) -> Self { - let n = u8::to_le(self as u8); - let p = &n as *const u8 as *const AnyAmbiguousAliases; - unsafe { *p } + Self(u8::to_le(self.0)) } #[inline] fn from_little_endian(self) -> Self { - let n = u8::from_le(self as u8); - let p = &n as *const u8 as *const AnyAmbiguousAliases; - unsafe { *p } + Self(u8::from_le(self.0)) } } -impl flatbuffers::Push for AnyAmbiguousAliases { - type Output = AnyAmbiguousAliases; - #[inline] - fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, *self); - } -} - +pub struct AnyUniqueAliasesUnionTableOffset {} +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MIN_ANY_AMBIGUOUS_ALIASES: u8 = 0; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] +pub const ENUM_MAX_ANY_AMBIGUOUS_ALIASES: u8 = 3; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] #[allow(non_camel_case_types)] pub const ENUM_VALUES_ANY_AMBIGUOUS_ALIASES: [AnyAmbiguousAliases; 4] = [ AnyAmbiguousAliases::NONE, AnyAmbiguousAliases::M1, AnyAmbiguousAliases::M2, - AnyAmbiguousAliases::M3 + AnyAmbiguousAliases::M3, ]; -#[allow(non_camel_case_types)] -pub const ENUM_NAMES_ANY_AMBIGUOUS_ALIASES: [&str; 4] = [ - "NONE", - "M1", - "M2", - "M3" -]; +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct AnyAmbiguousAliases(pub u8); +#[allow(non_upper_case_globals)] +impl AnyAmbiguousAliases { + pub const NONE: Self = Self(0); + pub const M1: Self = Self(1); + pub const M2: Self = Self(2); + pub const M3: Self = Self(3); + + pub const ENUM_MIN: u8 = 0; + pub const ENUM_MAX: u8 = 3; + pub const ENUM_VALUES: &'static [Self] = &[ + Self::NONE, + Self::M1, + Self::M2, + Self::M3, + ]; + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> Option<&'static str> { + match self { + Self::NONE => Some("NONE"), + Self::M1 => Some("M1"), + Self::M2 => Some("M2"), + Self::M3 => Some("M3"), + _ => None, + } + } +} +impl std::fmt::Debug for AnyAmbiguousAliases { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(name) = self.variant_name() { + f.write_str(name) + } else { + f.write_fmt(format_args!("", self.0)) + } + } +} +impl<'a> flatbuffers::Follow<'a> for AnyAmbiguousAliases { + type Inner = Self; + #[inline] + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self(flatbuffers::read_scalar_at::(buf, loc)) + } +} + +impl flatbuffers::Push for AnyAmbiguousAliases { + type Output = AnyAmbiguousAliases; + #[inline] + fn push(&self, dst: &mut [u8], _rest: &[u8]) { + flatbuffers::emplace_scalar::(dst, self.0); + } +} -pub fn enum_name_any_ambiguous_aliases(e: AnyAmbiguousAliases) -> &'static str { - let index = e as u8; - ENUM_NAMES_ANY_AMBIGUOUS_ALIASES[index as usize] +impl flatbuffers::EndianScalar for AnyAmbiguousAliases { + #[inline] + fn to_little_endian(self) -> Self { + Self(u8::to_le(self.0)) + } + #[inline] + fn from_little_endian(self) -> Self { + Self(u8::from_le(self.0)) + } } pub struct AnyAmbiguousAliasesUnionTableOffset {} diff --git a/tests/namespace_test/namespace_test1_generated.rs b/tests/namespace_test/namespace_test1_generated.rs index 77e5d9b5ef3..98c51bbc6d6 100644 --- a/tests/namespace_test/namespace_test1_generated.rs +++ b/tests/namespace_test/namespace_test1_generated.rs @@ -1,6 +1,7 @@ // automatically generated by the FlatBuffers compiler, do not modify +#![allow(unused_imports, dead_code)] use std::mem; use std::cmp::Ordering; @@ -25,39 +26,58 @@ pub mod namespace_b { extern crate flatbuffers; use self::flatbuffers::EndianScalar; -#[allow(non_camel_case_types)] -#[repr(i8)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum EnumInNestedNS { - A = 0, - B = 1, - C = 2, - -} - +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] pub const ENUM_MIN_ENUM_IN_NESTED_NS: i8 = 0; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] pub const ENUM_MAX_ENUM_IN_NESTED_NS: i8 = 2; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] +#[allow(non_camel_case_types)] +pub const ENUM_VALUES_ENUM_IN_NESTED_NS: [EnumInNestedNS; 3] = [ + EnumInNestedNS::A, + EnumInNestedNS::B, + EnumInNestedNS::C, +]; -impl<'a> flatbuffers::Follow<'a> for EnumInNestedNS { - type Inner = Self; - #[inline] - fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - flatbuffers::read_scalar_at::(buf, loc) +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct EnumInNestedNS(pub i8); +#[allow(non_upper_case_globals)] +impl EnumInNestedNS { + pub const A: Self = Self(0); + pub const B: Self = Self(1); + pub const C: Self = Self(2); + + pub const ENUM_MIN: i8 = 0; + pub const ENUM_MAX: i8 = 2; + pub const ENUM_VALUES: &'static [Self] = &[ + Self::A, + Self::B, + Self::C, + ]; + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> Option<&'static str> { + match self { + Self::A => Some("A"), + Self::B => Some("B"), + Self::C => Some("C"), + _ => None, + } } } - -impl flatbuffers::EndianScalar for EnumInNestedNS { - #[inline] - fn to_little_endian(self) -> Self { - let n = i8::to_le(self as i8); - let p = &n as *const i8 as *const EnumInNestedNS; - unsafe { *p } +impl std::fmt::Debug for EnumInNestedNS { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(name) = self.variant_name() { + f.write_str(name) + } else { + f.write_fmt(format_args!("", self.0)) + } } +} +impl<'a> flatbuffers::Follow<'a> for EnumInNestedNS { + type Inner = Self; #[inline] - fn from_little_endian(self) -> Self { - let n = i8::from_le(self as i8); - let p = &n as *const i8 as *const EnumInNestedNS; - unsafe { *p } + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self(flatbuffers::read_scalar_at::(buf, loc)) } } @@ -65,27 +85,19 @@ impl flatbuffers::Push for EnumInNestedNS { type Output = EnumInNestedNS; #[inline] fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, *self); + flatbuffers::emplace_scalar::(dst, self.0); } } -#[allow(non_camel_case_types)] -pub const ENUM_VALUES_ENUM_IN_NESTED_NS: [EnumInNestedNS; 3] = [ - EnumInNestedNS::A, - EnumInNestedNS::B, - EnumInNestedNS::C -]; - -#[allow(non_camel_case_types)] -pub const ENUM_NAMES_ENUM_IN_NESTED_NS: [&str; 3] = [ - "A", - "B", - "C" -]; - -pub fn enum_name_enum_in_nested_ns(e: EnumInNestedNS) -> &'static str { - let index = e as i8; - ENUM_NAMES_ENUM_IN_NESTED_NS[index as usize] +impl flatbuffers::EndianScalar for EnumInNestedNS { + #[inline] + fn to_little_endian(self) -> Self { + Self(i8::to_le(self.0)) + } + #[inline] + fn from_little_endian(self) -> Self { + Self(i8::from_le(self.0)) + } } // struct StructInNestedNS, aligned to 4 diff --git a/tests/namespace_test/namespace_test2_generated.rs b/tests/namespace_test/namespace_test2_generated.rs index dfdd8c51fff..c14f189c47b 100644 --- a/tests/namespace_test/namespace_test2_generated.rs +++ b/tests/namespace_test/namespace_test2_generated.rs @@ -1,6 +1,7 @@ // automatically generated by the FlatBuffers compiler, do not modify +#![allow(unused_imports, dead_code)] use crate::namespace_test1_generated::*; use std::mem; diff --git a/tests/optional_scalars2_generated.rs b/tests/optional_scalars2_generated.rs index 8e10527f56a..15bf4e73f68 100644 --- a/tests/optional_scalars2_generated.rs +++ b/tests/optional_scalars2_generated.rs @@ -1,6 +1,7 @@ // automatically generated by the FlatBuffers compiler, do not modify +#![allow(unused_imports, dead_code)] use std::mem; use std::cmp::Ordering; @@ -17,39 +18,58 @@ pub mod optional_scalars { extern crate flatbuffers; use self::flatbuffers::EndianScalar; -#[allow(non_camel_case_types)] -#[repr(i8)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum OptionalByte { - None = 0, - One = 1, - Two = 2, - -} - +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] pub const ENUM_MIN_OPTIONAL_BYTE: i8 = 0; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] pub const ENUM_MAX_OPTIONAL_BYTE: i8 = 2; +#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")] +#[allow(non_camel_case_types)] +pub const ENUM_VALUES_OPTIONAL_BYTE: [OptionalByte; 3] = [ + OptionalByte::None, + OptionalByte::One, + OptionalByte::Two, +]; -impl<'a> flatbuffers::Follow<'a> for OptionalByte { - type Inner = Self; - #[inline] - fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - flatbuffers::read_scalar_at::(buf, loc) +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct OptionalByte(pub i8); +#[allow(non_upper_case_globals)] +impl OptionalByte { + pub const None: Self = Self(0); + pub const One: Self = Self(1); + pub const Two: Self = Self(2); + + pub const ENUM_MIN: i8 = 0; + pub const ENUM_MAX: i8 = 2; + pub const ENUM_VALUES: &'static [Self] = &[ + Self::None, + Self::One, + Self::Two, + ]; + /// Returns the variant's name or "" if unknown. + pub fn variant_name(self) -> Option<&'static str> { + match self { + Self::None => Some("None"), + Self::One => Some("One"), + Self::Two => Some("Two"), + _ => None, + } } } - -impl flatbuffers::EndianScalar for OptionalByte { - #[inline] - fn to_little_endian(self) -> Self { - let n = i8::to_le(self as i8); - let p = &n as *const i8 as *const OptionalByte; - unsafe { *p } +impl std::fmt::Debug for OptionalByte { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if let Some(name) = self.variant_name() { + f.write_str(name) + } else { + f.write_fmt(format_args!("", self.0)) + } } +} +impl<'a> flatbuffers::Follow<'a> for OptionalByte { + type Inner = Self; #[inline] - fn from_little_endian(self) -> Self { - let n = i8::from_le(self as i8); - let p = &n as *const i8 as *const OptionalByte; - unsafe { *p } + fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self(flatbuffers::read_scalar_at::(buf, loc)) } } @@ -57,27 +77,19 @@ impl flatbuffers::Push for OptionalByte { type Output = OptionalByte; #[inline] fn push(&self, dst: &mut [u8], _rest: &[u8]) { - flatbuffers::emplace_scalar::(dst, *self); + flatbuffers::emplace_scalar::(dst, self.0); } } -#[allow(non_camel_case_types)] -pub const ENUM_VALUES_OPTIONAL_BYTE: [OptionalByte; 3] = [ - OptionalByte::None, - OptionalByte::One, - OptionalByte::Two -]; - -#[allow(non_camel_case_types)] -pub const ENUM_NAMES_OPTIONAL_BYTE: [&str; 3] = [ - "None", - "One", - "Two" -]; - -pub fn enum_name_optional_byte(e: OptionalByte) -> &'static str { - let index = e as i8; - ENUM_NAMES_OPTIONAL_BYTE[index as usize] +impl flatbuffers::EndianScalar for OptionalByte { + #[inline] + fn to_little_endian(self) -> Self { + Self(i8::to_le(self.0)) + } + #[inline] + fn from_little_endian(self) -> Self { + Self(i8::from_le(self.0)) + } } pub enum ScalarStuffOffset {} diff --git a/tests/rust_usage_test/Cargo.toml b/tests/rust_usage_test/Cargo.toml index 6fa98a9a8f7..664396d01c7 100644 --- a/tests/rust_usage_test/Cargo.toml +++ b/tests/rust_usage_test/Cargo.toml @@ -32,6 +32,11 @@ path = "../../samples/sample_flexbuffers.rs" name = "sample_flexbuffers_serde" path = "../../samples/sample_flexbuffers_serde.rs" +[[bin]] +name = "sample_flatbuffers" +path = "../../samples/sample_binary.rs" + + [dev-dependencies] quickcheck = "0.6" # TODO(rw): look into moving to criterion.rs diff --git a/tests/rust_usage_test/tests/integration_test.rs b/tests/rust_usage_test/tests/integration_test.rs index 58a673fc71c..cc0abbe2b2b 100644 --- a/tests/rust_usage_test/tests/integration_test.rs +++ b/tests/rust_usage_test/tests/integration_test.rs @@ -29,15 +29,12 @@ extern crate quickcheck_derive; mod flexbuffers_tests; mod optional_scalars_test; -#[allow(dead_code, unused_imports)] #[path = "../../include_test/include_test1_generated.rs"] pub mod include_test1_generated; -#[allow(dead_code, unused_imports)] #[path = "../../include_test/sub/include_test2_generated.rs"] pub mod include_test2_generated; -#[allow(dead_code, unused_imports)] #[path = "../../monster_test_generated.rs"] mod monster_test_generated; pub use monster_test_generated::my_game; @@ -265,83 +262,41 @@ mod generated_constants { #[test] fn enum_constants_are_public() { - assert_eq!(1, my_game::example::ENUM_MIN_COLOR); - assert_eq!(8, my_game::example::ENUM_MAX_COLOR); - assert_eq!(my_game::example::ENUM_VALUES_COLOR, [ - my_game::example::Color::Red, - my_game::example::Color::Green, - my_game::example::Color::Blue, - ]); - assert_eq!(my_game::example::ENUM_NAMES_COLOR, [ - "Red", - "Green", - "", - "", - "", - "", - "", - "Blue" - ]); - - assert_eq!(-1, my_game::example::ENUM_MIN_RACE); - assert_eq!(2, my_game::example::ENUM_MAX_RACE); - assert_eq!(my_game::example::ENUM_VALUES_RACE, [ + assert_eq!(-1, my_game::example::Race::ENUM_MIN); + assert_eq!(2, my_game::example::Race::ENUM_MAX); + assert_eq!(my_game::example::Race::ENUM_VALUES, [ my_game::example::Race::None, my_game::example::Race::Human, my_game::example::Race::Dwarf, my_game::example::Race::Elf, ]); - assert_eq!(my_game::example::ENUM_NAMES_RACE, [ - "None", - "Human", - "Dwarf", - "Elf" - ]); - assert_eq!(0, my_game::example::ENUM_MIN_ANY); - assert_eq!(3, my_game::example::ENUM_MAX_ANY); - assert_eq!(my_game::example::ENUM_VALUES_ANY, [ + assert_eq!(0, my_game::example::Any::ENUM_MIN); + assert_eq!(3, my_game::example::Any::ENUM_MAX); + assert_eq!(my_game::example::Any::ENUM_VALUES, [ my_game::example::Any::NONE, my_game::example::Any::Monster, my_game::example::Any::TestSimpleTableWithEnum, my_game::example::Any::MyGame_Example2_Monster, ]); - assert_eq!(my_game::example::ENUM_NAMES_ANY, [ - "NONE", - "Monster", - "TestSimpleTableWithEnum", - "MyGame_Example2_Monster" - ]); - assert_eq!(0, my_game::example::ENUM_MIN_ANY_UNIQUE_ALIASES); - assert_eq!(3, my_game::example::ENUM_MAX_ANY_UNIQUE_ALIASES); - assert_eq!(my_game::example::ENUM_VALUES_ANY_UNIQUE_ALIASES, [ + assert_eq!(0, my_game::example::AnyUniqueAliases::ENUM_MIN); + assert_eq!(3, my_game::example::AnyUniqueAliases::ENUM_MAX); + assert_eq!(my_game::example::AnyUniqueAliases::ENUM_VALUES, [ my_game::example::AnyUniqueAliases::NONE, my_game::example::AnyUniqueAliases::M, my_game::example::AnyUniqueAliases::TS, my_game::example::AnyUniqueAliases::M2, ]); - assert_eq!(my_game::example::ENUM_NAMES_ANY_UNIQUE_ALIASES, [ - "NONE", - "M", - "TS", - "M2" - ]); - assert_eq!(0, my_game::example::ENUM_MIN_ANY_AMBIGUOUS_ALIASES); - assert_eq!(3, my_game::example::ENUM_MAX_ANY_AMBIGUOUS_ALIASES); - assert_eq!(my_game::example::ENUM_VALUES_ANY_AMBIGUOUS_ALIASES, [ + assert_eq!(0, my_game::example::AnyAmbiguousAliases::ENUM_MIN); + assert_eq!(3, my_game::example::AnyAmbiguousAliases::ENUM_MAX); + assert_eq!(my_game::example::AnyAmbiguousAliases::ENUM_VALUES, [ my_game::example::AnyAmbiguousAliases::NONE, my_game::example::AnyAmbiguousAliases::M1, my_game::example::AnyAmbiguousAliases::M2, my_game::example::AnyAmbiguousAliases::M3, ]); - assert_eq!(my_game::example::ENUM_NAMES_ANY_AMBIGUOUS_ALIASES, [ - "NONE", - "M1", - "M2", - "M3" - ]); } } @@ -732,19 +687,18 @@ mod roundtrip_generated_code { test4: Some(v), ..Default::default()}); assert_eq!(m.test4().unwrap(), &[my_game::example::Test::new(127, -128), my_game::example::Test::new(3, 123), my_game::example::Test::new(100, 101)][..]); } - // TODO(rw) this passes, but I don't want to change the monster test schema right now - // #[test] - // fn vector_of_enum_store() { - // let mut b = flatbuffers::FlatBufferBuilder::new(); - // let v = b.create_vector::(&[my_game::example::Color::Red, my_game::example::Color::Green][..]); - // let name = b.create_string("foo"); - // let m = build_mon(&mut b, &my_game::example::MonsterArgs{ - // name: Some(name), - // vector_of_enum: Some(v), ..Default::default()}); - // assert_eq!(m.vector_of_enum().unwrap().len(), 2); - // assert_eq!(m.vector_of_enum().unwrap().get(0), my_game::example::Color::Red); - // assert_eq!(m.vector_of_enum().unwrap().get(1), my_game::example::Color::Green); - // } + #[test] + fn vector_of_enums_store() { + let mut b = flatbuffers::FlatBufferBuilder::new(); + let v = b.create_vector::(&[my_game::example::Color::Red, my_game::example::Color::Green][..]); + let name = b.create_string("foo"); + let m = build_mon(&mut b, &my_game::example::MonsterArgs{ + name: Some(name), + vector_of_enums: Some(v), ..Default::default()}); + assert_eq!(m.vector_of_enums().unwrap().len(), 2); + assert_eq!(m.vector_of_enums().unwrap().get(0), my_game::example::Color::Red); + assert_eq!(m.vector_of_enums().unwrap().get(1), my_game::example::Color::Green); + } #[test] fn vector_of_table_store() { let b = &mut flatbuffers::FlatBufferBuilder::new();