Add a FlatbufferType implementation for a Schema
Change-Id: Ia58d86edc7bcfd1835087d8d8674b790dcbfaa67
diff --git a/aos/BUILD b/aos/BUILD
index 96c5b3d..7c976b1 100644
--- a/aos/BUILD
+++ b/aos/BUILD
@@ -316,14 +316,14 @@
)
flatbuffer_ts_library(
- name = "json_to_flatbuffer_flatbuffer_ts",
+ name = "json_to_flatbuffer_fbs_ts",
srcs = ["json_to_flatbuffer.fbs"],
target_compatible_with = ["@platforms//os:linux"],
visibility = ["//aos:__subpackages__"],
)
flatbuffer_cc_library(
- name = "json_to_flatbuffer_flatbuffer",
+ name = "json_to_flatbuffer_fbs",
srcs = ["json_to_flatbuffer.fbs"],
gen_reflections = 1,
target_compatible_with = ["@platforms//os:linux"],
@@ -377,10 +377,13 @@
srcs = [
"json_to_flatbuffer_test.cc",
],
+ data = [
+ ":json_to_flatbuffer_fbs_reflection_out",
+ ],
target_compatible_with = ["@platforms//os:linux"],
deps = [
":json_to_flatbuffer",
- ":json_to_flatbuffer_flatbuffer",
+ ":json_to_flatbuffer_fbs",
"//aos/testing:googletest",
],
)
@@ -391,12 +394,12 @@
"flatbuffer_introspection_test.cc",
],
data = [
- ":json_to_flatbuffer_flatbuffer_reflection_out",
+ ":json_to_flatbuffer_fbs_reflection_out",
],
target_compatible_with = ["@platforms//os:linux"],
deps = [
":json_to_flatbuffer",
- ":json_to_flatbuffer_flatbuffer",
+ ":json_to_flatbuffer_fbs",
"//aos/testing:googletest",
"//aos/util:file",
"@com_github_google_flatbuffers//:flatbuffers",
@@ -426,7 +429,7 @@
deps = [
":flatbuffer_merge",
":json_to_flatbuffer",
- ":json_to_flatbuffer_flatbuffer",
+ ":json_to_flatbuffer_fbs",
"//aos/testing:googletest",
],
)
@@ -578,7 +581,7 @@
deps = [
":flatbuffers",
":json_to_flatbuffer",
- ":json_to_flatbuffer_flatbuffer",
+ ":json_to_flatbuffer_fbs",
"//aos/testing:googletest",
],
)
diff --git a/aos/flatbuffer_utils.cc b/aos/flatbuffer_utils.cc
index b0615df..3429fe4 100644
--- a/aos/flatbuffer_utils.cc
+++ b/aos/flatbuffer_utils.cc
@@ -1,6 +1,7 @@
#include "aos/flatbuffer_utils.h"
#include "flatbuffers/minireflect.h"
+#include "flatbuffers/reflection_generated.h"
#include "glog/logging.h"
namespace aos {
@@ -9,6 +10,12 @@
if (type_table_) {
return type_table_->st != flatbuffers::ST_ENUM;
}
+ if (object_) {
+ return true;
+ }
+ if (enum_) {
+ return enum_->is_union();
+ }
LOG(FATAL) << "Unimplemented";
}
@@ -16,6 +23,12 @@
if (type_table_) {
return type_table_->st == flatbuffers::ST_ENUM;
}
+ if (object_) {
+ return false;
+ }
+ if (enum_) {
+ return !enum_->is_union();
+ }
LOG(FATAL) << "Unimplemented";
}
@@ -30,6 +43,11 @@
DCHECK(FieldType(index).IsSequence());
return true;
}
+ if (object_ || enum_) {
+ const reflection::BaseType base_type = ReflectionElementBaseType(index);
+ return base_type == reflection::BaseType::Obj ||
+ base_type == reflection::BaseType::Union;
+ }
LOG(FATAL) << "Unimplemented";
}
@@ -48,11 +66,20 @@
DCHECK(FieldType(index).IsEnum());
return true;
}
+ if (object_ || enum_) {
+ const reflection::BaseType base_type = ReflectionElementBaseType(index);
+ if (base_type == reflection::BaseType::Obj ||
+ base_type == reflection::BaseType::Union) {
+ return false;
+ }
+ return ReflectionType(index)->index() >= 0;
+ }
LOG(FATAL) << "Unimplemented";
}
std::optional<int64_t> FlatbufferType::EnumValue(std::string_view name) const {
DCHECK(IsEnum());
+ DCHECK(!object_);
if (type_table_) {
for (size_t i = 0; i < type_table_->num_elems; ++i) {
if (name == type_table_->names[i]) {
@@ -65,6 +92,15 @@
}
return std::nullopt;
}
+ if (enum_) {
+ for (size_t i = 0; i < enum_->values()->size(); ++i) {
+ const auto *const value = enum_->values()->Get(i);
+ if (name == value->name()->string_view()) {
+ return value->value();
+ }
+ }
+ return std::nullopt;
+ }
LOG(FATAL) << "Unimplemented";
}
@@ -75,6 +111,12 @@
const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
return type_code.is_repeating;
}
+ if (object_ || enum_) {
+ const reflection::BaseType type = ReflectionType(index)->base_type();
+ CHECK(type != reflection::BaseType::None);
+ return type == reflection::BaseType::Vector ||
+ type == reflection::BaseType::Array;
+ }
LOG(FATAL) << "Unimplemented";
}
@@ -88,6 +130,24 @@
}
return -1;
}
+ if (object_) {
+ for (size_t i = 0; i < object_->fields()->size(); ++i) {
+ const reflection::Field *const field = object_->fields()->Get(i);
+ if (field_name == field->name()->string_view()) {
+ return field->id();
+ }
+ }
+ return -1;
+ }
+ if (enum_) {
+ for (size_t i = 0; i < enum_->values()->size(); ++i) {
+ const reflection::EnumVal *const value = enum_->values()->Get(i);
+ if (field_name == value->name()->string_view()) {
+ return value->value();
+ }
+ }
+ return -1;
+ }
LOG(FATAL) << "Unimplemented";
}
@@ -97,9 +157,59 @@
DCHECK_LT(static_cast<size_t>(index), type_table_->num_elems);
return type_table_->names[index];
}
+ if (object_) {
+ return ReflectionObjectField(index)->name()->string_view();
+ }
+ if (enum_) {
+ return ReflectionEnumValue(index)->name()->string_view();
+ }
LOG(FATAL) << "Unimplemented";
}
+namespace {
+
+flatbuffers::ElementaryType ElementaryTypeFromBaseType(
+ reflection::BaseType base_type) {
+ switch (base_type) {
+ case reflection::BaseType::None:
+ LOG(FATAL) << "Invalid schema";
+ case reflection::BaseType::UType:
+ return flatbuffers::ElementaryType::ET_UTYPE;
+ case reflection::BaseType::Bool:
+ return flatbuffers::ElementaryType::ET_BOOL;
+ case reflection::BaseType::Byte:
+ return flatbuffers::ElementaryType::ET_CHAR;
+ case reflection::BaseType::UByte:
+ return flatbuffers::ElementaryType::ET_UCHAR;
+ case reflection::BaseType::Short:
+ return flatbuffers::ElementaryType::ET_SHORT;
+ case reflection::BaseType::UShort:
+ return flatbuffers::ElementaryType::ET_USHORT;
+ case reflection::BaseType::Int:
+ return flatbuffers::ElementaryType::ET_INT;
+ case reflection::BaseType::UInt:
+ return flatbuffers::ElementaryType::ET_UINT;
+ case reflection::BaseType::Long:
+ return flatbuffers::ElementaryType::ET_LONG;
+ case reflection::BaseType::ULong:
+ return flatbuffers::ElementaryType::ET_ULONG;
+ case reflection::BaseType::Float:
+ return flatbuffers::ElementaryType::ET_FLOAT;
+ case reflection::BaseType::Double:
+ return flatbuffers::ElementaryType::ET_DOUBLE;
+ case reflection::BaseType::String:
+ return flatbuffers::ElementaryType::ET_STRING;
+ case reflection::BaseType::Obj:
+ return flatbuffers::ElementaryType::ET_SEQUENCE;
+ case reflection::BaseType::Union:
+ return flatbuffers::ElementaryType::ET_SEQUENCE;
+ default:
+ LOG(FATAL) << "Unknown BaseType";
+ }
+}
+
+} // namespace
+
flatbuffers::ElementaryType FlatbufferType::FieldElementaryType(
int index) const {
DCHECK(IsSequence());
@@ -108,14 +218,69 @@
const flatbuffers::TypeCode &type_code = type_table_->type_codes[index];
return static_cast<flatbuffers::ElementaryType>(type_code.base_type);
}
+ if (object_ || enum_) {
+ return ElementaryTypeFromBaseType(ReflectionElementBaseType(index));
+ }
LOG(FATAL) << "Unimplemented";
}
+namespace {
+
+size_t BaseTypeInlineSize(reflection::BaseType base_type) {
+ switch (base_type) {
+ case reflection::BaseType::None:
+ LOG(FATAL) << "Invalid schema";
+ case reflection::BaseType::UType:
+ case reflection::BaseType::Bool:
+ case reflection::BaseType::Byte:
+ case reflection::BaseType::UByte:
+ return 1;
+ case reflection::BaseType::Short:
+ case reflection::BaseType::UShort:
+ return 2;
+ case reflection::BaseType::Int:
+ case reflection::BaseType::UInt:
+ case reflection::BaseType::Float:
+ case reflection::BaseType::String:
+ return 4;
+ case reflection::BaseType::Long:
+ case reflection::BaseType::ULong:
+ case reflection::BaseType::Double:
+ return 8;
+ case reflection::BaseType::Union:
+ return 4;
+ default:
+ LOG(FATAL) << "Unknown BaseType";
+ }
+}
+
+} // namespace
+
size_t FlatbufferType::FieldInlineSize(int index) const {
DCHECK(IsSequence());
if (type_table_) {
return flatbuffers::InlineSize(FieldElementaryType(index), type_table_);
}
+ if (object_ || enum_) {
+ const reflection::Type *const type = ReflectionType(index);
+ const reflection::BaseType element_base_type =
+ ReflectionElementBaseType(index);
+ int element_size;
+ if (element_base_type == reflection::BaseType::Obj) {
+ const FlatbufferType field_type = FieldType(index);
+ if (field_type.object_ && field_type.object_->is_struct()) {
+ element_size = field_type.object_->bytesize();
+ } else {
+ element_size = 4;
+ }
+ } else {
+ element_size = BaseTypeInlineSize(element_base_type);
+ }
+ if (type->base_type() == reflection::BaseType::Array) {
+ return element_size * type->fixed_length();
+ }
+ return element_size;
+ }
LOG(FATAL) << "Unimplemented";
}
@@ -124,6 +289,12 @@
if (type_table_) {
return type_table_->num_elems;
}
+ if (object_) {
+ return object_->fields()->size();
+ }
+ if (enum_) {
+ return enum_->values()->size();
+ }
LOG(FATAL) << "Unimplemented";
}
@@ -141,7 +312,62 @@
type_table_->type_refs[type_code.sequence_ref];
return FlatbufferType(type_function());
}
+ if (object_ || enum_) {
+ const reflection::BaseType base_type = ReflectionElementBaseType(index);
+ const int object_index = ReflectionType(index)->index();
+ CHECK(object_index >= 0) << ": Invalid schema";
+ if (base_type == reflection::BaseType::Obj ||
+ base_type == reflection::BaseType::Union) {
+ DCHECK_LT(static_cast<size_t>(object_index), schema_->objects()->size());
+ return FlatbufferType(schema_, schema_->objects()->Get(object_index));
+ } else {
+ DCHECK_LT(static_cast<size_t>(object_index), schema_->enums()->size());
+ return FlatbufferType(schema_, schema_->enums()->Get(object_index));
+ }
+ }
LOG(FATAL) << "Unimplemented";
}
+const reflection::Type *FlatbufferType::ReflectionType(int index) const {
+ if (object_) {
+ return ReflectionObjectField(index)->type();
+ } else {
+ return ReflectionEnumValue(index)->union_type();
+ }
+}
+
+const reflection::Field *FlatbufferType::ReflectionObjectField(
+ int index) const {
+ DCHECK(object_);
+ const auto result = std::find_if(
+ object_->fields()->begin(), object_->fields()->end(),
+ [index](const reflection::Field *field) { return field->id() == index; });
+ DCHECK(result != object_->fields()->end());
+ return *result;
+}
+
+const reflection::EnumVal *FlatbufferType::ReflectionEnumValue(
+ int index) const {
+ DCHECK(enum_);
+ const auto result =
+ std::find_if(enum_->values()->begin(), enum_->values()->end(),
+ [index](const reflection::EnumVal *value) {
+ return value->value() == index;
+ });
+ DCHECK(result != enum_->values()->end());
+ return *result;
+}
+
+reflection::BaseType FlatbufferType::ReflectionElementBaseType(
+ int index) const {
+ const reflection::Type *const type = ReflectionType(index);
+ reflection::BaseType base_type = type->base_type();
+ if (base_type == reflection::BaseType::Vector ||
+ base_type == reflection::BaseType::Array) {
+ base_type = type->element();
+ }
+ CHECK(base_type != reflection::BaseType::None);
+ return base_type;
+}
+
} // namespace aos
diff --git a/aos/flatbuffer_utils.h b/aos/flatbuffer_utils.h
index 2118fd6..0287b6d 100644
--- a/aos/flatbuffer_utils.h
+++ b/aos/flatbuffer_utils.h
@@ -5,6 +5,7 @@
#include <string_view>
#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/reflection_generated.h"
#include "glog/logging.h"
namespace aos {
@@ -25,6 +26,9 @@
// Implicit on purpose, to allow freely creating a FlatbufferType.
FlatbufferType(const flatbuffers::TypeTable *type_table)
: type_table_(CHECK_NOTNULL(type_table)) {}
+ FlatbufferType(const reflection::Schema *schema)
+ : schema_(CHECK_NOTNULL(schema)),
+ object_(DCHECK_NOTNULL(schema->root_table())) {}
// This is deliberately copyable, for ease of memory management. It is cheap
// to pass by value.
@@ -92,7 +96,22 @@
FlatbufferType FieldType(int index) const;
private:
+ explicit FlatbufferType(const reflection::Schema *schema,
+ const reflection::Object *object)
+ : schema_(DCHECK_NOTNULL(schema)), object_(DCHECK_NOTNULL(object)) {}
+ explicit FlatbufferType(const reflection::Schema *schema,
+ const reflection::Enum *fb_enum)
+ : schema_(DCHECK_NOTNULL(schema)), enum_(DCHECK_NOTNULL(fb_enum)) {}
+
+ const reflection::Type *ReflectionType(int index) const;
+ const reflection::Field *ReflectionObjectField(int index) const;
+ const reflection::EnumVal *ReflectionEnumValue(int index) const;
+ reflection::BaseType ReflectionElementBaseType(int index) const;
+
const flatbuffers::TypeTable *type_table_ = nullptr;
+ const reflection::Schema *schema_ = nullptr;
+ const reflection::Object *object_ = nullptr;
+ const reflection::Enum *enum_ = nullptr;
};
} // namespace aos
diff --git a/aos/json_to_flatbuffer_test.cc b/aos/json_to_flatbuffer_test.cc
index dd70908..9dc12d2 100644
--- a/aos/json_to_flatbuffer_test.cc
+++ b/aos/json_to_flatbuffer_test.cc
@@ -11,22 +11,33 @@
public:
JsonToFlatbufferTest() {}
+ FlatbufferVector<reflection::Schema> Schema() {
+ return FileToFlatbuffer<reflection::Schema>("aos/json_to_flatbuffer.bfbs");
+ }
+
bool JsonAndBack(const ::std::string str) { return JsonAndBack(str, str); }
bool JsonAndBack(const ::std::string in, const ::std::string out) {
printf("Testing: %s\n", in.c_str());
- FlatbufferDetachedBuffer<Configuration> fb =
+ FlatbufferDetachedBuffer<Configuration> fb_typetable =
JsonToFlatbuffer<Configuration>(in.data());
+ FlatbufferDetachedBuffer<Configuration> fb_reflection =
+ JsonToFlatbuffer(in.data(), FlatbufferType(&Schema().message()));
- if (fb.span().size() == 0) {
+ if (fb_typetable.span().size() == 0) {
+ return false;
+ }
+ if (fb_reflection.span().size() == 0) {
return false;
}
- const ::std::string back = FlatbufferToJson(fb);
+ const ::std::string back_typetable = FlatbufferToJson(fb_typetable);
+ const ::std::string back_reflection = FlatbufferToJson(fb_reflection);
- printf("Back to string: %s\n", back.c_str());
+ printf("Back to string via TypeTable: %s\n", back_typetable.c_str());
+ printf("Back to string via reflection: %s\n", back_reflection.c_str());
- return back == out;
+ return back_typetable == out && back_reflection == out;
}
};
@@ -222,20 +233,35 @@
json_short += " ] }";
json_long += ", 101 ] }";
- const FlatbufferDetachedBuffer<Configuration> fb_short(
+ const FlatbufferDetachedBuffer<Configuration> fb_short_typetable(
JsonToFlatbuffer<Configuration>(json_short));
- ASSERT_GT(fb_short.span().size(), 0);
- const FlatbufferDetachedBuffer<Configuration> fb_long(
+ ASSERT_GT(fb_short_typetable.span().size(), 0);
+ const FlatbufferDetachedBuffer<Configuration> fb_long_typetable(
JsonToFlatbuffer<Configuration>(json_long));
- ASSERT_GT(fb_long.span().size(), 0);
+ ASSERT_GT(fb_long_typetable.span().size(), 0);
+ const FlatbufferDetachedBuffer<Configuration> fb_short_reflection(
+ JsonToFlatbuffer(json_short, FlatbufferType(&Schema().message())));
+ ASSERT_GT(fb_short_reflection.span().size(), 0);
+ const FlatbufferDetachedBuffer<Configuration> fb_long_reflection(
+ JsonToFlatbuffer(json_long, FlatbufferType(&Schema().message())));
+ ASSERT_GT(fb_long_reflection.span().size(), 0);
- const std::string back_json_short = FlatbufferToJson<Configuration>(
- fb_short, {.multi_line = false, .max_vector_size = 100});
- const std::string back_json_long = FlatbufferToJson<Configuration>(
- fb_long, {.multi_line = false, .max_vector_size = 100});
+ const std::string back_json_short_typetable = FlatbufferToJson<Configuration>(
+ fb_short_typetable, {.multi_line = false, .max_vector_size = 100});
+ const std::string back_json_long_typetable = FlatbufferToJson<Configuration>(
+ fb_long_typetable, {.multi_line = false, .max_vector_size = 100});
+ const std::string back_json_short_reflection =
+ FlatbufferToJson<Configuration>(
+ fb_short_reflection, {.multi_line = false, .max_vector_size = 100});
+ const std::string back_json_long_reflection = FlatbufferToJson<Configuration>(
+ fb_long_reflection, {.multi_line = false, .max_vector_size = 100});
- EXPECT_EQ(json_short, back_json_short);
- EXPECT_EQ("{ \"vector_foo_int\": [ ... 101 elements ... ] }", back_json_long);
+ EXPECT_EQ(json_short, back_json_short_typetable);
+ EXPECT_EQ(json_short, back_json_short_reflection);
+ EXPECT_EQ("{ \"vector_foo_int\": [ ... 101 elements ... ] }",
+ back_json_long_typetable);
+ EXPECT_EQ("{ \"vector_foo_int\": [ ... 101 elements ... ] }",
+ back_json_long_reflection);
}
// Tests that a nullptr buffer prints nullptr.
diff --git a/aos/network/www/BUILD b/aos/network/www/BUILD
index a153ff3..1caa57c 100644
--- a/aos/network/www/BUILD
+++ b/aos/network/www/BUILD
@@ -74,7 +74,7 @@
deps = [
":reflection_ts",
"//aos:configuration_ts_fbs",
- "//aos:json_to_flatbuffer_flatbuffer_ts",
+ "//aos:json_to_flatbuffer_fbs_ts",
"//aos/network/www:proxy",
"@com_github_google_flatbuffers//ts:flatbuffers_ts",
],
@@ -87,7 +87,7 @@
visibility = ["//visibility:public"],
deps = [
"//aos:configuration_ts_fbs",
- "//aos:json_to_flatbuffer_flatbuffer_ts",
+ "//aos:json_to_flatbuffer_fbs_ts",
"@com_github_google_flatbuffers//ts:flatbuffers_ts",
],
)
@@ -144,7 +144,7 @@
src = "test_config_file.json",
flatbuffers = [
"//aos:configuration_fbs",
- "//aos:json_to_flatbuffer_flatbuffer",
+ "//aos:json_to_flatbuffer_fbs",
],
target_compatible_with = ["@platforms//os:linux"],
visibility = ["//visibility:public"],