Started implementation for private flags in rust (#7269)

Adds flag to the cpp to fix bad annotations in all the languages

Addresses comments to the PR, and fixes logic for leaking annotations
This commit is contained in:
mustiikhalil
2022-06-05 23:04:05 +02:00
committed by GitHub
parent 967df08b1d
commit 11a1988705
13 changed files with 924 additions and 11 deletions

View File

@@ -603,6 +603,7 @@ struct IDLOptions {
bool json_nested_flexbuffers;
bool json_nested_legacy_flatbuffers;
bool ts_flat_file;
bool no_leak_private_annotations;
// Possible options for the more general generator below.
enum Language {
@@ -702,6 +703,7 @@ struct IDLOptions {
json_nested_flexbuffers(true),
json_nested_legacy_flatbuffers(false),
ts_flat_file(false),
no_leak_private_annotations(false),
mini_reflect(IDLOptions::kNone),
require_explicit_ids(false),
rust_serialize(false),
@@ -993,6 +995,9 @@ class Parser : public ParserState {
FLATBUFFERS_CHECKED_ERROR ParseRoot(const char *_source,
const char **include_paths,
const char *source_filename);
FLATBUFFERS_CHECKED_ERROR CheckPrivateLeak();
FLATBUFFERS_CHECKED_ERROR CheckPrivatelyLeakedFields(
const Definition &def, const Definition &value_type);
FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source,
const char **include_paths,
const char *source_filename,

View File

@@ -456,6 +456,11 @@ flatc(
prefix=cpp_17_prefix,
)
# Private annotations
annotations_test_schema = "private_annotation_test.fbs"
flatc(RUST_OPTS + ["--no-leak-private-annotation", "--gen-object-api"], prefix="private_annotation_test", schema=annotations_test_schema)
# Sample files
samples_schema = "monster.fbs"
flatc(BASE_OPTS + CPP_OPTS + LOBSTER_OPTS, schema=samples_schema, cwd=samples_path)

View File

@@ -221,6 +221,9 @@ const static FlatCOption options[] = {
"Only generated one typescript file per .fbs file." },
{ "", "annotate", "SCHEMA",
"Annotate the provided BINARY_FILE with the specified SCHEMA file." },
{ "", "no-leak-private-annotation", "",
"Prevents multiple type of annotations within a Fbs SCHEMA file."
"Currently this is required to generate private types in Rust" },
};
static void AppendTextWrappedString(std::stringstream &ss, std::string &text,
@@ -596,6 +599,8 @@ int FlatCompiler::Compile(int argc, const char **argv) {
opts.json_nested_legacy_flatbuffers = true;
} else if (arg == "--ts-flat-files") {
opts.ts_flat_file = true;
} else if (arg == "--no-leak-private-annotation") {
opts.no_leak_private_annotations = true;
} else if (arg == "--annotate") {
if (++argi >= argc) Error("missing path following: " + arg, true);
annotate_schema = flatbuffers::PosixPath(argv[argi]);

View File

@@ -698,6 +698,9 @@ class RustGenerator : public BaseGenerator {
// an enum match function,
// and an enum array of values
void GenEnum(const EnumDef &enum_def) {
const bool is_private = parser_.opts.no_leak_private_annotations &&
(enum_def.attributes.Lookup("private") != nullptr);
code_.SetValue("ACCESS_TYPE", is_private ? "pub(crate)" : "pub");
code_.SetValue("ENUM_TY", namer_.Type(enum_def));
code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
code_.SetValue("ENUM_NAMESPACE", namer_.Namespace(enum_def.name));
@@ -718,7 +721,7 @@ class RustGenerator : public BaseGenerator {
code_ += " flatbuffers::bitflags::bitflags! {";
GenComment(enum_def.doc_comment, " ");
code_ += " #[derive(Default)]";
code_ += " pub struct {{ENUM_TY}}: {{BASE_TYPE}} {";
code_ += " {{ACCESS_TYPE}} struct {{ENUM_TY}}: {{BASE_TYPE}} {";
ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
this->GenComment(ev.doc_comment, " ");
code_ += " const {{VARIANT}} = {{VALUE}};";
@@ -764,7 +767,7 @@ class RustGenerator : public BaseGenerator {
"#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, "
"Default)]";
code_ += "#[repr(transparent)]";
code_ += "pub struct {{ENUM_TY}}(pub {{BASE_TYPE}});";
code_ += "{{ACCESS_TYPE}} struct {{ENUM_TY}}(pub {{BASE_TYPE}});";
code_ += "#[allow(non_upper_case_globals)]";
code_ += "impl {{ENUM_TY}} {";
ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
@@ -881,7 +884,7 @@ class RustGenerator : public BaseGenerator {
if (enum_def.is_union) {
// Generate typesafe offset(s) for unions
code_.SetValue("UNION_TYPE", namer_.Type(enum_def));
code_ += "pub struct {{UNION_TYPE}}UnionTableOffset {}";
code_ += "{{ACCESS_TYPE}} struct {{UNION_TYPE}}UnionTableOffset {}";
code_ += "";
if (parser_.opts.generate_object_based_api) { GenUnionObject(enum_def); }
}
@@ -916,7 +919,7 @@ class RustGenerator : public BaseGenerator {
// intended.
code_ += "#[non_exhaustive]";
code_ += "#[derive(Debug, Clone, PartialEq)]";
code_ += "pub enum {{ENUM_OTY}} {";
code_ += "{{ACCESS_TYPE}} enum {{ENUM_OTY}} {";
code_ += " NONE,";
ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
code_ += "{{NATIVE_VARIANT}}(Box<{{U_ELEMENT_TABLE_TYPE}}>),";
@@ -1620,18 +1623,22 @@ class RustGenerator : public BaseGenerator {
// Generate an accessor struct, builder struct, and create function for a
// table.
void GenTable(const StructDef &struct_def) {
const bool is_private = parser_.opts.no_leak_private_annotations &&
(struct_def.attributes.Lookup("private") != nullptr);
code_.SetValue("ACCESS_TYPE", is_private ? "pub(crate)" : "pub");
code_.SetValue("STRUCT_TY", namer_.Type(struct_def));
code_.SetValue("STRUCT_FN", namer_.Function(struct_def));
// Generate an offset type, the base type, the Follow impl, and the
// init_from_table impl.
code_ += "pub enum {{STRUCT_TY}}Offset {}";
code_ += "{{ACCESS_TYPE}} enum {{STRUCT_TY}}Offset {}";
code_ += "#[derive(Copy, Clone, PartialEq)]";
code_ += "";
GenComment(struct_def.doc_comment);
code_ += "pub struct {{STRUCT_TY}}<'a> {";
code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}<'a> {";
code_ += " pub _tab: flatbuffers::Table<'a>,";
code_ += "}";
code_ += "";
@@ -1965,7 +1972,7 @@ class RustGenerator : public BaseGenerator {
// Generate an args struct:
code_.SetValue("MAYBE_LT",
TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
code_ += "pub struct {{STRUCT_TY}}Args{{MAYBE_LT}} {";
code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}Args{{MAYBE_LT}} {";
ForAllTableFields(struct_def, [&](const FieldDef &field) {
code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
code_ += " pub {{FIELD}}: {{PARAM_TYPE}},";
@@ -2054,7 +2061,7 @@ class RustGenerator : public BaseGenerator {
}
// Generate a builder struct:
code_ += "pub struct {{STRUCT_TY}}Builder<'a: 'b, 'b> {";
code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}Builder<'a: 'b, 'b> {";
code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
code_ +=
" start_: flatbuffers::WIPOffset<"
@@ -2175,7 +2182,7 @@ class RustGenerator : public BaseGenerator {
// Generate the native object.
code_ += "#[non_exhaustive]";
code_ += "#[derive(Debug, Clone, PartialEq)]";
code_ += "pub struct {{STRUCT_OTY}} {";
code_ += "{{ACCESS_TYPE}} struct {{STRUCT_OTY}} {";
ForAllObjectTableFields(table, [&](const FieldDef &field) {
// Union objects combine both the union discriminant and value, so we
// skip making a field for the discriminant.
@@ -2583,6 +2590,9 @@ class RustGenerator : public BaseGenerator {
}
// Generate an accessor struct with constructor for a flatbuffers struct.
void GenStruct(const StructDef &struct_def) {
const bool is_private = parser_.opts.no_leak_private_annotations &&
(struct_def.attributes.Lookup("private") != nullptr);
code_.SetValue("ACCESS_TYPE", is_private ? "pub(crate)" : "pub");
// Generates manual padding and alignment.
// Variables are private because they contain little endian data on all
// platforms.
@@ -2600,7 +2610,7 @@ class RustGenerator : public BaseGenerator {
code_ += "// struct {{STRUCT_TY}}, aligned to {{ALIGN}}";
code_ += "#[repr(transparent)]";
code_ += "#[derive(Clone, Copy, PartialEq)]";
code_ += "pub struct {{STRUCT_TY}}(pub [u8; {{STRUCT_SIZE}}]);";
code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}(pub [u8; {{STRUCT_SIZE}}]);";
code_ += "impl Default for {{STRUCT_TY}} { ";
code_ += " fn default() -> Self { ";
code_ += " Self([0; {{STRUCT_SIZE}}])";
@@ -2847,7 +2857,7 @@ class RustGenerator : public BaseGenerator {
if (parser_.opts.generate_object_based_api) {
// Struct declaration
code_ += "#[derive(Debug, Clone, PartialEq, Default)]";
code_ += "pub struct {{STRUCT_OTY}} {";
code_ += "{{ACCESS_TYPE}} struct {{STRUCT_OTY}} {";
ForAllStructFields(struct_def, [&](const FieldDef &field) {
(void)field; // unused.
code_ += "pub {{FIELD}}: {{FIELD_OTY}},";

View File

@@ -3266,19 +3266,78 @@ CheckedError Parser::ParseRoot(const char *source, const char **include_paths,
for (auto val_it = enum_def.Vals().begin();
val_it != enum_def.Vals().end(); ++val_it) {
auto &val = **val_it;
if (!(opts.lang_to_generate != 0 && SupportsAdvancedUnionFeatures()) &&
(IsStruct(val.union_type) || IsString(val.union_type)))
return Error(
"only tables can be union elements in the generated language: " +
val.name);
}
}
}
auto err = CheckPrivateLeak();
if (err.Check()) return err;
// Parse JSON object only if the scheme has been parsed.
if (token_ == '{') { ECHECK(DoParseJson()); }
return NoError();
}
CheckedError Parser::CheckPrivateLeak() {
if (!opts.no_leak_private_annotations) return NoError();
// Iterate over all structs/tables to validate we arent leaking
// any private (structs/tables/enums)
for (auto it = structs_.vec.begin(); it != structs_.vec.end(); it++) {
auto &struct_def = **it;
for (auto fld_it = struct_def.fields.vec.begin();
fld_it != struct_def.fields.vec.end(); ++fld_it) {
auto &field = **fld_it;
if (field.value.type.enum_def) {
auto err =
CheckPrivatelyLeakedFields(struct_def, *field.value.type.enum_def);
if (err.Check()) { return err; }
} else if (field.value.type.struct_def) {
auto err = CheckPrivatelyLeakedFields(struct_def,
*field.value.type.struct_def);
if (err.Check()) { return err; }
}
}
}
// Iterate over all enums to validate we arent leaking
// any private (structs/tables)
for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
auto &enum_def = **it;
if (enum_def.is_union) {
for (auto val_it = enum_def.Vals().begin();
val_it != enum_def.Vals().end(); ++val_it) {
auto &val = **val_it;
if (val.union_type.struct_def) {
auto err =
CheckPrivatelyLeakedFields(enum_def, *val.union_type.struct_def);
if (err.Check()) { return err; }
}
}
}
}
return NoError();
}
CheckedError Parser::CheckPrivatelyLeakedFields(const Definition &def,
const Definition &value_type) {
if (!opts.no_leak_private_annotations) return NoError();
const auto is_private = def.attributes.Lookup("private");
const auto is_field_private = value_type.attributes.Lookup("private");
if (!is_private && is_field_private) {
return Error(
"Leaking private implementation, verify all objects have similar "
"annotations");
}
return NoError();
}
// Generate a unique hash for a file based on its name and contents (if any).
static uint64_t HashFile(const char *source_filename, const char *source) {
uint64_t hash = 0;

View File

@@ -0,0 +1,18 @@
enum AB:byte (private) {
A,
B,
}
struct Object (private) {
value: int;
}
union Any (private) { Game, Annotations }
table Game (private) {
value: int;
}
table Annotations (private) {
value: int;
}

View File

@@ -0,0 +1,97 @@
// automatically generated by the FlatBuffers compiler, do not modify
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::*;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_AB: i8 = 0;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MAX_AB: i8 = 1;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
#[allow(non_camel_case_types)]
pub const ENUM_VALUES_AB: [AB; 2] = [
AB::A,
AB::B,
];
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(transparent)]
pub(crate) struct AB(pub i8);
#[allow(non_upper_case_globals)]
impl AB {
pub const A: Self = Self(0);
pub const B: Self = Self(1);
pub const ENUM_MIN: i8 = 0;
pub const ENUM_MAX: i8 = 1;
pub const ENUM_VALUES: &'static [Self] = &[
Self::A,
Self::B,
];
/// 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"),
_ => None,
}
}
}
impl core::fmt::Debug for AB {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
if let Some(name) = self.variant_name() {
f.write_str(name)
} else {
f.write_fmt(format_args!("<UNKNOWN {:?}>", self.0))
}
}
}
impl<'a> flatbuffers::Follow<'a> for AB {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
let b = unsafe {
flatbuffers::read_scalar_at::<i8>(buf, loc)
};
Self(b)
}
}
impl flatbuffers::Push for AB {
type Output = AB;
#[inline]
fn push(&self, dst: &mut [u8], _rest: &[u8]) {
unsafe { flatbuffers::emplace_scalar::<i8>(dst, self.0); }
}
}
impl flatbuffers::EndianScalar for AB {
#[inline]
fn to_little_endian(self) -> Self {
let b = i8::to_le(self.0);
Self(b)
}
#[inline]
#[allow(clippy::wrong_self_convention)]
fn from_little_endian(self) -> Self {
let b = i8::from_le(self.0);
Self(b)
}
}
impl<'a> flatbuffers::Verifiable for AB {
#[inline]
fn run_verifier(
v: &mut flatbuffers::Verifier, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
i8::run_verifier(v, pos)
}
}
impl flatbuffers::SimpleToVerifyInSlice for AB {}

View File

@@ -0,0 +1,137 @@
// automatically generated by the FlatBuffers compiler, do not modify
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(crate) enum AnnotationsOffset {}
#[derive(Copy, Clone, PartialEq)]
pub(crate) struct Annotations<'a> {
pub _tab: flatbuffers::Table<'a>,
}
impl<'a> flatbuffers::Follow<'a> for Annotations<'a> {
type Inner = Annotations<'a>;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: flatbuffers::Table { buf, loc } }
}
}
impl<'a> Annotations<'a> {
pub const VT_VALUE: flatbuffers::VOffsetT = 4;
pub const fn get_fully_qualified_name() -> &'static str {
"Annotations"
}
#[inline]
pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
Annotations { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
_fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
args: &'args AnnotationsArgs
) -> flatbuffers::WIPOffset<Annotations<'bldr>> {
let mut builder = AnnotationsBuilder::new(_fbb);
builder.add_value(args.value);
builder.finish()
}
pub fn unpack(&self) -> AnnotationsT {
let value = self.value();
AnnotationsT {
value,
}
}
#[inline]
pub fn value(&self) -> i32 {
self._tab.get::<i32>(Annotations::VT_VALUE, Some(0)).unwrap()
}
}
impl flatbuffers::Verifiable for Annotations<'_> {
#[inline]
fn run_verifier(
v: &mut flatbuffers::Verifier, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
v.visit_table(pos)?
.visit_field::<i32>("value", Self::VT_VALUE, false)?
.finish();
Ok(())
}
}
pub(crate) struct AnnotationsArgs {
pub value: i32,
}
impl<'a> Default for AnnotationsArgs {
#[inline]
fn default() -> Self {
AnnotationsArgs {
value: 0,
}
}
}
pub(crate) struct AnnotationsBuilder<'a: 'b, 'b> {
fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b> AnnotationsBuilder<'a, 'b> {
#[inline]
pub fn add_value(&mut self, value: i32) {
self.fbb_.push_slot::<i32>(Annotations::VT_VALUE, value, 0);
}
#[inline]
pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> AnnotationsBuilder<'a, 'b> {
let start = _fbb.start_table();
AnnotationsBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn finish(self) -> flatbuffers::WIPOffset<Annotations<'a>> {
let o = self.fbb_.end_table(self.start_);
flatbuffers::WIPOffset::new(o.value())
}
}
impl core::fmt::Debug for Annotations<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut ds = f.debug_struct("Annotations");
ds.field("value", &self.value());
ds.finish()
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct AnnotationsT {
pub value: i32,
}
impl Default for AnnotationsT {
fn default() -> Self {
Self {
value: 0,
}
}
}
impl AnnotationsT {
pub fn pack<'b>(
&self,
_fbb: &mut flatbuffers::FlatBufferBuilder<'b>
) -> flatbuffers::WIPOffset<Annotations<'b>> {
let value = self.value;
Annotations::create(_fbb, &AnnotationsArgs{
value,
})
}
}

View File

@@ -0,0 +1,174 @@
// automatically generated by the FlatBuffers compiler, do not modify
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::*;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_ANY: u8 = 0;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MAX_ANY: u8 = 2;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
#[allow(non_camel_case_types)]
pub const ENUM_VALUES_ANY: [Any; 3] = [
Any::NONE,
Any::Game,
Any::Annotations,
];
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(transparent)]
pub(crate) struct Any(pub u8);
#[allow(non_upper_case_globals)]
impl Any {
pub const NONE: Self = Self(0);
pub const Game: Self = Self(1);
pub const Annotations: Self = Self(2);
pub const ENUM_MIN: u8 = 0;
pub const ENUM_MAX: u8 = 2;
pub const ENUM_VALUES: &'static [Self] = &[
Self::NONE,
Self::Game,
Self::Annotations,
];
/// Returns the variant's name or "" if unknown.
pub fn variant_name(self) -> Option<&'static str> {
match self {
Self::NONE => Some("NONE"),
Self::Game => Some("Game"),
Self::Annotations => Some("Annotations"),
_ => None,
}
}
}
impl core::fmt::Debug for Any {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
if let Some(name) = self.variant_name() {
f.write_str(name)
} else {
f.write_fmt(format_args!("<UNKNOWN {:?}>", self.0))
}
}
}
impl<'a> flatbuffers::Follow<'a> for Any {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
let b = unsafe {
flatbuffers::read_scalar_at::<u8>(buf, loc)
};
Self(b)
}
}
impl flatbuffers::Push for Any {
type Output = Any;
#[inline]
fn push(&self, dst: &mut [u8], _rest: &[u8]) {
unsafe { flatbuffers::emplace_scalar::<u8>(dst, self.0); }
}
}
impl flatbuffers::EndianScalar for Any {
#[inline]
fn to_little_endian(self) -> Self {
let b = u8::to_le(self.0);
Self(b)
}
#[inline]
#[allow(clippy::wrong_self_convention)]
fn from_little_endian(self) -> Self {
let b = u8::from_le(self.0);
Self(b)
}
}
impl<'a> flatbuffers::Verifiable for Any {
#[inline]
fn run_verifier(
v: &mut flatbuffers::Verifier, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
u8::run_verifier(v, pos)
}
}
impl flatbuffers::SimpleToVerifyInSlice for Any {}
pub(crate) struct AnyUnionTableOffset {}
#[allow(clippy::upper_case_acronyms)]
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum AnyT {
NONE,
Game(Box<GameT>),
Annotations(Box<AnnotationsT>),
}
impl Default for AnyT {
fn default() -> Self {
Self::NONE
}
}
impl AnyT {
pub fn any_type(&self) -> Any {
match self {
Self::NONE => Any::NONE,
Self::Game(_) => Any::Game,
Self::Annotations(_) => Any::Annotations,
}
}
pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder) -> Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>> {
match self {
Self::NONE => None,
Self::Game(v) => Some(v.pack(fbb).as_union_value()),
Self::Annotations(v) => Some(v.pack(fbb).as_union_value()),
}
}
/// If the union variant matches, return the owned GameT, setting the union to NONE.
pub fn take_game(&mut self) -> Option<Box<GameT>> {
if let Self::Game(_) = self {
let v = core::mem::replace(self, Self::NONE);
if let Self::Game(w) = v {
Some(w)
} else {
unreachable!()
}
} else {
None
}
}
/// If the union variant matches, return a reference to the GameT.
pub fn as_game(&self) -> Option<&GameT> {
if let Self::Game(v) = self { Some(v.as_ref()) } else { None }
}
/// If the union variant matches, return a mutable reference to the GameT.
pub fn as_game_mut(&mut self) -> Option<&mut GameT> {
if let Self::Game(v) = self { Some(v.as_mut()) } else { None }
}
/// If the union variant matches, return the owned AnnotationsT, setting the union to NONE.
pub fn take_annotations(&mut self) -> Option<Box<AnnotationsT>> {
if let Self::Annotations(_) = self {
let v = core::mem::replace(self, Self::NONE);
if let Self::Annotations(w) = v {
Some(w)
} else {
unreachable!()
}
} else {
None
}
}
/// If the union variant matches, return a reference to the AnnotationsT.
pub fn as_annotations(&self) -> Option<&AnnotationsT> {
if let Self::Annotations(v) = self { Some(v.as_ref()) } else { None }
}
/// If the union variant matches, return a mutable reference to the AnnotationsT.
pub fn as_annotations_mut(&mut self) -> Option<&mut AnnotationsT> {
if let Self::Annotations(v) = self { Some(v.as_mut()) } else { None }
}
}

