Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add advance feature indicators to reflection #6546

Merged
merged 8 commits into from
Apr 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/flatbuffers/idl.h
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ class Parser : public ParserState {
root_struct_def_(nullptr),
opts(options),
uses_flexbuffers_(false),
advanced_features_(0),
source_(nullptr),
anonymous_counter_(0),
parse_depth_counter_(0) {
Expand Down Expand Up @@ -1011,6 +1012,8 @@ class Parser : public ParserState {
IDLOptions opts;
bool uses_flexbuffers_;

uint64_t advanced_features_;

private:
const char *source_;

Expand Down
58 changes: 54 additions & 4 deletions include/flatbuffers/reflection_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,44 @@ inline const char *EnumNameBaseType(BaseType e) {
return EnumNamesBaseType()[index];
}

enum AdvancedFeatures {
AdvancedArrayFeatures = 1ULL,
AdvancedUnionFeatures = 2ULL,
OptionalScalars = 4ULL,
DefaultVectorsAndStrings = 8ULL
};

inline const AdvancedFeatures (&EnumValuesAdvancedFeatures())[4] {
static const AdvancedFeatures values[] = {
AdvancedArrayFeatures,
AdvancedUnionFeatures,
OptionalScalars,
DefaultVectorsAndStrings
};
return values;
}

inline const char * const *EnumNamesAdvancedFeatures() {
static const char * const names[9] = {
"AdvancedArrayFeatures",
"AdvancedUnionFeatures",
"",
"OptionalScalars",
"",
"",
"",
"DefaultVectorsAndStrings",
nullptr
};
return names;
}

inline const char *EnumNameAdvancedFeatures(AdvancedFeatures e) {
if (flatbuffers::IsOutRange(e, AdvancedArrayFeatures, DefaultVectorsAndStrings)) return "";
const size_t index = static_cast<size_t>(e) - static_cast<size_t>(AdvancedArrayFeatures);
return EnumNamesAdvancedFeatures()[index];
}

struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef TypeBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
Expand Down Expand Up @@ -1063,7 +1101,8 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_FILE_IDENT = 8,
VT_FILE_EXT = 10,
VT_ROOT_TABLE = 12,
VT_SERVICES = 14
VT_SERVICES = 14,
VT_ADVANCED_FEATURES = 16
};
const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *>(VT_OBJECTS);
Expand All @@ -1083,6 +1122,9 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const flatbuffers::Vector<flatbuffers::Offset<reflection::Service>> *services() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::Service>> *>(VT_SERVICES);
}
reflection::AdvancedFeatures advanced_features() const {
return static_cast<reflection::AdvancedFeatures>(GetField<uint64_t>(VT_ADVANCED_FEATURES, 0));
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffsetRequired(verifier, VT_OBJECTS) &&
Expand All @@ -1100,6 +1142,7 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyOffset(verifier, VT_SERVICES) &&
verifier.VerifyVector(services()) &&
verifier.VerifyVectorOfTables(services()) &&
VerifyField<uint64_t>(verifier, VT_ADVANCED_FEATURES) &&
verifier.EndTable();
}
};
Expand All @@ -1126,6 +1169,9 @@ struct SchemaBuilder {
void add_services(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Service>>> services) {
fbb_.AddOffset(Schema::VT_SERVICES, services);
}
void add_advanced_features(reflection::AdvancedFeatures advanced_features) {
fbb_.AddElement<uint64_t>(Schema::VT_ADVANCED_FEATURES, static_cast<uint64_t>(advanced_features), 0);
}
explicit SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
Expand All @@ -1146,8 +1192,10 @@ inline flatbuffers::Offset<Schema> CreateSchema(
flatbuffers::Offset<flatbuffers::String> file_ident = 0,
flatbuffers::Offset<flatbuffers::String> file_ext = 0,
flatbuffers::Offset<reflection::Object> root_table = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Service>>> services = 0) {
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Service>>> services = 0,
reflection::AdvancedFeatures advanced_features = static_cast<reflection::AdvancedFeatures>(0)) {
SchemaBuilder builder_(_fbb);
builder_.add_advanced_features(advanced_features);
builder_.add_services(services);
builder_.add_root_table(root_table);
builder_.add_file_ext(file_ext);
Expand All @@ -1164,7 +1212,8 @@ inline flatbuffers::Offset<Schema> CreateSchemaDirect(
const char *file_ident = nullptr,
const char *file_ext = nullptr,
flatbuffers::Offset<reflection::Object> root_table = 0,
std::vector<flatbuffers::Offset<reflection::Service>> *services = nullptr) {
std::vector<flatbuffers::Offset<reflection::Service>> *services = nullptr,
reflection::AdvancedFeatures advanced_features = static_cast<reflection::AdvancedFeatures>(0)) {
auto objects__ = objects ? _fbb.CreateVectorOfSortedTables<reflection::Object>(objects) : 0;
auto enums__ = enums ? _fbb.CreateVectorOfSortedTables<reflection::Enum>(enums) : 0;
auto file_ident__ = file_ident ? _fbb.CreateString(file_ident) : 0;
Expand All @@ -1177,7 +1226,8 @@ inline flatbuffers::Offset<Schema> CreateSchemaDirect(
file_ident__,
file_ext__,
root_table,
services__);
services__,
advanced_features);
}

inline const reflection::Schema *GetSchema(const void *buf) {
Expand Down
9 changes: 9 additions & 0 deletions reflection/reflection.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,22 @@ table Service {
documentation:[string];
}

// New schema language features that are not supported by old code generators.
enum AdvancedFeatures : ulong (bit_flags) {
AdvancedArrayFeatures,
AdvancedUnionFeatures,
OptionalScalars,
DefaultVectorsAndStrings,
}

table Schema {
objects:[Object] (required); // Sorted.
enums:[Enum] (required); // Sorted.
file_ident:string;
file_ext:string;
root_table:Object;
services:[Service]; // Sorted.
advanced_features:AdvancedFeatures;
}

root_type Schema;
Expand Down
33 changes: 22 additions & 11 deletions src/idl_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -765,10 +765,13 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
if (!struct_def.fixed && IsArray(type))
return Error("fixed-length array in table must be wrapped in struct");

if (IsArray(type) && !SupportsAdvancedArrayFeatures()) {
return Error(
"Arrays are not yet supported in all "
"the specified programming languages.");
if (IsArray(type)) {
advanced_features_ |= reflection::AdvancedArrayFeatures;
if (!SupportsAdvancedArrayFeatures()) {
return Error(
"Arrays are not yet supported in all "
"the specified programming languages.");
}
}

FieldDef *typefield = nullptr;
Expand All @@ -778,6 +781,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
type.enum_def->underlying_type, &typefield));
} else if (IsVector(type) && type.element == BASE_TYPE_UNION) {
advanced_features_ |= reflection::AdvancedUnionFeatures;
// Only cpp, js and ts supports the union vector feature so far.
if (!SupportsAdvancedUnionFeatures()) {
return Error(
Expand All @@ -802,11 +806,16 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
return Error(
"default values are not supported for struct fields, table fields, "
"or in structs.");
if ((IsString(type) || IsVector(type)) && field->value.constant != "0" &&
field->value.constant != "null" && !SupportsDefaultVectorsAndStrings())
return Error(
"Default values for strings and vectors are not supported in one of "
"the specified programming languages");
if (IsString(type) || IsVector(type)) {
advanced_features_ |= reflection::DefaultVectorsAndStrings;
if (field->value.constant != "0" && field->value.constant != "null" &&
!SupportsDefaultVectorsAndStrings()) {
return Error(
"Default values for strings and vectors are not supported in one "
"of the specified programming languages");
}
}

if (IsVector(type) && field->value.constant != "0" &&
field->value.constant != "[]") {
return Error("The only supported default for vectors is `[]`.");
Expand Down Expand Up @@ -891,6 +900,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
}

if (field->IsScalarOptional()) {
advanced_features_ |= reflection::OptionalScalars;
if (type.enum_def && type.enum_def->Lookup("null")) {
FLATBUFFERS_ASSERT(IsInteger(type.base_type));
return Error(
Expand Down Expand Up @@ -3498,7 +3508,8 @@ void Parser::Serialize() {
auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
auto schema_offset = reflection::CreateSchema(
builder_, objs__, enum__, fiid__, fext__,
(root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__);
(root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__,
static_cast<reflection::AdvancedFeatures>(advanced_features_));
if (opts.size_prefixed) {
builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
} else {
Expand Down Expand Up @@ -3915,7 +3926,7 @@ bool Parser::Deserialize(const reflection::Schema *schema) {
}
}
}

advanced_features_ = schema->advanced_features();
return true;
}

Expand Down
Binary file modified tests/arrays_test.bfbs
Binary file not shown.