mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-12 07:50:59 +00:00
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:
@@ -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]);
|
||||
|
||||
@@ -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}},";
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user