Add binary schema reflection (#7932)

* Add binary schema reflection

* remove not-used parameter

* move logic from object API to base API

* forward declare

* remove duplicate code gen that was stompping on the edits

* reduce to just typedef generation

* fixed bazel rules to not stomp

* more bazel fixes to support additional generated files
This commit is contained in:
Derek Bailey
2023-05-04 16:12:45 -07:00
committed by GitHub
parent 67084b9921
commit 01a7bc3c58
6 changed files with 83 additions and 11 deletions

View File

@@ -614,7 +614,6 @@ if(FLATBUFFERS_BUILD_TESTS)
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/samples" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/samples" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
# TODO Add (monster_test.fbs monsterdata_test.json)->monsterdata_test.mon # TODO Add (monster_test.fbs monsterdata_test.json)->monsterdata_test.mon
compile_flatbuffers_schema_to_cpp(tests/monster_test.fbs)
compile_flatbuffers_schema_to_binary(tests/monster_test.fbs) compile_flatbuffers_schema_to_binary(tests/monster_test.fbs)
compile_flatbuffers_schema_to_cpp_opt(tests/namespace_test/namespace_test1.fbs "--no-includes;--gen-compare;--gen-name-strings") compile_flatbuffers_schema_to_cpp_opt(tests/namespace_test/namespace_test1.fbs "--no-includes;--gen-compare;--gen-name-strings")
compile_flatbuffers_schema_to_cpp_opt(tests/namespace_test/namespace_test2.fbs "--no-includes;--gen-compare;--gen-name-strings") compile_flatbuffers_schema_to_cpp_opt(tests/namespace_test/namespace_test2.fbs "--no-includes;--gen-compare;--gen-name-strings")

View File

@@ -165,6 +165,7 @@ def flatbuffer_cc_library(
name, name,
srcs, srcs,
srcs_filegroup_name = "", srcs_filegroup_name = "",
outs = [],
out_prefix = "", out_prefix = "",
deps = [], deps = [],
includes = [], includes = [],
@@ -185,6 +186,7 @@ def flatbuffer_cc_library(
srcs_filegroup_name: Name of the output filegroup that holds srcs. Pass this srcs_filegroup_name: Name of the output filegroup that holds srcs. Pass this
filegroup into the `includes` parameter of any other filegroup into the `includes` parameter of any other
flatbuffer_cc_library that depends on this one's schemas. flatbuffer_cc_library that depends on this one's schemas.
outs: Additional outputs expected to be generated by flatc.
out_prefix: Prepend this path to the front of all generated files. Usually out_prefix: Prepend this path to the front of all generated files. Usually
is a directory name. is a directory name.
deps: Optional, list of other flatbuffer_cc_library's to depend on. Cannot be specified deps: Optional, list of other flatbuffer_cc_library's to depend on. Cannot be specified
@@ -232,7 +234,7 @@ def flatbuffer_cc_library(
flatbuffer_library_public( flatbuffer_library_public(
name = srcs_lib, name = srcs_lib,
srcs = srcs, srcs = srcs,
outs = output_headers, outs = outs + output_headers,
language_flag = "-c", language_flag = "-c",
out_prefix = out_prefix, out_prefix = out_prefix,
includes = includes, includes = includes,

View File

@@ -280,6 +280,16 @@ class CppGenerator : public BaseGenerator {
if (!opts_.cpp_includes.empty()) { code_ += ""; } if (!opts_.cpp_includes.empty()) { code_ += ""; }
} }
void GenEmbeddedIncludes() {
if (parser_.opts.binary_schema_gen_embed && parser_.root_struct_def_) {
const std::string file_path =
GeneratedFileName(opts_.include_prefix, file_name_ + "_bfbs", opts_);
code_ += "// For access to the binary schema that produced this file.";
code_ += "#include \"" + file_path + "\"";
code_ += "";
}
}
std::string EscapeKeyword(const std::string &name) const { std::string EscapeKeyword(const std::string &name) const {
return keywords_.find(name) == keywords_.end() ? name : name + "_"; return keywords_.find(name) == keywords_.end() ? name : name + "_";
} }
@@ -408,6 +418,7 @@ class CppGenerator : public BaseGenerator {
if (opts_.include_dependence_headers) { GenIncludeDependencies(); } if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
GenExtraIncludes(); GenExtraIncludes();
GenEmbeddedIncludes();
FLATBUFFERS_ASSERT(!cur_name_space_); FLATBUFFERS_ASSERT(!cur_name_space_);
@@ -2152,6 +2163,15 @@ class CppGenerator : public BaseGenerator {
code_ += ""; code_ += "";
} }
// Adds a typedef to the binary schema type so one could get the bfbs based
// on the type at runtime.
void GenBinarySchemaTypeDef(const StructDef *struct_def) {
if (struct_def && opts_.binary_schema_gen_embed) {
code_ += " typedef " + WrapInNameSpace(*struct_def) +
"BinarySchema BinarySchema;";
}
}
void GenNativeTablePost(const StructDef &struct_def) { void GenNativeTablePost(const StructDef &struct_def) {
if (opts_.gen_compare) { if (opts_.gen_compare) {
const auto native_name = NativeName(Name(struct_def), &struct_def, opts_); const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
@@ -2687,6 +2707,8 @@ class CppGenerator : public BaseGenerator {
code_ += " typedef {{NATIVE_NAME}} NativeTableType;"; code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
} }
code_ += " typedef {{STRUCT_NAME}}Builder Builder;"; code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
GenBinarySchemaTypeDef(parser_.root_struct_def_);
if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; } if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
if (opts_.mini_reflect != IDLOptions::kNone) { if (opts_.mini_reflect != IDLOptions::kNone) {
code_ += code_ +=

View File

@@ -1,6 +1,6 @@
load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin")
load("@rules_cc//cc:defs.bzl", "cc_test") load("@rules_cc//cc:defs.bzl", "cc_test")
load("//:build_defs.bzl", "flatbuffer_cc_library") load("//:build_defs.bzl", "DEFAULT_FLATC_ARGS", "flatbuffer_cc_library")
package(default_visibility = ["//visibility:private"]) package(default_visibility = ["//visibility:private"])
@@ -160,6 +160,7 @@ cc_library(
], ],
hdrs = [ hdrs = [
"monster_test.grpc.fb.h", "monster_test.grpc.fb.h",
"monster_test_bfbs_generated.h",
"monster_test_generated.h", "monster_test_generated.h",
], ],
includes = ["."], includes = ["."],
@@ -182,6 +183,13 @@ flatbuffer_cc_library(
flatbuffer_cc_library( flatbuffer_cc_library(
name = "monster_test_cc_fbs", name = "monster_test_cc_fbs",
srcs = ["monster_test.fbs"], srcs = ["monster_test.fbs"],
outs = ["monster_test_bfbs_generated.h"],
flatc_args = DEFAULT_FLATC_ARGS + [
"--bfbs-comments",
"--bfbs-builtins",
"--bfbs-gen-embed",
"--bfbs-filenames tests",
],
include_paths = ["tests/include_test"], include_paths = ["tests/include_test"],
visibility = ["//grpc/tests:__subpackages__"], visibility = ["//grpc/tests:__subpackages__"],
deps = [":include_test_fbs"], deps = [":include_test_fbs"],

View File

@@ -15,6 +15,9 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 23 &&
FLATBUFFERS_VERSION_REVISION == 3, FLATBUFFERS_VERSION_REVISION == 3,
"Non-compatible flatbuffers version included"); "Non-compatible flatbuffers version included");
// For access to the binary schema that produced this file.
#include "monster_test_bfbs_generated.h"
namespace MyGame { namespace MyGame {
struct InParentNamespace; struct InParentNamespace;
@@ -946,6 +949,7 @@ struct InParentNamespaceT : public ::flatbuffers::NativeTable {
struct InParentNamespace FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { struct InParentNamespace FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef InParentNamespaceT NativeTableType; typedef InParentNamespaceT NativeTableType;
typedef InParentNamespaceBuilder Builder; typedef InParentNamespaceBuilder Builder;
typedef MyGame::Example::MonsterBinarySchema BinarySchema;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return InParentNamespaceTypeTable(); return InParentNamespaceTypeTable();
} }
@@ -990,6 +994,7 @@ struct MonsterT : public ::flatbuffers::NativeTable {
struct Monster FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { struct Monster FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef MonsterT NativeTableType; typedef MonsterT NativeTableType;
typedef MonsterBuilder Builder; typedef MonsterBuilder Builder;
typedef MyGame::Example::MonsterBinarySchema BinarySchema;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return MonsterTypeTable(); return MonsterTypeTable();
} }
@@ -1037,6 +1042,7 @@ struct TestSimpleTableWithEnumT : public ::flatbuffers::NativeTable {
struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef TestSimpleTableWithEnumT NativeTableType; typedef TestSimpleTableWithEnumT NativeTableType;
typedef TestSimpleTableWithEnumBuilder Builder; typedef TestSimpleTableWithEnumBuilder Builder;
typedef MyGame::Example::MonsterBinarySchema BinarySchema;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return TestSimpleTableWithEnumTypeTable(); return TestSimpleTableWithEnumTypeTable();
} }
@@ -1097,6 +1103,7 @@ struct StatT : public ::flatbuffers::NativeTable {
struct Stat FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { struct Stat FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef StatT NativeTableType; typedef StatT NativeTableType;
typedef StatBuilder Builder; typedef StatBuilder Builder;
typedef MyGame::Example::MonsterBinarySchema BinarySchema;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return StatTypeTable(); return StatTypeTable();
} }
@@ -1201,6 +1208,7 @@ struct ReferrableT : public ::flatbuffers::NativeTable {
struct Referrable FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { struct Referrable FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef ReferrableT NativeTableType; typedef ReferrableT NativeTableType;
typedef ReferrableBuilder Builder; typedef ReferrableBuilder Builder;
typedef MyGame::Example::MonsterBinarySchema BinarySchema;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return ReferrableTypeTable(); return ReferrableTypeTable();
} }
@@ -1327,6 +1335,7 @@ struct MonsterT : public ::flatbuffers::NativeTable {
struct Monster FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { struct Monster FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef MonsterT NativeTableType; typedef MonsterT NativeTableType;
typedef MonsterBuilder Builder; typedef MonsterBuilder Builder;
typedef MyGame::Example::MonsterBinarySchema BinarySchema;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return MonsterTypeTable(); return MonsterTypeTable();
} }
@@ -2429,6 +2438,7 @@ struct TypeAliasesT : public ::flatbuffers::NativeTable {
struct TypeAliases FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { struct TypeAliases FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef TypeAliasesT NativeTableType; typedef TypeAliasesT NativeTableType;
typedef TypeAliasesBuilder Builder; typedef TypeAliasesBuilder Builder;
typedef MyGame::Example::MonsterBinarySchema BinarySchema;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return TypeAliasesTypeTable(); return TypeAliasesTypeTable();
} }

View File

@@ -25,6 +25,7 @@
#include "flatbuffers/flatbuffers.h" #include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h" #include "flatbuffers/idl.h"
#include "flatbuffers/minireflect.h" #include "flatbuffers/minireflect.h"
#include "flatbuffers/reflection_generated.h"
#include "flatbuffers/registry.h" #include "flatbuffers/registry.h"
#include "flatbuffers/util.h" #include "flatbuffers/util.h"
#include "fuzz_test.h" #include "fuzz_test.h"
@@ -912,7 +913,7 @@ void NativeTypeTest() {
// Guard against -Wunused-function on platforms without file tests. // Guard against -Wunused-function on platforms without file tests.
#ifndef FLATBUFFERS_NO_FILE_TESTS #ifndef FLATBUFFERS_NO_FILE_TESTS
// VS10 does not support typed enums, exclude from tests // VS10 does not support typed enums, exclude from tests
#if !defined(_MSC_VER) || _MSC_VER >= 1700 # if !defined(_MSC_VER) || _MSC_VER >= 1700
void FixedLengthArrayJsonTest(const std::string &tests_data_path, bool binary) { void FixedLengthArrayJsonTest(const std::string &tests_data_path, bool binary) {
// load FlatBuffer schema (.fbs) and JSON from disk // load FlatBuffer schema (.fbs) and JSON from disk
std::string schemafile; std::string schemafile;
@@ -1031,7 +1032,7 @@ void FixedLengthArraySpanTest(const std::string &tests_data_path) {
std::equal(const_d_c.begin(), const_d_c.end(), mutable_d_c.begin())); std::equal(const_d_c.begin(), const_d_c.end(), mutable_d_c.begin()));
} }
// test little endian array of int32 // test little endian array of int32
# if FLATBUFFERS_LITTLEENDIAN # if FLATBUFFERS_LITTLEENDIAN
{ {
flatbuffers::span<const int32_t, 2> const_d_a = flatbuffers::span<const int32_t, 2> const_d_a =
flatbuffers::make_span(*const_nested.a()); flatbuffers::make_span(*const_nested.a());
@@ -1046,12 +1047,12 @@ void FixedLengthArraySpanTest(const std::string &tests_data_path) {
TEST_ASSERT( TEST_ASSERT(
std::equal(const_d_a.begin(), const_d_a.end(), mutable_d_a.begin())); std::equal(const_d_a.begin(), const_d_a.end(), mutable_d_a.begin()));
} }
# endif # endif
} }
#else # else
void FixedLengthArrayJsonTest(bool /*binary*/) {} void FixedLengthArrayJsonTest(bool /*binary*/) {}
void FixedLengthArraySpanTest() {} void FixedLengthArraySpanTest() {}
#endif # endif
void TestEmbeddedBinarySchema(const std::string &tests_data_path) { void TestEmbeddedBinarySchema(const std::string &tests_data_path) {
// load JSON from disk // load JSON from disk
@@ -1101,6 +1102,37 @@ void TestEmbeddedBinarySchema(const std::string &tests_data_path) {
} }
#endif #endif
template<typename T> void EmbeddedSchemaAccessByType() {
// Get the binary schema from the Type itself.
// Verify the schema is OK.
flatbuffers::Verifier verifierEmbeddedSchema(
T::TableType::BinarySchema::data(), T::TableType::BinarySchema::size());
TEST_EQ(reflection::VerifySchemaBuffer(verifierEmbeddedSchema), true);
// Reflect it.
auto schema = reflection::GetSchema(T::TableType::BinarySchema::data());
// This should equal the expected root table.
TEST_EQ_STR(schema->root_table()->name()->c_str(), "MyGame.Example.Monster");
}
void EmbeddedSchemaAccess() {
// Get the binary schema for the monster.
// Verify the schema is OK.
flatbuffers::Verifier verifierEmbeddedSchema(Monster::BinarySchema::data(),
Monster::BinarySchema::size());
TEST_EQ(reflection::VerifySchemaBuffer(verifierEmbeddedSchema), true);
// Reflect it.
auto schema = reflection::GetSchema(Monster::BinarySchema::data());
// This should equal the expected root table.
TEST_EQ_STR(schema->root_table()->name()->c_str(), "MyGame.Example.Monster");
// Repeat above, but do so through a template parameter:
EmbeddedSchemaAccessByType<StatT>();
}
void NestedVerifierTest() { void NestedVerifierTest() {
// Create a nested monster. // Create a nested monster.
flatbuffers::FlatBufferBuilder nested_builder; flatbuffers::FlatBufferBuilder nested_builder;
@@ -1458,9 +1490,7 @@ void NativeInlineTableVectorTest() {
TestNativeInlineTableT unpacked; TestNativeInlineTableT unpacked;
root->UnPackTo(&unpacked); root->UnPackTo(&unpacked);
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) { TEST_ASSERT(unpacked.t[i] == test.t[i]); }
TEST_ASSERT(unpacked.t[i] == test.t[i]);
}
TEST_ASSERT(unpacked.t == test.t); TEST_ASSERT(unpacked.t == test.t);
} }
@@ -1620,6 +1650,7 @@ int FlatBufferTests(const std::string &tests_data_path) {
StructKeyInStructTest(); StructKeyInStructTest();
NestedStructKeyInStructTest(); NestedStructKeyInStructTest();
FixedSizedStructArrayKeyInStructTest(); FixedSizedStructArrayKeyInStructTest();
EmbeddedSchemaAccess();
return 0; return 0;
} }
} // namespace } // namespace