View File

@@ -0,0 +1,137 @@
// automatically generated by the FlatBuffers compiler, do not modify
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(crate) enum GameOffset {}
#[derive(Copy, Clone, PartialEq)]
pub(crate) struct Game<'a> {
pub _tab: flatbuffers::Table<'a>,
}
impl<'a> flatbuffers::Follow<'a> for Game<'a> {
type Inner = Game<'a>;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: flatbuffers::Table { buf, loc } }
}
}
impl<'a> Game<'a> {
pub const VT_VALUE: flatbuffers::VOffsetT = 4;
pub const fn get_fully_qualified_name() -> &'static str {
"Game"
}
#[inline]
pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
Game { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
_fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
args: &'args GameArgs
) -> flatbuffers::WIPOffset<Game<'bldr>> {
let mut builder = GameBuilder::new(_fbb);
builder.add_value(args.value);
builder.finish()
}
pub fn unpack(&self) -> GameT {
let value = self.value();
GameT {
value,
}
}
#[inline]
pub fn value(&self) -> i32 {
self._tab.get::<i32>(Game::VT_VALUE, Some(0)).unwrap()
}
}
impl flatbuffers::Verifiable for Game<'_> {
#[inline]
fn run_verifier(
v: &mut flatbuffers::Verifier, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
v.visit_table(pos)?
.visit_field::<i32>("value", Self::VT_VALUE, false)?
.finish();
Ok(())
}
}
pub(crate) struct GameArgs {
pub value: i32,
}
impl<'a> Default for GameArgs {
#[inline]
fn default() -> Self {
GameArgs {
value: 0,
}
}
}
pub(crate) struct GameBuilder<'a: 'b, 'b> {
fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b> GameBuilder<'a, 'b> {
#[inline]
pub fn add_value(&mut self, value: i32) {
self.fbb_.push_slot::<i32>(Game::VT_VALUE, value, 0);
}
#[inline]
pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> GameBuilder<'a, 'b> {
let start = _fbb.start_table();
GameBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn finish(self) -> flatbuffers::WIPOffset<Game<'a>> {
let o = self.fbb_.end_table(self.start_);
flatbuffers::WIPOffset::new(o.value())
}
}
impl core::fmt::Debug for Game<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut ds = f.debug_struct("Game");
ds.field("value", &self.value());
ds.finish()
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct GameT {
pub value: i32,
}
impl Default for GameT {
fn default() -> Self {
Self {
value: 0,
}
}
}
impl GameT {
pub fn pack<'b>(
&self,
_fbb: &mut flatbuffers::FlatBufferBuilder<'b>
) -> flatbuffers::WIPOffset<Game<'b>> {
let value = self.value;
Game::create(_fbb, &GameArgs{
value,
})
}
}

View File

@@ -0,0 +1,11 @@
// Automatically generated by the Flatbuffers compiler. Do not modify.
mod ab_generated;
pub use self::ab_generated::*;
mod any_generated;
pub use self::any_generated::*;
mod object_generated;
pub use self::object_generated::*;
mod game_generated;
pub use self::game_generated::*;
mod annotations_generated;
pub use self::annotations_generated::*;

View File

@@ -0,0 +1,131 @@
// automatically generated by the FlatBuffers compiler, do not modify
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::*;
// struct Object, aligned to 4
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq)]
pub(crate) struct Object(pub [u8; 4]);
impl Default for Object {
fn default() -> Self {
Self([0; 4])
}
}
impl core::fmt::Debug for Object {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("Object")
.field("value", &self.value())
.finish()
}
}
impl flatbuffers::SimpleToVerifyInSlice for Object {}
impl flatbuffers::SafeSliceAccess for Object {}
impl<'a> flatbuffers::Follow<'a> for Object {
type Inner = &'a Object;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
<&'a Object>::follow(buf, loc)
}
}
impl<'a> flatbuffers::Follow<'a> for &'a Object {
type Inner = &'a Object;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
flatbuffers::follow_cast_ref::<Object>(buf, loc)
}
}
impl<'b> flatbuffers::Push for Object {
type Output = Object;
#[inline]
fn push(&self, dst: &mut [u8], _rest: &[u8]) {
let src = unsafe {
::core::slice::from_raw_parts(self as *const Object as *const u8, Self::size())
};
dst.copy_from_slice(src);
}
}
impl<'b> flatbuffers::Push for &'b Object {
type Output = Object;
#[inline]
fn push(&self, dst: &mut [u8], _rest: &[u8]) {
let src = unsafe {
::core::slice::from_raw_parts(*self as *const Object as *const u8, Self::size())
};
dst.copy_from_slice(src);
}
}
impl<'a> flatbuffers::Verifiable for Object {
#[inline]
fn run_verifier(
v: &mut flatbuffers::Verifier, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
v.in_buffer::<Self>(pos)
}
}
impl<'a> Object {
#[allow(clippy::too_many_arguments)]
pub fn new(
value: i32,
) -> Self {
let mut s = Self([0; 4]);
s.set_value(value);
s
}
pub const fn get_fully_qualified_name() -> &'static str {
"Object"
}
pub fn value(&self) -> i32 {
let mut mem = core::mem::MaybeUninit::<i32>::uninit();
unsafe {
core::ptr::copy_nonoverlapping(
self.0[0..].as_ptr(),
mem.as_mut_ptr() as *mut u8,
core::mem::size_of::<i32>(),
);
mem.assume_init()
}.from_little_endian()
}
pub fn set_value(&mut self, x: i32) {
let x_le = x.to_little_endian();
unsafe {
core::ptr::copy_nonoverlapping(
&x_le as *const i32 as *const u8,
self.0[0..].as_mut_ptr(),
core::mem::size_of::<i32>(),
);
}
}
pub fn unpack(&self) -> ObjectT {
ObjectT {
value: self.value(),
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub(crate) struct ObjectT {
pub value: i32,
}
impl ObjectT {
pub fn pack(&self) -> Object {
Object::new(
self.value,
)
}
}

View File

@@ -4324,6 +4324,129 @@ void FlatbuffersIteratorsTest() {
void FlatbuffersIteratorsTest() {}
#endif
void PrivateAnnotationsLeaks() {
// Simple schemas and a "has optional scalar" sentinal.
std::vector<std::string> schemas;
std::vector<std::string> failure_schemas;
// (private) (table/struct)
schemas.push_back(
"table Monster (private) { mana: int; }"
"struct ABC (private) { mana: int; }");
// (public) (table/struct)
schemas.push_back(
"table Monster { mana: int; }"
"struct ABC { mana: int; }");
// (private) (union) containing (private) (table/struct)
schemas.push_back(
"table Monster (private) { mana: int; } "
"struct ABC (private) { mana: int; } "
"union Any (private) { Monster, ABC } ");
// (public) (union) containing (public) (table/struct)
schemas.push_back(
"table Monster { mana: int; }"
"struct ABC { mana: int; }"
"union Any { Monster, ABC }");
// (private) (table/struct/enum)
schemas.push_back(
"table Monster (private) { mana: int; }"
"struct ABC (private) { mana: int; }"
"enum Race:byte (private) { None = -1, Human = 0, }");
// (public) (table/struct/enum)
schemas.push_back(
"table Monster { mana: int; }"
"struct ABC { mana: int; }"
"enum Race:byte { None = -1, Human = 0, }");
// (private) (union) containing (private) (table/struct)
schemas.push_back(
"table Monster (private) { mana: int; }"
"struct ABC (private) { mana: int; }"
"enum Race:byte (private) { None = -1, Human = 0, }"
"union Any (private) { Monster, ABC }");
// (public) (union) containing (public) (table/struct)
schemas.push_back(
"table Monster { mana: int; }"
"struct ABC { mana: int; }"
"enum Race:byte { None = -1, Human = 0, }"
"union Any { Monster, ABC }");
// (private) (table), (public struct)
schemas.push_back(
"table Monster (private) { mana: int; }"
"struct ABC { mana: int; }");
// (private) (table), (public) (struct/enum)
schemas.push_back(
"table Monster (private) { mana: int; }"
"struct ABC { mana: int; }"
"enum Race:byte { None = -1, Human = 0, }");
// (public) (struct) containing (public) (enum)
schemas.push_back(
"enum Race:byte { None = -1, Human = 0, }"
"table Monster { mana: int; }"
"struct ABC { mana: int; type: Race; }");
// (public) (union) containing (private) (table) & (public) (struct)
failure_schemas.push_back(
"table Monster (private) { mana: int; }"
"struct ABC { mana: int; }"
"union Any { Monster, ABC }");
// (public) (union) containing (private) (table/struct)
failure_schemas.push_back(
"table Monster (private) { mana: int; }"
"struct ABC (private) { mana: int; }"
"enum Race:byte { None = -1, Human = 0, }"
"union Any { Monster, ABC }");
// (public) (table) containing (private) (struct)
failure_schemas.push_back(
"table Monster { mana: int; ab: ABC; }"
"struct ABC (private) { mana: int; }");
// (public) (struct) containing (private) (enum)
failure_schemas.push_back(
"enum Race:byte (private) { None = -1, Human = 0, }"
"table Monster { mana: int; }"
"struct ABC { mana: int; type: Race; }");
flatbuffers::IDLOptions opts;
opts.lang_to_generate = flatbuffers::IDLOptions::Language::kSwift;
opts.no_leak_private_annotations = true;
for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
flatbuffers::Parser parser(opts);
TEST_ASSERT(parser.Parse(schema->c_str()));
}
for (auto schema = failure_schemas.begin(); schema < failure_schemas.end();
schema++) {
flatbuffers::Parser parser(opts);
TEST_EQ(false, parser.Parse(schema->c_str()));
}
opts.no_leak_private_annotations = false;
for (auto schema = schemas.begin(); schema < schemas.end(); schema++) {
flatbuffers::Parser parser(opts);
TEST_ASSERT(parser.Parse(schema->c_str()));
}
for (auto schema = failure_schemas.begin(); schema < failure_schemas.end();
schema++) {
flatbuffers::Parser parser(opts);
TEST_ASSERT(parser.Parse(schema->c_str()));
}
}
int FlatBufferTests() {
// clang-format off
@@ -4425,6 +4548,7 @@ int FlatBufferTests() {
StructUnionTest();
WarningsAsErrorsTest();
NestedVerifierTest();
PrivateAnnotationsLeaks();
return 0;
}