Merge commit '7c1ae250acb4120322b01a666993ed63c795ef21' into master
Update flatbuffers to latest master.
This adds an upstream flatbuffer_ts_library rule and changes the
typescript codegen, so ends up touching every typescript file we have
that uses flatbuffers. But it does clean up some of the hacks we had to
make to get that to work.
Had to hack the flatbuffer_ts_library a bit because I forgot to make
imports work nicely for cross-repo things.
And of course, the original motivation for this is that it gives us
proper handling of transitive dependencies for
flatbuffer_cc_library, if we start using the deps attribute!
Had to modify the codegen for the new declaration_file attribute in
flatbuffer schemas to make it just be the filename rather than including
the path. Modifying that to make it use a workspace-relative path was
looking obnoxious. It's definitely feasible, but since we don't actually
need that attribute, just make it be a filename for now.
Change-Id: I523a758cafa512fa2a686c9705d23337a26798ca
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
Signed-off-by: James Kuszmaul <jabukuszmaul+collab@gmail.com>
diff --git a/third_party/flatbuffers/src/BUILD b/third_party/flatbuffers/src/BUILD.bazel
similarity index 72%
rename from third_party/flatbuffers/src/BUILD
rename to third_party/flatbuffers/src/BUILD.bazel
index 63f0426..d8bbfcd 100644
--- a/third_party/flatbuffers/src/BUILD
+++ b/third_party/flatbuffers/src/BUILD.bazel
@@ -1,3 +1,6 @@
+# @unused
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
+
package(
default_visibility = ["//visibility:private"],
)
@@ -14,6 +17,15 @@
"util.cpp",
],
hdrs = ["//:public_headers"],
+ linkopts = select({
+ # TODO: Bazel uses `clang` instead of `clang++` to link
+ # C++ code on BSD. Temporarily adding these linker flags while
+ # we wait for Bazel to resolve
+ # https://github.com/bazelbuild/bazel/issues/12023.
+ "//:platform_freebsd": ["-lm"],
+ "//:platform_openbsd": ["-lm"],
+ "//conditions:default": [],
+ }),
strip_include_prefix = "/include",
visibility = ["//:__pkg__"],
)
@@ -22,6 +34,9 @@
cc_library(
name = "flatc_library",
srcs = [
+ "bfbs_gen.h",
+ "bfbs_gen_lua.cpp",
+ "bfbs_gen_lua.h",
"flatc.cpp",
],
hdrs = [
@@ -38,6 +53,9 @@
cc_library(
name = "flatc",
srcs = [
+ "bfbs_gen.h",
+ "bfbs_gen_lua.cpp",
+ "bfbs_gen_lua.h",
"flatc_main.cpp",
"idl_gen_cpp.cpp",
"idl_gen_csharp.cpp",
@@ -45,7 +63,6 @@
"idl_gen_go.cpp",
"idl_gen_grpc.cpp",
"idl_gen_java.cpp",
- "idl_gen_js_ts.cpp",
"idl_gen_json_schema.cpp",
"idl_gen_kotlin.cpp",
"idl_gen_lobster.cpp",
@@ -55,6 +72,8 @@
"idl_gen_rust.cpp",
"idl_gen_swift.cpp",
"idl_gen_text.cpp",
+ "idl_gen_ts.cpp",
+ "namer.h",
"util.cpp",
],
hdrs = [
diff --git a/third_party/flatbuffers/src/bfbs_gen.h b/third_party/flatbuffers/src/bfbs_gen.h
new file mode 100644
index 0000000..27baef9
--- /dev/null
+++ b/third_party/flatbuffers/src/bfbs_gen.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_BFBS_GEN_H_
+#define FLATBUFFERS_BFBS_GEN_H_
+
+#include <cstdint>
+
+#include "flatbuffers/bfbs_generator.h"
+#include "flatbuffers/reflection_generated.h"
+
+namespace flatbuffers {
+
+void ForAllEnums(
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *enums,
+ std::function<void(const reflection::Enum *)> func) {
+ for (auto it = enums->cbegin(); it != enums->cend(); ++it) { func(*it); }
+}
+
+void ForAllObjects(
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects,
+ std::function<void(const reflection::Object *)> func) {
+ for (auto it = objects->cbegin(); it != objects->cend(); ++it) { func(*it); }
+}
+
+void ForAllEnumValues(const reflection::Enum *enum_def,
+ std::function<void(const reflection::EnumVal *)> func) {
+ for (auto it = enum_def->values()->cbegin(); it != enum_def->values()->cend();
+ ++it) {
+ func(*it);
+ }
+}
+
+void ForAllDocumentation(
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
+ *documentation,
+ std::function<void(const flatbuffers::String *)> func) {
+ if (!documentation) { return; }
+ for (auto it = documentation->cbegin(); it != documentation->cend(); ++it) {
+ func(*it);
+ }
+}
+
+// Maps the field index into object->fields() to the field's ID (the ith element
+// in the return vector).
+static std::vector<uint32_t> FieldIdToIndex(const reflection::Object *object) {
+ std::vector<uint32_t> field_index_by_id;
+ field_index_by_id.resize(object->fields()->size());
+
+ // Create the mapping of field ID to the index into the vector.
+ for (uint32_t i = 0; i < object->fields()->size(); ++i) {
+ auto field = object->fields()->Get(i);
+ field_index_by_id[field->id()] = i;
+ }
+
+ return field_index_by_id;
+}
+
+static bool IsStructOrTable(const reflection::BaseType base_type) {
+ return base_type == reflection::BaseType::Obj;
+}
+
+static bool IsScalar(const reflection::BaseType base_type) {
+ return base_type >= reflection::BaseType::UType && base_type <= reflection::BaseType::Double;
+}
+
+static bool IsFloatingPoint(const reflection::BaseType base_type) {
+ return base_type == reflection::BaseType::Float || base_type == reflection::BaseType::Double;
+}
+
+static bool IsBool(const reflection::BaseType base_type) {
+ return base_type == reflection::BaseType::Bool;
+}
+
+static bool IsSingleByte(const reflection::BaseType base_type) {
+ return base_type >= reflection::BaseType::UType && base_type <= reflection::BaseType::UByte;
+}
+
+static bool IsVector(const reflection::BaseType base_type) {
+ return base_type == reflection::BaseType::Vector;
+}
+
+static std::string Denamespace(const flatbuffers::String *name,
+ std::string &ns) {
+ const size_t pos = name->str().find_last_of('.');
+ if (pos == std::string::npos) {
+ ns = "";
+ return name->str();
+ }
+ ns = name->str().substr(0, pos);
+ return name->str().substr(pos + 1);
+}
+
+static std::string Denamespace(const flatbuffers::String *name) {
+ std::string ns;
+ return Denamespace(name, ns);
+}
+
+// A concrete base Flatbuffer Generator that specific language generators can
+// derive from.
+class BaseBfbsGenerator : public BfbsGenerator {
+ public:
+ virtual ~BaseBfbsGenerator() {}
+ BaseBfbsGenerator() : schema_(nullptr) {}
+
+ virtual GeneratorStatus GenerateFromSchema(
+ const reflection::Schema *schema) = 0;
+
+ //
+ virtual uint64_t SupportedAdvancedFeatures() const = 0;
+
+ // Override of the Generator::generate method that does the initial
+ // deserialization and verification steps.
+ GeneratorStatus Generate(const uint8_t *buffer,
+ int64_t length) FLATBUFFERS_OVERRIDE {
+ flatbuffers::Verifier verifier(buffer, static_cast<size_t>(length));
+ if (!reflection::VerifySchemaBuffer(verifier)) {
+ return FAILED_VERIFICATION;
+ }
+
+ // Store the root schema since there are cases where leaf nodes refer to
+ // things in the root schema (e.g., indexing the objects).
+ schema_ = reflection::GetSchema(buffer);
+
+ const uint64_t advance_features = static_cast<uint64_t>(schema_->advanced_features());
+ if (advance_features > SupportedAdvancedFeatures()) {
+ return FAILED_VERIFICATION;
+ }
+
+ GeneratorStatus status = GenerateFromSchema(schema_);
+ schema_ = nullptr;
+ return status;
+ }
+
+ protected:
+ const reflection::Object *GetObject(const reflection::Type *type) const {
+ if (type->index() >= 0 && IsStructOrTable(type->base_type())) {
+ return GetObjectByIndex(type->index());
+ }
+ return nullptr;
+ }
+
+ const reflection::Enum *GetEnum(const reflection::Type *type) const {
+ // TODO(derekbailey): it would be better to have a explicit list of allowed
+ // base types, instead of negating Obj types.
+ if (type->index() >= 0 && !IsStructOrTable(type->base_type())) {
+ return GetEnumByIndex(type->index());
+ }
+ return nullptr;
+ }
+
+ // Used to get a object that is reference by index. (e.g.
+ // reflection::Type::index). Returns nullptr if no object is available.
+ const reflection::Object *GetObjectByIndex(int32_t index) const {
+ if (!schema_ || index < 0 ||
+ index >= static_cast<int32_t>(schema_->objects()->size())) {
+ return nullptr;
+ }
+ return schema_->objects()->Get(index);
+ }
+
+ // Used to get a enum that is reference by index. (e.g.
+ // reflection::Type::index). Returns nullptr if no enum is available.
+ const reflection::Enum *GetEnumByIndex(int32_t index) const {
+ if (!schema_ || index < 0 ||
+ index >= static_cast<int32_t>(schema_->enums()->size())) {
+ return nullptr;
+ }
+ return schema_->enums()->Get(index);
+ }
+
+ void ForAllFields(const reflection::Object *object, bool reverse,
+ std::function<void(const reflection::Field *)> func) const {
+ const std::vector<uint32_t> field_to_id_map = FieldIdToIndex(object);
+ for (size_t i = 0; i < field_to_id_map.size(); ++i) {
+ func(object->fields()->Get(
+ field_to_id_map[reverse ? field_to_id_map.size() - (i + 1) : i]));
+ }
+ }
+
+ bool IsTable(const reflection::Type *type, bool use_element = false) const {
+ return !IsStruct(type, use_element);
+ }
+
+ bool IsStruct(const reflection::Type *type, bool use_element = false) const {
+ const reflection::BaseType base_type =
+ use_element ? type->element() : type->base_type();
+ return IsStructOrTable(base_type) &&
+ GetObjectByIndex(type->index())->is_struct();
+ }
+
+ const reflection::Schema *schema_;
+};
+
+} // namespace flatbuffers
+
+#endif // FLATBUFFERS_BFBS_GEN_H_
diff --git a/third_party/flatbuffers/src/bfbs_gen_lua.cpp b/third_party/flatbuffers/src/bfbs_gen_lua.cpp
new file mode 100644
index 0000000..18e171c
--- /dev/null
+++ b/third_party/flatbuffers/src/bfbs_gen_lua.cpp
@@ -0,0 +1,628 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bfbs_gen_lua.h"
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+// Ensure no includes to flatc internals. bfbs_gen.h and generator.h are OK.
+#include "bfbs_gen.h"
+#include "flatbuffers/bfbs_generator.h"
+
+// The intermediate representation schema.
+#include "flatbuffers/reflection_generated.h"
+
+namespace flatbuffers {
+namespace {
+
+// To reduce typing
+namespace r = ::reflection;
+
+class LuaBfbsGenerator : public BaseBfbsGenerator {
+ public:
+ explicit LuaBfbsGenerator(const std::string &flatc_version)
+ : BaseBfbsGenerator(),
+ keywords_(),
+ requires_(),
+ current_obj_(nullptr),
+ current_enum_(nullptr),
+ flatc_version_(flatc_version) {
+ static const char *const keywords[] = {
+ "and", "break", "do", "else", "elseif", "end", "false", "for",
+ "function", "goto", "if", "in", "local", "nil", "not", "or",
+ "repeat", "return", "then", "true", "until", "while"
+ };
+ keywords_.insert(std::begin(keywords), std::end(keywords));
+ }
+
+ GeneratorStatus GenerateFromSchema(const r::Schema *schema)
+ FLATBUFFERS_OVERRIDE {
+ if (!GenerateEnums(schema->enums())) { return FAILED; }
+ if (!GenerateObjects(schema->objects(), schema->root_table())) {
+ return FAILED;
+ }
+ return OK;
+ }
+
+ uint64_t SupportedAdvancedFeatures() const FLATBUFFERS_OVERRIDE {
+ return 0xF;
+ }
+
+ protected:
+ bool GenerateEnums(
+ const flatbuffers::Vector<flatbuffers::Offset<r::Enum>> *enums) {
+ ForAllEnums(enums, [&](const r::Enum *enum_def) {
+ std::string code;
+
+ StartCodeBlock(enum_def);
+
+ std::string ns;
+ const std::string enum_name =
+ NormalizeName(Denamespace(enum_def->name(), ns));
+
+ GenerateDocumentation(enum_def->documentation(), "", code);
+ code += "local " + enum_name + " = {\n";
+
+ ForAllEnumValues(enum_def, [&](const reflection::EnumVal *enum_val) {
+ GenerateDocumentation(enum_val->documentation(), " ", code);
+ code += " " + NormalizeName(enum_val->name()) + " = " +
+ NumToString(enum_val->value()) + ",\n";
+ });
+ code += "}\n";
+ code += "\n";
+
+ EmitCodeBlock(code, enum_name, ns, enum_def->declaration_file()->str());
+ });
+ return true;
+ }
+
+ bool GenerateObjects(
+ const flatbuffers::Vector<flatbuffers::Offset<r::Object>> *objects,
+ const r::Object *root_object) {
+ ForAllObjects(objects, [&](const r::Object *object) {
+ std::string code;
+
+ StartCodeBlock(object);
+
+ // Register the main flatbuffers module.
+ RegisterRequires("flatbuffers", "flatbuffers");
+
+ std::string ns;
+ const std::string object_name =
+ NormalizeName(Denamespace(object->name(), ns));
+
+ GenerateDocumentation(object->documentation(), "", code);
+
+ code += "local " + object_name + " = {}\n";
+ code += "local mt = {}\n";
+ code += "\n";
+ code += "function " + object_name + ".New()\n";
+ code += " local o = {}\n";
+ code += " setmetatable(o, {__index = mt})\n";
+ code += " return o\n";
+ code += "end\n";
+ code += "\n";
+
+ if (object == root_object) {
+ code += "function " + object_name + ".GetRootAs" + object_name +
+ "(buf, offset)\n";
+ code += " if type(buf) == \"string\" then\n";
+ code += " buf = flatbuffers.binaryArray.New(buf)\n";
+ code += " end\n";
+ code += "\n";
+ code += " local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)\n";
+ code += " local o = " + object_name + ".New()\n";
+ code += " o:Init(buf, n + offset)\n";
+ code += " return o\n";
+ code += "end\n";
+ code += "\n";
+ }
+
+ // Generates a init method that receives a pre-existing accessor object,
+ // so that objects can be reused.
+
+ code += "function mt:Init(buf, pos)\n";
+ code += " self.view = flatbuffers.view.New(buf, pos)\n";
+ code += "end\n";
+ code += "\n";
+
+ // Create all the field accessors.
+ ForAllFields(object, /*reverse=*/false, [&](const r::Field *field) {
+ // Skip writing deprecated fields altogether.
+ if (field->deprecated()) { return; }
+
+ const std::string field_name = NormalizeName(field->name());
+ const std::string field_name_camel_case =
+ ConvertCase(field_name, Case::kUpperCamel);
+ const r::BaseType base_type = field->type()->base_type();
+
+ // Generate some fixed strings so we don't repeat outselves later.
+ const std::string getter_signature =
+ "function mt:" + field_name_camel_case + "()\n";
+ const std::string offset_prefix = "local o = self.view:Offset(" +
+ NumToString(field->offset()) + ")\n";
+ const std::string offset_prefix_2 = "if o ~= 0 then\n";
+
+ GenerateDocumentation(field->documentation(), "", code);
+
+ if (IsScalar(base_type)) {
+ code += getter_signature;
+
+ if (object->is_struct()) {
+ // TODO(derekbailey): it would be nice to modify the view:Get to
+ // just pass in the offset and not have to add it its own
+ // self.view.pos.
+ code += " return " + GenerateGetter(field->type()) +
+ "self.view.pos + " + NumToString(field->offset()) + ")\n";
+ } else {
+ // Table accessors
+ code += " " + offset_prefix;
+ code += " " + offset_prefix_2;
+
+ std::string getter =
+ GenerateGetter(field->type()) + "self.view.pos + o)";
+ if (IsBool(base_type)) { getter = "(" + getter + " ~=0)"; }
+ code += " return " + getter + "\n";
+ code += " end\n";
+ code += " return " + DefaultValue(field) + "\n";
+ }
+ code += "end\n";
+ code += "\n";
+ } else {
+ switch (base_type) {
+ case r::BaseType::String: {
+ code += getter_signature;
+ code += " " + offset_prefix;
+ code += " " + offset_prefix_2;
+ code += " return " + GenerateGetter(field->type()) +
+ "self.view.pos + o)\n";
+ code += " end\n";
+ code += "end\n";
+ code += "\n";
+ break;
+ }
+ case r::BaseType::Obj: {
+ if (object->is_struct()) {
+ code += "function mt:" + field_name_camel_case + "(obj)\n";
+ code += " obj:Init(self.view.bytes, self.view.pos + " +
+ NumToString(field->offset()) + ")\n";
+ code += " return obj\n";
+ code += "end\n";
+ code += "\n";
+ } else {
+ code += getter_signature;
+ code += " " + offset_prefix;
+ code += " " + offset_prefix_2;
+
+ const r::Object *field_object = GetObject(field->type());
+ if (!field_object) {
+ // TODO(derekbailey): this is an error condition. we
+ // should report it better.
+ return;
+ }
+ code += " local x = " +
+ std::string(
+ field_object->is_struct()
+ ? "self.view.pos + o\n"
+ : "self.view:Indirect(self.view.pos + o)\n");
+ const std::string require_name = RegisterRequires(field);
+ code += " local obj = " + require_name + ".New()\n";
+ code += " obj:Init(self.view.bytes, x)\n";
+ code += " return obj\n";
+ code += " end\n";
+ code += "end\n";
+ code += "\n";
+ }
+ break;
+ }
+ case r::BaseType::Union: {
+ code += getter_signature;
+ code += " " + offset_prefix;
+ code += " " + offset_prefix_2;
+ code +=
+ " local obj = "
+ "flatbuffers.view.New(flatbuffers.binaryArray.New("
+ "0), 0)\n";
+ code += " " + GenerateGetter(field->type()) + "obj, o)\n";
+ code += " return obj\n";
+ code += " end\n";
+ code += "end\n";
+ code += "\n";
+ break;
+ }
+ case r::BaseType::Array:
+ case r::BaseType::Vector: {
+ const r::BaseType vector_base_type = field->type()->element();
+ int32_t element_size = field->type()->element_size();
+ code += "function mt:" + field_name_camel_case + "(j)\n";
+ code += " " + offset_prefix;
+ code += " " + offset_prefix_2;
+
+ if (IsStructOrTable(vector_base_type)) {
+ code += " local x = self.view:Vector(o)\n";
+ code +=
+ " x = x + ((j-1) * " + NumToString(element_size) + ")\n";
+ if (IsTable(field->type(), /*use_element=*/true)) {
+ code += " x = self.view:Indirect(x)\n";
+ } else {
+ // Vector of structs are inline, so we need to query the
+ // size of the struct.
+ const reflection::Object *obj =
+ GetObjectByIndex(field->type()->index());
+ element_size = obj->bytesize();
+ }
+
+ // Include the referenced type, thus we need to make sure
+ // we set `use_element` to true.
+ const std::string require_name =
+ RegisterRequires(field, /*use_element=*/true);
+ code += " local obj = " + require_name + ".New()\n";
+ code += " obj:Init(self.view.bytes, x)\n";
+ code += " return obj\n";
+ } else {
+ code += " local a = self.view:Vector(o)\n";
+ code += " return " + GenerateGetter(field->type()) +
+ "a + ((j-1) * " + NumToString(element_size) + "))\n";
+ }
+ code += " end\n";
+ // Only generate a default value for those types that are
+ // supported.
+ if (!IsStructOrTable(vector_base_type)) {
+ code +=
+ " return " +
+ std::string(vector_base_type == r::BaseType::String ? "''\n" : "0\n");
+ }
+ code += "end\n";
+ code += "\n";
+
+ // If the vector is composed of single byte values, we
+ // generate a helper function to get it as a byte string in
+ // Lua.
+ if (IsSingleByte(vector_base_type)) {
+ code += "function mt:" + field_name_camel_case +
+ "AsString(start, stop)\n";
+ code += " return self.view:VectorAsString(" +
+ NumToString(field->offset()) + ", start, stop)\n";
+ code += "end\n";
+ code += "\n";
+ }
+
+ // We also make a new accessor to query just the length of the
+ // vector.
+ code += "function mt:" + field_name_camel_case + "Length()\n";
+ code += " " + offset_prefix;
+ code += " " + offset_prefix_2;
+ code += " return self.view:VectorLen(o)\n";
+ code += " end\n";
+ code += " return 0\n";
+ code += "end\n";
+ code += "\n";
+ break;
+ }
+ default: {
+ return;
+ }
+ }
+ }
+ return;
+ });
+
+ // Create all the builders
+ if (object->is_struct()) {
+ code += "function " + object_name + ".Create" + object_name +
+ "(builder" + GenerateStructBuilderArgs(object) + ")\n";
+ code += AppendStructBuilderBody(object);
+ code += " return builder:Offset()\n";
+ code += "end\n";
+ code += "\n";
+ } else {
+ // Table builders
+ code += "function " + object_name + ".Start(builder)\n";
+ code += " builder:StartObject(" +
+ NumToString(object->fields()->size()) + ")\n";
+ code += "end\n";
+ code += "\n";
+
+ ForAllFields(object, /*reverse=*/false, [&](const r::Field *field) {
+ if (field->deprecated()) { return; }
+
+ const std::string field_name = NormalizeName(field->name());
+
+ code += "function " + object_name + ".Add" +
+ ConvertCase(field_name, Case::kUpperCamel) + "(builder, " +
+ ConvertCase(field_name, Case::kLowerCamel) + ")\n";
+ code += " builder:Prepend" + GenerateMethod(field) + "Slot(" +
+ NumToString(field->id()) + ", " +
+ ConvertCase(field_name, Case::kLowerCamel) + ", " +
+ DefaultValue(field) + ")\n";
+ code += "end\n";
+ code += "\n";
+
+ if (IsVector(field->type()->base_type())) {
+ code += "function " + object_name + ".Start" +
+ ConvertCase(field_name, Case::kUpperCamel) +
+ "Vector(builder, numElems)\n";
+
+ const int32_t element_size = field->type()->element_size();
+ int32_t alignment = 0;
+ if (IsStruct(field->type(), /*use_element=*/true)) {
+ alignment = GetObjectByIndex(field->type()->index())->minalign();
+ } else {
+ alignment = element_size;
+ }
+
+ code += " return builder:StartVector(" +
+ NumToString(element_size) + ", numElems, " +
+ NumToString(alignment) + ")\n";
+ code += "end\n";
+ code += "\n";
+ }
+ });
+
+ code += "function " + object_name + ".End(builder)\n";
+ code += " return builder:EndObject()\n";
+ code += "end\n";
+ code += "\n";
+ }
+
+ EmitCodeBlock(code, object_name, ns, object->declaration_file()->str());
+ });
+ return true;
+ }
+
+ private:
+ void GenerateDocumentation(
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
+ *documentation,
+ std::string indent, std::string &code) const {
+ flatbuffers::ForAllDocumentation(
+ documentation, [&](const flatbuffers::String *str) {
+ code += indent + "--" + str->str() + "\n";
+ });
+ }
+
+ std::string GenerateStructBuilderArgs(const r::Object *object,
+ std::string prefix = "") const {
+ std::string signature;
+ ForAllFields(object, /*reverse=*/false, [&](const r::Field *field) {
+ if (IsStructOrTable(field->type()->base_type())) {
+ const r::Object *field_object = GetObject(field->type());
+ signature += GenerateStructBuilderArgs(
+ field_object, prefix + NormalizeName(field->name()) + "_");
+ } else {
+ signature +=
+ ", " + prefix +
+ ConvertCase(NormalizeName(field->name()), Case::kLowerCamel);
+ }
+ });
+ return signature;
+ }
+
+ std::string AppendStructBuilderBody(const r::Object *object,
+ std::string prefix = "") const {
+ std::string code;
+ code += " builder:Prep(" + NumToString(object->minalign()) + ", " +
+ NumToString(object->bytesize()) + ")\n";
+
+ // We need to reverse the order we iterate over, since we build the
+ // buffer backwards.
+ ForAllFields(object, /*reverse=*/true, [&](const r::Field *field) {
+ const int32_t num_padding_bytes = field->padding();
+ if (num_padding_bytes) {
+ code += " builder:Pad(" + NumToString(num_padding_bytes) + ")\n";
+ }
+ if (IsStructOrTable(field->type()->base_type())) {
+ const r::Object *field_object = GetObject(field->type());
+ code += AppendStructBuilderBody(
+ field_object, prefix + NormalizeName(field->name()) + "_");
+ } else {
+ code += " builder:Prepend" + GenerateMethod(field) + "(" + prefix +
+ ConvertCase(NormalizeName(field->name()), Case::kLowerCamel) +
+ ")\n";
+ }
+ });
+
+ return code;
+ }
+
+ std::string GenerateMethod(const r::Field *field) const {
+ const r::BaseType base_type = field->type()->base_type();
+ if (IsScalar(base_type)) {
+ return ConvertCase(GenerateType(base_type), Case::kUpperCamel);
+ }
+ if (IsStructOrTable(base_type)) { return "Struct"; }
+ return "UOffsetTRelative";
+ }
+
+ std::string GenerateGetter(const r::Type *type,
+ bool element_type = false) const {
+ switch (element_type ? type->element() : type->base_type()) {
+ case r::BaseType::String: return "self.view:String(";
+ case r::BaseType::Union: return "self.view:Union(";
+ case r::BaseType::Vector: return GenerateGetter(type, true);
+ default:
+ return "self.view:Get(flatbuffers.N." +
+ ConvertCase(GenerateType(type, element_type),
+ Case::kUpperCamel) +
+ ", ";
+ }
+ }
+
+ std::string GenerateType(const r::Type *type,
+ bool element_type = false) const {
+ const r::BaseType base_type =
+ element_type ? type->element() : type->base_type();
+ if (IsScalar(base_type)) { return GenerateType(base_type); }
+ switch (base_type) {
+ case r::BaseType::String: return "string";
+ case r::BaseType::Vector: return GenerateGetter(type, true);
+ case r::BaseType::Obj: {
+ const r::Object *obj = GetObject(type);
+ return NormalizeName(Denamespace(obj->name()));
+ };
+ default: return "*flatbuffers.Table";
+ }
+ }
+
+ std::string GenerateType(const r::BaseType base_type) const {
+ // Need to override the default naming to match the Lua runtime libraries.
+ // TODO(derekbailey): make overloads in the runtime libraries to avoid this.
+ switch (base_type) {
+ case r::BaseType::None: return "uint8";
+ case r::BaseType::UType: return "uint8";
+ case r::BaseType::Byte: return "int8";
+ case r::BaseType::UByte: return "uint8";
+ case r::BaseType::Short: return "int16";
+ case r::BaseType::UShort: return "uint16";
+ case r::BaseType::Int: return "int32";
+ case r::BaseType::UInt: return "uint32";
+ case r::BaseType::Long: return "int64";
+ case r::BaseType::ULong: return "uint64";
+ case r::BaseType::Float: return "Float32";
+ case r::BaseType::Double: return "Float64";
+ default: return r::EnumNameBaseType(base_type);
+ }
+ }
+
+ std::string DefaultValue(const r::Field *field) const {
+ const r::BaseType base_type = field->type()->base_type();
+ if (IsFloatingPoint(base_type)) {
+ return NumToString(field->default_real());
+ }
+ if (IsBool(base_type)) {
+ return field->default_integer() ? "true" : "false";
+ }
+ if (IsScalar(base_type)) { return NumToString((field->default_integer())); }
+ // represents offsets
+ return "0";
+ }
+
+ std::string NormalizeName(const std::string name) const {
+ return keywords_.find(name) == keywords_.end() ? name : "_" + name;
+ }
+
+ std::string NormalizeName(const flatbuffers::String *name) const {
+ return NormalizeName(name->str());
+ }
+
+ void StartCodeBlock(const reflection::Enum *enum_def) {
+ current_enum_ = enum_def;
+ current_obj_ = nullptr;
+ requires_.clear();
+ }
+
+ void StartCodeBlock(const reflection::Object *object) {
+ current_obj_ = object;
+ current_enum_ = nullptr;
+ requires_.clear();
+ }
+
+ std::string RegisterRequires(const r::Field *field,
+ bool use_element = false) {
+ std::string type_name;
+
+ const r::BaseType type =
+ use_element ? field->type()->element() : field->type()->base_type();
+
+ if (IsStructOrTable(type)) {
+ const r::Object *object = GetObjectByIndex(field->type()->index());
+ if (object == current_obj_) { return Denamespace(object->name()); }
+ type_name = object->name()->str();
+ } else {
+ const r::Enum *enum_def = GetEnumByIndex(field->type()->index());
+ if (enum_def == current_enum_) { return Denamespace(enum_def->name()); }
+ type_name = enum_def->name()->str();
+ }
+
+ // Prefix with double __ to avoid name clashing, since these are defined
+ // at the top of the file and have lexical scoping. Replace '.' with '_'
+ // so it can be a legal identifier.
+ std::string name = "__" + type_name;
+ std::replace(name.begin(), name.end(), '.', '_');
+
+ return RegisterRequires(name, type_name);
+ }
+
+ std::string RegisterRequires(const std::string &local_name,
+ const std::string &requires_name) {
+ requires_[local_name] = requires_name;
+ return local_name;
+ }
+
+ void EmitCodeBlock(const std::string &code_block, const std::string &name,
+ const std::string &ns,
+ const std::string &declaring_file) const {
+ const std::string root_type = schema_->root_table()->name()->str();
+ const std::string root_file =
+ schema_->root_table()->declaration_file()->str();
+ const std::string full_qualified_name = ns.empty() ? name : ns + "." + name;
+
+ std::string code = "--[[ " + full_qualified_name + "\n\n";
+ code +=
+ " Automatically generated by the FlatBuffers compiler, do not "
+ "modify.\n";
+ code += " Or modify. I'm a message, not a cop.\n";
+ code += "\n";
+ code += " flatc version: " + flatc_version_ + "\n";
+ code += "\n";
+ code += " Declared by : " + declaring_file + "\n";
+ code += " Rooting type : " + root_type + " (" + root_file + ")\n";
+ code += "\n--]]\n\n";
+
+ if (!requires_.empty()) {
+ for (auto it = requires_.cbegin(); it != requires_.cend(); ++it) {
+ code += "local " + it->first + " = require('" + it->second + "')\n";
+ }
+ code += "\n";
+ }
+
+ code += code_block;
+ code += "return " + name;
+
+ // Namespaces are '.' deliminted, so replace it with the path separator.
+ std::string path = ns;
+
+ if (path.empty()) {
+ path = ".";
+ } else {
+ std::replace(path.begin(), path.end(), '.', '/');
+ }
+
+ // TODO(derekbailey): figure out a save file without depending on util.h
+ EnsureDirExists(path);
+ const std::string file_name = path + "/" + name + ".lua";
+ SaveFile(file_name.c_str(), code, false);
+ }
+
+ std::unordered_set<std::string> keywords_;
+ std::map<std::string, std::string> requires_;
+ const r::Object *current_obj_;
+ const r::Enum *current_enum_;
+ const std::string flatc_version_;
+};
+} // namespace
+
+std::unique_ptr<BfbsGenerator> NewLuaBfbsGenerator(
+ const std::string &flatc_version) {
+ return std::unique_ptr<LuaBfbsGenerator>(new LuaBfbsGenerator(flatc_version));
+}
+
+} // namespace flatbuffers
diff --git a/third_party/flatbuffers/src/bfbs_gen_lua.h b/third_party/flatbuffers/src/bfbs_gen_lua.h
new file mode 100644
index 0000000..6861282
--- /dev/null
+++ b/third_party/flatbuffers/src/bfbs_gen_lua.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_BFBS_GEN_LUA_H_
+#define FLATBUFFERS_BFBS_GEN_LUA_H_
+
+#include <memory>
+#include <string>
+
+#include "flatbuffers/bfbs_generator.h"
+
+namespace flatbuffers {
+
+// Constructs a new Lua Code generator.
+std::unique_ptr<BfbsGenerator> NewLuaBfbsGenerator(
+ const std::string &flatc_version);
+
+} // namespace flatbuffers
+
+#endif // FLATBUFFERS_BFBS_GEN_LUA_H_
\ No newline at end of file
diff --git a/third_party/flatbuffers/src/clang-format-all.sh b/third_party/flatbuffers/src/clang-format-all.sh
deleted file mode 100644
index 3fd9e33..0000000
--- a/third_party/flatbuffers/src/clang-format-all.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-# Running it twice corrects some bugs in clang-format.
-for run in {1..2}
-do
- clang-format -i -style=file include/flatbuffers/* src/*.cpp tests/*.cpp samples/*.cpp grpc/src/compiler/schema_interface.h grpc/tests/*.cpp
-done
-git checkout include/flatbuffers/reflection_generated.h
diff --git a/third_party/flatbuffers/src/clang-format-git.sh b/third_party/flatbuffers/src/clang-format-git.sh
deleted file mode 100644
index 0611cbb..0000000
--- a/third_party/flatbuffers/src/clang-format-git.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-# Running it twice corrects some bugs in clang-format.
-for run in {1..2}
-do
- git clang-format HEAD^ -- include/flatbuffers/* src/*.cpp tests/*.cpp samples/*.cpp grpc/src/compiler/schema_interface.h grpc/tests/*.cpp
-done
-git checkout include/flatbuffers/reflection_generated.h
diff --git a/third_party/flatbuffers/src/code_generators.cpp b/third_party/flatbuffers/src/code_generators.cpp
index 30f8cb3..e449a1d 100644
--- a/third_party/flatbuffers/src/code_generators.cpp
+++ b/third_party/flatbuffers/src/code_generators.cpp
@@ -60,7 +60,7 @@
// Update the text to everything after the }}.
text = text.substr(end + 2);
}
- if (!text.empty() && string_back(text) == '\\') {
+ if (!text.empty() && text.back() == '\\') {
text.pop_back();
ignore_ident_ = true;
stream_ << text;
@@ -84,20 +84,24 @@
std::string BaseGenerator::NamespaceDir(const Parser &parser,
const std::string &path,
- const Namespace &ns) {
+ const Namespace &ns,
+ const bool dasherize) {
EnsureDirExists(path);
if (parser.opts.one_file) return path;
std::string namespace_dir = path; // Either empty or ends in separator.
auto &namespaces = ns.components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
- namespace_dir += *it + kPathSeparator;
+ namespace_dir +=
+ !dasherize ? *it : ConvertCase(*it, Case::kDasher, Case::kUpperCamel);
+ namespace_dir += kPathSeparator;
EnsureDirExists(namespace_dir);
}
return namespace_dir;
}
-std::string BaseGenerator::NamespaceDir(const Namespace &ns) const {
- return BaseGenerator::NamespaceDir(parser_, path_, ns);
+std::string BaseGenerator::NamespaceDir(const Namespace &ns,
+ const bool dasherize) const {
+ return BaseGenerator::NamespaceDir(parser_, path_, ns, dasherize);
}
std::string BaseGenerator::FullNamespace(const char *separator,
@@ -301,14 +305,10 @@
return this->NaN(static_cast<double>(v));
}
-std::string JavaCSharpMakeRule(const Parser &parser, const std::string &path,
+std::string JavaCSharpMakeRule(const bool java, const Parser &parser,
+ const std::string &path,
const std::string &file_name) {
- FLATBUFFERS_ASSERT(parser.opts.lang == IDLOptions::kJava ||
- parser.opts.lang == IDLOptions::kCSharp);
-
- std::string file_extension =
- (parser.opts.lang == IDLOptions::kJava) ? ".java" : ".cs";
-
+ const std::string file_extension = java ? ".java" : ".cs";
std::string make_rule;
for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
@@ -337,6 +337,15 @@
return make_rule;
}
+std::string JavaMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ return JavaCSharpMakeRule(true, parser, path, file_name);
+}
+std::string CSharpMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ return JavaCSharpMakeRule(false, parser, path, file_name);
+}
+
std::string BinaryFileName(const Parser &parser, const std::string &path,
const std::string &file_name) {
auto ext = parser.file_extension_.length() ? parser.file_extension_ : "bin";
diff --git a/third_party/flatbuffers/src/flatc.cpp b/third_party/flatbuffers/src/flatc.cpp
index 1233ff9..3b2ef9f 100644
--- a/third_party/flatbuffers/src/flatc.cpp
+++ b/third_party/flatbuffers/src/flatc.cpp
@@ -17,6 +17,9 @@
#include "flatbuffers/flatc.h"
#include <list>
+#include <sstream>
+
+#include "flatbuffers/util.h"
namespace flatbuffers {
@@ -56,129 +59,274 @@
params_.error_fn(this, err, usage, show_exe_name);
}
+const static FlatCOption options[] = {
+ { "o", "", "PATH", "Prefix PATH to all generated files." },
+ { "I", "", "PATH", "Search for includes in the specified path." },
+ { "M", "", "", "Print make rules for generated files." },
+ { "", "version", "", "Print the version number of flatc and exit." },
+ { "h", "help", "", "Prints this help text and exit." },
+ { "", "strict-json", "",
+ "Strict JSON: field names must be / will be quoted, no trailing commas in "
+ "tables/vectors." },
+ { "", "allow-non-utf8", "",
+ "Pass non-UTF-8 input through parser and emit nonstandard \\x escapes in "
+ "JSON. (Default is to raise parse error on non-UTF-8 input.)" },
+ { "", "natural-utf8", "",
+ "Output strings with UTF-8 as human-readable strings. By default, UTF-8 "
+ "characters are printed as \\uXXXX escapes." },
+ { "", "defaults-json", "",
+ "Output fields whose value is the default when writing JSON" },
+ { "", "unknown-json", "",
+ "Allow fields in JSON that are not defined in the schema. These fields "
+ "will be discared when generating binaries." },
+ { "", "no-prefix", "",
+ "Don't prefix enum values with the enum type in C++." },
+ { "", "scoped-enums", "",
+ "Use C++11 style scoped and strongly typed enums. Also implies "
+ "--no-prefix." },
+ { "", "gen-inclues", "",
+ "(deprecated), this is the default behavior. If the original behavior is "
+ "required (no include statements) use --no-includes." },
+ { "", "no-includes", "",
+ "Don't generate include statements for included schemas the generated "
+ "file depends on (C++, Python, Proto-to-Fbs)." },
+ { "", "gen-mutable", "",
+ "Generate accessors that can mutate buffers in-place." },
+ { "", "gen-onefile", "",
+ "Generate a single output file for C#, Go, Java, Kotlin and Python. "
+ "Implies --no-include." },
+ { "", "gen-name-strings", "",
+ "Generate type name functions for C++ and Rust." },
+ { "", "gen-object-api", "", "Generate an additional object-based API." },
+ { "", "gen-compare", "", "Generate operator== for object-based API types." },
+ { "", "gen-nullable", "",
+ "Add Clang _Nullable for C++ pointer. or @Nullable for Java" },
+ { "", "java-checkerframe", "", "Add @Pure for Java." },
+ { "", "gen-generated", "", "Add @Generated annotation for Java." },
+ { "", "gen-jvmstatic", "",
+ "Add @JvmStatic annotation for Kotlin methods in companion object for "
+ "interop from Java to Kotlin." },
+ { "", "gen-all", "",
+ "Generate not just code for the current schema files, but for all files it "
+ "includes as well. If the language uses a single file for output (by "
+ "default the case for C++ and JS), all code will end up in this one "
+ "file." },
+ { "", "gen-json-emit", "",
+ "Generates encoding code which emits Flatbuffers into JSON" },
+ { "", "cpp-include", "", "Adds an #include in generated file." },
+ { "", "cpp-ptr-type", "T",
+ "Set object API pointer type (default std::unique_ptr)." },
+ { "", "cpp-str-type", "T",
+ "Set object API string type (default std::string). T::c_str(), T::length() "
+ "and T::empty() must be supported. The custom type also needs to be "
+ "constructible from std::string (see the --cpp-str-flex-ctor option to "
+ "change this behavior)" },
+ { "", "cpp-str-flex-ctor", "",
+ "Don't construct custom string types by passing std::string from "
+ "Flatbuffers, but (char* + length)." },
+ { "", "cpp-field-case-style", "STYLE",
+ "Generate C++ fields using selected case style. Supported STYLE values: * "
+ "'unchanged' - leave unchanged (default) * 'upper' - schema snake_case "
+ "emits UpperCamel; * 'lower' - schema snake_case emits lowerCamel." },
+ { "", "cpp-std", "CPP_STD",
+ "Generate a C++ code using features of selected C++ standard. Supported "
+ "CPP_STD values: * 'c++0x' - generate code compatible with old compilers; "
+ "'c++11' - use C++11 code generator (default); * 'c++17' - use C++17 "
+ "features in generated code (experimental)." },
+ { "", "cpp-static-reflection", "",
+ "When using C++17, generate extra code to provide compile-time (static) "
+ "reflection of Flatbuffers types. Requires --cpp-std to be \"c++17\" or "
+ "higher." },
+ { "", "object-prefix", "PREFIX",
+ "Customize class prefix for C++ object-based API." },
+ { "", "object-suffix", "SUFFIX",
+ "Customize class suffix for C++ object-based API. Default Value is "
+ "\"T\"." },
+ { "", "go-namespace", "", "Generate the overriding namespace in Golang." },
+ { "", "go-import", "IMPORT",
+ "Generate the overriding import for flatbuffers in Golang (default is "
+ "\"github.com/google/flatbuffers/go\")." },
+ { "", "raw-binary", "",
+ "Allow binaries without file_identifier to be read. This may crash flatc "
+ "given a mismatched schema." },
+ { "", "size-prefixed", "", "Input binaries are size prefixed buffers." },
+ { "", "proto", "", "Input is a .proto, translate to .fbs." },
+ { "", "proto-namespace-suffix", "SUFFIX",
+ "Add this namespace to any flatbuffers generated from protobufs." },
+ { "", "oneof-union", "", "Translate .proto oneofs to flatbuffer unions." },
+ { "", "grpc", "", "Generate GRPC interfaces for the specified languages." },
+ { "", "schema", "", "Serialize schemas instead of JSON (use with -b)." },
+ { "", "bfbs-filenames", "PATH",
+ "Sets the root path where reflection filenames in reflection.fbs are "
+ "relative to. The 'root' is denoted with `//`. E.g. if PATH=/a/b/c "
+ "then /a/d/e.fbs will be serialized as //../d/e.fbs. (PATH defaults to the "
+ "directory of the first provided schema file." },
+ { "", "bfbs-comments", "", "Add doc comments to the binary schema files." },
+ { "", "bfbs-builtins", "",
+ "Add builtin attributes to the binary schema files." },
+ { "", "bfbs-gen-embed", "",
+ "Generate code to embed the bfbs schema to the source." },
+ { "", "conform", "FILE",
+ "Specify a schema the following schemas should be an evolution of. Gives "
+ "errors if not." },
+ { "", "conform-includes", "PATH",
+ "Include path for the schema given with --conform PATH" },
+ { "", "filename-suffix", "SUFFIX",
+ "The suffix appended to the generated file names (Default is "
+ "'_generated')." },
+ { "", "filename-ext", "EXT",
+ "The extension appended to the generated file names. Default is "
+ "language-specific (e.g., '.h' for C++)" },
+ { "", "include-prefix", "PATH",
+ "Prefix this PATH to any generated include statements." },
+ { "", "keep-prefix", "",
+ "Keep original prefix of schema include statement." },
+ { "", "reflect-types", "",
+ "Add minimal type reflection to code generation." },
+ { "", "reflect-names", "", "Add minimal type/name reflection." },
+ { "", "rust-serialize", "",
+ "Implement serde::Serialize on generated Rust types." },
+ { "", "rust-module-root-file", "",
+ "Generate rust code in individual files with a module root file." },
+ { "", "root-type", "T", "Select or override the default root_type." },
+ { "", "require-explicit-ids", "",
+ "When parsing schemas, require explicit ids (id: x)." },
+ { "", "force-defaults", "",
+ "Emit default values in binary output from JSON" },
+ { "", "force-empty", "",
+ "When serializing from object API representation, force strings and "
+ "vectors to empty rather than null." },
+ { "", "force-empty-vectors", "",
+ "When serializing from object API representation, force vectors to empty "
+ "rather than null." },
+ { "", "flexbuffers", "",
+ "Used with \"binary\" and \"json\" options, it generates data using "
+ "schema-less FlexBuffers." },
+ { "", "no-warnings", "", "Inhibit all warnings messages." },
+ { "", "warning-as-errors", "", "Treat all warnings as errors." },
+ { "", "cs-global-alias", "",
+ "Prepend \"global::\" to all user generated csharp classes and "
+ "structs." },
+ { "", "cs-gen-json-serializer", "",
+ "Allows (de)serialization of JSON text in the Object API. (requires "
+ "--gen-object-api)." },
+ { "", "json-nested-bytes", "",
+ "Allow a nested_flatbuffer field to be parsed as a vector of bytes"
+ "in JSON, which is unsafe unless checked by a verifier afterwards." },
+ { "", "ts-flat-files", "",
+ "Only generated one typescript file per .fbs file." },
+};
+
+static void AppendTextWrappedString(std::stringstream &ss, std::string &text,
+ size_t max_col, size_t start_col) {
+ size_t max_line_length = max_col - start_col;
+
+ if (text.length() > max_line_length) {
+ size_t ideal_break_location = text.rfind(' ', max_line_length);
+ size_t length = std::min(max_line_length, ideal_break_location);
+ ss << text.substr(0, length) << "\n";
+ ss << std::string(start_col, ' ');
+ std::string rest_of_description = text.substr(
+ ((ideal_break_location < max_line_length || text.at(length) == ' ')
+ ? length + 1
+ : length));
+ AppendTextWrappedString(ss, rest_of_description, max_col, start_col);
+ } else {
+ ss << text;
+ }
+}
+
+static void AppendOption(std::stringstream &ss, const FlatCOption &option,
+ size_t max_col, size_t min_col_for_description) {
+ size_t chars = 2;
+ ss << " ";
+ if (!option.short_opt.empty()) {
+ chars += 2 + option.short_opt.length();
+ ss << "-" << option.short_opt;
+ if (!option.long_opt.empty()) {
+ chars++;
+ ss << ",";
+ }
+ ss << " ";
+ }
+ if (!option.long_opt.empty()) {
+ chars += 3 + option.long_opt.length();
+ ss << "--" << option.long_opt << " ";
+ }
+ if (!option.parameter.empty()) {
+ chars += 1 + option.parameter.length();
+ ss << option.parameter << " ";
+ }
+ size_t start_of_description = chars;
+ if (start_of_description > min_col_for_description) {
+ ss << "\n";
+ start_of_description = min_col_for_description;
+ ss << std::string(start_of_description, ' ');
+ } else {
+ while (start_of_description < min_col_for_description) {
+ ss << " ";
+ start_of_description++;
+ }
+ }
+ if (!option.description.empty()) {
+ std::string description = option.description;
+ AppendTextWrappedString(ss, description, max_col, start_of_description);
+ }
+ ss << "\n";
+}
+
+static void AppendShortOption(std::stringstream &ss,
+ const FlatCOption &option) {
+ if (!option.short_opt.empty()) {
+ ss << "-" << option.short_opt;
+ if (!option.long_opt.empty()) { ss << "|"; }
+ }
+ if (!option.long_opt.empty()) { ss << "--" << option.long_opt; }
+}
+
+std::string FlatCompiler::GetShortUsageString(const char *program_name) const {
+ std::stringstream ss;
+ ss << "Usage: " << program_name << " [";
+ for (size_t i = 0; i < params_.num_generators; ++i) {
+ const Generator &g = params_.generators[i];
+ AppendShortOption(ss, g.option);
+ ss << ", ";
+ }
+ for (const FlatCOption &option : options) {
+ AppendShortOption(ss, option);
+ ss << ", ";
+ }
+ ss.seekp(-2, ss.cur);
+ ss << "]... FILE... [-- FILE...]";
+ std::string help = ss.str();
+ std::stringstream ss_textwrap;
+ AppendTextWrappedString(ss_textwrap, help, 80, 0);
+ return ss_textwrap.str();
+}
+
std::string FlatCompiler::GetUsageString(const char *program_name) const {
std::stringstream ss;
ss << "Usage: " << program_name << " [OPTION]... FILE... [-- FILE...]\n";
for (size_t i = 0; i < params_.num_generators; ++i) {
const Generator &g = params_.generators[i];
-
- std::stringstream full_name;
- full_name << std::setw(16) << std::left << g.generator_opt_long;
- const char *name = g.generator_opt_short ? g.generator_opt_short : " ";
- const char *help = g.generator_help;
-
- ss << " " << full_name.str() << " " << name << " " << help << ".\n";
+ AppendOption(ss, g.option, 80, 25);
}
- // clang-format off
- // Output width
- // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
- ss <<
- " -o PATH Prefix PATH to all generated files.\n"
- " -I PATH Search for includes in the specified path.\n"
- " -M Print make rules for generated files.\n"
- " --version Print the version number of flatc and exit.\n"
- " --strict-json Strict JSON: field names must be / will be quoted,\n"
- " no trailing commas in tables/vectors.\n"
- " --allow-non-utf8 Pass non-UTF-8 input through parser and emit nonstandard\n"
- " \\x escapes in JSON. (Default is to raise parse error on\n"
- " non-UTF-8 input.)\n"
- " --natural-utf8 Output strings with UTF-8 as human-readable strings.\n"
- " By default, UTF-8 characters are printed as \\uXXXX escapes.\n"
- " --defaults-json Output fields whose value is the default when\n"
- " writing JSON\n"
- " --unknown-json Allow fields in JSON that are not defined in the\n"
- " schema. These fields will be discared when generating\n"
- " binaries.\n"
- " --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
- " --scoped-enums Use C++11 style scoped and strongly typed enums.\n"
- " also implies --no-prefix.\n"
- " --gen-includes (deprecated), this is the default behavior.\n"
- " If the original behavior is required (no include\n"
- " statements) use --no-includes.\n"
- " --no-includes Don\'t generate include statements for included\n"
- " schemas the generated file depends on (C++ / Python).\n"
- " --gen-mutable Generate accessors that can mutate buffers in-place.\n"
- " --gen-onefile Generate single output file for C# and Go.\n"
- " --gen-name-strings Generate type name functions for C++ and Rust.\n"
- " --gen-object-api Generate an additional object-based API.\n"
- " --gen-compare Generate operator== for object-based API types.\n"
- " --gen-nullable Add Clang _Nullable for C++ pointer. or @Nullable for Java\n"
- " --java-checkerframe work Add @Pure for Java.\n"
- " --gen-generated Add @Generated annotation for Java\n"
- " --gen-jvmstatic Add @JvmStatic annotation for Kotlin methods\n"
- " in companion object for interop from Java to Kotlin.\n"
- " --gen-all Generate not just code for the current schema files,\n"
- " but for all files it includes as well.\n"
- " If the language uses a single file for output (by default\n"
- " the case for C++ and JS), all code will end up in this one\n"
- " file.\n"
- " --cpp-include Adds an #include in generated file.\n"
- " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\n"
- " --cpp-str-type T Set object API string type (default std::string).\n"
- " T::c_str(), T::length() and T::empty() must be supported.\n"
- " The custom type also needs to be constructible from std::string\n"
- " (see the --cpp-str-flex-ctor option to change this behavior).\n"
- " --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n"
- " from Flatbuffers, but (char* + length).\n"
- " --cpp-std CPP_STD Generate a C++ code using features of selected C++ standard.\n"
- " Supported CPP_STD values:\n"
- " * 'c++0x' - generate code compatible with old compilers;\n"
- " * 'c++11' - use C++11 code generator (default);\n"
- " * 'c++17' - use C++17 features in generated code (experimental).\n"
- " --object-prefix Customise class prefix for C++ object-based API.\n"
- " --object-suffix Customise class suffix for C++ object-based API.\n"
- " Default value is \"T\".\n"
- " --no-js-exports Removes Node.js style export lines in JS.\n"
- " --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n"
- " --es6-js-export Uses ECMAScript 6 export style lines in JS.\n"
- " --go-namespace Generate the overrided namespace in Golang.\n"
- " --go-import Generate the overrided import for flatbuffers in Golang\n"
- " (default is \"github.com/google/flatbuffers/go\").\n"
- " --raw-binary Allow binaries without file_indentifier to be read.\n"
- " This may crash flatc given a mismatched schema.\n"
- " --size-prefixed Input binaries are size prefixed buffers.\n"
- " --proto Input is a .proto, translate to .fbs.\n"
- " --proto-namespace-suffix Add this namespace to any flatbuffers generated\n"
- " SUFFIX from protobufs.\n"
- " --oneof-union Translate .proto oneofs to flatbuffer unions.\n"
- " --grpc Generate GRPC interfaces for the specified languages.\n"
- " --schema Serialize schemas instead of JSON (use with -b).\n"
- " --bfbs-comments Add doc comments to the binary schema files.\n"
- " --bfbs-builtins Add builtin attributes to the binary schema files.\n"
- " --bfbs-gen-embed Generate code to embed the bfbs schema to the source.\n"
- " --conform FILE Specify a schema the following schemas should be\n"
- " an evolution of. Gives errors if not.\n"
- " --conform-includes Include path for the schema given with --conform PATH\n"
- " --filename-suffix The suffix appended to the generated file names.\n"
- " Default is '_generated'.\n"
- " --filename-ext The extension appended to the generated file names.\n"
- " Default is language-specific (e.g., '.h' for C++)\n"
- " --include-prefix Prefix this path to any generated include statements.\n"
- " PATH\n"
- " --keep-prefix Keep original prefix of schema include statement.\n"
- " --no-fb-import Don't include flatbuffers import statement for TypeScript.\n"
- " --no-ts-reexport Don't re-export imported dependencies for TypeScript.\n"
- " --short-names Use short function names for JS and TypeScript.\n"
- " --reflect-types Add minimal type reflection to code generation.\n"
- " --reflect-names Add minimal type/name reflection.\n"
- " --root-type T Select or override the default root_type\n"
- " --require-explicit-ids When parsing schemas, require explicit ids (id: x).\n"
- " --force-defaults Emit default values in binary output from JSON\n"
- " --force-empty When serializing from object API representation,\n"
- " force strings and vectors to empty rather than null.\n"
- " --force-empty-vectors When serializing from object API representation,\n"
- " force vectors to empty rather than null.\n"
- " --flexbuffers Used with \"binary\" and \"json\" options, it generates\n"
- " data using schema-less FlexBuffers.\n"
- "FILEs may be schemas (must end in .fbs), binary schemas (must end in .bfbs),\n"
- "or JSON files (conforming to preceding schema). FILEs after the -- must be\n"
- "binary flatbuffer format files.\n"
- "Output files are named using the base file name of the input,\n"
- "and written to the current directory or the path given by -o.\n"
- "example: " << program_name << " -c -b schema1.fbs schema2.fbs data.json\n";
- // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
- // clang-format on
+ ss << "\n";
+ for (const FlatCOption &option : options) {
+ AppendOption(ss, option, 80, 25);
+ }
+ ss << "\n";
+
+ std::string files_description =
+ "FILEs may be schemas (must end in .fbs), binary schemas (must end in "
+ ".bfbs) or JSON files (conforming to preceding schema). FILEs after the "
+ "-- must be binary flatbuffer format files. Output files are named using "
+ "the base file name of the input, and written to the current directory "
+ "or the path given by -o. example: " +
+ std::string(program_name) + " -c -b schema1.fbs schema2.fbs data.json";
+ AppendTextWrappedString(ss, files_description, 80, 0);
+ ss << "\n";
return ss.str();
}
@@ -187,6 +335,8 @@
return 0;
}
+ if (argc <= 1) { Error("Need to provide at least one argument."); }
+
flatbuffers::IDLOptions opts;
std::string output_path;
@@ -195,6 +345,7 @@
bool raw_binary = false;
bool schema_binary = false;
bool grpc_enabled = false;
+ bool requires_bfbs = false;
std::vector<std::string> filenames;
std::list<std::string> include_directories_storage;
std::vector<const char *> include_directories;
@@ -203,7 +354,9 @@
size_t binary_files_from = std::numeric_limits<size_t>::max();
std::string conform_to_schema;
- for (int argi = 0; argi < argc; argi++) {
+ const char *program_name = argv[0];
+
+ for (int argi = 1; argi < argc; argi++) {
std::string arg = argv[argi];
if (arg[0] == '-') {
if (filenames.size() && arg[1] != '-')
@@ -218,6 +371,11 @@
flatbuffers::PosixPath(argv[argi]));
include_directories.push_back(
include_directories_storage.back().c_str());
+ } else if (arg == "--bfbs-filenames") {
+ if (++argi > argc) Error("missing path following: " + arg, true);
+ opts.project_root = argv[argi];
+ if (!DirExists(opts.project_root.c_str()))
+ Error(arg + " is not a directory: " + opts.project_root);
} else if (arg == "--conform") {
if (++argi >= argc) Error("missing path following: " + arg, true);
conform_to_schema = flatbuffers::PosixPath(argv[argi]);
@@ -239,14 +397,6 @@
opts.allow_non_utf8 = true;
} else if (arg == "--natural-utf8") {
opts.natural_utf8 = true;
- } else if (arg == "--no-js-exports") {
- opts.skip_js_exports = true;
- } else if (arg == "--goog-js-export") {
- opts.use_goog_js_export_format = true;
- opts.use_ES6_js_export_format = false;
- } else if (arg == "--es6-js-export") {
- opts.use_goog_js_export_format = false;
- opts.use_ES6_js_export_format = true;
} else if (arg == "--go-namespace") {
if (++argi >= argc) Error("missing golang namespace" + arg, true);
opts.go_namespace = argv[argi];
@@ -285,12 +435,25 @@
opts.cpp_object_api_string_flexible_constructor = true;
} else if (arg == "--no-cpp-direct-copy") {
opts.cpp_direct_copy = false;
+ } else if (arg == "--cpp-field-case-style") {
+ if (++argi >= argc) Error("missing case style following: " + arg, true);
+ if (!strcmp(argv[argi], "unchanged"))
+ opts.cpp_object_api_field_case_style =
+ IDLOptions::CaseStyle_Unchanged;
+ else if (!strcmp(argv[argi], "upper"))
+ opts.cpp_object_api_field_case_style = IDLOptions::CaseStyle_Upper;
+ else if (!strcmp(argv[argi], "lower"))
+ opts.cpp_object_api_field_case_style = IDLOptions::CaseStyle_Lower;
+ else
+ Error("unknown case style: " + std::string(argv[argi]), true);
} else if (arg == "--gen-nullable") {
opts.gen_nullable = true;
} else if (arg == "--java-checkerframework") {
opts.java_checkerframework = true;
} else if (arg == "--gen-generated") {
opts.gen_generated = true;
+ } else if (arg == "--gen-json-emit") {
+ opts.gen_json_coders = true;
} else if (arg == "--object-prefix") {
if (++argi >= argc) Error("missing prefix following: " + arg, true);
opts.object_prefix = argv[argi];
@@ -300,7 +463,6 @@
} else if (arg == "--gen-all") {
opts.generate_all = true;
opts.include_dependence_headers = false;
- opts.reexport_ts_modules = false;
} else if (arg == "--gen-includes") {
// Deprecated, remove this option some time in the future.
Warn("warning: --gen-includes is deprecated (it is now default)\n");
@@ -308,6 +470,7 @@
opts.include_dependence_headers = false;
} else if (arg == "--gen-onefile") {
opts.one_file = true;
+ opts.include_dependence_headers = false;
} else if (arg == "--raw-binary") {
raw_binary = true;
} else if (arg == "--size-prefixed") {
@@ -328,6 +491,9 @@
} else if (arg == "--version") {
printf("flatc version %s\n", FLATC_VERSION());
exit(0);
+ } else if (arg == "--help" || arg == "-h") {
+ printf("%s\n", GetUsageString(program_name).c_str());
+ exit(0);
} else if (arg == "--grpc") {
grpc_enabled = true;
} else if (arg == "--bfbs-comments") {
@@ -336,16 +502,14 @@
opts.binary_schema_builtins = true;
} else if (arg == "--bfbs-gen-embed") {
opts.binary_schema_gen_embed = true;
- } else if (arg == "--no-fb-import") {
- opts.skip_flatbuffers_import = true;
- } else if (arg == "--no-ts-reexport") {
- opts.reexport_ts_modules = false;
- } else if (arg == "--short-names") {
- opts.js_ts_short_names = true;
} else if (arg == "--reflect-types") {
opts.mini_reflect = IDLOptions::kTypes;
} else if (arg == "--reflect-names") {
opts.mini_reflect = IDLOptions::kTypesAndNames;
+ } else if (arg == "--rust-serialize") {
+ opts.rust_serialize = true;
+ } else if (arg == "--rust-module-root-file") {
+ opts.rust_module_root_file = true;
} else if (arg == "--require-explicit-ids") {
opts.require_explicit_ids = true;
} else if (arg == "--root-type") {
@@ -372,22 +536,40 @@
opts.use_flexbuffers = true;
} else if (arg == "--gen-jvmstatic") {
opts.gen_jvmstatic = true;
+ } else if (arg == "--no-warnings") {
+ opts.no_warnings = true;
+ } else if (arg == "--warnings-as-errors") {
+ opts.warnings_as_errors = true;
} else if (arg == "--cpp-std") {
if (++argi >= argc)
Error("missing C++ standard specification" + arg, true);
opts.cpp_std = argv[argi];
+ } else if (arg.rfind("--cpp-std=", 0) == 0) {
+ opts.cpp_std = arg.substr(std::string("--cpp-std=").size());
+ } else if (arg == "--cpp-static-reflection") {
+ opts.cpp_static_reflection = true;
+ } else if (arg == "--cs-global-alias") {
+ opts.cs_global_alias = true;
+ } else if (arg == "--json-nested-bytes") {
+ opts.json_nested_legacy_flatbuffers = true;
+ } else if (arg == "--ts-flat-files") {
+ opts.ts_flat_file = true;
} else {
for (size_t i = 0; i < params_.num_generators; ++i) {
- if (arg == params_.generators[i].generator_opt_long ||
- (params_.generators[i].generator_opt_short &&
- arg == params_.generators[i].generator_opt_short)) {
+ if (arg == "--" + params_.generators[i].option.long_opt ||
+ arg == "-" + params_.generators[i].option.short_opt) {
generator_enabled[i] = true;
any_generator = true;
opts.lang_to_generate |= params_.generators[i].lang;
+ if (params_.generators[i].bfbs_generator) {
+ opts.binary_schema_comments = true;
+ requires_bfbs = true;
+ }
goto found;
}
}
Error("unknown commandline argument: " + arg, true);
+
found:;
}
} else {
@@ -404,6 +586,16 @@
Error("no options: specify at least one generator.", true);
}
+ if (opts.cs_gen_json_serializer && !opts.generate_object_based_api) {
+ Error(
+ "--cs-gen-json-serializer requires --gen-object-api to be set as "
+ "well.");
+ }
+
+ if (opts.ts_flat_file && opts.generate_all) {
+ Error("Combining --ts-flat-file and --gen-all is not supported.");
+ }
+
flatbuffers::Parser conform_parser;
if (!conform_to_schema.empty()) {
std::string contents;
@@ -431,8 +623,11 @@
bool is_binary =
static_cast<size_t>(file_it - filenames.begin()) >= binary_files_from;
auto ext = flatbuffers::GetExtension(filename);
- auto is_schema = ext == "fbs" || ext == "proto";
- auto is_binary_schema = ext == reflection::SchemaExtension();
+ const bool is_schema = ext == "fbs" || ext == "proto";
+ if (is_schema && opts.project_root.empty()) {
+ opts.project_root = StripFileName(filename);
+ }
+ const bool is_binary_schema = ext == reflection::SchemaExtension();
if (is_binary) {
parser->builder_.Clear();
parser->builder_.PushFlatBuffer(
@@ -464,20 +659,24 @@
contents.length() != strlen(contents.c_str())) {
Error("input file appears to be binary: " + filename, true);
}
- if (is_schema) {
+ if (is_schema || is_binary_schema) {
// If we're processing multiple schemas, make sure to start each
// one from scratch. If it depends on previous schemas it must do
// so explicitly using an include.
parser.reset(new flatbuffers::Parser(opts));
}
+ // Try to parse the file contents (binary schema/flexbuffer/textual
+ // schema)
if (is_binary_schema) {
LoadBinarySchema(*parser.get(), filename, contents);
- }
- if (opts.use_flexbuffers) {
+ } else if (opts.use_flexbuffers) {
if (opts.lang_to_generate == IDLOptions::kJson) {
- parser->flex_root_ = flexbuffers::GetRoot(
- reinterpret_cast<const uint8_t *>(contents.c_str()),
- contents.size());
+ auto data = reinterpret_cast<const uint8_t *>(contents.c_str());
+ auto size = contents.size();
+ std::vector<uint8_t> reuse_tracker;
+ if (!flexbuffers::VerifyBuffer(data, size, &reuse_tracker))
+ Error("flexbuffers file failed to verify: " + filename, false);
+ parser->flex_root_ = flexbuffers::GetRoot(data, size);
} else {
parser->flex_builder_.Clear();
ParseFile(*parser.get(), filename, contents, include_directories);
@@ -494,7 +693,7 @@
}
if ((is_schema || is_binary_schema) && !conform_to_schema.empty()) {
auto err = parser->ConformTo(conform_parser);
- if (!err.empty()) Error("schemas don\'t conform: " + err);
+ if (!err.empty()) Error("schemas don\'t conform: " + err, false);
}
if (schema_binary || opts.binary_schema_gen_embed) {
parser->Serialize();
@@ -503,21 +702,42 @@
parser->file_extension_ = reflection::SchemaExtension();
}
}
-
std::string filebase =
flatbuffers::StripPath(flatbuffers::StripExtension(filename));
+ // If one of the generators uses bfbs, serialize the parser and get
+ // the serialized buffer and length.
+ const uint8_t *bfbs_buffer = nullptr;
+ int64_t bfbs_length = 0;
+ if (requires_bfbs) {
+ parser->Serialize();
+ bfbs_buffer = parser->builder_.GetBufferPointer();
+ bfbs_length = parser->builder_.GetSize();
+ }
+
for (size_t i = 0; i < params_.num_generators; ++i) {
- parser->opts.lang = params_.generators[i].lang;
if (generator_enabled[i]) {
if (!print_make_rules) {
flatbuffers::EnsureDirExists(output_path);
- if ((!params_.generators[i].schema_only ||
- (is_schema || is_binary_schema)) &&
- !params_.generators[i].generate(*parser.get(), output_path,
- filebase)) {
- Error(std::string("Unable to generate ") +
- params_.generators[i].lang_name + " for " + filebase);
+
+ // Prefer bfbs generators if present.
+ if (params_.generators[i].bfbs_generator) {
+ const GeneratorStatus status =
+ params_.generators[i].bfbs_generator->Generate(bfbs_buffer,
+ bfbs_length);
+ if (status != OK) {
+ Error(std::string("Unable to generate ") +
+ params_.generators[i].lang_name + " for " + filebase +
+ " using bfbs generator.");
+ }
+ } else {
+ if ((!params_.generators[i].schema_only ||
+ (is_schema || is_binary_schema)) &&
+ !params_.generators[i].generate(*parser.get(), output_path,
+ filebase)) {
+ Error(std::string("Unable to generate ") +
+ params_.generators[i].lang_name + " for " + filebase);
+ }
}
} else {
if (params_.generators[i].make_rule == nullptr) {
@@ -559,6 +779,19 @@
// in any files coming up next.
parser->MarkGenerated();
}
+
+ // Once all the files have been parsed, run any generators Parsing Completed
+ // function for final generation.
+ for (size_t i = 0; i < params_.num_generators; ++i) {
+ if (generator_enabled[i] &&
+ params_.generators[i].parsing_completed != nullptr) {
+ if (!params_.generators[i].parsing_completed(*parser, output_path)) {
+ Error("failed running parsing completed for " +
+ std::string(params_.generators[i].lang_name));
+ }
+ }
+ }
+
return 0;
}
diff --git a/third_party/flatbuffers/src/flatc_main.cpp b/third_party/flatbuffers/src/flatc_main.cpp
index c942bda..abcab24 100644
--- a/third_party/flatbuffers/src/flatc_main.cpp
+++ b/third_party/flatbuffers/src/flatc_main.cpp
@@ -14,6 +14,11 @@
* limitations under the License.
*/
+#include <cstdio>
+#include <memory>
+
+#include "bfbs_gen_lua.h"
+#include "flatbuffers/base.h"
#include "flatbuffers/flatc.h"
#include "flatbuffers/util.h"
@@ -23,16 +28,16 @@
const std::string &warn, bool show_exe_name) {
(void)flatc;
if (show_exe_name) { printf("%s: ", g_program_name); }
- printf("warning: %s\n", warn.c_str());
+ fprintf(stderr, "\nwarning:\n %s\n\n", warn.c_str());
}
static void Error(const flatbuffers::FlatCompiler *flatc,
const std::string &err, bool usage, bool show_exe_name) {
if (show_exe_name) { printf("%s: ", g_program_name); }
- printf("error: %s\n", err.c_str());
if (usage && flatc) {
- printf("%s", flatc->GetUsageString(g_program_name).c_str());
+ fprintf(stderr, "%s\n", flatc->GetShortUsageString(g_program_name).c_str());
}
+ fprintf(stderr, "\nerror:\n %s\n\n", err.c_str());
exit(1);
}
@@ -50,66 +55,96 @@
// Prevent Appveyor-CI hangs.
flatbuffers::SetupDefaultCRTReportMode();
+ const std::string flatbuffers_version(flatbuffers::FLATBUFFERS_VERSION());
+
+ std::unique_ptr<flatbuffers::BfbsGenerator> bfbs_gen_lua =
+ flatbuffers::NewLuaBfbsGenerator(flatbuffers_version);
+
g_program_name = argv[0];
const flatbuffers::FlatCompiler::Generator generators[] = {
- { flatbuffers::GenerateBinary, "-b", "--binary", "binary", false, nullptr,
+ { flatbuffers::GenerateBinary, "binary", false, nullptr,
flatbuffers::IDLOptions::kBinary,
- "Generate wire format binaries for any data definitions",
- flatbuffers::BinaryMakeRule },
- { flatbuffers::GenerateTextFile, "-t", "--json", "text", false, nullptr,
+ flatbuffers::FlatCOption{
+ "b", "binary", "",
+ "Generate wire format binaries for any data definitions" },
+ flatbuffers::BinaryMakeRule, nullptr, nullptr },
+ { flatbuffers::GenerateTextFile, "text", false, nullptr,
flatbuffers::IDLOptions::kJson,
- "Generate text output for any data definitions",
- flatbuffers::TextMakeRule },
- { flatbuffers::GenerateCPP, "-c", "--cpp", "C++", true,
- flatbuffers::GenerateCppGRPC, flatbuffers::IDLOptions::kCpp,
- "Generate C++ headers for tables/structs", flatbuffers::CPPMakeRule },
- { flatbuffers::GenerateGo, "-g", "--go", "Go", true,
- flatbuffers::GenerateGoGRPC, flatbuffers::IDLOptions::kGo,
- "Generate Go files for tables/structs", nullptr },
- { flatbuffers::GenerateJava, "-j", "--java", "Java", true,
- flatbuffers::GenerateJavaGRPC, flatbuffers::IDLOptions::kJava,
- "Generate Java classes for tables/structs",
- flatbuffers::JavaCSharpMakeRule },
- { flatbuffers::GenerateJSTS, "-s", "--js", "JavaScript", true, nullptr,
- flatbuffers::IDLOptions::kJs,
- "Generate JavaScript code for tables/structs",
- flatbuffers::JSTSMakeRule },
- { flatbuffers::GenerateDart, "-d", "--dart", "Dart", true, nullptr,
+ flatbuffers::FlatCOption{
+ "t", "json", "", "Generate text output for any data definitions" },
+
+ flatbuffers::TextMakeRule, nullptr, nullptr },
+ { flatbuffers::GenerateCPP, "C++", true, flatbuffers::GenerateCppGRPC,
+ flatbuffers::IDLOptions::kCpp,
+ flatbuffers::FlatCOption{ "c", "cpp", "",
+ "Generate C++ headers for tables/structs" },
+ flatbuffers::CPPMakeRule, nullptr, nullptr },
+ { flatbuffers::GenerateGo, "Go", true, flatbuffers::GenerateGoGRPC,
+ flatbuffers::IDLOptions::kGo,
+ flatbuffers::FlatCOption{ "g", "go", "",
+ "Generate Go files for tables/structs" },
+ nullptr, nullptr, nullptr },
+ { flatbuffers::GenerateJava, "Java", true, flatbuffers::GenerateJavaGRPC,
+ flatbuffers::IDLOptions::kJava,
+ flatbuffers::FlatCOption{ "j", "java", "",
+ "Generate Java classes for tables/structs" },
+ flatbuffers::JavaMakeRule, nullptr, nullptr },
+ { flatbuffers::GenerateDart, "Dart", true, nullptr,
flatbuffers::IDLOptions::kDart,
- "Generate Dart classes for tables/structs", flatbuffers::DartMakeRule },
- { flatbuffers::GenerateJSTS, "-T", "--ts", "TypeScript", true,
- flatbuffers::GenerateTSGRPC, flatbuffers::IDLOptions::kTs,
- "Generate TypeScript code for tables/structs",
- flatbuffers::JSTSMakeRule },
- { flatbuffers::GenerateCSharp, "-n", "--csharp", "C#", true, nullptr,
+ flatbuffers::FlatCOption{ "d", "dart", "",
+ "Generate Dart classes for tables/structs" },
+ flatbuffers::DartMakeRule, nullptr, nullptr },
+ { flatbuffers::GenerateTS, "TypeScript", true, flatbuffers::GenerateTSGRPC,
+ flatbuffers::IDLOptions::kTs,
+ flatbuffers::FlatCOption{ "T", "ts", "",
+ "Generate TypeScript code for tables/structs" },
+ flatbuffers::TSMakeRule, nullptr, nullptr },
+ { flatbuffers::GenerateCSharp, "C#", true, nullptr,
flatbuffers::IDLOptions::kCSharp,
- "Generate C# classes for tables/structs",
- flatbuffers::JavaCSharpMakeRule },
- { flatbuffers::GeneratePython, "-p", "--python", "Python", true,
+ flatbuffers::FlatCOption{ "n", "csharp", "",
+ "Generate C# classes for tables/structs" },
+ flatbuffers::CSharpMakeRule, nullptr, nullptr },
+ { flatbuffers::GeneratePython, "Python", true,
flatbuffers::GeneratePythonGRPC, flatbuffers::IDLOptions::kPython,
- "Generate Python files for tables/structs", nullptr },
- { flatbuffers::GenerateLobster, nullptr, "--lobster", "Lobster", true,
- nullptr, flatbuffers::IDLOptions::kLobster,
- "Generate Lobster files for tables/structs", nullptr },
- { flatbuffers::GenerateLua, "-l", "--lua", "Lua", true, nullptr,
- flatbuffers::IDLOptions::kLua, "Generate Lua files for tables/structs",
- nullptr },
- { flatbuffers::GenerateRust, "-r", "--rust", "Rust", true, nullptr,
- flatbuffers::IDLOptions::kRust, "Generate Rust files for tables/structs",
- flatbuffers::RustMakeRule },
- { flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true, nullptr,
- flatbuffers::IDLOptions::kPhp, "Generate PHP files for tables/structs",
- nullptr },
- { flatbuffers::GenerateKotlin, nullptr, "--kotlin", "Kotlin", true, nullptr,
+ flatbuffers::FlatCOption{ "p", "python", "",
+ "Generate Python files for tables/structs" },
+ nullptr, nullptr, nullptr },
+ { flatbuffers::GenerateLobster, "Lobster", true, nullptr,
+ flatbuffers::IDLOptions::kLobster,
+ flatbuffers::FlatCOption{ "", "lobster", "",
+ "Generate Lobster files for tables/structs" },
+ nullptr, nullptr, nullptr },
+ { flatbuffers::GenerateLua, "Lua", true, nullptr,
+ flatbuffers::IDLOptions::kLua,
+ flatbuffers::FlatCOption{ "l", "lua", "",
+ "Generate Lua files for tables/structs" },
+ nullptr, bfbs_gen_lua.get(), nullptr },
+ { flatbuffers::GenerateRust, "Rust", true, nullptr,
+ flatbuffers::IDLOptions::kRust,
+ flatbuffers::FlatCOption{ "r", "rust", "",
+ "Generate Rust files for tables/structs" },
+ flatbuffers::RustMakeRule, nullptr,
+ flatbuffers::GenerateRustModuleRootFile },
+ { flatbuffers::GeneratePhp, "PHP", true, nullptr,
+ flatbuffers::IDLOptions::kPhp,
+ flatbuffers::FlatCOption{ "", "php", "",
+ "Generate PHP files for tables/structs" },
+ nullptr, nullptr, nullptr },
+ { flatbuffers::GenerateKotlin, "Kotlin", true, nullptr,
flatbuffers::IDLOptions::kKotlin,
- "Generate Kotlin classes for tables/structs", nullptr },
- { flatbuffers::GenerateJsonSchema, nullptr, "--jsonschema", "JsonSchema",
- true, nullptr, flatbuffers::IDLOptions::kJsonSchema,
- "Generate Json schema", nullptr },
- { flatbuffers::GenerateSwift, nullptr, "--swift", "swift", true,
- flatbuffers::GenerateSwiftGRPC, flatbuffers::IDLOptions::kSwift,
- "Generate Swift files for tables/structs", nullptr },
+ flatbuffers::FlatCOption{ "", "kotlin", "",
+ "Generate Kotlin classes for tables/structs" },
+ nullptr, nullptr, nullptr },
+ { flatbuffers::GenerateJsonSchema, "JsonSchema", true, nullptr,
+ flatbuffers::IDLOptions::kJsonSchema,
+ flatbuffers::FlatCOption{ "", "jsonschema", "", "Generate Json schema" },
+ nullptr, nullptr, nullptr },
+ { flatbuffers::GenerateSwift, "swift", true, flatbuffers::GenerateSwiftGRPC,
+ flatbuffers::IDLOptions::kSwift,
+ flatbuffers::FlatCOption{ "", "swift", "",
+ "Generate Swift files for tables/structs" },
+ nullptr, nullptr, nullptr },
};
flatbuffers::FlatCompiler::InitParams params;
@@ -119,5 +154,5 @@
params.error_fn = Error;
flatbuffers::FlatCompiler flatc(params);
- return flatc.Compile(argc - 1, argv + 1);
+ return flatc.Compile(argc, argv);
}
diff --git a/third_party/flatbuffers/src/idl_gen_cpp.cpp b/third_party/flatbuffers/src/idl_gen_cpp.cpp
index e5ec0f8..ef7f60a 100644
--- a/third_party/flatbuffers/src/idl_gen_cpp.cpp
+++ b/third_party/flatbuffers/src/idl_gen_cpp.cpp
@@ -1,4 +1,4 @@
- /*
+/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -243,6 +243,30 @@
return keywords_.find(name) == keywords_.end() ? name : name + "_";
}
+ std::string Name(const FieldDef &field) const {
+ // the union type field suffix is immutable.
+ static size_t union_suffix_len = strlen(UnionTypeFieldSuffix());
+ const bool is_union_type = field.value.type.base_type == BASE_TYPE_UTYPE;
+ // early return if no case transformation required
+ if (opts_.cpp_object_api_field_case_style ==
+ IDLOptions::CaseStyle_Unchanged)
+ return EscapeKeyword(field.name);
+ std::string name = field.name;
+ // do not change the case style of the union type field suffix
+ if (is_union_type) {
+ FLATBUFFERS_ASSERT(name.length() > union_suffix_len);
+ name.erase(name.length() - union_suffix_len, union_suffix_len);
+ }
+ if (opts_.cpp_object_api_field_case_style == IDLOptions::CaseStyle_Upper)
+ name = ConvertCase(name, Case::kUpperCamel);
+ else if (opts_.cpp_object_api_field_case_style ==
+ IDLOptions::CaseStyle_Lower)
+ name = ConvertCase(name, Case::kLowerCamel);
+ // restore the union field type suffix
+ if (is_union_type) name.append(UnionTypeFieldSuffix(), union_suffix_len);
+ return EscapeKeyword(name);
+ }
+
std::string Name(const Definition &def) const {
return EscapeKeyword(def.name);
}
@@ -269,6 +293,9 @@
code_ += "#pragma clang system_header\n\n";
}
+ code_ += "#include \"flatbuffers/flatbuffers.h\"";
+ code_ += "";
+
SetNameSpace(struct_def.defined_namespace);
auto name = Name(struct_def);
code_.SetValue("STRUCT_NAME", name);
@@ -492,6 +519,17 @@
code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
code_ += "}";
code_ += "";
+
+ code_ += "inline \\";
+ code_ +=
+ "{{CPP_NAME}} "
+ "*{{NULLABLE_EXT}}GetMutableSizePrefixed{{STRUCT_NAME}}(void "
+ "*buf) {";
+ code_ +=
+ " return "
+ "flatbuffers::GetMutableSizePrefixedRoot<{{CPP_NAME}}>(buf);";
+ code_ += "}";
+ code_ += "";
}
if (parser_.file_identifier_.length()) {
@@ -508,6 +546,16 @@
code_ += " buf, {{STRUCT_NAME}}Identifier());";
code_ += "}";
code_ += "";
+
+ // Check if a size-prefixed buffer has the identifier.
+ code_ += "inline \\";
+ code_ +=
+ "bool SizePrefixed{{STRUCT_NAME}}BufferHasIdentifier(const void "
+ "*buf) {";
+ code_ += " return flatbuffers::BufferHasIdentifier(";
+ code_ += " buf, {{STRUCT_NAME}}Identifier(), true);";
+ code_ += "}";
+ code_ += "";
}
// The root verifier.
@@ -561,8 +609,7 @@
if (opts_.generate_object_based_api) {
// A convenient root unpack function.
- auto native_name =
- NativeName(WrapInNameSpace(struct_def), &struct_def, opts_);
+ auto native_name = WrapNativeNameInNameSpace(struct_def, opts_);
code_.SetValue("UNPACK_RETURN",
GenTypeNativePtr(native_name, nullptr, false));
code_.SetValue("UNPACK_TYPE",
@@ -635,8 +682,9 @@
}
bool VectorElementUserFacing(const Type &type) const {
- return opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums &&
- IsEnum(type);
+ return (opts_.scoped_enums && IsEnum(type)) ||
+ (opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums &&
+ IsEnum(type));
}
void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
@@ -720,6 +768,12 @@
: name;
}
+ std::string WrapNativeNameInNameSpace(const StructDef &struct_def,
+ const IDLOptions &opts) {
+ return WrapInNameSpace(struct_def.defined_namespace,
+ NativeName(Name(struct_def), &struct_def, opts));
+ }
+
const std::string &PtrType(const FieldDef *field) {
auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
return attr ? attr->constant : opts_.cpp_object_api_pointer_type;
@@ -770,7 +824,7 @@
}
std::string GenTypeNative(const Type &type, bool invector,
- const FieldDef &field) {
+ const FieldDef &field, bool forcopy = false) {
switch (type.base_type) {
case BASE_TYPE_STRING: {
return NativeString(&field);
@@ -791,14 +845,14 @@
if (IsStruct(type)) {
auto native_type = type.struct_def->attributes.Lookup("native_type");
if (native_type) { type_name = native_type->constant; }
- if (invector || field.native_inline) {
+ if (invector || field.native_inline || forcopy) {
return type_name;
} else {
return GenTypeNativePtr(type_name, &field, false);
}
} else {
- return GenTypeNativePtr(NativeName(type_name, type.struct_def, opts_),
- &field, false);
+ const auto nn = WrapNativeNameInNameSpace(*type.struct_def, opts_);
+ return forcopy ? nn : GenTypeNativePtr(nn, &field, false);
}
}
case BASE_TYPE_UNION: {
@@ -889,16 +943,16 @@
return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
}
- std::string GetUnionElement(const EnumVal &ev, bool wrap, bool actual_type,
- bool native_type = false) {
+ std::string GetUnionElement(const EnumVal &ev, bool native_type,
+ const IDLOptions &opts) {
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
- auto name = actual_type ? ev.union_type.struct_def->name : Name(ev);
- return wrap ? WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
- name)
- : name;
+ auto name = ev.union_type.struct_def->name;
+ if (native_type) {
+ name = NativeName(name, ev.union_type.struct_def, opts);
+ }
+ return WrapInNameSpace(ev.union_type.struct_def->defined_namespace, name);
} else if (IsString(ev.union_type)) {
- return actual_type ? (native_type ? "std::string" : "flatbuffers::String")
- : Name(ev);
+ return native_type ? "std::string" : "flatbuffers::String";
} else {
FLATBUFFERS_ASSERT(false);
return Name(ev);
@@ -912,10 +966,12 @@
}
std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
- return "bool Verify" + Name(enum_def) + "Vector" +
+ auto name = Name(enum_def);
+ auto type = opts_.scoped_enums ? name : "uint8_t";
+ return "bool Verify" + name + "Vector" +
"(flatbuffers::Verifier &verifier, " +
"const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
- "const flatbuffers::Vector<uint8_t> *types)";
+ "const flatbuffers::Vector<" + type + "> *types)";
}
std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
@@ -1014,10 +1070,9 @@
? bt - BASE_TYPE_UTYPE + ET_UTYPE
: ET_SEQUENCE;
int ref_idx = -1;
- std::string ref_name =
- type.struct_def
- ? WrapInNameSpace(*type.struct_def)
- : type.enum_def ? WrapInNameSpace(*type.enum_def) : "";
+ std::string ref_name = type.struct_def ? WrapInNameSpace(*type.struct_def)
+ : type.enum_def ? WrapInNameSpace(*type.enum_def)
+ : "";
if (!ref_name.empty()) {
auto rit = type_refs.begin();
for (; rit != type_refs.end(); ++rit) {
@@ -1269,7 +1324,7 @@
if (it == enum_def.Vals().begin()) {
code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
} else {
- auto name = GetUnionElement(ev, true, true);
+ auto name = GetUnionElement(ev, false, opts_);
code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
}
@@ -1281,11 +1336,30 @@
}
if (opts_.generate_object_based_api && enum_def.is_union) {
- // Generate a union type
+ // Generate a union type and a trait type for it.
code_.SetValue("NAME", Name(enum_def));
FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
+ if (!enum_def.uses_multiple_type_instances) {
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+
+ if (it == enum_def.Vals().begin()) {
+ code_ += "template<typename T> struct {{NAME}}UnionTraits {";
+ } else {
+ auto name = GetUnionElement(ev, true, opts_);
+ code_ += "template<> struct {{NAME}}UnionTraits<" + name + "> {";
+ }
+
+ auto value = GetEnumValUse(enum_def, ev);
+ code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
+ code_ += "};";
+ code_ += "";
+ }
+ }
+
code_ += "struct {{NAME}}Union {";
code_ += " {{NAME}} type;";
code_ += " void *value;";
@@ -1309,18 +1383,15 @@
code_ += " void Reset();";
code_ += "";
if (!enum_def.uses_multiple_type_instances) {
- code_ += "#ifndef FLATBUFFERS_CPP98_STL";
code_ += " template <typename T>";
code_ += " void Set(T&& val) {";
- code_ += " using RT = typename std::remove_reference<T>::type;";
+ code_ += " typedef typename std::remove_reference<T>::type RT;";
code_ += " Reset();";
- code_ +=
- " type = {{NAME}}Traits<typename RT::TableType>::enum_value;";
+ code_ += " type = {{NAME}}UnionTraits<RT>::enum_value;";
code_ += " if (type != {{NONE}}) {";
code_ += " value = new RT(std::forward<T>(val));";
code_ += " }";
code_ += " }";
- code_ += "#endif // FLATBUFFERS_CPP98_STL";
code_ += "";
}
code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
@@ -1332,9 +1403,7 @@
const auto &ev = **it;
if (ev.IsZero()) { continue; }
- const auto native_type =
- NativeName(GetUnionElement(ev, true, true, true),
- ev.union_type.struct_def, opts_);
+ const auto native_type = GetUnionElement(ev, true, opts_);
code_.SetValue("NATIVE_TYPE", native_type);
code_.SetValue("NATIVE_NAME", Name(ev));
code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
@@ -1366,9 +1435,7 @@
const auto &ev = **it;
code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
if (ev.IsNonZero()) {
- const auto native_type =
- NativeName(GetUnionElement(ev, true, true, true),
- ev.union_type.struct_def, opts_);
+ const auto native_type = GetUnionElement(ev, true, opts_);
code_.SetValue("NATIVE_TYPE", native_type);
code_ += " case {{NATIVE_ID}}: {";
code_ +=
@@ -1422,15 +1489,17 @@
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
if (ev.IsNonZero()) {
- code_.SetValue("TYPE", GetUnionElement(ev, true, true));
+ code_.SetValue("TYPE", GetUnionElement(ev, false, opts_));
code_ += " case {{LABEL}}: {";
auto getptr =
" auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
if (ev.union_type.struct_def->fixed) {
+ code_.SetValue("ALIGN",
+ NumToString(ev.union_type.struct_def->minalign));
code_ +=
- " return verifier.Verify<{{TYPE}}>(static_cast<const "
- "uint8_t *>(obj), 0);";
+ " return verifier.VerifyField<{{TYPE}}>("
+ "static_cast<const uint8_t *>(obj), 0, {{ALIGN}});";
} else {
code_ += getptr;
code_ += " return verifier.VerifyTable(ptr);";
@@ -1470,6 +1539,7 @@
if (opts_.generate_object_based_api) {
// Generate union Unpack() and Pack() functions.
code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
+ code_ += " (void)resolver;";
code_ += " switch (type) {";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
++it) {
@@ -1477,7 +1547,7 @@
if (ev.IsZero()) { continue; }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
- code_.SetValue("TYPE", GetUnionElement(ev, true, true));
+ code_.SetValue("TYPE", GetUnionElement(ev, false, opts_));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
@@ -1500,6 +1570,7 @@
code_ += "";
code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
+ code_ += " (void)_rehasher;";
code_ += " switch (type) {";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
++it) {
@@ -1507,15 +1578,14 @@
if (ev.IsZero()) { continue; }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
- code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
- ev.union_type.struct_def, opts_));
- code_.SetValue("NAME", GetUnionElement(ev, false, true));
+ code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
if (ev.union_type.struct_def->fixed) {
code_ += " return _fbb.CreateStruct(*ptr).Union();";
} else {
+ code_.SetValue("NAME", ev.union_type.struct_def->name);
code_ +=
" return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
}
@@ -1541,11 +1611,12 @@
const auto &ev = **it;
if (ev.IsZero()) { continue; }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
- code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
- ev.union_type.struct_def, opts_));
+ code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
code_ += " case {{LABEL}}: {";
bool copyable = true;
- if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ if (opts_.g_cpp_std < cpp::CPP_STD_11 &&
+ ev.union_type.base_type == BASE_TYPE_STRUCT &&
+ !ev.union_type.struct_def->fixed) {
// Don't generate code to copy if table is not copyable.
// TODO(wvo): make tables copyable instead.
for (auto fit = ev.union_type.struct_def->fields.vec.begin();
@@ -1586,8 +1657,7 @@
const auto &ev = **it;
if (ev.IsZero()) { continue; }
code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
- code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
- ev.union_type.struct_def, opts_));
+ code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
code_ += " case {{LABEL}}: {";
code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
code_ += " delete ptr;";
@@ -1632,7 +1702,7 @@
if (!opts_.generate_name_strings) { return; }
auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
code_.SetValue("NAME", fullname);
- code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
+ code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR_CPP11");
code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
code_ += " return \"{{NAME}}\";";
code_ += " }";
@@ -1670,6 +1740,8 @@
} else {
return "0";
}
+ } else if (IsStruct(type) && (field.value.constant == "0")) {
+ return "nullptr";
} else {
return GenDefaultConstant(field);
}
@@ -1746,13 +1818,50 @@
}
}
+ // Returns true if `struct_def` needs a copy constructor and assignment
+ // operator because it has one or more table members, struct members with a
+ // custom cpp_type and non-naked pointer type, or vector members of those.
+ bool NeedsCopyCtorAssignOp(const StructDef &struct_def) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ const auto &type = field.value.type;
+ if (field.deprecated) continue;
+ if (type.base_type == BASE_TYPE_STRUCT) {
+ const auto cpp_type = field.attributes.Lookup("cpp_type");
+ const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
+ const bool is_ptr = !(IsStruct(type) && field.native_inline) ||
+ (cpp_type && cpp_ptr_type->constant != "naked");
+ if (is_ptr) { return true; }
+ } else if (IsVector(type)) {
+ const auto vec_type = type.VectorType();
+ if (vec_type.base_type == BASE_TYPE_UTYPE) continue;
+ const auto cpp_type = field.attributes.Lookup("cpp_type");
+ const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
+ const bool is_ptr =
+ (vec_type.base_type == BASE_TYPE_STRUCT && !IsStruct(vec_type)) ||
+ (cpp_type && cpp_ptr_type->constant != "naked");
+ if (is_ptr) { return true; }
+ }
+ }
+ return false;
+ }
+
// Generate the default constructor for this struct. Properly initialize all
// scalar members with default values.
void GenDefaultConstructor(const StructDef &struct_def) {
code_.SetValue("NATIVE_NAME",
NativeName(Name(struct_def), &struct_def, opts_));
- // In >= C++11, default member initializers are generated.
- if (opts_.g_cpp_std >= cpp::CPP_STD_11) { return; }
+ // In >= C++11, default member initializers are generated. To allow for
+ // aggregate initialization, do not emit a default constructor at all, with
+ // the exception of types that need a copy/move ctors and assignment
+ // operators.
+ if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
+ if (NeedsCopyCtorAssignOp(struct_def)) {
+ code_ += " {{NATIVE_NAME}}() = default;";
+ }
+ return;
+ }
std::string initializer_list;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
@@ -1796,6 +1905,126 @@
code_ += " }";
}
+ // Generate the >= C++11 copy/move constructor and assignment operator
+ // declarations if required. Tables that are default-copyable do not get
+ // user-provided copy/move constructors and assignment operators so they
+ // remain aggregates.
+ void GenCopyMoveCtorAndAssigOpDecls(const StructDef &struct_def) {
+ if (opts_.g_cpp_std < cpp::CPP_STD_11) return;
+ if (!NeedsCopyCtorAssignOp(struct_def)) return;
+ code_.SetValue("NATIVE_NAME",
+ NativeName(Name(struct_def), &struct_def, opts_));
+ code_ += " {{NATIVE_NAME}}(const {{NATIVE_NAME}} &o);";
+ code_ +=
+ " {{NATIVE_NAME}}({{NATIVE_NAME}}&&) FLATBUFFERS_NOEXCEPT = "
+ "default;";
+ code_ +=
+ " {{NATIVE_NAME}} &operator=({{NATIVE_NAME}} o) FLATBUFFERS_NOEXCEPT;";
+ }
+
+ // Generate the >= C++11 copy constructor and assignment operator definitions.
+ void GenCopyCtorAssignOpDefs(const StructDef &struct_def) {
+ if (opts_.g_cpp_std < cpp::CPP_STD_11) return;
+ if (!NeedsCopyCtorAssignOp(struct_def)) return;
+ std::string initializer_list;
+ std::string vector_copies;
+ std::string swaps;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ const auto &type = field.value.type;
+ if (field.deprecated || type.base_type == BASE_TYPE_UTYPE) continue;
+ if (type.base_type == BASE_TYPE_STRUCT) {
+ if (!initializer_list.empty()) { initializer_list += ",\n "; }
+ const auto cpp_type = field.attributes.Lookup("cpp_type");
+ const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
+ auto type_name = (cpp_type) ? cpp_type->constant
+ : GenTypeNative(type, /*invector*/ false,
+ field, /*forcopy*/ true);
+ const bool is_ptr = !(IsStruct(type) && field.native_inline) ||
+ (cpp_type && cpp_ptr_type->constant != "naked");
+ CodeWriter cw;
+ cw.SetValue("FIELD", Name(field));
+ cw.SetValue("TYPE", type_name);
+ if (is_ptr) {
+ cw +=
+ "{{FIELD}}((o.{{FIELD}}) ? new {{TYPE}}(*o.{{FIELD}}) : "
+ "nullptr)\\";
+ initializer_list += cw.ToString();
+ } else {
+ cw += "{{FIELD}}(o.{{FIELD}})\\";
+ initializer_list += cw.ToString();
+ }
+ } else if (IsVector(type)) {
+ const auto vec_type = type.VectorType();
+ if (vec_type.base_type == BASE_TYPE_UTYPE) continue;
+ const auto cpp_type = field.attributes.Lookup("cpp_type");
+ const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
+ const auto type_name = (cpp_type)
+ ? cpp_type->constant
+ : GenTypeNative(vec_type, /*invector*/ true,
+ field, /*forcopy*/ true);
+ const bool is_ptr =
+ (vec_type.base_type == BASE_TYPE_STRUCT && !IsStruct(vec_type)) ||
+ (cpp_type && cpp_ptr_type->constant != "naked");
+ CodeWriter cw(" ");
+ cw.SetValue("FIELD", Name(field));
+ cw.SetValue("TYPE", type_name);
+ if (is_ptr) {
+ // Use emplace_back to construct the potentially-smart pointer element
+ // from a raw pointer to a new-allocated copy.
+ cw.IncrementIdentLevel();
+ cw += "{{FIELD}}.reserve(o.{{FIELD}}.size());";
+ cw +=
+ "for (const auto &{{FIELD}}_ : o.{{FIELD}}) { "
+ "{{FIELD}}.emplace_back(({{FIELD}}_) ? new {{TYPE}}(*{{FIELD}}_) "
+ ": nullptr); }";
+ vector_copies += cw.ToString();
+ } else {
+ // For non-pointer elements, use std::vector's copy constructor in the
+ // initializer list. This will yield better performance than an insert
+ // range loop for trivially-copyable element types.
+ if (!initializer_list.empty()) { initializer_list += ",\n "; }
+ cw += "{{FIELD}}(o.{{FIELD}})\\";
+ initializer_list += cw.ToString();
+ }
+ } else {
+ if (!initializer_list.empty()) { initializer_list += ",\n "; }
+ CodeWriter cw;
+ cw.SetValue("FIELD", Name(field));
+ cw += "{{FIELD}}(o.{{FIELD}})\\";
+ initializer_list += cw.ToString();
+ }
+ {
+ if (!swaps.empty()) { swaps += "\n "; }
+ CodeWriter cw;
+ cw.SetValue("FIELD", Name(field));
+ cw += "std::swap({{FIELD}}, o.{{FIELD}});\\";
+ swaps += cw.ToString();
+ }
+ }
+ if (!initializer_list.empty()) {
+ initializer_list = "\n : " + initializer_list;
+ }
+ if (!swaps.empty()) { swaps = " " + swaps; }
+
+ code_.SetValue("NATIVE_NAME",
+ NativeName(Name(struct_def), &struct_def, opts_));
+ code_.SetValue("INIT_LIST", initializer_list);
+ code_.SetValue("VEC_COPY", vector_copies);
+ code_.SetValue("SWAPS", swaps);
+
+ code_ +=
+ "inline {{NATIVE_NAME}}::{{NATIVE_NAME}}(const {{NATIVE_NAME}} &o)"
+ "{{INIT_LIST}} {";
+ code_ += "{{VEC_COPY}}}\n";
+ code_ +=
+ "inline {{NATIVE_NAME}} &{{NATIVE_NAME}}::operator="
+ "({{NATIVE_NAME}} o) FLATBUFFERS_NOEXCEPT {";
+ code_ += "{{SWAPS}}";
+ code_ += " return *this;\n}\n";
+ }
+
void GenCompareOperator(const StructDef &struct_def,
std::string accessSuffix = "") {
std::string compare_op;
@@ -1808,7 +2037,18 @@
field.value.type.element != BASE_TYPE_UTYPE)) {
if (!compare_op.empty()) { compare_op += " &&\n "; }
auto accessor = Name(field) + accessSuffix;
- compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
+ if (struct_def.fixed || field.native_inline ||
+ field.value.type.base_type != BASE_TYPE_STRUCT) {
+ compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
+ } else {
+ // Deep compare of std::unique_ptr. Null is not equal to empty.
+ std::string both_null =
+ "(lhs." + accessor + " == rhs." + accessor + ")";
+ std::string not_null_and_equal = "(lhs." + accessor + " && rhs." +
+ accessor + " && *lhs." + accessor +
+ " == *rhs." + accessor + ")";
+ compare_op += "(" + both_null + " || " + not_null_and_equal + ")";
+ }
}
}
@@ -1873,21 +2113,33 @@
}
GenOperatorNewDelete(struct_def);
GenDefaultConstructor(struct_def);
+ GenCopyMoveCtorAndAssigOpDecls(struct_def);
code_ += "};";
- if (opts_.gen_compare) GenCompareOperator(struct_def);
code_ += "";
}
+ void GenNativeTablePost(const StructDef &struct_def) {
+ if (opts_.gen_compare) {
+ const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+ code_.SetValue("NATIVE_NAME", native_name);
+ GenCompareOperator(struct_def);
+ code_ += "";
+ }
+ }
+
// Generate the code to call the appropriate Verify function(s) for a field.
void GenVerifyCall(const FieldDef &field, const char *prefix) {
code_.SetValue("PRE", prefix);
code_.SetValue("NAME", Name(field));
- code_.SetValue("REQUIRED", field.required ? "Required" : "");
+ code_.SetValue("REQUIRED", field.IsRequired() ? "Required" : "");
code_.SetValue("SIZE", GenTypeSize(field.value.type));
code_.SetValue("OFFSET", GenFieldOffsetName(field));
if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
+ code_.SetValue("ALIGN", NumToString(InlineAlignment(field.value.type)));
code_ +=
- "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
+ "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, "
+ "{{OFFSET}}, {{ALIGN}})\\";
} else {
code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
}
@@ -1934,6 +2186,19 @@
}
default: break;
}
+
+ auto nfn = GetNestedFlatBufferName(field);
+ if (!nfn.empty()) {
+ code_.SetValue("CPP_NAME", nfn);
+ // FIXME: file_identifier.
+ code_ +=
+ "{{PRE}}verifier.VerifyNestedFlatBuffer<{{CPP_NAME}}>"
+ "({{NAME}}(), nullptr)\\";
+ } else if (field.flexbuffer) {
+ code_ +=
+ "{{PRE}}flexbuffers::VerifyNestedFlexBuffer"
+ "({{NAME}}(), verifier)\\";
+ }
break;
}
default: {
@@ -1957,8 +2222,8 @@
code_ += " }";
if (is_string) {
- code_ += " int KeyCompareWithValue(const char *val) const {";
- code_ += " return strcmp({{FIELD_NAME}}()->c_str(), val);";
+ code_ += " int KeyCompareWithValue(const char *_{{FIELD_NAME}}) const {";
+ code_ += " return strcmp({{FIELD_NAME}}()->c_str(), _{{FIELD_NAME}});";
code_ += " }";
} else {
FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
@@ -1969,10 +2234,11 @@
}
// Returns {field<val: -1, field==val: 0, field>val: +1}.
code_.SetValue("KEY_TYPE", type);
- code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {";
code_ +=
- " return static_cast<int>({{FIELD_NAME}}() > val) - "
- "static_cast<int>({{FIELD_NAME}}() < val);";
+ " int KeyCompareWithValue({{KEY_TYPE}} _{{FIELD_NAME}}) const {";
+ code_ +=
+ " return static_cast<int>({{FIELD_NAME}}() > _{{FIELD_NAME}}) - "
+ "static_cast<int>({{FIELD_NAME}}() < _{{FIELD_NAME}});";
code_ += " }";
}
}
@@ -1989,7 +2255,7 @@
for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
auto &ev = **u_it;
if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
- auto full_struct_name = GetUnionElement(ev, true, true);
+ auto full_struct_name = GetUnionElement(ev, false, opts_);
// @TODO: Mby make this decisions more universal? How?
code_.SetValue("U_GET_TYPE",
@@ -2053,6 +2319,131 @@
if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
}
+ void GenTableFieldType(const FieldDef &field) {
+ const auto &type = field.value.type;
+ const auto offset_str = GenFieldOffsetName(field);
+ if (!field.IsScalarOptional()) {
+ std::string afterptr = " *" + NullableExtension();
+ code_.SetValue("FIELD_TYPE",
+ GenTypeGet(type, "", "const ", afterptr.c_str(), true));
+ code_ += " {{FIELD_TYPE}}\\";
+ } else {
+ code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
+ code_ += " {{FIELD_TYPE}}\\";
+ }
+ }
+
+ void GenStructFieldType(const FieldDef &field) {
+ const auto is_array = IsArray(field.value.type);
+ std::string field_type =
+ GenTypeGet(field.value.type, "", is_array ? "" : "const ",
+ is_array ? "" : " &", true);
+ code_.SetValue("FIELD_TYPE", field_type);
+ code_ += " {{FIELD_TYPE}}\\";
+ }
+
+ void GenFieldTypeHelper(const StructDef &struct_def) {
+ if (struct_def.fields.vec.empty()) { return; }
+ code_ += " template<size_t Index>";
+ code_ += " using FieldType = \\";
+ code_ += "decltype(std::declval<type>().get_field<Index>());";
+ }
+
+ void GenIndexBasedFieldGetter(const StructDef &struct_def) {
+ if (struct_def.fields.vec.empty()) { return; }
+ code_ += " template<size_t Index>";
+ code_ += " auto get_field() const {";
+
+ size_t index = 0;
+ bool need_else = false;
+ // Generate one index-based getter for each field.
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) {
+ // Deprecated fields won't be accessible.
+ continue;
+ }
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("FIELD_INDEX",
+ std::to_string(static_cast<long long>(index++)));
+ if (need_else) {
+ code_ += " else \\";
+ } else {
+ code_ += " \\";
+ }
+ need_else = true;
+ code_ += "if constexpr (Index == {{FIELD_INDEX}}) \\";
+ code_ += "return {{FIELD_NAME}}();";
+ }
+ code_ += " else static_assert(Index != Index, \"Invalid Field Index\");";
+ code_ += " }";
+ }
+
+ // Sample for Vec3:
+ //
+ // static constexpr std::array<const char *, 3> field_names = {
+ // "x",
+ // "y",
+ // "z"
+ // };
+ //
+ void GenFieldNames(const StructDef &struct_def) {
+ code_ += " static constexpr std::array<\\";
+ code_ += "const char *, fields_number> field_names = {\\";
+ if (struct_def.fields.vec.empty()) {
+ code_ += "};";
+ return;
+ }
+ code_ += "";
+ // Generate the field_names elements.
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) {
+ // Deprecated fields won't be accessible.
+ continue;
+ }
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_ += " \"{{FIELD_NAME}}\"\\";
+ if (it + 1 != struct_def.fields.vec.end()) { code_ += ","; }
+ }
+ code_ += "\n };";
+ }
+
+ void GenFieldsNumber(const StructDef &struct_def) {
+ const auto non_deprecated_field_count = std::count_if(
+ struct_def.fields.vec.begin(), struct_def.fields.vec.end(),
+ [](const FieldDef *field) { return !field->deprecated; });
+ code_.SetValue(
+ "FIELD_COUNT",
+ std::to_string(static_cast<long long>(non_deprecated_field_count)));
+ code_ += " static constexpr size_t fields_number = {{FIELD_COUNT}};";
+ }
+
+ void GenTraitsStruct(const StructDef &struct_def) {
+ code_.SetValue(
+ "FULLY_QUALIFIED_NAME",
+ struct_def.defined_namespace->GetFullyQualifiedName(Name(struct_def)));
+ code_ += "struct {{STRUCT_NAME}}::Traits {";
+ code_ += " using type = {{STRUCT_NAME}};";
+ if (!struct_def.fixed) {
+ // We have a table and not a struct.
+ code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
+ }
+ if (opts_.cpp_static_reflection) {
+ code_ += " static constexpr auto name = \"{{STRUCT_NAME}}\";";
+ code_ +=
+ " static constexpr auto fully_qualified_name = "
+ "\"{{FULLY_QUALIFIED_NAME}}\";";
+ GenFieldsNumber(struct_def);
+ GenFieldNames(struct_def);
+ GenFieldTypeHelper(struct_def);
+ }
+ code_ += "};";
+ code_ += "";
+ }
+
void GenTableFieldSetter(const FieldDef &field) {
const auto &type = field.value.type;
const bool is_scalar = IsScalar(type.base_type);
@@ -2068,15 +2459,25 @@
code_.SetValue("FIELD_VALUE",
GenUnderlyingCast(field, false, "_" + Name(field)));
- code_ +=
- " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
- "_{{FIELD_NAME}}) {";
+ code_ += " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} _{{FIELD_NAME}}\\";
if (false == field.IsScalarOptional()) {
code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
+ code_.SetValue(
+ "INTERFACE_DEFAULT_VALUE",
+ GenUnderlyingCast(field, true, GenDefaultConstant(field)));
+
+ // GenUnderlyingCast for a bool field generates 0 != 0
+ // So the type has to be checked and the appropriate default chosen
+ if (IsBool(field.value.type.base_type)) {
+ code_ += " = {{DEFAULT_VALUE}}) {";
+ } else {
+ code_ += " = {{INTERFACE_DEFAULT_VALUE}}) {";
+ }
code_ +=
" return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
"{{DEFAULT_VALUE}});";
} else {
+ code_ += ") {";
code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
}
code_ += " }";
@@ -2102,6 +2503,21 @@
}
+ std::string GetNestedFlatBufferName(const FieldDef &field) {
+ auto nested = field.attributes.Lookup("nested_flatbuffer");
+ if (!nested) return "";
+ std::string qualified_name = nested->constant;
+ auto nested_root = parser_.LookupStruct(nested->constant);
+ if (nested_root == nullptr) {
+ qualified_name =
+ parser_.current_namespace_->GetFullyQualifiedName(nested->constant);
+ nested_root = parser_.LookupStruct(qualified_name);
+ }
+ FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
+ (void)nested_root;
+ return TranslateNameSpace(qualified_name);
+ }
+
// Generate an accessor struct, builder structs & function for a table.
void GenTable(const StructDef &struct_def) {
if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
@@ -2165,19 +2581,9 @@
GenTableFieldGetter(field);
if (opts_.mutable_buffer) { GenTableFieldSetter(field); }
- auto nested = field.attributes.Lookup("nested_flatbuffer");
- if (nested) {
- std::string qualified_name = nested->constant;
- auto nested_root = parser_.LookupStruct(nested->constant);
- if (nested_root == nullptr) {
- qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
- nested->constant);
- nested_root = parser_.LookupStruct(qualified_name);
- }
- FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
- (void)nested_root;
- code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
-
+ auto nfn = GetNestedFlatBufferName(field);
+ if (!nfn.empty()) {
+ code_.SetValue("CPP_NAME", nfn);
code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
code_ +=
" return "
@@ -2201,6 +2607,8 @@
if (field.key) { GenKeyFieldMethods(field); }
}
+ if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
+
// Generate a verifier function that can check a buffer from an untrusted
// source will never cause reads outside the buffer.
code_ += " bool Verify(flatbuffers::Verifier &verifier) const {";
@@ -2242,7 +2650,7 @@
auto &ev = **u_it;
if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
- auto full_struct_name = GetUnionElement(ev, true, true);
+ auto full_struct_name = GetUnionElement(ev, false, opts_);
code_.SetValue(
"U_ELEMENT_TYPE",
@@ -2359,7 +2767,7 @@
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
- if (!field.deprecated && field.required) {
+ if (!field.deprecated && field.IsRequired()) {
code_.SetValue("FIELD_NAME", Name(field));
code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
@@ -2408,13 +2816,7 @@
// Definition for type traits for this table type. This allows querying var-
// ious compile-time traits of the table.
- if (opts_.g_cpp_std >= cpp::CPP_STD_17) {
- code_ += "struct {{STRUCT_NAME}}::Traits {";
- code_ += " using type = {{STRUCT_NAME}};";
- code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
- code_ += "};";
- code_ += "";
- }
+ if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
// Generate a CreateXDirect function with vector types as parameters
if (opts_.cpp_direct_copy && has_string_or_vector_fields) {
@@ -2481,8 +2883,7 @@
if (!field.deprecated) {
code_.SetValue("FIELD_NAME", Name(field));
code_ += ",\n {{FIELD_NAME}}\\";
- if (IsString(field.value.type) ||
- IsVector(field.value.type)) {
+ if (IsString(field.value.type) || IsVector(field.value.type)) {
code_ += "__\\";
}
}
@@ -2514,20 +2915,26 @@
}
}
case BASE_TYPE_STRUCT: {
- const auto name = WrapInNameSpace(*type.struct_def);
if (IsStruct(type)) {
- auto native_type = type.struct_def->attributes.Lookup("native_type");
+ const auto &struct_attrs = type.struct_def->attributes;
+ const auto native_type = struct_attrs.Lookup("native_type");
if (native_type) {
- return "flatbuffers::UnPack(*" + val + ")";
+ std::string unpack_call = "flatbuffers::UnPack";
+ const auto pack_name = struct_attrs.Lookup("native_type_pack_name");
+ if (pack_name) { unpack_call += pack_name->constant; }
+ unpack_call += "(*" + val + ")";
+ return unpack_call;
} else if (invector || afield.native_inline) {
return "*" + val;
} else {
+ const auto name = WrapInNameSpace(*type.struct_def);
const auto ptype = GenTypeNativePtr(name, &afield, true);
return ptype + "(new " + name + "(*" + val + "))";
}
} else {
const auto ptype = GenTypeNativePtr(
- NativeName(name, type.struct_def, opts_), &afield, true);
+ WrapNativeNameInNameSpace(*type.struct_def, opts_), &afield,
+ true);
return ptype + "(" + val + "->UnPack(_resolver))";
}
}
@@ -2570,9 +2977,7 @@
WrapInNameSpace(*field.value.type.enum_def) + ">(";
}
indexing += "_e->Get(_i)";
- if (field.value.type.enum_def) {
- indexing += ")";
- }
+ if (field.value.type.enum_def) { indexing += ")"; }
if (field.value.type.element == BASE_TYPE_BOOL) {
indexing += " != 0";
}
@@ -2612,9 +3017,19 @@
code += "/* else do nothing */";
}
} else {
+ const bool is_pointer =
+ field.value.type.VectorType().base_type == BASE_TYPE_STRUCT &&
+ !IsStruct(field.value.type.VectorType());
+ if (is_pointer) {
+ code += "if(_o->" + name + "[_i]" + ") { ";
+ code += indexing + "->UnPackTo(_o->" + name +
+ "[_i].get(), _resolver);";
+ code += " } else { ";
+ }
code += "_o->" + name + "[_i]" + access + " = ";
code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
field);
+ if (is_pointer) { code += "; }"; }
}
code += "; } }";
}
@@ -2661,8 +3076,17 @@
} else {
// Generate code for assigning the value, of the form:
// _o->field = value;
+ const bool is_pointer =
+ field.value.type.base_type == BASE_TYPE_STRUCT &&
+ !IsStruct(field.value.type);
+ if (is_pointer) {
+ code += "{ if(_o->" + Name(field) + ") { ";
+ code += "_e->UnPackTo(_o->" + Name(field) + ".get(), _resolver);";
+ code += " } else { ";
+ }
code += "_o->" + Name(field) + " = ";
code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
+ if (is_pointer) { code += " } }"; }
}
break;
}
@@ -2706,7 +3130,7 @@
// in _o->field before attempting to access it. If there isn't,
// depending on set_empty_strings_to_null either set it to 0 or an empty
// string.
- if (!field.required) {
+ if (!field.IsRequired()) {
auto empty_value = opts_.set_empty_strings_to_null
? "0"
: "_fbb.CreateSharedString(\"\")";
@@ -2744,15 +3168,24 @@
}
case BASE_TYPE_STRUCT: {
if (IsStruct(vector_type)) {
- auto native_type =
- field.value.type.struct_def->attributes.Lookup("native_type");
+ const auto &struct_attrs =
+ field.value.type.struct_def->attributes;
+ const auto native_type = struct_attrs.Lookup("native_type");
if (native_type) {
code += "_fbb.CreateVectorOfNativeStructs<";
- code += WrapInNameSpace(*vector_type.struct_def) + ">";
+ code += WrapInNameSpace(*vector_type.struct_def) + ", " +
+ native_type->constant + ">";
+ code += "(" + value;
+ const auto pack_name =
+ struct_attrs.Lookup("native_type_pack_name");
+ if (pack_name) {
+ code += ", flatbuffers::Pack" + pack_name->constant;
+ }
+ code += ")";
} else {
code += "_fbb.CreateVectorOfStructs";
+ code += "(" + value + ")";
}
- code += "(" + value + ")";
} else {
code += "_fbb.CreateVector<flatbuffers::Offset<";
code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
@@ -2781,10 +3214,15 @@
}
case BASE_TYPE_UTYPE: {
value = StripUnionType(value);
- code += "_fbb.CreateVector<uint8_t>(" + value +
- ".size(), [](size_t i, _VectorArgs *__va) { "
- "return static_cast<uint8_t>(__va->_" +
- value + "[i].type); }, &_va)";
+ auto type = opts_.scoped_enums ? Name(*field.value.type.enum_def)
+ : "uint8_t";
+ auto enum_value = "__va->_" + value + "[i].type";
+ if (!opts_.scoped_enums)
+ enum_value = "static_cast<uint8_t>(" + enum_value + ")";
+
+ code += "_fbb.CreateVector<" + type + ">(" + value +
+ ".size(), [](size_t i, _VectorArgs *__va) { return " +
+ enum_value + "; }, &_va)";
break;
}
default: {
@@ -2815,7 +3253,7 @@
// If set_empty_vectors_to_null option is enabled, for optional fields,
// check to see if there actually is any data in _o->field before
// attempting to access it.
- if (opts_.set_empty_vectors_to_null && !field.required) {
+ if (opts_.set_empty_vectors_to_null && !field.IsRequired()) {
code = value + ".size() ? " + code + " : 0";
}
break;
@@ -2827,10 +3265,14 @@
}
case BASE_TYPE_STRUCT: {
if (IsStruct(field.value.type)) {
- auto native_type =
- field.value.type.struct_def->attributes.Lookup("native_type");
+ const auto &struct_attribs = field.value.type.struct_def->attributes;
+ const auto native_type = struct_attribs.Lookup("native_type");
if (native_type) {
- code += "flatbuffers::Pack(" + value + ")";
+ code += "flatbuffers::Pack";
+ const auto pack_name =
+ struct_attribs.Lookup("native_type_pack_name");
+ if (pack_name) { code += pack_name->constant; }
+ code += "(" + value + ")";
} else if (field.native_inline) {
code += "&" + value;
} else {
@@ -2855,18 +3297,22 @@
// Generate code for tables that needs to come after the regular definition.
void GenTablePost(const StructDef &struct_def) {
+ if (opts_.generate_object_based_api) { GenNativeTablePost(struct_def); }
+
code_.SetValue("STRUCT_NAME", Name(struct_def));
code_.SetValue("NATIVE_NAME",
NativeName(Name(struct_def), &struct_def, opts_));
if (opts_.generate_object_based_api) {
+ // Generate the >= C++11 copy ctor and assignment operator definitions.
+ GenCopyCtorAssignOpDefs(struct_def);
+
// Generate the X::UnPack() method.
code_ +=
"inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
- auto native_name =
- NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
+ auto native_name = WrapNativeNameInNameSpace(struct_def, parser_.opts);
code_.SetValue("POINTER_TYPE",
GenTypeNativePtr(native_name, nullptr, false));
code_ +=
@@ -3191,6 +3637,8 @@
code_ += "";
code_ += " public:";
+ if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
+
// Make TypeTable accessible via the generated struct.
if (opts_.mini_reflect != IDLOptions::kNone) {
code_ +=
@@ -3276,12 +3724,19 @@
}
code_.SetValue("NATIVE_NAME", Name(struct_def));
GenOperatorNewDelete(struct_def);
+
+ if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
+
code_ += "};";
code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
code_ += "";
+
+ // Definition for type traits for this table type. This allows querying var-
+ // ious compile-time traits of the table.
+ if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
}
// Set up the correct namespace. Only open a namespace if the existing one is
@@ -3331,7 +3786,7 @@
cpp::IDLOptionsCpp opts(parser.opts);
// The '--cpp_std' argument could be extended (like ASAN):
// Example: "flatc --cpp_std c++17:option1:option2".
- auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++0X";
+ auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++11";
std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper);
if (cpp_std == "C++0X") {
opts.g_cpp_std = cpp::CPP_STD_X0;
@@ -3354,6 +3809,13 @@
// The opts.scoped_enums has priority.
opts.g_only_fixed_enums |= opts.scoped_enums;
+ if (opts.cpp_static_reflection && opts.g_cpp_std < cpp::CPP_STD_17) {
+ LogCompilerError(
+ "--cpp-static-reflection requires using --cpp-std at \"C++17\" or "
+ "higher.");
+ return false;
+ }
+
cpp::CppGenerator generator(parser, path, file_name, opts);
return generator.generate();
}
diff --git a/third_party/flatbuffers/src/idl_gen_csharp.cpp b/third_party/flatbuffers/src/idl_gen_csharp.cpp
index d2f14f0..cb605de 100644
--- a/third_party/flatbuffers/src/idl_gen_csharp.cpp
+++ b/third_party/flatbuffers/src/idl_gen_csharp.cpp
@@ -16,15 +16,13 @@
// independent from idl_parser, since this code is not needed for most clients
+#include <unordered_set>
+
#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
-#if defined(FLATBUFFERS_CPP98_STL)
-# include <cctype>
-#endif // defined(FLATBUFFERS_CPP98_STL)
-
namespace flatbuffers {
static TypedFloatConstantGenerator CSharpFloatGen("Double.", "Single.", "NaN",
@@ -46,8 +44,100 @@
public:
CSharpGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", ".", "cs"),
- cur_name_space_(nullptr) {}
+ : BaseGenerator(parser, path, file_name,
+ parser.opts.cs_global_alias ? "global::" : "", ".", "cs"),
+ cur_name_space_(nullptr) {
+ // clang-format off
+
+ // List of keywords retrieved from here:
+ // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/
+
+ // One per line to ease comparisons to that list are easier
+
+ static const char *const keywords[] = {
+ "abstract",
+ "as",
+ "base",
+ "bool",
+ "break",
+ "byte",
+ "case",
+ "catch",
+ "char",
+ "checked",
+ "class",
+ "const",
+ "continue",
+ "decimal",
+ "default",
+ "delegate",
+ "do",
+ "double",
+ "else",
+ "enum",
+ "event",
+ "explicit",
+ "extern",
+ "false",
+ "finally",
+ "fixed",
+ "float",
+ "for",
+ "foreach",
+ "goto",
+ "if",
+ "implicit",
+ "in",
+ "int",
+ "interface",
+ "internal",
+ "is",
+ "lock",
+ "long",
+ "namespace",
+ "new",
+ "null",
+ "object",
+ "operator",
+ "out",
+ "override",
+ "params",
+ "private",
+ "protected",
+ "public",
+ "readonly",
+ "ref",
+ "return",
+ "sbyte",
+ "sealed",
+ "short",
+ "sizeof",
+ "stackalloc",
+ "static",
+ "string",
+ "struct",
+ "switch",
+ "this",
+ "throw",
+ "true",
+ "try",
+ "typeof",
+ "uint",
+ "ulong",
+ "unchecked",
+ "unsafe",
+ "ushort",
+ "using",
+ "virtual",
+ "void",
+ "volatile",
+ "while",
+ nullptr,
+ // clang-format on
+ };
+
+ for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+ }
CSharpGenerator &operator=(const CSharpGenerator &);
@@ -65,7 +155,7 @@
one_file_code += enumcode;
} else {
if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
- false))
+ false, parser_.opts))
return false;
}
}
@@ -81,22 +171,45 @@
one_file_code += declcode;
} else {
if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
- true))
+ true, parser_.opts))
return false;
}
}
if (parser_.opts.one_file) {
return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
- true);
+ true, parser_.opts);
}
return true;
}
+ private:
+ std::unordered_set<std::string> keywords_;
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : "@" + name;
+ }
+
+ std::string Name(const FieldDef &field) const {
+ std::string name = ConvertCase(field.name, Case::kUpperCamel);
+ return EscapeKeyword(name);
+ }
+
+ std::string Name(const Definition &def) const {
+ return EscapeKeyword(def.name);
+ }
+
+ std::string NamespacedName(const Definition &def) const {
+ return WrapInNameSpace(def.defined_namespace, Name(def));
+ }
+
+ std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
+
// Save out the generated code for a single class while adding
// declaration boilerplate.
bool SaveType(const std::string &defname, const Namespace &ns,
- const std::string &classcode, bool needs_includes) const {
+ const std::string &classcode, bool needs_includes,
+ const IDLOptions &options) const {
if (!classcode.length()) return true;
std::string code =
@@ -117,7 +230,10 @@
}
code += classcode;
if (!namespace_name.empty()) { code += "\n}\n"; }
- auto filename = NamespaceDir(ns) + defname + ".cs";
+ auto filename = NamespaceDir(ns) + defname;
+ if (options.one_file) { filename += options.filename_suffix; }
+ filename +=
+ options.filename_extension.empty() ? ".cs" : options.filename_extension;
return SaveFile(filename.c_str(), code, false);
}
@@ -134,9 +250,9 @@
// clang-format on
if (enableLangOverrides) {
- if (IsEnum(type)) return WrapInNameSpace(*type.enum_def);
+ if (IsEnum(type)) return NamespacedName(*type.enum_def);
if (type.base_type == BASE_TYPE_STRUCT) {
- return "Offset<" + WrapInNameSpace(*type.struct_def) + ">";
+ return "Offset<" + NamespacedName(*type.struct_def) + ">";
}
}
@@ -151,7 +267,7 @@
switch (type.base_type) {
case BASE_TYPE_STRING: return "string";
case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
- case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
+ case BASE_TYPE_STRUCT: return NamespacedName(*type.struct_def);
case BASE_TYPE_UNION: return "TTable";
default: return "Table";
}
@@ -165,12 +281,12 @@
}
std::string GenOffsetType(const StructDef &struct_def) const {
- return "Offset<" + WrapInNameSpace(struct_def) + ">";
+ return "Offset<" + NamespacedName(struct_def) + ">";
}
std::string GenOffsetConstruct(const StructDef &struct_def,
const std::string &variable_name) const {
- return "new Offset<" + WrapInNameSpace(struct_def) + ">(" + variable_name +
+ return "new Offset<" + NamespacedName(struct_def) + ">(" + variable_name +
")";
}
@@ -179,7 +295,7 @@
if (IsSeries(type)) {
return DestinationCast(type.VectorType());
} else {
- if (IsEnum(type)) return "(" + WrapInNameSpace(*type.enum_def) + ")";
+ if (IsEnum(type)) return "(" + NamespacedName(*type.enum_def) + ")";
}
return "";
}
@@ -190,17 +306,19 @@
// would be cast down to int before being put onto the buffer. In C#, one cast
// directly cast an Enum to its underlying type, which is essential before
// putting it onto the buffer.
- std::string SourceCast(const Type &type) const {
+ std::string SourceCast(const Type &type,
+ const bool isOptional = false) const {
if (IsSeries(type)) {
return SourceCast(type.VectorType());
} else {
- if (IsEnum(type)) return "(" + GenTypeBasic(type, false) + ")";
+ if (IsEnum(type))
+ return "(" + GenTypeBasic(type, false) + (isOptional ? "?" : "") + ")";
}
return "";
}
- std::string SourceCastBasic(const Type &type) const {
- return IsScalar(type.base_type) ? SourceCast(type) : "";
+ std::string SourceCastBasic(const Type &type, const bool isOptional) const {
+ return IsScalar(type.base_type) ? SourceCast(type, isOptional) : "";
}
std::string GenEnumDefaultValue(const FieldDef &field) const {
@@ -208,7 +326,7 @@
FLATBUFFERS_ASSERT(value.type.enum_def);
auto &enum_def = *value.type.enum_def;
auto enum_val = enum_def.FindByValue(value.constant);
- return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+ return enum_val ? (NamespacedName(enum_def) + "." + Name(*enum_val))
: value.constant;
}
@@ -252,7 +370,7 @@
switch (value.type.base_type) {
case BASE_TYPE_STRING: return "default(StringOffset)";
case BASE_TYPE_STRUCT:
- return "default(Offset<" + WrapInNameSpace(*value.type.struct_def) +
+ return "default(Offset<" + NamespacedName(*value.type.struct_def) +
">)";
case BASE_TYPE_VECTOR: return "default(VectorOffset)";
default: break;
@@ -293,14 +411,14 @@
} else {
code += "public ";
}
- code += "enum " + enum_def.name;
+ code += "enum " + Name(enum_def);
code += " : " + GenTypeBasic(enum_def.underlying_type, false);
code += "\n{\n";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
auto &ev = **it;
GenComment(ev.doc_comment, code_ptr, &comment_config, " ");
code += " ";
- code += ev.name + " = ";
+ code += Name(ev) + " = ";
code += enum_def.ToString(ev);
code += ",\n";
}
@@ -334,7 +452,7 @@
if (type.base_type == BASE_TYPE_BOOL) {
getter = "0!=" + getter;
} else if (GenTypeBasic(type, false) != "byte") {
- getter += MakeCamel(GenTypeBasic(type, false));
+ getter += ConvertCase(GenTypeBasic(type, false), Case::kUpperCamel);
}
return getter;
}
@@ -350,7 +468,7 @@
auto dest_cast = DestinationCast(type);
auto getter = data_buffer + ".Get";
if (GenTypeBasic(type, false) != "byte") {
- getter += MakeCamel(GenTypeBasic(type, false));
+ getter += ConvertCase(GenTypeBasic(type, false), Case::kUpperCamel);
}
getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
dest_mask;
@@ -364,7 +482,7 @@
std::string setter = "__p.bb.Put";
if (GenTypeBasic(type, false) != "byte" &&
type.base_type != BASE_TYPE_BOOL) {
- setter += MakeCamel(GenTypeBasic(type, false));
+ setter += ConvertCase(GenTypeBasic(type, false), Case::kUpperCamel);
}
return setter;
} else {
@@ -374,8 +492,9 @@
// Returns the method name for use with add/put calls.
std::string GenMethod(const Type &type) const {
- return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type, false))
- : (IsStruct(type) ? "Struct" : "Offset");
+ return IsScalar(type.base_type)
+ ? ConvertCase(GenTypeBasic(type, false), Case::kUpperCamel)
+ : (IsStruct(type) ? "Struct" : "Offset");
}
// Recursively generate arguments for a constructor, to deal with nested
@@ -395,7 +514,8 @@
// don't clash, and to make it obvious these arguments are constructing
// a nested struct, prefix the name with the field name.
GenStructArgs(*field_type.struct_def, code_ptr,
- (nameprefix + (field.name + "_")).c_str(), array_cnt);
+ (nameprefix + (EscapeKeyword(field.name) + "_")).c_str(),
+ array_cnt);
} else {
code += ", ";
code += GenTypeBasic(type);
@@ -407,7 +527,7 @@
}
code += " ";
code += nameprefix;
- code += MakeCamel(field.name, true);
+ code += Name(field);
}
}
}
@@ -454,7 +574,7 @@
code += indent + " builder.Put";
code += GenMethod(type) + "(";
code += SourceCast(type);
- auto argname = nameprefix + MakeCamel(field.name, true);
+ auto argname = nameprefix + Name(field);
code += argname;
size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
if (array_cnt > 0) {
@@ -553,7 +673,7 @@
// Force compile time error if not using the same version runtime.
code += " public static void ValidateVersion() {";
code += " FlatBufferConstants.";
- code += "FLATBUFFERS_1_12_0(); ";
+ code += "FLATBUFFERS_2_0_0(); ";
code += "}\n";
// Generate a special accessor for the table that when used as the root
@@ -618,7 +738,8 @@
std::string dest_mask = "";
std::string dest_cast = DestinationCast(field.value.type);
std::string src_cast = SourceCast(field.value.type);
- std::string field_name_camel = MakeCamel(field.name, true);
+ std::string field_name_camel = Name(field);
+ if (field_name_camel == struct_def.name) { field_name_camel += "_"; }
std::string method_start =
" public " + type_name_dest + optional + " " + field_name_camel;
std::string obj = "(new " + type_name + "())";
@@ -745,8 +866,7 @@
HasUnionStringValue(*vectortype.enum_def)) {
code += member_suffix;
code += "}\n";
- code += " public string " + MakeCamel(field.name, true) +
- "AsString(int j)";
+ code += " public string " + Name(field) + "AsString(int j)";
code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
code += "(" + index + ") : null";
}
@@ -759,8 +879,7 @@
if (HasUnionStringValue(*field.value.type.enum_def)) {
code += member_suffix;
code += "}\n";
- code += " public string " + MakeCamel(field.name, true) +
- "AsString()";
+ code += " public string " + Name(field) + "AsString()";
code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
code += "(o + __p.bb_pos) : null";
}
@@ -795,7 +914,7 @@
code += member_suffix;
code += "}\n";
if (IsVector(field.value.type)) {
- code += " public int " + MakeCamel(field.name, true);
+ code += " public int " + Name(field);
code += "Length";
code += " { get";
code += offset_prefix;
@@ -810,9 +929,9 @@
for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
auto &key_field = **kit;
if (key_field.key) {
- auto qualified_name = WrapInNameSpace(sd);
+ auto qualified_name = NamespacedName(sd);
code += " public " + qualified_name + "? ";
- code += MakeCamel(field.name, true) + "ByKey(";
+ code += Name(field) + "ByKey(";
code += GenTypeGet(key_field.value.type) + " key)";
code += offset_prefix;
code += qualified_name + ".__lookup_by_key(";
@@ -831,7 +950,7 @@
code += "#if ENABLE_SPAN_T\n";
code += " public Span<" + GenTypeBasic(field.value.type.VectorType()) +
"> Get";
- code += MakeCamel(field.name, true);
+ code += Name(field);
code += "Bytes() { return ";
code += "__p.__vector_as_span<" +
GenTypeBasic(field.value.type.VectorType()) + ">(";
@@ -841,7 +960,7 @@
code += "); }\n";
code += "#else\n";
code += " public ArraySegment<byte>? Get";
- code += MakeCamel(field.name, true);
+ code += Name(field);
code += "Bytes() { return ";
code += "__p.__vector_as_arraysegment(";
code += NumToString(field.value.offset);
@@ -852,7 +971,7 @@
code += " public ";
code += GenTypeBasic(field.value.type.VectorType());
code += "[] Get";
- code += MakeCamel(field.name, true);
+ code += Name(field);
code += "Array() { ";
if (IsEnum(field.value.type.VectorType())) {
// Since __vector_as_array does not work for enum types,
@@ -881,9 +1000,9 @@
}
// generate object accessors if is nested_flatbuffer
if (field.nested_flatbuffer) {
- auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
+ auto nested_type_name = NamespacedName(*field.nested_flatbuffer);
auto nested_method_name =
- MakeCamel(field.name, true) + "As" + field.nested_flatbuffer->name;
+ Name(field) + "As" + field.nested_flatbuffer->name;
auto get_nested_method_name = nested_method_name;
get_nested_method_name = "Get" + nested_method_name;
conditional_cast = "(" + nested_type_name + "?)";
@@ -904,15 +1023,16 @@
is_series ? field.value.type.VectorType() : field.value.type;
// Boolean parameters have to be explicitly converted to byte
// representation.
- auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
- ? "(byte)(" + field.name + " ? 1 : 0)"
- : field.name;
- auto mutator_prefix = MakeCamel("mutate", true);
+ auto setter_parameter =
+ underlying_type.base_type == BASE_TYPE_BOOL
+ ? "(byte)(" + EscapeKeyword(field.name) + " ? 1 : 0)"
+ : EscapeKeyword(field.name);
+ auto mutator_prefix = "Mutate";
// A vector mutator also needs the index of the vector element it should
// mutate.
auto mutator_params = (is_series ? "(int j, " : "(") +
- GenTypeGet(underlying_type) + " " + field.name +
- ") { ";
+ GenTypeGet(underlying_type) + " " +
+ EscapeKeyword(field.name) + ") { ";
auto setter_index =
is_series
? "__p." +
@@ -926,7 +1046,7 @@
if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) {
code += " public ";
code += struct_def.fixed ? "void " : "bool ";
- code += mutator_prefix + MakeCamel(field.name, true);
+ code += mutator_prefix + Name(field);
code += mutator_params;
if (struct_def.fixed) {
code += GenSetter(underlying_type) + "(" + setter_index + ", ";
@@ -942,9 +1062,10 @@
}
if (parser_.opts.java_primitive_has_method &&
IsScalar(field.value.type.base_type) && !struct_def.fixed) {
- auto vt_offset_constant = " public static final int VT_" +
- MakeScreamingCamel(field.name) + " = " +
- NumToString(field.value.offset) + ";";
+ auto vt_offset_constant =
+ " public static final int VT_" +
+ ConvertCase(field.name, Case::kScreamingSnake) + " = " +
+ NumToString(field.value.offset) + ";";
code += vt_offset_constant;
code += "\n";
@@ -1002,13 +1123,13 @@
field.value.type.struct_def->defined_namespace,
GenTypeName_ObjectAPI(field.value.type.struct_def->name, opts));
code += " ";
- code += field.name;
+ code += EscapeKeyword(field.name);
code += " = null";
} else {
code += GenTypeBasic(field.value.type);
if (field.IsScalarOptional()) { code += "?"; }
code += " ";
- code += field.name;
+ code += EscapeKeyword(field.name);
if (!IsScalar(field.value.type.base_type)) code += "Offset";
code += " = ";
@@ -1028,13 +1149,13 @@
size == SizeOf(field.value.type.base_type))) {
code += " " + struct_def.name + ".";
code += "Add";
- code += MakeCamel(field.name) + "(builder, ";
+ code += Name(field) + "(builder, ";
if (IsStruct(field.value.type) &&
opts.generate_object_based_api) {
code += GenTypePointer(field.value.type) + ".Pack(builder, " +
- field.name + ")";
+ EscapeKeyword(field.name) + ")";
} else {
- code += field.name;
+ code += EscapeKeyword(field.name);
if (!IsScalar(field.value.type.base_type)) code += "Offset";
}
@@ -1062,17 +1183,17 @@
if (field.deprecated) continue;
if (field.key) key_field = &field;
code += " public static void Add";
- code += MakeCamel(field.name);
+ code += Name(field);
code += "(FlatBufferBuilder builder, ";
code += GenTypeBasic(field.value.type);
- auto argname = MakeCamel(field.name, false);
+ auto argname = ConvertCase(field.name, Case::kLowerCamel);
if (!IsScalar(field.value.type.base_type)) argname += "Offset";
if (field.IsScalarOptional()) { code += "?"; }
- code += " " + argname + ") { builder.Add";
+ code += " " + EscapeKeyword(argname) + ") { builder.Add";
code += GenMethod(field.value.type) + "(";
code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
- code += SourceCastBasic(field.value.type);
- code += argname;
+ code += SourceCastBasic(field.value.type, field.IsScalarOptional());
+ code += EscapeKeyword(argname);
if (!IsScalar(field.value.type.base_type) &&
field.value.type.base_type != BASE_TYPE_UNION) {
code += ".Value";
@@ -1093,7 +1214,7 @@
field_has_create_set.insert(&field);
code += " public static VectorOffset ";
code += "Create";
- code += MakeCamel(field.name);
+ code += Name(field);
code += "Vector(FlatBufferBuilder builder, ";
code += GenTypeBasic(vector_type) + "[] data) ";
code += "{ builder.StartVector(";
@@ -1105,7 +1226,11 @@
code += "Add";
code += GenMethod(vector_type);
code += "(";
- code += SourceCastBasic(vector_type);
+ // At the moment there is no support of the type Vector with
+ // optional enum, e.g. if we have enum type SomeEnum there is no way
+ // to define `SomeEmum?[] enums` in FlatBuffer schema, so isOptional
+ // = false
+ code += SourceCastBasic(vector_type, false);
code += "data[i]";
if (vector_type.base_type == BASE_TYPE_STRUCT ||
IsString(vector_type))
@@ -1115,7 +1240,7 @@
code += " public static VectorOffset ";
code += "Create";
- code += MakeCamel(field.name);
+ code += Name(field);
code += "VectorBlock(FlatBufferBuilder builder, ";
code += GenTypeBasic(vector_type) + "[] data) ";
code += "{ builder.StartVector(";
@@ -1127,7 +1252,7 @@
// Generate a method to start a vector, data to be added manually
// after.
code += " public static void Start";
- code += MakeCamel(field.name);
+ code += Name(field);
code += "Vector(FlatBufferBuilder builder, int numElems) ";
code += "{ builder.StartVector(";
code += NumToString(elem_size);
@@ -1142,7 +1267,7 @@
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
- if (!field.deprecated && field.required) {
+ if (!field.deprecated && field.IsRequired()) {
code += " builder.Required(o, ";
code += NumToString(field.value.offset);
code += "); // " + field.name + "\n";
@@ -1215,7 +1340,7 @@
GenPackUnPack_ObjectAPI(struct_def, code_ptr, opts, struct_has_create,
field_has_create_set);
}
- code += "};\n\n";
+ code += "}\n\n";
if (opts.generate_object_based_api) {
GenStruct_ObjectAPI(struct_def, code_ptr, opts);
@@ -1305,19 +1430,27 @@
code += " }\n\n";
// As<T>
code += " public T As<T>() where T : class { return this.Value as T; }\n";
- // As
+ // As, From
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
auto &ev = **it;
if (ev.union_type.base_type == BASE_TYPE_NONE) continue;
auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts);
- if (ev.union_type.base_type == BASE_TYPE_STRUCT &&
- ev.union_type.struct_def->attributes.Lookup("private")) {
- code += " internal ";
- } else {
- code += " public ";
- }
- code += type_name + " As" + ev.name + "() { return this.As<" + type_name +
- ">(); }\n";
+ std::string accessibility =
+ (ev.union_type.base_type == BASE_TYPE_STRUCT &&
+ ev.union_type.struct_def->attributes.Lookup("private"))
+ ? "internal"
+ : "public";
+ // As
+ code += " " + accessibility + " " + type_name + " As" + ev.name +
+ "() { return this.As<" + type_name + ">(); }\n";
+ // From
+ auto lower_ev_name = ev.name;
+ std::transform(lower_ev_name.begin(), lower_ev_name.end(),
+ lower_ev_name.begin(), CharToLower);
+ code += " " + accessibility + " static " + union_name + " From" +
+ ev.name + "(" + type_name + " _" + lower_ev_name +
+ ") { return new " + union_name + "{ Type = " + Name(enum_def) +
+ "." + Name(ev) + ", Value = _" + lower_ev_name + " }; }\n";
}
code += "\n";
// Pack()
@@ -1329,7 +1462,7 @@
if (ev.union_type.base_type == BASE_TYPE_NONE) {
code += " default: return 0;\n";
} else {
- code += " case " + enum_def.name + "." + ev.name + ": return ";
+ code += " case " + Name(enum_def) + "." + Name(ev) + ": return ";
if (IsString(ev.union_type)) {
code += "builder.CreateString(_o.As" + ev.name + "()).Value;\n";
} else {
@@ -1414,7 +1547,7 @@
code += " default: break;\n";
} else {
auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts);
- code += " case " + enum_def.name + "." + ev.name +
+ code += " case " + Name(enum_def) + "." + Name(ev) +
": _o.Value = serializer.Deserialize<" + type_name +
">(reader); break;\n";
}
@@ -1450,7 +1583,7 @@
} else {
code += indent + varialbe_name + " = new ";
}
- code += WrapInNameSpace(enum_def) + "Union();\n";
+ code += NamespacedName(enum_def) + "Union();\n";
code += indent + varialbe_name + ".Type = this." + camel_name + "Type" +
type_suffix + ";\n";
code +=
@@ -1461,7 +1594,7 @@
if (ev.union_type.base_type == BASE_TYPE_NONE) {
code += indent + " default: break;\n";
} else {
- code += indent + " case " + WrapInNameSpace(enum_def) + "." + ev.name +
+ code += indent + " case " + NamespacedName(enum_def) + "." + ev.name +
":\n";
code += indent + " " + varialbe_name + ".Value = this." + camel_name;
if (IsString(ev.union_type)) {
@@ -1499,7 +1632,7 @@
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
- auto camel_name = MakeCamel(field.name);
+ auto camel_name = Name(field);
auto start = " _o." + camel_name + " = ";
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT: {
@@ -1573,7 +1706,7 @@
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
- auto camel_name = MakeCamel(field.name);
+ auto camel_name = Name(field);
// pre
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT: {
@@ -1627,12 +1760,12 @@
break;
case BASE_TYPE_UTYPE:
property_name = camel_name.substr(0, camel_name.size() - 4);
- array_type = WrapInNameSpace(*field.value.type.enum_def);
+ array_type = NamespacedName(*field.value.type.enum_def);
to_array = "_o." + property_name + "[_j].Type";
break;
case BASE_TYPE_UNION:
array_type = "int";
- to_array = WrapInNameSpace(*field.value.type.enum_def) +
+ to_array = NamespacedName(*field.value.type.enum_def) +
"Union.Pack(builder, _o." + property_name + "[_j])";
break;
default: gen_for_loop = false; break;
@@ -1687,7 +1820,7 @@
}
case BASE_TYPE_UNION: {
code += " var _" + field.name + "_type = _o." + camel_name +
- " == null ? " + WrapInNameSpace(*field.value.type.enum_def) +
+ " == null ? " + NamespacedName(*field.value.type.enum_def) +
".NONE : " + "_o." + camel_name + ".Type;\n";
code +=
" var _" + field.name + " = _o." + camel_name +
@@ -1706,7 +1839,7 @@
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
- auto camel_name = MakeCamel(field.name);
+ auto camel_name = Name(field);
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT: {
if (struct_def.fixed) {
@@ -1760,7 +1893,7 @@
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
- auto camel_name = MakeCamel(field.name);
+ auto camel_name = Name(field);
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT: {
if (field.value.type.struct_def->fixed) {
@@ -1856,7 +1989,7 @@
}
code += "] = _o";
for (size_t i = 0, j = 0; i < array_lengths.size(); ++i) {
- code += "." + MakeCamel(array_lengths[i].name);
+ code += "." + ConvertCase(array_lengths[i].name, Case::kUpperCamel);
if (array_lengths[i].length <= 0) continue;
code += "[idx" + NumToString(j++) + "]";
}
@@ -1867,7 +2000,7 @@
} else {
code += "_o";
for (size_t i = 0; i < array_lengths.size(); ++i) {
- code += "." + MakeCamel(array_lengths[i].name);
+ code += "." + ConvertCase(array_lengths[i].name, Case::kUpperCamel);
}
code += ";";
}
@@ -1910,13 +2043,13 @@
type_name.replace(type_name.length() - type_name_length,
type_name_length, new_type_name);
} else if (type.element == BASE_TYPE_UNION) {
- type_name = WrapInNameSpace(*type.enum_def) + "Union";
+ type_name = NamespacedName(*type.enum_def) + "Union";
}
break;
}
case BASE_TYPE_UNION: {
- type_name = WrapInNameSpace(*type.enum_def) + "Union";
+ type_name = NamespacedName(*type.enum_def) + "Union";
break;
}
default: break;
@@ -1959,10 +2092,11 @@
if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
if (field.value.type.element == BASE_TYPE_UTYPE) continue;
auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
- auto camel_name = MakeCamel(field.name, true);
+ if (field.IsScalarOptional()) type_name += "?";
+ auto camel_name = Name(field);
if (opts.cs_gen_json_serializer) {
if (IsUnion(field.value.type)) {
- auto utype_name = WrapInNameSpace(*field.value.type.enum_def);
+ auto utype_name = NamespacedName(*field.value.type.enum_def);
code +=
" [Newtonsoft.Json.JsonProperty(\"" + field.name + "_type\")]\n";
if (IsVector(field.value.type)) {
@@ -2025,7 +2159,7 @@
if (field.deprecated) continue;
if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
if (field.value.type.element == BASE_TYPE_UTYPE) continue;
- code += " this." + MakeCamel(field.name) + " = ";
+ code += " this." + Name(field) + " = ";
auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
if (IsScalar(field.value.type.base_type)) {
code += GenDefaultValue(field) + ";\n";
diff --git a/third_party/flatbuffers/src/idl_gen_dart.cpp b/third_party/flatbuffers/src/idl_gen_dart.cpp
index eec05a7..ff2c1a5 100644
--- a/third_party/flatbuffers/src/idl_gen_dart.cpp
+++ b/third_party/flatbuffers/src/idl_gen_dart.cpp
@@ -63,7 +63,7 @@
code.clear();
code = code + "// " + FlatBuffersGeneratedWarning() + "\n";
code = code +
- "// ignore_for_file: unused_import, unused_field, "
+ "// ignore_for_file: unused_import, unused_field, unused_element, "
"unused_local_variable\n\n";
if (!kv->first.empty()) { code += "library " + kv->first + ";\n\n"; }
@@ -154,10 +154,12 @@
static std::string EscapeKeyword(const std::string &name) {
for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
- if (name == keywords[i]) { return MakeCamel(name + "_", false); }
+ if (name == keywords[i]) {
+ return ConvertCase(name + "_", Case::kLowerCamel);
+ }
}
- return MakeCamel(name, false);
+ return ConvertCase(name, Case::kLowerCamel);
}
void GenerateEnums(namespace_code_map *namespace_code) {
@@ -225,23 +227,34 @@
GenDocComment(enum_def.doc_comment, &code, "");
auto name = enum_def.is_union ? enum_def.name + "TypeId" : enum_def.name;
- auto is_bit_flags = enum_def.attributes.Lookup("bit_flags");
+ const bool is_bit_flags =
+ enum_def.attributes.Lookup("bit_flags") != nullptr;
+ // The flatbuffer schema language allows bit flag enums to potentially have
+ // a default value of zero, even if it's not a valid enum value...
+ const bool permit_zero = is_bit_flags;
code += "class " + name + " {\n";
code += " final int value;\n";
code += " const " + name + "._(this.value);\n\n";
code += " factory " + name + ".fromValue(int value) {\n";
- code += " if (value == null) value = 0;\n";
-
- code += " if (!values.containsKey(value)) {\n";
- code +=
- " throw new StateError('Invalid value $value for bit flag enum ";
+ code += " final result = values[value];\n";
+ code += " if (result == null) {\n";
+ if (permit_zero) {
+ code += " if (value == 0) {\n";
+ code += " return " + name + "._(0);\n";
+ code += " } else {\n";
+ }
+ code += " throw StateError('Invalid value $value for bit flag enum ";
code += name + "');\n";
+ if (permit_zero) { code += " }\n"; }
code += " }\n";
- code += " return values[value];\n";
+ code += " return result;\n";
code += " }\n\n";
+ code += " static " + name + "? _createOrNull(int? value) => \n";
+ code += " value == null ? null : " + name + ".fromValue(value);\n\n";
+
// this is meaningless for bit_flags
// however, note that unlike "regular" dart enums this enum can still have
// holes.
@@ -263,19 +276,20 @@
if (it != enum_def.Vals().begin()) { code += '\n'; }
GenDocComment(ev.doc_comment, &code, "", " ");
}
- code += " static const " + name + " " + ev.name + " = ";
- code += "const " + name + "._(" + enum_def.ToString(ev) + ");\n";
+ code += " static const " + name + " " + ev.name + " = " + name + "._(" +
+ enum_def.ToString(ev) + ");\n";
}
- code += " static const values = {";
+ code += " static const Map<int, " + name + "> values = {\n";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
auto &ev = **it;
- code += enum_def.ToString(ev) + ": " + ev.name + ",";
+ if (it != enum_def.Vals().begin()) code += ",\n";
+ code += " " + enum_def.ToString(ev) + ": " + ev.name;
}
code += "};\n\n";
- code += " static const " + _kFb + ".Reader<" + name +
- "> reader = const _" + name + "Reader();\n\n";
+ code += " static const " + _kFb + ".Reader<" + name + "> reader = _" +
+ name + "Reader();\n\n";
code += " @override\n";
code += " String toString() {\n";
code += " return '" + name + "{value: $value}';\n";
@@ -298,7 +312,7 @@
code += " @override\n";
code +=
" " + name + " read(" + _kFb + ".BufferContext bc, int offset) =>\n";
- code += " new " + name + ".fromValue(const " + _kFb + "." +
+ code += " " + name + ".fromValue(const " + _kFb + "." +
GenType(enum_def.underlying_type) + "Reader().read(bc, offset));\n";
code += "}\n\n";
}
@@ -327,30 +341,41 @@
std::string GenReaderTypeName(const Type &type, Namespace *current_namespace,
const FieldDef &def,
- bool parent_is_vector = false) {
+ bool parent_is_vector = false, bool lazy = true,
+ bool constConstruct = true) {
+ std::string prefix = (constConstruct ? "const " : "") + _kFb;
if (type.base_type == BASE_TYPE_BOOL) {
- return "const " + _kFb + ".BoolReader()";
+ return prefix + ".BoolReader()";
} else if (IsVector(type)) {
- return "const " + _kFb + ".ListReader<" +
+ if (!type.VectorType().enum_def) {
+ if (type.VectorType().base_type == BASE_TYPE_CHAR) {
+ return prefix + ".Int8ListReader(" + (lazy ? ")" : "lazy: false)");
+ }
+ if (type.VectorType().base_type == BASE_TYPE_UCHAR) {
+ return prefix + ".Uint8ListReader(" + (lazy ? ")" : "lazy: false)");
+ }
+ }
+ return prefix + ".ListReader<" +
GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
- GenReaderTypeName(type.VectorType(), current_namespace, def,
- true) +
- ")";
+ GenReaderTypeName(type.VectorType(), current_namespace, def, true,
+ true, false) +
+ (lazy ? ")" : ", lazy: false)");
} else if (IsString(type)) {
- return "const " + _kFb + ".StringReader()";
+ return prefix + ".StringReader()";
}
if (IsScalar(type.base_type)) {
if (type.enum_def && parent_is_vector) {
return GenDartTypeName(type, current_namespace, def) + ".reader";
}
- return "const " + _kFb + "." + GenType(type) + "Reader()";
+ return prefix + "." + GenType(type) + "Reader()";
} else {
return GenDartTypeName(type, current_namespace, def) + ".reader";
}
}
std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
- const FieldDef &def, bool addBuilder = false) {
+ const FieldDef &def,
+ std::string struct_type_suffix = "") {
if (type.enum_def) {
if (type.enum_def->is_union && type.base_type != BASE_TYPE_UNION) {
return type.enum_def->name + "TypeId";
@@ -375,18 +400,26 @@
case BASE_TYPE_DOUBLE: return "double";
case BASE_TYPE_STRING: return "String";
case BASE_TYPE_STRUCT:
- return MaybeWrapNamespace(
- type.struct_def->name + (addBuilder ? "ObjectBuilder" : ""),
- current_namespace, def);
+ return MaybeWrapNamespace(type.struct_def->name + struct_type_suffix,
+ current_namespace, def);
case BASE_TYPE_VECTOR:
return "List<" +
GenDartTypeName(type.VectorType(), current_namespace, def,
- addBuilder) +
+ struct_type_suffix) +
">";
default: assert(0); return "dynamic";
}
}
+ std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
+ const FieldDef &def, bool nullable,
+ std::string struct_type_suffix) {
+ std::string typeName =
+ GenDartTypeName(type, current_namespace, def, struct_type_suffix);
+ if (nullable && typeName != "dynamic") typeName += "?";
+ return typeName;
+ }
+
static const std::string MaybeWrapNamespace(const std::string &type_name,
Namespace *current_ns,
const FieldDef &field) {
@@ -432,15 +465,15 @@
code += " " + object_name + "._(this._bc, this._bcOffset);\n";
if (!struct_def.fixed) {
code += " factory " + object_name + "(List<int> bytes) {\n";
- code += " " + _kFb + ".BufferContext rootRef = new " + _kFb +
- ".BufferContext.fromBytes(bytes);\n";
+ code +=
+ " final rootRef = " + _kFb + ".BufferContext.fromBytes(bytes);\n";
code += " return reader.read(rootRef, 0);\n";
code += " }\n";
}
code += "\n";
code += " static const " + _kFb + ".Reader<" + object_name +
- "> reader = const " + reader_name + "();\n\n";
+ "> reader = " + reader_name + "();\n\n";
code += " final " + _kFb + ".BufferContext _bc;\n";
code += " final int _bcOffset;\n\n";
@@ -456,8 +489,23 @@
GenImplementationGetters(struct_def, non_deprecated_fields, &code);
+ if (parser_.opts.generate_object_based_api) {
+ code +=
+ "\n" + GenStructObjectAPIUnpack(struct_def, non_deprecated_fields);
+
+ code += "\n static int pack(fb.Builder fbBuilder, " + struct_def.name +
+ "T? object) {\n";
+ code += " if (object == null) return 0;\n";
+ code += " return object.pack(fbBuilder);\n";
+ code += " }\n";
+ }
+
code += "}\n\n";
+ if (parser_.opts.generate_object_based_api) {
+ code += GenStructObjectAPI(struct_def, non_deprecated_fields);
+ }
+
GenReader(struct_def, &reader_name, &reader_code);
GenBuilder(struct_def, non_deprecated_fields, &builder_name, &builder_code);
GenObjectBuilder(struct_def, non_deprecated_fields, &object_builder_name,
@@ -469,6 +517,122 @@
(*namespace_code)[object_namespace] += code;
}
+ // Generate an accessor struct with constructor for a flatbuffers struct.
+ std::string GenStructObjectAPI(
+ const StructDef &struct_def,
+ const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
+ std::string code;
+ GenDocComment(struct_def.doc_comment, &code, "");
+
+ std::string class_name = struct_def.name + "T";
+ code += "class " + class_name + " implements " + _kFb + ".Packable {\n";
+
+ std::string constructor_args;
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ const FieldDef &field = *it->second;
+
+ std::string field_name = ConvertCase(field.name, Case::kLowerCamel);
+ std::string defaultValue = getDefaultValue(field.value);
+ std::string type_name =
+ GenDartTypeName(field.value.type, struct_def.defined_namespace, field,
+ defaultValue.empty() && !struct_def.fixed, "T");
+
+ GenDocComment(field.doc_comment, &code, "", " ");
+ code += " " + type_name + " " + field_name + ";\n";
+
+ if (!constructor_args.empty()) constructor_args += ",\n";
+ constructor_args += " ";
+ constructor_args += (struct_def.fixed ? "required " : "");
+ constructor_args += "this." + field_name;
+ if (!struct_def.fixed && !defaultValue.empty()) {
+ if (IsEnum(field.value.type)) {
+ auto &enum_def = *field.value.type.enum_def;
+ if (auto val = enum_def.FindByValue(defaultValue)) {
+ constructor_args += " = " + enum_def.name + "." + val->name;
+ } else {
+ constructor_args +=
+ " = const " + enum_def.name + "._(" + defaultValue + ")";
+ }
+ } else {
+ constructor_args += " = " + defaultValue;
+ }
+ }
+ }
+
+ if (!constructor_args.empty()) {
+ code += "\n " + class_name + "({\n" + constructor_args + "});\n\n";
+ }
+
+ code += GenStructObjectAPIPack(struct_def, non_deprecated_fields);
+ code += "\n";
+ code += GenToString(class_name, non_deprecated_fields);
+
+ code += "}\n\n";
+ return code;
+ }
+
+ // Generate function `StructNameT unpack()`
+ std::string GenStructObjectAPIUnpack(
+ const StructDef &struct_def,
+ const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
+ std::string constructor_args;
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ const FieldDef &field = *it->second;
+
+ std::string field_name = ConvertCase(field.name, Case::kLowerCamel);
+ if (!constructor_args.empty()) constructor_args += ",\n";
+ constructor_args += " " + field_name + ": ";
+
+ const Type &type = field.value.type;
+ std::string defaultValue = getDefaultValue(field.value);
+ bool isNullable = defaultValue.empty() && !struct_def.fixed;
+ std::string nullableValueAccessOperator = isNullable ? "?" : "";
+ if (type.base_type == BASE_TYPE_STRUCT) {
+ constructor_args +=
+ field_name + nullableValueAccessOperator + ".unpack()";
+ } else if (type.base_type == BASE_TYPE_VECTOR) {
+ if (type.VectorType().base_type == BASE_TYPE_STRUCT) {
+ constructor_args += field_name + nullableValueAccessOperator +
+ ".map((e) => e.unpack()).toList()";
+ } else {
+ constructor_args +=
+ GenReaderTypeName(field.value.type, struct_def.defined_namespace,
+ field, false, false);
+ constructor_args += ".vTableGet";
+ std::string offset = NumToString(field.value.offset);
+ constructor_args +=
+ isNullable
+ ? "Nullable(_bc, _bcOffset, " + offset + ")"
+ : "(_bc, _bcOffset, " + offset + ", " + defaultValue + ")";
+ }
+ } else {
+ constructor_args += field_name;
+ }
+ }
+
+ std::string class_name = struct_def.name + "T";
+ std::string code = " " + class_name + " unpack() => " + class_name + "(";
+ if (!constructor_args.empty()) code += "\n" + constructor_args;
+ code += ");\n";
+ return code;
+ }
+
+ // Generate function `StructNameT pack()`
+ std::string GenStructObjectAPIPack(
+ const StructDef &struct_def,
+ const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
+ std::string code;
+
+ code += " @override\n";
+ code += " int pack(fb.Builder fbBuilder) {\n";
+ code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields,
+ false, true);
+ code += " }\n";
+ return code;
+ }
+
std::string NamespaceAliasFromUnionType(Namespace *root_namespace,
const Type &type) {
const std::vector<std::string> qualified_name_parts =
@@ -510,9 +674,12 @@
auto pair = *it;
auto &field = *pair.second;
- std::string field_name = MakeCamel(field.name, false);
- std::string type_name = GenDartTypeName(
- field.value.type, struct_def.defined_namespace, field, false);
+ std::string field_name = ConvertCase(field.name, Case::kLowerCamel);
+ std::string defaultValue = getDefaultValue(field.value);
+ bool isNullable = defaultValue.empty() && !struct_def.fixed;
+ std::string type_name =
+ GenDartTypeName(field.value.type, struct_def.defined_namespace, field,
+ isNullable, "");
GenDocComment(field.doc_comment, &code, "", " ");
@@ -528,8 +695,8 @@
auto enum_name = NamespaceAliasFromUnionType(
enum_def.defined_namespace, ev.union_type);
code += " case " + enum_def.ToString(ev) + ": return " +
- enum_name + ".reader.vTableGet(_bc, _bcOffset, " +
- NumToString(field.value.offset) + ", null);\n";
+ enum_name + ".reader.vTableGetNullable(_bc, _bcOffset, " +
+ NumToString(field.value.offset) + ");\n";
}
code += " default: return null;\n";
code += " }\n";
@@ -538,10 +705,9 @@
code += " => ";
if (field.value.type.enum_def &&
field.value.type.base_type != BASE_TYPE_VECTOR) {
- code += "new " +
- GenDartTypeName(field.value.type,
+ code += GenDartTypeName(field.value.type,
struct_def.defined_namespace, field) +
- ".fromValue(";
+ (isNullable ? "._createOrNull(" : ".fromValue(");
}
code += GenReaderTypeName(field.value.type,
@@ -550,33 +716,13 @@
code +=
".read(_bc, _bcOffset + " + NumToString(field.value.offset) + ")";
} else {
- code += ".vTableGet(_bc, _bcOffset, " +
- NumToString(field.value.offset) + ", ";
- if (!field.value.constant.empty() && field.value.constant != "0") {
- if (IsBool(field.value.type.base_type)) {
- code += "true";
- } else if (field.value.constant == "nan" ||
- field.value.constant == "+nan" ||
- field.value.constant == "-nan") {
- code += "double.nan";
- } else if (field.value.constant == "inf" ||
- field.value.constant == "+inf") {
- code += "double.infinity";
- } else if (field.value.constant == "-inf") {
- code += "double.negativeInfinity";
- } else {
- code += field.value.constant;
- }
+ code += ".vTableGet";
+ std::string offset = NumToString(field.value.offset);
+ if (isNullable) {
+ code += "Nullable(_bc, _bcOffset, " + offset + ")";
} else {
- if (IsBool(field.value.type.base_type)) {
- code += "false";
- } else if (IsScalar(field.value.type.base_type)) {
- code += "0";
- } else {
- code += "null";
- }
+ code += "(_bc, _bcOffset, " + offset + ", " + defaultValue + ")";
}
- code += ")";
}
if (field.value.type.enum_def &&
field.value.type.base_type != BASE_TYPE_VECTOR) {
@@ -587,20 +733,50 @@
}
code += "\n";
+ code += GenToString(struct_def.name, non_deprecated_fields);
+ }
+ std::string GenToString(
+ const std::string &object_name,
+ const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
+ std::string code;
code += " @override\n";
code += " String toString() {\n";
- code += " return '" + struct_def.name + "{";
+ code += " return '" + object_name + "{";
for (auto it = non_deprecated_fields.begin();
it != non_deprecated_fields.end(); ++it) {
auto pair = *it;
auto &field = *pair.second;
- code +=
- MakeCamel(field.name, false) + ": $" + MakeCamel(field.name, false);
+ code += ConvertCase(field.name, Case::kLowerCamel) + ": $" +
+ ConvertCase(field.name, Case::kLowerCamel);
if (it != non_deprecated_fields.end() - 1) { code += ", "; }
}
code += "}';\n";
code += " }\n";
+ return code;
+ }
+
+ std::string getDefaultValue(const Value &value) const {
+ if (!value.constant.empty() && value.constant != "0") {
+ if (IsBool(value.type.base_type)) {
+ return "true";
+ } else if (value.constant == "nan" || value.constant == "+nan" ||
+ value.constant == "-nan") {
+ return "double.nan";
+ } else if (value.constant == "inf" || value.constant == "+inf") {
+ return "double.infinity";
+ } else if (value.constant == "-inf") {
+ return "double.negativeInfinity";
+ } else {
+ return value.constant;
+ }
+ } else if (IsBool(value.type.base_type)) {
+ return "false";
+ } else if (IsScalar(value.type.base_type) && !IsUnion(value.type)) {
+ return "0";
+ } else {
+ return "";
+ }
}
void GenReader(const StructDef &struct_def, std::string *reader_name_ptr,
@@ -624,7 +800,7 @@
}
code += " @override\n";
code += " " + impl_name +
- " createObject(fb.BufferContext bc, int offset) => \n new " +
+ " createObject(fb.BufferContext bc, int offset) => \n " +
impl_name + "._(bc, offset);\n";
code += "}\n\n";
}
@@ -637,9 +813,7 @@
auto &builder_name = *builder_name_ptr;
code += "class " + builder_name + " {\n";
- code += " " + builder_name + "(this.fbBuilder) {\n";
- code += " assert(fbBuilder != null);\n";
- code += " }\n\n";
+ code += " " + builder_name + "(this.fbBuilder);\n\n";
code += " final " + _kFb + ".Builder fbBuilder;\n\n";
if (struct_def.fixed) {
@@ -688,7 +862,7 @@
} else {
code += " fbBuilder.put" + GenType(field.value.type) + "(";
code += field.name;
- if (field.value.type.enum_def) { code += "?.value"; }
+ if (field.value.type.enum_def) { code += ".value"; }
code += ");\n";
}
}
@@ -703,7 +877,8 @@
auto &code = *code_ptr;
code += " void begin() {\n";
- code += " fbBuilder.startTable();\n";
+ code += " fbBuilder.startTable(" +
+ NumToString(struct_def.fields.vec.size()) + ");\n";
code += " }\n\n";
for (auto it = non_deprecated_fields.begin();
@@ -713,21 +888,23 @@
auto offset = pair.first;
if (IsScalar(field.value.type.base_type)) {
- code += " int add" + MakeCamel(field.name) + "(";
+ code += " int add" + ConvertCase(field.name, Case::kUpperCamel) + "(";
code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
field);
- code += " " + MakeCamel(field.name, false) + ") {\n";
+ code += "? " + ConvertCase(field.name, Case::kLowerCamel) + ") {\n";
code += " fbBuilder.add" + GenType(field.value.type) + "(" +
NumToString(offset) + ", ";
- code += MakeCamel(field.name, false);
+ code += ConvertCase(field.name, Case::kLowerCamel);
if (field.value.type.enum_def) { code += "?.value"; }
code += ");\n";
} else if (IsStruct(field.value.type)) {
- code += " int add" + MakeCamel(field.name) + "(int offset) {\n";
+ code += " int add" + ConvertCase(field.name, Case::kUpperCamel) +
+ "(int offset) {\n";
code +=
" fbBuilder.addStruct(" + NumToString(offset) + ", offset);\n";
} else {
- code += " int add" + MakeCamel(field.name) + "Offset(int offset) {\n";
+ code += " int add" + ConvertCase(field.name, Case::kUpperCamel) +
+ "Offset(int? offset) {\n";
code +=
" fbBuilder.addOffset(" + NumToString(offset) + ", offset);\n";
}
@@ -756,8 +933,8 @@
code += " final " +
GenDartTypeName(field.value.type, struct_def.defined_namespace,
- field, true) +
- " _" + MakeCamel(field.name, false) + ";\n";
+ field, !struct_def.fixed, "ObjectBuilder") +
+ " _" + ConvertCase(field.name, Case::kLowerCamel) + ";\n";
}
code += "\n";
code += " " + builder_name + "(";
@@ -769,10 +946,11 @@
auto pair = *it;
auto &field = *pair.second;
- code += " " +
+ code += " ";
+ code += (struct_def.fixed ? "required " : "") +
GenDartTypeName(field.value.type, struct_def.defined_namespace,
- field, true) +
- " " + MakeCamel(field.name, false) + ",\n";
+ field, !struct_def.fixed, "ObjectBuilder") +
+ " " + ConvertCase(field.name, Case::kLowerCamel) + ",\n";
}
code += " })\n";
code += " : ";
@@ -781,8 +959,8 @@
auto pair = *it;
auto &field = *pair.second;
- code += "_" + MakeCamel(field.name, false) + " = " +
- MakeCamel(field.name, false);
+ code += "_" + ConvertCase(field.name, Case::kLowerCamel) + " = " +
+ ConvertCase(field.name, Case::kLowerCamel);
if (it == non_deprecated_fields.end() - 1) {
code += ";\n\n";
} else {
@@ -795,75 +973,102 @@
code += " /// Finish building, and store into the [fbBuilder].\n";
code += " @override\n";
- code += " int finish(\n";
- code += " " + _kFb + ".Builder fbBuilder) {\n";
- code += " assert(fbBuilder != null);\n";
-
- for (auto it = non_deprecated_fields.begin();
- it != non_deprecated_fields.end(); ++it) {
- auto pair = *it;
- auto &field = *pair.second;
-
- if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type))
- continue;
-
- code += " final int " + MakeCamel(field.name, false) + "Offset";
- if (IsVector(field.value.type)) {
- code +=
- " = _" + MakeCamel(field.name, false) + "?.isNotEmpty == true\n";
- code += " ? fbBuilder.writeList";
- switch (field.value.type.VectorType().base_type) {
- case BASE_TYPE_STRING:
- code += "(_" + MakeCamel(field.name, false) +
- ".map((b) => fbBuilder.writeString(b)).toList())";
- break;
- case BASE_TYPE_STRUCT:
- if (field.value.type.struct_def->fixed) {
- code += "OfStructs(_" + MakeCamel(field.name, false) + ")";
- } else {
- code += "(_" + MakeCamel(field.name, false) +
- ".map((b) => b.getOrCreateOffset(fbBuilder)).toList())";
- }
- break;
- default:
- code += GenType(field.value.type.VectorType()) + "(_" +
- MakeCamel(field.name, false);
- if (field.value.type.enum_def) { code += ".map((f) => f.value)"; }
- code += ")";
- }
- code += "\n : null;\n";
- } else if (IsString(field.value.type)) {
- code += " = fbBuilder.writeString(_" + MakeCamel(field.name, false) +
- ");\n";
- } else {
- code += " = _" + MakeCamel(field.name, false) +
- "?.getOrCreateOffset(fbBuilder);\n";
- }
- }
-
- code += "\n";
- if (struct_def.fixed) {
- StructObjectBuilderBody(non_deprecated_fields, code_ptr);
- } else {
- TableObjectBuilderBody(non_deprecated_fields, code_ptr);
- }
+ code += " int finish(" + _kFb + ".Builder fbBuilder) {\n";
+ code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields);
code += " }\n\n";
code += " /// Convenience method to serialize to byte list.\n";
code += " @override\n";
- code += " Uint8List toBytes([String fileIdentifier]) {\n";
- code += " " + _kFb + ".Builder fbBuilder = new ";
- code += _kFb + ".Builder();\n";
- code += " int offset = finish(fbBuilder);\n";
- code += " return fbBuilder.finish(offset, fileIdentifier);\n";
+ code += " Uint8List toBytes([String? fileIdentifier]) {\n";
+ code += " final fbBuilder = " + _kFb +
+ ".Builder(deduplicateTables: false);\n";
+ code += " fbBuilder.finish(finish(fbBuilder), fileIdentifier);\n";
+ code += " return fbBuilder.buffer;\n";
code += " }\n";
code += "}\n";
}
- void StructObjectBuilderBody(
- std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
- std::string *code_ptr, bool prependUnderscore = true) {
- auto &code = *code_ptr;
+ std::string GenObjectBuilderImplementation(
+ const StructDef &struct_def,
+ const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
+ bool prependUnderscore = true, bool pack = false) {
+ std::string code;
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ const FieldDef &field = *it->second;
+
+ if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type))
+ continue;
+
+ std::string offset_name =
+ ConvertCase(field.name, Case::kLowerCamel) + "Offset";
+ std::string field_name = (prependUnderscore ? "_" : "") +
+ ConvertCase(field.name, Case::kLowerCamel);
+
+ // custom handling for fixed-sized struct in pack()
+ if (pack && IsVector(field.value.type) &&
+ field.value.type.VectorType().base_type == BASE_TYPE_STRUCT &&
+ field.value.type.struct_def->fixed) {
+ code += " int? " + offset_name + ";\n";
+ code += " if (" + field_name + " != null) {\n";
+ code +=
+ " for (var e in " + field_name + "!) { e.pack(fbBuilder); }\n";
+ code += " " + ConvertCase(field.name, Case::kLowerCamel) +
+ "Offset = fbBuilder.endStructVector(" + field_name +
+ "!.length);\n";
+ code += " }\n";
+ continue;
+ }
+
+ code += " final int? " + offset_name;
+ if (IsVector(field.value.type)) {
+ code += " = " + field_name + " == null ? null\n";
+ code += " : fbBuilder.writeList";
+ switch (field.value.type.VectorType().base_type) {
+ case BASE_TYPE_STRING:
+ code +=
+ "(" + field_name + "!.map(fbBuilder.writeString).toList());\n";
+ break;
+ case BASE_TYPE_STRUCT:
+ if (field.value.type.struct_def->fixed) {
+ code += "OfStructs(" + field_name + "!);\n";
+ } else {
+ code += "(" + field_name + "!.map((b) => b." +
+ (pack ? "pack" : "getOrCreateOffset") +
+ "(fbBuilder)).toList());\n";
+ }
+ break;
+ default:
+ code +=
+ GenType(field.value.type.VectorType()) + "(" + field_name + "!";
+ if (field.value.type.enum_def) {
+ code += ".map((f) => f.value).toList()";
+ }
+ code += ");\n";
+ }
+ } else if (IsString(field.value.type)) {
+ code += " = " + field_name + " == null ? null\n";
+ code += " : fbBuilder.writeString(" + field_name + "!);\n";
+ } else {
+ code += " = " + field_name + "?." +
+ (pack ? "pack" : "getOrCreateOffset") + "(fbBuilder);\n";
+ }
+ }
+
+ if (struct_def.fixed) {
+ code += StructObjectBuilderBody(non_deprecated_fields, prependUnderscore,
+ pack);
+ } else {
+ code += TableObjectBuilderBody(struct_def, non_deprecated_fields,
+ prependUnderscore, pack);
+ }
+ return code;
+ }
+
+ std::string StructObjectBuilderBody(
+ const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
+ bool prependUnderscore = true, bool pack = false) {
+ std::string code;
for (auto it = non_deprecated_fields.rbegin();
it != non_deprecated_fields.rend(); ++it) {
@@ -877,24 +1082,27 @@
if (IsStruct(field.value.type)) {
code += " ";
if (prependUnderscore) { code += "_"; }
- code += field.name + ".finish(fbBuilder);\n";
+ code += field.name + (pack ? ".pack" : ".finish") + "(fbBuilder);\n";
} else {
code += " fbBuilder.put" + GenType(field.value.type) + "(";
if (prependUnderscore) { code += "_"; }
code += field.name;
- if (field.value.type.enum_def) { code += "?.value"; }
+ if (field.value.type.enum_def) { code += ".value"; }
code += ");\n";
}
}
code += " return fbBuilder.offset;\n";
+ return code;
}
- void TableObjectBuilderBody(
- std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
- std::string *code_ptr, bool prependUnderscore = true) {
- std::string &code = *code_ptr;
- code += " fbBuilder.startTable();\n";
+ std::string TableObjectBuilderBody(
+ const StructDef &struct_def,
+ const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
+ bool prependUnderscore = true, bool pack = false) {
+ std::string code;
+ code += " fbBuilder.startTable(" +
+ NumToString(struct_def.fields.vec.size()) + ");\n";
for (auto it = non_deprecated_fields.begin();
it != non_deprecated_fields.end(); ++it) {
@@ -902,29 +1110,29 @@
auto &field = *pair.second;
auto offset = pair.first;
+ std::string field_name = (prependUnderscore ? "_" : "") +
+ ConvertCase(field.name, Case::kLowerCamel);
+
if (IsScalar(field.value.type.base_type)) {
code += " fbBuilder.add" + GenType(field.value.type) + "(" +
- NumToString(offset) + ", ";
- if (prependUnderscore) { code += "_"; }
- code += MakeCamel(field.name, false);
- if (field.value.type.enum_def) { code += "?.value"; }
+ NumToString(offset) + ", " + field_name;
+ if (field.value.type.enum_def) {
+ bool isNullable = getDefaultValue(field.value).empty();
+ code += (isNullable || !pack) ? "?.value" : ".value";
+ }
code += ");\n";
} else if (IsStruct(field.value.type)) {
- code += " if (";
- if (prependUnderscore) { code += "_"; }
- code += MakeCamel(field.name, false) + " != null) {\n";
- code += " fbBuilder.addStruct(" + NumToString(offset) + ", ";
- code += "_" + MakeCamel(field.name, false) + ".finish(fbBuilder));\n";
+ code += " if (" + field_name + " != null) {\n";
+ code += " fbBuilder.addStruct(" + NumToString(offset) + ", " +
+ field_name + (pack ? "!.pack" : "!.finish") + "(fbBuilder));\n";
code += " }\n";
} else {
- code +=
- " if (" + MakeCamel(field.name, false) + "Offset != null) {\n";
- code += " fbBuilder.addOffset(" + NumToString(offset) + ", " +
- MakeCamel(field.name, false) + "Offset);\n";
- code += " }\n";
+ code += " fbBuilder.addOffset(" + NumToString(offset) + ", " +
+ ConvertCase(field.name, Case::kLowerCamel) + "Offset);\n";
}
}
code += " return fbBuilder.endTable();\n";
+ return code;
}
};
} // namespace dart
@@ -937,8 +1145,6 @@
std::string DartMakeRule(const Parser &parser, const std::string &path,
const std::string &file_name) {
- assert(parser.opts.lang <= IDLOptions::kMAX);
-
auto filebase =
flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
dart::DartGenerator generator(parser, path, file_name);
diff --git a/third_party/flatbuffers/src/idl_gen_fbs.cpp b/third_party/flatbuffers/src/idl_gen_fbs.cpp
index e6c8a4a..35c1a7d 100644
--- a/third_party/flatbuffers/src/idl_gen_fbs.cpp
+++ b/third_party/flatbuffers/src/idl_gen_fbs.cpp
@@ -136,7 +136,7 @@
GenComment(field.doc_comment, &schema, nullptr, " ");
schema += " " + field.name + ":" + GenType(field.value.type);
if (field.value.constant != "0") schema += " = " + field.value.constant;
- if (field.required) schema += " (required)";
+ if (field.IsRequired()) schema += " (required)";
schema += ";\n";
}
}
diff --git a/third_party/flatbuffers/src/idl_gen_go.cpp b/third_party/flatbuffers/src/idl_gen_go.cpp
index 68cc01f..306a022 100644
--- a/third_party/flatbuffers/src/idl_gen_go.cpp
+++ b/third_party/flatbuffers/src/idl_gen_go.cpp
@@ -23,6 +23,7 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
+#include "namer.h"
#ifdef _WIN32
# include <direct.h>
@@ -38,20 +39,39 @@
namespace go {
// see https://golang.org/ref/spec#Keywords
-static const char *const g_golang_keywords[] = {
- "break", "default", "func", "interface", "select", "case", "defer",
- "go", "map", "struct", "chan", "else", "goto", "package",
- "switch", "const", "fallthrough", "if", "range", "type", "continue",
- "for", "import", "return", "var",
-};
+std::set<std::string> GoKeywords() {
+ return {
+ "break", "default", "func", "interface", "select",
+ "case", "defer", "go", "map", "struct",
+ "chan", "else", "goto", "package", "switch",
+ "const", "fallthrough", "if", "range", "type",
+ "continue", "for", "import", "return", "var",
+ };
+}
-static std::string GoIdentity(const std::string &name) {
- for (size_t i = 0;
- i < sizeof(g_golang_keywords) / sizeof(g_golang_keywords[0]); i++) {
- if (name == g_golang_keywords[i]) { return MakeCamel(name + "_", false); }
- }
-
- return MakeCamel(name, false);
+Namer::Config GoDefaultConfig() {
+ // Note that the functions with user defined types in the name use
+ // upper camel case for all but the user defined type itself, which is keep
+ // cased. Despite being a function, we interpret it as a Type.
+ return { /*types=*/Case::kKeep,
+ /*constants=*/Case::kUnknown,
+ /*methods=*/Case::kUpperCamel,
+ /*functions=*/Case::kUpperCamel,
+ /*fields=*/Case::kUpperCamel,
+ /*variables=*/Case::kLowerCamel,
+ /*variants=*/Case::kKeep,
+ /*enum_variant_seperator=*/"", // I.e. Concatenate.
+ /*namespaces=*/Case::kKeep,
+ /*namespace_seperator=*/"__",
+ /*object_prefix=*/"",
+ /*object_suffix=*/"T",
+ /*keyword_prefix=*/"",
+ /*keyword_suffix=*/"_",
+ /*filenames=*/Case::kKeep,
+ /*directories=*/Case::kKeep,
+ /*output_path=*/"",
+ /*filename_suffix=*/"",
+ /*filename_extension=*/".go" };
}
class GoGenerator : public BaseGenerator {
@@ -60,7 +80,9 @@
const std::string &file_name, const std::string &go_namespace)
: BaseGenerator(parser, path, file_name, "" /* not used*/,
"" /* not used */, "go"),
- cur_name_space_(nullptr) {
+ cur_name_space_(nullptr),
+ namer_({ GoDefaultConfig().WithFlagOptions(parser.opts, path),
+ GoKeywords() }) {
std::istringstream iss(go_namespace);
std::string component;
while (std::getline(iss, component, '.')) {
@@ -118,6 +140,7 @@
private:
Namespace go_namespace_;
Namespace *cur_name_space_;
+ const Namer namer_;
struct NamespacePtrLess {
bool operator()(const Namespace *a, const Namespace *b) const {
@@ -137,7 +160,7 @@
void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
- code += "type " + struct_def.name + " struct {\n\t";
+ code += "type " + namer_.Type(struct_def.name) + " struct {\n\t";
// _ is reserved in flatbuffers field names, so no chance of name conflict:
code += "_tab ";
@@ -148,7 +171,7 @@
// Construct the name of the type for this enum.
std::string GetEnumTypeName(const EnumDef &enum_def) {
return WrapInNameSpaceAndTrack(enum_def.defined_namespace,
- GoIdentity(enum_def.name));
+ namer_.Type(enum_def.name));
}
// Create a type for the enum values.
@@ -169,8 +192,7 @@
size_t max_name_length, std::string *code_ptr) {
std::string &code = *code_ptr;
code += "\t";
- code += enum_def.name;
- code += ev.name;
+ code += namer_.EnumVariant(enum_def.name, ev.name);
code += " ";
code += std::string(max_name_length - ev.name.length(), ' ');
code += GetEnumTypeName(enum_def);
@@ -197,8 +219,7 @@
size_t max_name_length, std::string *code_ptr) {
std::string &code = *code_ptr;
code += "\t";
- code += enum_def.name;
- code += ev.name;
+ code += namer_.EnumVariant(enum_def.name, ev.name);
code += ": ";
code += std::string(max_name_length - ev.name.length(), ' ');
code += "\"";
@@ -215,8 +236,9 @@
// Generate String() method on enum type.
void EnumStringer(const EnumDef &enum_def, std::string *code_ptr) {
std::string &code = *code_ptr;
- code += "func (v " + enum_def.name + ") String() string {\n";
- code += "\tif s, ok := EnumNames" + enum_def.name + "[v]; ok {\n";
+ const std::string enum_type = namer_.Type(enum_def.name);
+ code += "func (v " + enum_type + ") String() string {\n";
+ code += "\tif s, ok := EnumNames" + enum_type + "[v]; ok {\n";
code += "\t\treturn s\n";
code += "\t}\n";
code += "\treturn \"" + enum_def.name;
@@ -228,7 +250,7 @@
void BeginEnumValues(const EnumDef &enum_def, std::string *code_ptr) {
std::string &code = *code_ptr;
code += "var EnumValues";
- code += enum_def.name;
+ code += namer_.Type(enum_def.name);
code += " = map[string]" + GetEnumTypeName(enum_def) + "{\n";
}
@@ -240,8 +262,7 @@
code += ev.name;
code += "\": ";
code += std::string(max_name_length - ev.name.length(), ' ');
- code += enum_def.name;
- code += ev.name;
+ code += namer_.EnumVariant(enum_def.name, ev.name);
code += ",\n";
}
@@ -255,20 +276,22 @@
void NewRootTypeFromBuffer(const StructDef &struct_def,
std::string *code_ptr) {
std::string &code = *code_ptr;
- std::string size_prefix[] = { "", "SizePrefixed" };
+ const std::string size_prefix[] = { "", "SizePrefixed" };
+ const std::string struct_type = namer_.Type(struct_def.name);
for (int i = 0; i < 2; i++) {
- code += "func Get" + size_prefix[i] + "RootAs";
- code += struct_def.name;
+ code += "func Get" + size_prefix[i] + "RootAs" + struct_type;
code += "(buf []byte, offset flatbuffers.UOffsetT) ";
- code += "*" + struct_def.name + "";
+ code += "*" + struct_type + "";
code += " {\n";
if (i == 0) {
code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n";
} else {
- code += "\tn := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])\n";
+ code +=
+ "\tn := "
+ "flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])\n";
}
- code += "\tx := &" + struct_def.name + "{}\n";
+ code += "\tx := &" + struct_type + "{}\n";
if (i == 0) {
code += "\tx.Init(buf, n+offset)\n";
} else {
@@ -313,7 +336,7 @@
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += " " + MakeCamel(field.name) + "Length(";
+ code += " " + namer_.Function(field.name) + "Length(";
code += ") int " + OffsetPrefix(field);
code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n";
code += "\treturn 0\n}\n\n";
@@ -325,7 +348,7 @@
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += " " + MakeCamel(field.name) + "Bytes(";
+ code += " " + namer_.Function(field.name) + "Bytes(";
code += ") []byte " + OffsetPrefix(field);
code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n";
code += "\treturn nil\n}\n\n";
@@ -337,7 +360,7 @@
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
- code += " " + MakeCamel(field.name);
+ code += " " + namer_.Function(field.name);
code += "() " + TypeName(field) + " {\n";
code += "\treturn " +
CastToEnum(field.value.type,
@@ -352,10 +375,18 @@
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
- code += " " + MakeCamel(field.name);
+ code += " " + namer_.Function(field.name);
code += "() " + TypeName(field) + " ";
- code += OffsetPrefix(field) + "\t\treturn ";
+ code += OffsetPrefix(field);
+ if (field.IsScalarOptional()) {
+ code += "\t\tv := ";
+ } else {
+ code += "\t\treturn ";
+ }
code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)");
+ if (field.IsScalarOptional()) {
+ code += "\n\t\treturn &v";
+ }
code += "\n\t}\n";
code += "\treturn " + GenConstant(field) + "\n";
code += "}\n\n";
@@ -367,7 +398,7 @@
const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += " " + MakeCamel(field.name);
+ code += " " + namer_.Function(field.name);
code += "(obj *" + TypeName(field);
code += ") *" + TypeName(field);
code += " {\n";
@@ -386,7 +417,7 @@
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += " " + MakeCamel(field.name);
+ code += " " + namer_.Function(field.name);
code += "(obj *";
code += TypeName(field);
code += ") *" + TypeName(field) + " " + OffsetPrefix(field);
@@ -408,7 +439,7 @@
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += " " + MakeCamel(field.name);
+ code += " " + namer_.Function(field.name);
code += "() " + TypeName(field) + " ";
code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type);
code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n";
@@ -420,7 +451,7 @@
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += " " + MakeCamel(field.name) + "(";
+ code += " " + namer_.Function(field.name) + "(";
code += "obj " + GenTypePointer(field.value.type) + ") bool ";
code += OffsetPrefix(field);
code += "\t\t" + GenGetter(field.value.type);
@@ -436,7 +467,7 @@
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
- code += " " + MakeCamel(field.name);
+ code += " " + namer_.Function(field.name);
code += "(obj *" + TypeName(field);
code += ", j int) bool " + OffsetPrefix(field);
code += "\t\tx := rcv._tab.Vector(o)\n";
@@ -459,7 +490,7 @@
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
- code += " " + MakeCamel(field.name);
+ code += " " + namer_.Function(field.name);
code += "(j int) " + TypeName(field) + " ";
code += OffsetPrefix(field);
code += "\t\ta := rcv._tab.Vector(o)\n";
@@ -507,7 +538,7 @@
} else {
std::string &code = *code_ptr;
code += std::string(", ") + nameprefix;
- code += GoIdentity(field.name);
+ code += namer_.Variable(field.name);
code += " " + TypeName(field);
}
}
@@ -537,7 +568,7 @@
} else {
code += "\tbuilder.Prepend" + GenMethod(field) + "(";
code += CastToBaseType(field.value.type,
- nameprefix + GoIdentity(field.name)) +
+ nameprefix + namer_.Variable(field.name)) +
")\n";
}
}
@@ -552,7 +583,7 @@
// Get the value of a table's starting offset.
void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
- code += "func " + struct_def.name + "Start";
+ code += "func " + namer_.Type(struct_def.name) + "Start";
code += "(builder *flatbuffers.Builder) {\n";
code += "\tbuilder.StartObject(";
code += NumToString(struct_def.fields.vec.size());
@@ -563,35 +594,46 @@
void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
const size_t offset, std::string *code_ptr) {
std::string &code = *code_ptr;
- code += "func " + struct_def.name + "Add" + MakeCamel(field.name);
+ const std::string field_var = namer_.Variable(field.name);
+ code += "func " + namer_.Type(struct_def.name) + "Add" +
+ namer_.Function(field.name);
code += "(builder *flatbuffers.Builder, ";
- code += GoIdentity(field.name) + " ";
+ code += field_var + " ";
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
code += "flatbuffers.UOffsetT";
} else {
- code += TypeName(field);
+ code += GenTypeGet(field.value.type);
}
- code += ") {\n";
- code += "\tbuilder.Prepend";
- code += GenMethod(field) + "Slot(";
- code += NumToString(offset) + ", ";
- if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
- code += "flatbuffers.UOffsetT";
+ code += ") {\n\t";
+ code += "builder.Prepend";
+ code += GenMethod(field);
+ if (field.IsScalarOptional()) {
code += "(";
- code += GoIdentity(field.name) + ")";
} else {
- code += CastToBaseType(field.value.type, GoIdentity(field.name));
+ code += "Slot(" + NumToString(offset) + ", ";
}
- code += ", " + GenConstant(field);
- code += ")\n}\n";
+ if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+ code += "flatbuffers.UOffsetT";
+ code += "(" + field_var + ")";
+ } else {
+ code += CastToBaseType(field.value.type, field_var);
+ }
+ if (field.IsScalarOptional()) {
+ code += ")\n";
+ code += "\tbuilder.Slot(" + NumToString(offset);
+ } else {
+ code += ", " + GenConstant(field);
+ }
+ code += ")\n";
+ code += "}\n";
}
// Set the value of one of the members of a table's vector.
void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
- code += "func " + struct_def.name + "Start";
- code += MakeCamel(field.name);
+ code += "func " + namer_.Type(struct_def.name) + "Start";
+ code += namer_.Function(field.name);
code += "Vector(builder *flatbuffers.Builder, numElems int) ";
code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector(";
auto vector_type = field.value.type.VectorType();
@@ -605,7 +647,7 @@
// Get the offset of the end of a table.
void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
- code += "func " + struct_def.name + "End";
+ code += "func " + namer_.Type(struct_def.name) + "End";
code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT ";
code += "{\n\treturn builder.EndObject()\n}\n";
}
@@ -613,7 +655,7 @@
// Generate the receiver for function signatures.
void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
- code += "func (rcv *" + struct_def.name + ")";
+ code += "func (rcv *" + namer_.Type(struct_def.name) + ")";
}
// Generate a struct field getter, conditioned on its child type(s).
@@ -663,11 +705,11 @@
void MutateScalarFieldOfStruct(const StructDef &struct_def,
const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
- std::string type = MakeCamel(GenTypeBasic(field.value.type));
- std::string setter = "rcv._tab.Mutate" + type;
+ std::string setter =
+ "rcv._tab.Mutate" + namer_.Method(GenTypeBasic(field.value.type));
GenReceiver(struct_def, code_ptr);
- code += " Mutate" + MakeCamel(field.name);
- code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter;
+ code += " Mutate" + namer_.Function(field.name);
+ code += "(n " + GenTypeGet(field.value.type) + ") bool {\n\treturn " + setter;
code += "(rcv._tab.Pos+flatbuffers.UOffsetT(";
code += NumToString(field.value.offset) + "), ";
code += CastToBaseType(field.value.type, "n") + ")\n}\n\n";
@@ -677,11 +719,11 @@
void MutateScalarFieldOfTable(const StructDef &struct_def,
const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
- std::string type = MakeCamel(GenTypeBasic(field.value.type));
- std::string setter = "rcv._tab.Mutate" + type + "Slot";
+ std::string setter = "rcv._tab.Mutate" +
+ namer_.Method(GenTypeBasic(field.value.type)) + "Slot";
GenReceiver(struct_def, code_ptr);
- code += " Mutate" + MakeCamel(field.name);
- code += "(n " + TypeName(field) + ") bool {\n\treturn ";
+ code += " Mutate" + namer_.Function(field.name);
+ code += "(n " + GenTypeGet(field.value.type) + ") bool {\n\treturn ";
code += setter + "(" + NumToString(field.value.offset) + ", ";
code += CastToBaseType(field.value.type, "n") + ")\n";
code += "}\n\n";
@@ -693,10 +735,10 @@
std::string *code_ptr) {
std::string &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
- std::string type = MakeCamel(GenTypeBasic(vectortype));
- std::string setter = "rcv._tab.Mutate" + type;
+ std::string setter =
+ "rcv._tab.Mutate" + namer_.Method(GenTypeBasic(vectortype));
GenReceiver(struct_def, code_ptr);
- code += " Mutate" + MakeCamel(field.name);
+ code += " Mutate" + namer_.Function(field.name);
code += "(j int, n " + TypeName(field) + ") bool ";
code += OffsetPrefix(field);
code += "\t\ta := rcv._tab.Vector(o)\n";
@@ -799,8 +841,11 @@
field.value.type.enum_def != nullptr &&
field.value.type.enum_def->is_union)
continue;
- code += "\t" + MakeCamel(field.name) + " " +
- NativeType(field.value.type) + "\n";
+ code += "\t" + namer_.Field(field.name) + " ";
+ if (field.IsScalarOptional()) {
+ code += "*";
+ }
+ code += NativeType(field.value.type) + "\n";
}
code += "}\n\n";
@@ -816,7 +861,7 @@
void GenNativeUnion(const EnumDef &enum_def, std::string *code_ptr) {
std::string &code = *code_ptr;
code += "type " + NativeName(enum_def) + " struct {\n";
- code += "\tType " + enum_def.name + "\n";
+ code += "\tType " + namer_.Type(enum_def.name) + "\n";
code += "\tValue interface{}\n";
code += "}\n\n";
}
@@ -832,7 +877,7 @@
++it2) {
const EnumVal &ev = **it2;
if (ev.IsZero()) continue;
- code += "\tcase " + enum_def.name + ev.name + ":\n";
+ code += "\tcase " + namer_.EnumVariant(enum_def.name, ev.name) + ":\n";
code += "\t\treturn t.Value.(" + NativeType(ev.union_type) +
").Pack(builder)\n";
}
@@ -844,7 +889,7 @@
void GenNativeUnionUnPack(const EnumDef &enum_def, std::string *code_ptr) {
std::string &code = *code_ptr;
- code += "func (rcv " + enum_def.name +
+ code += "func (rcv " + namer_.Type(enum_def.name) +
") UnPack(table flatbuffers.Table) *" + NativeName(enum_def) +
" {\n";
code += "\tswitch rcv {\n";
@@ -853,13 +898,14 @@
++it2) {
const EnumVal &ev = **it2;
if (ev.IsZero()) continue;
- code += "\tcase " + enum_def.name + ev.name + ":\n";
+ code += "\tcase " + namer_.EnumVariant(enum_def.name, ev.name) + ":\n";
code += "\t\tx := " + ev.union_type.struct_def->name + "{_tab: table}\n";
code += "\t\treturn &" +
WrapInNameSpaceAndTrack(enum_def.defined_namespace,
NativeName(enum_def)) +
- "{ Type: " + enum_def.name + ev.name + ", Value: x.UnPack() }\n";
+ "{ Type: " + namer_.EnumVariant(enum_def.name, ev.name) +
+ ", Value: x.UnPack() }\n";
}
code += "\t}\n";
code += "\treturn nil\n";
@@ -868,6 +914,7 @@
void GenNativeTablePack(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
+ const std::string struct_type = namer_.Type(struct_def.name);
code += "func (t *" + NativeName(struct_def) +
") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
@@ -878,53 +925,56 @@
if (field.deprecated) continue;
if (IsScalar(field.value.type.base_type)) continue;
- std::string offset = MakeCamel(field.name, false) + "Offset";
+ const std::string field_field = namer_.Field(field.name);
+ const std::string field_var = namer_.Variable(field.name);
+ const std::string offset = field_var + "Offset";
if (IsString(field.value.type)) {
- code += "\t" + offset + " := builder.CreateString(t." +
- MakeCamel(field.name) + ")\n";
+ code +=
+ "\t" + offset + " := builder.CreateString(t." + field_field + ")\n";
} else if (IsVector(field.value.type) &&
field.value.type.element == BASE_TYPE_UCHAR &&
field.value.type.enum_def == nullptr) {
code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
- code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
+ code += "\tif t." + field_field + " != nil {\n";
code += "\t\t" + offset + " = builder.CreateByteString(t." +
- MakeCamel(field.name) + ")\n";
+ field_field + ")\n";
code += "\t}\n";
} else if (IsVector(field.value.type)) {
code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
- code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
- std::string length = MakeCamel(field.name, false) + "Length";
- std::string offsets = MakeCamel(field.name, false) + "Offsets";
- code += "\t\t" + length + " := len(t." + MakeCamel(field.name) + ")\n";
+ code += "\tif t." + field_field + " != nil {\n";
+ std::string length = field_var + "Length";
+ std::string offsets = field_var + "Offsets";
+ code += "\t\t" + length + " := len(t." + field_field + ")\n";
if (field.value.type.element == BASE_TYPE_STRING) {
code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
length + ")\n";
code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
code += "\t\t\t" + offsets + "[j] = builder.CreateString(t." +
- MakeCamel(field.name) + "[j])\n";
+ field_field + "[j])\n";
code += "\t\t}\n";
} else if (field.value.type.element == BASE_TYPE_STRUCT &&
!field.value.type.struct_def->fixed) {
code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
length + ")\n";
code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
- code += "\t\t\t" + offsets + "[j] = t." + MakeCamel(field.name) +
+ code += "\t\t\t" + offsets + "[j] = t." + field_field +
"[j].Pack(builder)\n";
code += "\t\t}\n";
}
- code += "\t\t" + struct_def.name + "Start" + MakeCamel(field.name) +
+ code += "\t\t" + struct_type + "Start" + namer_.Function(field.name) +
"Vector(builder, " + length + ")\n";
code += "\t\tfor j := " + length + " - 1; j >= 0; j-- {\n";
if (IsScalar(field.value.type.element)) {
code += "\t\t\tbuilder.Prepend" +
- MakeCamel(GenTypeBasic(field.value.type.VectorType())) + "(" +
+ namer_.Method(GenTypeBasic(field.value.type.VectorType())) +
+ "(" +
CastToBaseType(field.value.type.VectorType(),
- "t." + MakeCamel(field.name) + "[j]") +
+ "t." + field_field + "[j]") +
")\n";
} else if (field.value.type.element == BASE_TYPE_STRUCT &&
field.value.type.struct_def->fixed) {
- code += "\t\t\tt." + MakeCamel(field.name) + "[j].Pack(builder)\n";
+ code += "\t\t\tt." + field_field + "[j].Pack(builder)\n";
} else {
code += "\t\t\tbuilder.PrependUOffsetT(" + offsets + "[j])\n";
}
@@ -933,90 +983,98 @@
code += "\t}\n";
} else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
if (field.value.type.struct_def->fixed) continue;
- code += "\t" + offset + " := t." + MakeCamel(field.name) +
- ".Pack(builder)\n";
+ code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n";
} else if (field.value.type.base_type == BASE_TYPE_UNION) {
- code += "\t" + offset + " := t." + MakeCamel(field.name) +
- ".Pack(builder)\n";
+ code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n";
code += "\t\n";
} else {
FLATBUFFERS_ASSERT(0);
}
}
- code += "\t" + struct_def.name + "Start(builder)\n";
+ code += "\t" + struct_type + "Start(builder)\n";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const FieldDef &field = **it;
if (field.deprecated) continue;
+ const std::string field_field = namer_.Field(field.name);
+ const std::string field_fn = namer_.Function(field.name);
+ const std::string offset = namer_.Variable(field.name) + "Offset";
- std::string offset = MakeCamel(field.name, false) + "Offset";
if (IsScalar(field.value.type.base_type)) {
+ std::string prefix;
+ if (field.IsScalarOptional()) {
+ code += "\tif t." + field_field + " != nil {\n\t";
+ prefix = "*";
+ }
if (field.value.type.enum_def == nullptr ||
!field.value.type.enum_def->is_union) {
- code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
- "(builder, t." + MakeCamel(field.name) + ")\n";
+ code += "\t" + struct_type + "Add" + field_fn + "(builder, " +
+ prefix + "t." + field_field + ")\n";
+ }
+ if (field.IsScalarOptional()) {
+ code += "\t}\n";
}
} else {
if (field.value.type.base_type == BASE_TYPE_STRUCT &&
field.value.type.struct_def->fixed) {
- code += "\t" + offset + " := t." + MakeCamel(field.name) +
- ".Pack(builder)\n";
+ code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n";
} else if (field.value.type.enum_def != nullptr &&
field.value.type.enum_def->is_union) {
- code += "\tif t." + MakeCamel(field.name) + " != nil {\n";
- code += "\t\t" + struct_def.name + "Add" +
- MakeCamel(field.name + UnionTypeFieldSuffix()) +
- "(builder, t." + MakeCamel(field.name) + ".Type)\n";
+ code += "\tif t." + field_field + " != nil {\n";
+ code += "\t\t" + struct_type + "Add" +
+ namer_.Method(field.name + UnionTypeFieldSuffix()) +
+ "(builder, t." + field_field + ".Type)\n";
code += "\t}\n";
}
- code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
- "(builder, " + offset + ")\n";
+ code += "\t" + struct_type + "Add" + field_fn + "(builder, " + offset +
+ ")\n";
}
}
- code += "\treturn " + struct_def.name + "End(builder)\n";
+ code += "\treturn " + struct_type + "End(builder)\n";
code += "}\n\n";
}
void GenNativeTableUnPack(const StructDef &struct_def,
std::string *code_ptr) {
std::string &code = *code_ptr;
+ const std::string struct_type = namer_.Type(struct_def.name);
- code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" +
+ code += "func (rcv *" + struct_type + ") UnPackTo(t *" +
NativeName(struct_def) + ") {\n";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const FieldDef &field = **it;
if (field.deprecated) continue;
- std::string field_name_camel = MakeCamel(field.name);
- std::string length = MakeCamel(field.name, false) + "Length";
+ const std::string field_field = namer_.Field(field.name);
+ const std::string field_var = namer_.Variable(field.name);
+ const std::string length = field_var + "Length";
if (IsScalar(field.value.type.base_type)) {
if (field.value.type.enum_def != nullptr &&
field.value.type.enum_def->is_union)
continue;
- code +=
- "\tt." + field_name_camel + " = rcv." + field_name_camel + "()\n";
+ code += "\tt." + field_field + " = rcv." + field_field + "()\n";
} else if (IsString(field.value.type)) {
- code += "\tt." + field_name_camel + " = string(rcv." +
- field_name_camel + "())\n";
+ code += "\tt." + field_field + " = string(rcv." + field_field + "())\n";
} else if (IsVector(field.value.type) &&
field.value.type.element == BASE_TYPE_UCHAR &&
field.value.type.enum_def == nullptr) {
- code += "\tt." + field_name_camel + " = rcv." + field_name_camel +
- "Bytes()\n";
+ code += "\tt." + field_field + " = rcv." + field_field + "Bytes()\n";
} else if (IsVector(field.value.type)) {
- code += "\t" + length + " := rcv." + field_name_camel + "Length()\n";
- code += "\tt." + field_name_camel + " = make(" +
+ code += "\t" + length + " := rcv." + field_field + "Length()\n";
+ code += "\tt." + field_field + " = make(" +
NativeType(field.value.type) + ", " + length + ")\n";
code += "\tfor j := 0; j < " + length + "; j++ {\n";
if (field.value.type.element == BASE_TYPE_STRUCT) {
- code += "\t\tx := " + field.value.type.struct_def->name + "{}\n";
- code += "\t\trcv." + field_name_camel + "(&x, j)\n";
+ code += "\t\tx := " +
+ WrapInNameSpaceAndTrack(*field.value.type.struct_def) +
+ "{}\n";
+ code += "\t\trcv." + field_field + "(&x, j)\n";
}
- code += "\t\tt." + field_name_camel + "[j] = ";
+ code += "\t\tt." + field_field + "[j] = ";
if (IsScalar(field.value.type.element)) {
- code += "rcv." + field_name_camel + "(j)";
+ code += "rcv." + field_field + "(j)";
} else if (field.value.type.element == BASE_TYPE_STRING) {
- code += "string(rcv." + field_name_camel + "(j))";
+ code += "string(rcv." + field_field + "(j))";
} else if (field.value.type.element == BASE_TYPE_STRUCT) {
code += "x.UnPack()";
} else {
@@ -1026,16 +1084,16 @@
code += "\n";
code += "\t}\n";
} else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
- code += "\tt." + field_name_camel + " = rcv." + field_name_camel +
- "(nil).UnPack()\n";
- } else if (field.value.type.base_type == BASE_TYPE_UNION) {
- std::string field_table = MakeCamel(field.name, false) + "Table";
- code += "\t" + field_table + " := flatbuffers.Table{}\n";
code +=
- "\tif rcv." + MakeCamel(field.name) + "(&" + field_table + ") {\n";
- code += "\t\tt." + field_name_camel + " = rcv." +
- MakeCamel(field.name + UnionTypeFieldSuffix()) + "().UnPack(" +
- field_table + ")\n";
+ "\tt." + field_field + " = rcv." + field_field + "(nil).UnPack()\n";
+ } else if (field.value.type.base_type == BASE_TYPE_UNION) {
+ const std::string field_table = field_var + "Table";
+ code += "\t" + field_table + " := flatbuffers.Table{}\n";
+ code += "\tif rcv." + namer_.Method(field.name) + "(&" + field_table +
+ ") {\n";
+ code += "\t\tt." + field_field + " = rcv." +
+ namer_.Method(field.name + UnionTypeFieldSuffix()) +
+ "().UnPack(" + field_table + ")\n";
code += "\t}\n";
} else {
FLATBUFFERS_ASSERT(0);
@@ -1043,7 +1101,7 @@
}
code += "}\n\n";
- code += "func (rcv *" + struct_def.name + ") UnPack() *" +
+ code += "func (rcv *" + struct_type + ") UnPack() *" +
NativeName(struct_def) + " {\n";
code += "\tif rcv == nil { return nil }\n";
code += "\tt := &" + NativeName(struct_def) + "{}\n";
@@ -1058,7 +1116,7 @@
code += "func (t *" + NativeName(struct_def) +
") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
code += "\tif t == nil { return 0 }\n";
- code += "\treturn Create" + struct_def.name + "(builder";
+ code += "\treturn Create" + namer_.Type(struct_def.name) + "(builder";
StructPackArgs(struct_def, "", code_ptr);
code += ")\n";
code += "}\n";
@@ -1072,10 +1130,10 @@
const FieldDef &field = **it;
if (field.value.type.base_type == BASE_TYPE_STRUCT) {
StructPackArgs(*field.value.type.struct_def,
- (nameprefix + MakeCamel(field.name) + ".").c_str(),
+ (nameprefix + namer_.Field(field.name) + ".").c_str(),
code_ptr);
} else {
- code += std::string(", t.") + nameprefix + MakeCamel(field.name);
+ code += std::string(", t.") + nameprefix + namer_.Field(field.name);
}
}
}
@@ -1084,22 +1142,22 @@
std::string *code_ptr) {
std::string &code = *code_ptr;
- code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" +
+ code += "func (rcv *" + namer_.Type(struct_def.name) + ") UnPackTo(t *" +
NativeName(struct_def) + ") {\n";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const FieldDef &field = **it;
if (field.value.type.base_type == BASE_TYPE_STRUCT) {
- code += "\tt." + MakeCamel(field.name) + " = rcv." +
- MakeCamel(field.name) + "(nil).UnPack()\n";
+ code += "\tt." + namer_.Field(field.name) + " = rcv." +
+ namer_.Method(field.name) + "(nil).UnPack()\n";
} else {
- code += "\tt." + MakeCamel(field.name) + " = rcv." +
- MakeCamel(field.name) + "()\n";
+ code += "\tt." + namer_.Field(field.name) + " = rcv." +
+ namer_.Method(field.name) + "()\n";
}
}
code += "}\n\n";
- code += "func (rcv *" + struct_def.name + ") UnPack() *" +
+ code += "func (rcv *" + namer_.Type(struct_def.name) + ") UnPack() *" +
NativeName(struct_def) + " {\n";
code += "\tif rcv == nil { return nil }\n";
code += "\tt := &" + NativeName(struct_def) + "{}\n";
@@ -1148,14 +1206,14 @@
case BASE_TYPE_STRING: return "rcv._tab.ByteVector";
case BASE_TYPE_UNION: return "rcv._tab.Union";
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
- default: return "rcv._tab.Get" + MakeCamel(GenTypeBasic(type));
+ default: return "rcv._tab.Get" + namer_.Function(GenTypeBasic(type));
}
}
// Returns the method name for use with add/put calls.
std::string GenMethod(const FieldDef &field) {
return IsScalar(field.value.type.base_type)
- ? MakeCamel(GenTypeBasic(field.value.type))
+ ? namer_.Method(GenTypeBasic(field.value.type))
: (IsStruct(field.value.type) ? "Struct" : "UOffsetT");
}
@@ -1188,7 +1246,11 @@
}
std::string TypeName(const FieldDef &field) {
- return GenTypeGet(field.value.type);
+ std::string prefix;
+ if (field.IsScalarOptional()) {
+ prefix = "*";
+ }
+ return prefix + GenTypeGet(field.value.type);
}
// If type is an enum, returns value with a cast to the enum type, otherwise
@@ -1212,6 +1274,9 @@
}
std::string GenConstant(const FieldDef &field) {
+ if (field.IsScalarOptional()) {
+ return "nil";
+ }
switch (field.value.type.base_type) {
case BASE_TYPE_BOOL:
return field.value.constant == "0" ? "false" : "true";
@@ -1219,14 +1284,12 @@
}
}
- std::string NativeName(const StructDef &struct_def) {
- return parser_.opts.object_prefix + struct_def.name +
- parser_.opts.object_suffix;
+ std::string NativeName(const StructDef &struct_def) const {
+ return namer_.ObjectType(struct_def.name);
}
- std::string NativeName(const EnumDef &enum_def) {
- return parser_.opts.object_prefix + enum_def.name +
- parser_.opts.object_suffix;
+ std::string NativeName(const EnumDef &enum_def) const {
+ return namer_.ObjectType(enum_def.name);
}
std::string NativeType(const Type &type) {
@@ -1303,34 +1366,20 @@
while (code.length() > 2 && code.substr(code.length() - 2) == "\n\n") {
code.pop_back();
}
- std::string filename = NamespaceDir(ns) + def.name + ".go";
+ std::string filename = namer_.Directories(ns.components) +
+ namer_.File(def.name, SkipFile::Suffix);
return SaveFile(filename.c_str(), code, false);
}
// Create the full name of the imported namespace (format: A__B__C).
- std::string NamespaceImportName(const Namespace *ns) {
- std::string s = "";
- for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
- if (s.size() == 0) {
- s += *it;
- } else {
- s += "__" + *it;
- }
- }
- return s;
+ std::string NamespaceImportName(const Namespace *ns) const {
+ return namer_.Namespace(ns->components);
}
// Create the full path for the imported namespace (format: A/B/C).
- std::string NamespaceImportPath(const Namespace *ns) {
- std::string s = "";
- for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
- if (s.size() == 0) {
- s += *it;
- } else {
- s += "/" + *it;
- }
- }
- return s;
+ std::string NamespaceImportPath(const Namespace *ns) const {
+ return namer_.Directories(ns->components,
+ SkipDir::OutputPathAndTrailingPathSeparator);
}
// Ensure that a type is prefixed with its go package import name if it is
@@ -1340,9 +1389,7 @@
if (CurrentNameSpace() == ns) return name;
tracked_imported_namespaces_.insert(ns);
-
- std::string import_name = NamespaceImportName(ns);
- return import_name + "." + name;
+ return NamespaceImportName(ns) + "." + name;
}
std::string WrapInNameSpaceAndTrack(const Definition &def) {
diff --git a/third_party/flatbuffers/src/idl_gen_grpc.cpp b/third_party/flatbuffers/src/idl_gen_grpc.cpp
index 394ebe3..6894ffb 100644
--- a/third_party/flatbuffers/src/idl_gen_grpc.cpp
+++ b/third_party/flatbuffers/src/idl_gen_grpc.cpp
@@ -24,7 +24,6 @@
#include "src/compiler/go_generator.h"
#include "src/compiler/java_generator.h"
#include "src/compiler/python_generator.h"
-#include "src/compiler/python_private_generator.h"
#include "src/compiler/swift_generator.h"
#include "src/compiler/ts_generator.h"
@@ -146,7 +145,12 @@
class FlatBufPrinter : public grpc_generator::Printer {
public:
- FlatBufPrinter(std::string *str) : str_(str), escape_char_('$'), indent_(0) {}
+ FlatBufPrinter(std::string *str, const char indentation_type)
+ : str_(str),
+ escape_char_('$'),
+ indent_(0),
+ indentation_size_(2),
+ indentation_type_(indentation_type) {}
void Print(const std::map<std::string, std::string> &vars,
const char *string_template) {
@@ -173,7 +177,7 @@
// Add this string, but for each part separated by \n, add indentation.
for (;;) {
// Current indentation.
- str_->insert(str_->end(), indent_ * 2, ' ');
+ str_->insert(str_->end(), indent_ * indentation_size_, indentation_type_);
// See if this contains more than one line.
const char *lf = strchr(s, '\n');
if (lf) {
@@ -187,17 +191,24 @@
}
}
+ void SetIndentationSize(const size_t size) {
+ FLATBUFFERS_ASSERT(str_->empty());
+ indentation_size_ = size;
+ }
+
void Indent() { indent_++; }
void Outdent() {
+ FLATBUFFERS_ASSERT(indent_ > 0);
indent_--;
- FLATBUFFERS_ASSERT(indent_ >= 0);
}
private:
std::string *str_;
char escape_char_;
- int indent_;
+ size_t indent_;
+ size_t indentation_size_;
+ char indentation_type_;
};
class FlatBufFile : public grpc_generator::File {
@@ -231,7 +242,9 @@
return StripExtension(file_name_);
}
- std::string message_header_ext() const { return "_generated.h"; }
+ std::string message_header_ext() const {
+ return parser_.opts.filename_suffix + ".h";
+ }
std::string service_header_ext() const { return ".grpc.fb.h"; }
@@ -277,8 +290,9 @@
}
std::unique_ptr<grpc_generator::Printer> CreatePrinter(
- std::string *str) const {
- return std::unique_ptr<grpc_generator::Printer>(new FlatBufPrinter(str));
+ std::string *str, const char indentation_type = ' ') const {
+ return std::unique_ptr<grpc_generator::Printer>(
+ new FlatBufPrinter(str, indentation_type));
}
private:
@@ -399,6 +413,45 @@
return JavaGRPCGenerator(parser, path, file_name).generate();
}
+class PythonGRPCGenerator : public flatbuffers::BaseGenerator {
+ private:
+ CodeWriter code_;
+
+ public:
+ PythonGRPCGenerator(const Parser &parser, const std::string &filename)
+ : BaseGenerator(parser, "", filename, "", "" /*Unused*/, "swift") {}
+
+ bool generate() {
+ code_.Clear();
+ code_ +=
+ "# Generated by the gRPC Python protocol compiler plugin. "
+ "DO NOT EDIT!\n";
+ code_ += "import grpc\n";
+
+ FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguagePython);
+
+ for (int i = 0; i < file.service_count(); i++) {
+ auto service = file.service(i);
+ code_ += grpc_python_generator::Generate(&file, service.get());
+ }
+ const auto final_code = code_.ToString();
+ const auto filename = GenerateFileName();
+ return SaveFile(filename.c_str(), final_code, false);
+ }
+
+ std::string GenerateFileName() {
+ std::string namespace_dir;
+ auto &namespaces = parser_.namespaces_.back()->components;
+ for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+ if (it != namespaces.begin()) namespace_dir += kPathSeparator;
+ namespace_dir += *it;
+ }
+ std::string grpc_py_filename = namespace_dir;
+ if (!namespace_dir.empty()) grpc_py_filename += kPathSeparator;
+ return grpc_py_filename + file_name_ + "_grpc_fb.py";
+ }
+};
+
bool GeneratePythonGRPC(const Parser &parser, const std::string & /*path*/,
const std::string &file_name) {
int nservices = 0;
@@ -408,28 +461,7 @@
}
if (!nservices) return true;
- grpc_python_generator::GeneratorConfiguration config;
- config.grpc_package_root = "grpc";
- config.beta_package_root = "grpc.beta";
- config.import_prefix = "";
-
- FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguagePython);
-
- grpc_python_generator::PrivateGenerator generator(config, &fbfile);
-
- std::string code = generator.GetGrpcServices();
- std::string namespace_dir;
- auto &namespaces = parser.namespaces_.back()->components;
- for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
- if (it != namespaces.begin()) namespace_dir += kPathSeparator;
- namespace_dir += *it;
- }
-
- std::string grpc_py_filename = namespace_dir;
- if (!namespace_dir.empty()) grpc_py_filename += kPathSeparator;
- grpc_py_filename += file_name + "_grpc_fb.py";
-
- return flatbuffers::SaveFile(grpc_py_filename.c_str(), code, false);
+ return PythonGRPCGenerator(parser, file_name).generate();
}
class SwiftGRPCGenerator : public flatbuffers::BaseGenerator {
diff --git a/third_party/flatbuffers/src/idl_gen_java.cpp b/third_party/flatbuffers/src/idl_gen_java.cpp
index c51f7bc..ee09391 100644
--- a/third_party/flatbuffers/src/idl_gen_java.cpp
+++ b/third_party/flatbuffers/src/idl_gen_java.cpp
@@ -21,10 +21,6 @@
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
-#if defined(FLATBUFFERS_CPP98_STL)
-# include <cctype>
-#endif // defined(FLATBUFFERS_CPP98_STL)
-
namespace flatbuffers {
namespace java {
@@ -39,6 +35,11 @@
};
class JavaGenerator : public BaseGenerator {
+ struct FieldArrayLength {
+ std::string name;
+ int length;
+ };
+
public:
JavaGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
@@ -63,6 +64,19 @@
/* needs_includes= */ false))
return false;
}
+
+ if (parser_.opts.generate_object_based_api && enum_def.is_union) {
+ enumcode = "";
+ GenEnum_ObjectAPI(enum_def, &enumcode, parser_.opts);
+ auto class_name = enum_def.name + "Union";
+ if (parser_.opts.one_file) {
+ one_file_code += enumcode;
+ } else {
+ if (!SaveType(class_name, *enum_def.defined_namespace, enumcode,
+ /* needs_includes= */ false))
+ return false;
+ }
+ }
}
for (auto it = parser_.structs_.vec.begin();
@@ -71,7 +85,7 @@
auto &struct_def = **it;
if (!parser_.opts.one_file)
cur_name_space_ = struct_def.defined_namespace;
- GenStruct(struct_def, &declcode);
+ GenStruct(struct_def, &declcode, parser_.opts);
if (parser_.opts.one_file) {
one_file_code += declcode;
} else {
@@ -79,6 +93,19 @@
/* needs_includes= */ true))
return false;
}
+
+ if (parser_.opts.generate_object_based_api) {
+ declcode = "";
+ GenStruct_ObjectAPI(struct_def, &declcode, parser_.opts);
+ auto class_name = GenTypeName_ObjectAPI(struct_def.name, parser_.opts);
+ if (parser_.opts.one_file) {
+ one_file_code += declcode;
+ } else {
+ if (!SaveType(class_name, *struct_def.defined_namespace, declcode,
+ /* needs_includes= */ true))
+ return false;
+ }
+ }
}
if (parser_.opts.one_file) {
@@ -231,11 +258,11 @@
} else {
if (castFromDest) {
if (type.base_type == BASE_TYPE_UINT)
- return "(int)";
+ return "(int) ";
else if (type.base_type == BASE_TYPE_USHORT)
- return "(short)";
+ return "(short) ";
else if (type.base_type == BASE_TYPE_UCHAR)
- return "(byte)";
+ return "(byte) ";
}
}
return "";
@@ -304,6 +331,7 @@
// That, and Java Enums are expensive, and not universally liked.
GenComment(enum_def.doc_comment, code_ptr, &comment_config);
+ code += "@SuppressWarnings(\"unused\")\n";
if (enum_def.attributes.Lookup("private")) {
// For Java, we leave the enum unmarked to indicate package-private
} else {
@@ -316,14 +344,14 @@
auto &ev = **it;
GenComment(ev.doc_comment, code_ptr, &comment_config, " ");
code += " public static final ";
- code += GenTypeBasic(enum_def.underlying_type);
+ code += GenTypeBasic(DestinationType(enum_def.underlying_type, false));
code += " ";
code += ev.name + " = ";
code += enum_def.ToString(ev);
code += ";\n";
}
- // Generate a generate string table for enum values.
+ // Generate a string table for enum values.
// Problem is, if values are very sparse that could generate really big
// tables. Ideally in that case we generate a map lookup instead, but for
// the moment we simply don't output a table at all.
@@ -331,7 +359,9 @@
// Average distance between values above which we consider a table
// "too sparse". Change at will.
static const uint64_t kMaxSparseness = 5;
- if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+ if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness &&
+ GenTypeBasic(DestinationType(enum_def.underlying_type, false)) !=
+ "long") {
code += "\n public static final String";
code += "[] names = { ";
auto val = enum_def.Vals().front();
@@ -345,7 +375,7 @@
code += "};\n\n";
code += " public static ";
code += "String";
- code += " " + MakeCamel("name", false);
+ code += " name";
code += "(int e) { return names[e";
if (enum_def.MinValue()->IsNonZero())
code += " - " + enum_def.MinValue()->name;
@@ -369,7 +399,7 @@
if (type.base_type == BASE_TYPE_BOOL) {
getter = "0!=" + getter;
} else if (GenTypeBasic(type) != "byte") {
- getter += MakeCamel(GenTypeBasic(type));
+ getter += ConvertCase(GenTypeBasic(type), Case::kUpperCamel);
}
return getter;
}
@@ -385,7 +415,7 @@
auto dest_cast = DestinationCast(type);
auto getter = data_buffer + ".get";
if (GenTypeBasic(type) != "byte") {
- getter += MakeCamel(GenTypeBasic(type));
+ getter += ConvertCase(GenTypeBasic(type), Case::kUpperCamel);
}
getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
dest_mask;
@@ -398,7 +428,7 @@
if (IsScalar(type.base_type)) {
std::string setter = "bb.put";
if (GenTypeBasic(type) != "byte" && type.base_type != BASE_TYPE_BOOL) {
- setter += MakeCamel(GenTypeBasic(type));
+ setter += ConvertCase(GenTypeBasic(type), Case::kUpperCamel);
}
return setter;
} else {
@@ -408,8 +438,9 @@
// Returns the method name for use with add/put calls.
std::string GenMethod(const Type &type) const {
- return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type))
- : (IsStruct(type) ? "Struct" : "Offset");
+ return IsScalar(type.base_type)
+ ? ConvertCase(GenTypeBasic(type), Case::kUpperCamel)
+ : (IsStruct(type) ? "Struct" : "Offset");
}
// Recursively generate arguments for a constructor, to deal with nested
@@ -433,11 +464,11 @@
(nameprefix + (field.name + "_")).c_str(), array_cnt);
} else {
code += ", ";
- code += GenTypeBasic(type);
+ code += GenTypeNameDest(field.value.type);
for (size_t i = 0; i < array_cnt; i++) code += "[]";
code += " ";
code += nameprefix;
- code += MakeCamel(field.name, false);
+ code += ConvertCase(field.name, Case::kLowerCamel);
}
}
}
@@ -484,7 +515,8 @@
code += indent + " builder.put";
code += GenMethod(type) + "(";
code += SourceCast(type);
- auto argname = nameprefix + MakeCamel(field.name, false);
+ auto argname =
+ nameprefix + ConvertCase(field.name, Case::kLowerCamel);
code += argname;
size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
for (size_t i = 0; in_array && i < array_cnt; i++) {
@@ -560,7 +592,8 @@
return key_getter;
}
- void GenStruct(StructDef &struct_def, std::string *code_ptr) const {
+ void GenStruct(StructDef &struct_def, std::string *code_ptr,
+ const IDLOptions &opts) const {
if (struct_def.generated) return;
std::string &code = *code_ptr;
@@ -591,7 +624,7 @@
// Force compile time error if not using the same version runtime.
code += " public static void ValidateVersion() {";
code += " Constants.";
- code += "FLATBUFFERS_1_12_0(); ";
+ code += "FLATBUFFERS_2_0_0(); ";
code += "}\n";
// Generate a special accessor for the table that when used as the root
@@ -649,9 +682,9 @@
std::string src_cast = SourceCast(field.value.type);
std::string method_start =
" public " +
- (field.required ? "" : GenNullableAnnotation(field.value.type)) +
+ (field.IsRequired() ? "" : GenNullableAnnotation(field.value.type)) +
GenPureAnnotation(field.value.type) + type_name_dest + optional +
- " " + MakeCamel(field.name, false);
+ " " + ConvertCase(field.name, Case::kLowerCamel);
std::string obj = "obj";
// Most field accessors need to retrieve and test the field offset first,
@@ -665,15 +698,15 @@
if (field.value.type.base_type == BASE_TYPE_STRUCT) {
// Calls the accessor that takes an accessor object with a new object.
code += method_start + "() { return ";
- code += MakeCamel(field.name, false);
+ code += ConvertCase(field.name, Case::kLowerCamel);
code += "(new ";
code += type_name + "()); }\n";
- } else if (IsVector(field.value.type) &&
+ } else if (IsSeries(field.value.type) &&
field.value.type.element == BASE_TYPE_STRUCT) {
// Accessors for vectors of structs also take accessor objects, this
// generates a variant without that argument.
code += method_start + "(int j) { return ";
- code += MakeCamel(field.name, false);
+ code += ConvertCase(field.name, Case::kLowerCamel);
code += "(new " + type_name + "(), j); }\n";
}
@@ -773,7 +806,7 @@
code += member_suffix;
code += "}\n";
if (IsVector(field.value.type)) {
- code += " public int " + MakeCamel(field.name, false);
+ code += " public int " + ConvertCase(field.name, Case::kLowerCamel);
code += "Length";
code += "()";
code += offset_prefix;
@@ -790,7 +823,7 @@
if (key_field.key) {
auto qualified_name = WrapInNameSpace(sd);
code += " public " + qualified_name + " ";
- code += MakeCamel(field.name, false) + "ByKey(";
+ code += ConvertCase(field.name, Case::kLowerCamel) + "ByKey(";
code += GenTypeNameDest(key_field.value.type) + " key)";
code += offset_prefix;
code += qualified_name + ".__lookup_by_key(";
@@ -799,7 +832,7 @@
code += "bb) : null; ";
code += "}\n";
code += " public " + qualified_name + " ";
- code += MakeCamel(field.name, false) + "ByKey(";
+ code += ConvertCase(field.name, Case::kLowerCamel) + "ByKey(";
code += qualified_name + " obj, ";
code += GenTypeNameDest(key_field.value.type) + " key)";
code += offset_prefix;
@@ -817,7 +850,8 @@
std::string vector_type_name;
const auto &element_base_type = field.value.type.VectorType().base_type;
if (IsScalar(element_base_type)) {
- vector_type_name = MakeCamel(type_name, true) + "Vector";
+ vector_type_name =
+ ConvertCase(type_name, Case::kUpperCamel) + "Vector";
} else if (element_base_type == BASE_TYPE_STRING) {
vector_type_name = "StringVector";
} else if (element_base_type == BASE_TYPE_UNION) {
@@ -825,12 +859,12 @@
} else {
vector_type_name = type_name + ".Vector";
}
- auto vector_method_start = GenNullableAnnotation(field.value.type) +
- " public " + vector_type_name + optional +
- " " + MakeCamel(field.name, false) +
- "Vector";
+ auto vector_method_start =
+ GenNullableAnnotation(field.value.type) + " public " +
+ vector_type_name + optional + " " +
+ ConvertCase(field.name, Case::kLowerCamel) + "Vector";
code += vector_method_start + "() { return ";
- code += MakeCamel(field.name, false) + "Vector";
+ code += ConvertCase(field.name, Case::kLowerCamel) + "Vector";
code += "(new " + vector_type_name + "()); }\n";
code += vector_method_start + "(" + vector_type_name + " obj)";
code += offset_prefix + conditional_cast + obj + ".__assign(";
@@ -846,7 +880,7 @@
IsScalar(field.value.type.VectorType().base_type)) ||
IsString(field.value.type)) {
code += " public ByteBuffer ";
- code += MakeCamel(field.name, false);
+ code += ConvertCase(field.name, Case::kLowerCamel);
code += "AsByteBuffer() { return ";
code += "__vector_as_bytebuffer(";
code += NumToString(field.value.offset) + ", ";
@@ -855,7 +889,7 @@
: InlineSize(field.value.type.VectorType()));
code += "); }\n";
code += " public ByteBuffer ";
- code += MakeCamel(field.name, false);
+ code += ConvertCase(field.name, Case::kLowerCamel);
code += "InByteBuffer(ByteBuffer _bb) { return ";
code += "__vector_in_bytebuffer(_bb, ";
code += NumToString(field.value.offset) + ", ";
@@ -867,8 +901,8 @@
// generate object accessors if is nested_flatbuffer
if (field.nested_flatbuffer) {
auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
- auto nested_method_name =
- MakeCamel(field.name, false) + "As" + field.nested_flatbuffer->name;
+ auto nested_method_name = ConvertCase(field.name, Case::kLowerCamel) +
+ "As" + field.nested_flatbuffer->name;
auto get_nested_method_name = nested_method_name;
code += " public " + nested_type_name + " ";
code += nested_method_name + "() { return ";
@@ -894,7 +928,7 @@
auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
? "(byte)(" + field.name + " ? 1 : 0)"
: field.name;
- auto mutator_prefix = MakeCamel("mutate", false);
+ auto mutator_prefix = "mutate";
// A vector mutator also needs the index of the vector element it should
// mutate.
auto mutator_params = (is_series ? "(int j, " : "(") +
@@ -912,7 +946,7 @@
if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) {
code += " public ";
code += struct_def.fixed ? "void " : "boolean ";
- code += mutator_prefix + MakeCamel(field.name, true);
+ code += mutator_prefix + ConvertCase(field.name, Case::kUpperCamel);
code += mutator_params;
if (struct_def.fixed) {
code += GenSetter(underlying_type) + "(" + setter_index + ", ";
@@ -928,17 +962,21 @@
}
if (parser_.opts.java_primitive_has_method &&
IsScalar(field.value.type.base_type) && !struct_def.fixed) {
- auto vt_offset_constant = " public static final int VT_" +
- MakeScreamingCamel(field.name) + " = " +
- NumToString(field.value.offset) + ";";
+ auto vt_offset_constant =
+ " public static final int VT_" +
+ ConvertCase(field.name, Case::kScreamingSnake) + " = " +
+ NumToString(field.value.offset) + ";";
code += vt_offset_constant;
code += "\n";
}
}
code += "\n";
+ auto struct_has_create = false;
+ std::set<flatbuffers::FieldDef *> field_has_create_set;
flatbuffers::FieldDef *key_field = nullptr;
if (struct_def.fixed) {
+ struct_has_create = true;
// create a struct constructor function
code += " public static " + GenOffsetType() + " ";
code += "create";
@@ -968,6 +1006,7 @@
// JVM specifications restrict default constructor params to be < 255.
// Longs and doubles take up 2 units, so we set the limit to be < 127.
if (has_no_struct_fields && num_fields && num_fields < 127) {
+ struct_has_create = true;
// Generate a table constructor of the form:
// public static int createName(FlatBufferBuilder builder, args...)
code += " public static " + GenOffsetType() + " ";
@@ -976,11 +1015,12 @@
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
+ auto field_name = ConvertCase(field.name, Case::kLowerCamel);
if (field.deprecated) continue;
code += ",\n ";
code += GenTypeBasic(DestinationType(field.value.type, false));
code += " ";
- code += field.name;
+ code += field_name;
if (!IsScalar(field.value.type.base_type)) code += "Offset";
}
code += ") {\n builder.";
@@ -991,12 +1031,14 @@
for (auto it = struct_def.fields.vec.rbegin();
it != struct_def.fields.vec.rend(); ++it) {
auto &field = **it;
+ auto field_name = ConvertCase(field.name, Case::kLowerCamel);
+ auto method_name = ConvertCase(field.name, Case::kUpperCamel);
if (!field.deprecated &&
(!struct_def.sortbysize ||
size == SizeOf(field.value.type.base_type))) {
code += " " + struct_def.name + ".";
code += "add";
- code += MakeCamel(field.name) + "(builder, " + field.name;
+ code += method_name + "(builder, " + field_name;
if (!IsScalar(field.value.type.base_type)) code += "Offset";
code += ");\n";
}
@@ -1022,10 +1064,10 @@
if (field.deprecated) continue;
if (field.key) key_field = &field;
code += " public static void add";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "(FlatBufferBuilder builder, ";
code += GenTypeBasic(DestinationType(field.value.type, false));
- auto argname = MakeCamel(field.name, false);
+ auto argname = ConvertCase(field.name, Case::kLowerCamel);
if (!IsScalar(field.value.type.base_type)) argname += "Offset";
code += " " + argname + ") { builder.add";
code += GenMethod(field.value.type) + "(";
@@ -1041,27 +1083,29 @@
auto alignment = InlineAlignment(vector_type);
auto elem_size = InlineSize(vector_type);
if (!IsStruct(vector_type)) {
+ field_has_create_set.insert(&field);
// generate a method to create a vector from a java array.
if ((vector_type.base_type == BASE_TYPE_CHAR ||
vector_type.base_type == BASE_TYPE_UCHAR)) {
// Handle byte[] and ByteBuffers separately for Java
code += " public static " + GenVectorOffsetType() + " ";
code += "create";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "Vector(FlatBufferBuilder builder, byte[] data) ";
code += "{ return builder.createByteVector(data); }\n";
code += " public static " + GenVectorOffsetType() + " ";
code += "create";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "Vector(FlatBufferBuilder builder, ByteBuffer data) ";
code += "{ return builder.createByteVector(data); }\n";
} else {
code += " public static " + GenVectorOffsetType() + " ";
code += "create";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "Vector(FlatBufferBuilder builder, ";
- code += GenTypeBasic(vector_type) + "[] data) ";
+ code += GenTypeBasic(DestinationType(vector_type, false)) +
+ "[] data) ";
code += "{ builder.startVector(";
code += NumToString(elem_size);
code += ", data.length, ";
@@ -1071,7 +1115,7 @@
code += "add";
code += GenMethod(vector_type);
code += "(";
- code += SourceCastBasic(vector_type, false);
+ code += SourceCastBasic(vector_type);
code += "data[i]";
code += "); return ";
code += "builder.endVector(); }\n";
@@ -1080,7 +1124,7 @@
// Generate a method to start a vector, data to be added manually
// after.
code += " public static void start";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "Vector(FlatBufferBuilder builder, int numElems) ";
code += "{ builder.startVector(";
code += NumToString(elem_size);
@@ -1095,7 +1139,7 @@
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
- if (!field.deprecated && field.required) {
+ if (!field.deprecated && field.IsRequired()) {
code += " builder.required(o, ";
code += NumToString(field.value.offset);
code += "); // " + field.name + "\n";
@@ -1157,13 +1201,16 @@
code += " }\n";
}
GenVectorAccessObject(struct_def, code_ptr);
- code += "}";
- code += "\n\n";
+ if (opts.generate_object_based_api) {
+ GenPackUnPack_ObjectAPI(struct_def, code_ptr, opts, struct_has_create,
+ field_has_create_set);
+ }
+ code += "}\n\n";
}
std::string GenOptionalScalarCheck(FieldDef &field) const {
if (!field.IsScalarOptional()) return "";
- return " public boolean has" + MakeCamel(field.name, true) +
+ return " public boolean has" + ConvertCase(field.name, Case::kUpperCamel) +
"() { return 0 != __offset(" + NumToString(field.value.offset) +
"); }\n";
}
@@ -1229,6 +1276,867 @@
code += " }\n";
}
+ std::string GenGetterFuncName_ObjectAPI(const std::string &field_name) const {
+ return "get" + ConvertCase(field_name, Case::kUpperCamel);
+ }
+
+ void GenEnum_ObjectAPI(EnumDef &enum_def, std::string *code_ptr,
+ const IDLOptions &opts) const {
+ auto &code = *code_ptr;
+ if (enum_def.generated) return;
+ code += "import com.google.flatbuffers.FlatBufferBuilder;\n\n";
+
+ if (!enum_def.attributes.Lookup("private")) { code += "public "; }
+ auto union_name = enum_def.name + "Union";
+ auto union_type =
+ GenTypeBasic(DestinationType(enum_def.underlying_type, false));
+ code += "class " + union_name + " {\n";
+ // Type
+ code += " private " + union_type + " type;\n";
+ // Value
+ code += " private Object value;\n";
+ code += "\n";
+ // getters and setters
+ code += " public " + union_type + " getType() { return type; }\n\n";
+ code += " public void setType(" + union_type +
+ " type) { this.type = type; }\n\n";
+ code += " public Object getValue() { return value; }\n\n";
+ code += " public void setValue(Object value) { this.value = value; }\n\n";
+ // Constructor
+ code += " public " + union_name + "() {\n";
+ code += " this.type = " + enum_def.name + "." +
+ enum_def.Vals()[0]->name + ";\n";
+ code += " this.value = null;\n";
+ code += " }\n\n";
+ // As
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) continue;
+ auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts, false, true);
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT &&
+ ev.union_type.struct_def->attributes.Lookup("private")) {
+ code += " ";
+ } else {
+ code += " public ";
+ }
+ code += type_name + " as" + ev.name + "() { return (" + type_name +
+ ") value; }\n";
+ }
+ code += "\n";
+ // pack()
+ code += " public static int pack(FlatBufferBuilder builder, " +
+ union_name + " _o) {\n";
+ code += " switch (_o.type) {\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) {
+ continue;
+ } else {
+ code += " case " + enum_def.name + "." + ev.name + ": return ";
+ if (IsString(ev.union_type)) {
+ code += "builder.createString(_o.as" + ev.name + "());\n";
+ } else {
+ code += GenTypeGet(ev.union_type) + ".pack(builder, _o.as" + ev.name +
+ "());\n";
+ }
+ }
+ }
+ code += " default: return 0;\n";
+ code += " }\n";
+ code += " }\n";
+ code += "}\n\n";
+ }
+
+ std::string GenSetterFuncName_ObjectAPI(const std::string &field_name) const {
+ return "set" + ConvertCase(field_name, Case::kUpperCamel);
+ }
+
+ std::string GenTypeName_ObjectAPI(const std::string &name,
+ const IDLOptions &opts) const {
+ return opts.object_prefix + name + opts.object_suffix;
+ }
+
+ void GenUnionUnPack_ObjectAPI(const EnumDef &enum_def, std::string *code_ptr,
+ const std::string &type_name,
+ const std::string &camel_name,
+ bool is_vector) const {
+ auto &code = *code_ptr;
+
+ std::string variable_type = type_name;
+ std::string variable_name =
+ "_o" + ConvertCase(camel_name, Case::kUpperCamel);
+ std::string type_params = "";
+ std::string value_params = "";
+ std::string func_suffix = "()";
+ std::string indent = " ";
+ if (is_vector) {
+ variable_type = type_name.substr(0, type_name.length() - 2);
+ variable_name += "Element";
+ type_params = "_j";
+ value_params = ", _j";
+ func_suffix = "(_j)";
+ indent = " ";
+ }
+ code += indent + variable_type + " " + variable_name + " = new " +
+ variable_type + "();\n";
+ code += indent +
+ GenTypeBasic(DestinationType(enum_def.underlying_type, false)) +
+ " " + variable_name + "Type = " + camel_name + "Type(" +
+ type_params + ");\n";
+ code += indent + variable_name + ".setType(" + variable_name + "Type);\n";
+ code += indent + "Table " + variable_name + "Value;\n";
+ code += indent + "switch (" + variable_name + "Type) {\n";
+ for (auto eit = enum_def.Vals().begin(); eit != enum_def.Vals().end();
+ ++eit) {
+ auto &ev = **eit;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) {
+ continue;
+ } else {
+ if (ev.union_type.base_type == BASE_TYPE_STRING ||
+ (ev.union_type.base_type == BASE_TYPE_STRUCT &&
+ ev.union_type.struct_def->fixed)) {
+ continue; // This branch is due to bad implemantation of Unions in
+ // Java which doesn't handle non Table types. Should be
+ // deleted when issue #6561 is fixed.
+ }
+ code += indent + " case " + WrapInNameSpace(enum_def) + "." + ev.name +
+ ":\n";
+ auto actual_type = GenTypeGet(ev.union_type);
+ code += indent + " " + variable_name + "Value = " + camel_name +
+ "(new " + actual_type + "()" + value_params + ");\n";
+ code += indent + " " + variable_name + ".setValue(" + variable_name +
+ "Value != null ? ((" + actual_type + ") " + variable_name +
+ "Value).unpack() : null);\n";
+ code += indent + " break;\n";
+ }
+ }
+ code += indent + " default: break;\n";
+ code += indent + "}\n";
+ if (is_vector) {
+ code += indent + "_o" + ConvertCase(camel_name, Case::kUpperCamel) +
+ "[_j] = " + variable_name + ";\n";
+ }
+ }
+
+ void GenPackUnPack_ObjectAPI(
+ StructDef &struct_def, std::string *code_ptr, const IDLOptions &opts,
+ bool struct_has_create,
+ const std::set<FieldDef *> &field_has_create) const {
+ auto &code = *code_ptr;
+ auto struct_name = GenTypeName_ObjectAPI(struct_def.name, opts);
+ // unpack()
+ code += " public " + struct_name + " unpack() {\n";
+ code += " " + struct_name + " _o = new " + struct_name + "();\n";
+ code += " unpackTo(_o);\n";
+ code += " return _o;\n";
+ code += " }\n";
+ // unpackTo()
+ code += " public void unpackTo(" + struct_name + " _o) {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
+ if (field.value.type.element == BASE_TYPE_UTYPE) continue;
+ auto camel_name = ConvertCase(field.name, Case::kLowerCamel);
+ auto camel_name_with_first = ConvertCase(field.name, Case::kUpperCamel);
+ auto type_name =
+ GenTypeGet_ObjectAPI(field.value.type, opts, false, true);
+ if (field.IsScalarOptional())
+ type_name = ConvertPrimitiveTypeToObjectWrapper_ObjectAPI(type_name);
+ auto start = " " + type_name + " _o" + camel_name_with_first + " = ";
+ auto call_setter = true;
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ auto fixed = struct_def.fixed && field.value.type.struct_def->fixed;
+ if (fixed) {
+ code += " " + camel_name + "().unpackTo(_o.get" +
+ camel_name_with_first + "());\n";
+ } else {
+ code += " if (" + camel_name + "() != null) ";
+ if (field.value.type.struct_def->fixed) {
+ code += camel_name + "().unpackTo(_o.get" +
+ camel_name_with_first + "());\n";
+ } else {
+ code += "_o." + GenSetterFuncName_ObjectAPI(field.name) + "(" +
+ camel_name + "().unpack());\n";
+ }
+ code += " else _o." + GenSetterFuncName_ObjectAPI(field.name) +
+ "(null);\n";
+ }
+ call_setter = false;
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ auto length_str = NumToString(field.value.type.fixed_length);
+ auto unpack_method =
+ field.value.type.struct_def == nullptr ? "" : ".unpack()";
+ code +=
+ start + "_o." + GenGetterFuncName_ObjectAPI(field.name) + "();\n";
+ code += " for (int _j = 0; _j < " + length_str + "; ++_j) { _o" +
+ camel_name_with_first + "[_j] = " + camel_name + "(_j)" +
+ unpack_method + "; }\n";
+ call_setter = false;
+ break;
+ }
+ case BASE_TYPE_VECTOR:
+ if (field.value.type.element == BASE_TYPE_UNION) {
+ code += start + "new " +
+ GenConcreteTypeGet_ObjectAPI(field.value.type, opts)
+ .substr(0, type_name.length() - 1) +
+ camel_name + "Length()];\n";
+ code += " for (int _j = 0; _j < " + camel_name +
+ "Length(); ++_j) {\n";
+ GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
+ type_name, camel_name, true);
+ code += " }\n";
+ } else if (field.value.type.element != BASE_TYPE_UTYPE) {
+ auto fixed = field.value.type.struct_def == nullptr;
+ code += start + "new " +
+ GenConcreteTypeGet_ObjectAPI(field.value.type, opts)
+ .substr(0, type_name.length() - 1) +
+ camel_name + "Length()];\n";
+ code +=
+ " for (int _j = 0; _j < " + camel_name + "Length(); ++_j) {";
+ code += "_o" + camel_name_with_first + "[_j] = ";
+ if (fixed) {
+ code += camel_name + "(_j)";
+ } else {
+ code += "(" + camel_name + "(_j) != null ? " + camel_name +
+ "(_j).unpack() : null)";
+ }
+ code += ";}\n";
+ }
+ break;
+ case BASE_TYPE_UTYPE: break;
+ case BASE_TYPE_UNION: {
+ GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
+ type_name, camel_name, false);
+ break;
+ }
+ default: {
+ if (field.IsScalarOptional()) {
+ code += start + "has" + camel_name_with_first + "() ? " +
+ camel_name + "() : null;\n";
+ } else {
+ code += start + camel_name + "();\n";
+ }
+ break;
+ }
+ }
+ if (call_setter) {
+ code += " _o." + GenSetterFuncName_ObjectAPI(field.name) + "(_o" +
+ camel_name_with_first + ");\n";
+ }
+ }
+ code += " }\n";
+ // pack()
+ code += " public static " + GenOffsetType() +
+ " pack(FlatBufferBuilder builder, " + struct_name + " _o) {\n";
+ code += " if (_o == null) return 0;\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto camel_name = ConvertCase(field.name, Case::kLowerCamel);
+ auto camel_name_with_first = ConvertCase(field.name, Case::kUpperCamel);
+ // pre
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ if (!field.value.type.struct_def->fixed) {
+ code += " " + GenOffsetType() + " _" + field.name + " = _o." +
+ GenGetterFuncName_ObjectAPI(field.name) +
+ "() == null ? 0 : " + GenTypeGet(field.value.type) +
+ ".pack(builder, _o." +
+ GenGetterFuncName_ObjectAPI(field.name) + "());\n";
+ } else if (struct_def.fixed && struct_has_create) {
+ std::vector<FieldArrayLength> array_lengths;
+ FieldArrayLength tmp_array_length = {
+ field.name,
+ field.value.type.fixed_length,
+ };
+ array_lengths.push_back(tmp_array_length);
+ GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
+ array_lengths);
+ }
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ std::string create_string = "createString";
+ code += " int _" + camel_name + " = _o." +
+ GenGetterFuncName_ObjectAPI(field.name) +
+ "() == null ? 0 : "
+ "builder." +
+ create_string + "(_o." +
+ GenGetterFuncName_ObjectAPI(field.name) + "());\n";
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ if (field_has_create.find(&field) != field_has_create.end()) {
+ auto property_name = camel_name;
+ auto gen_for_loop = true;
+ std::string array_name = "__" + camel_name;
+ std::string array_type = "";
+ std::string element_type = "";
+ std::string to_array = "";
+ switch (field.value.type.element) {
+ case BASE_TYPE_STRING: {
+ std::string create_string = "createString";
+ array_type = "int";
+ element_type = "String";
+ to_array += "builder." + create_string + "(_e)";
+ break;
+ }
+ case BASE_TYPE_STRUCT:
+ array_type = "int";
+ element_type =
+ GenTypeGet_ObjectAPI(field.value.type, opts, true, true);
+ ;
+ to_array = GenTypeGet(field.value.type) + ".pack(builder, _e)";
+ break;
+ case BASE_TYPE_UTYPE:
+ property_name = camel_name.substr(0, camel_name.size() - 4);
+ array_type = GenTypeBasic(DestinationType(
+ field.value.type.enum_def->underlying_type, false));
+ element_type = field.value.type.enum_def->name + "Union";
+ to_array = "_o." + GenGetterFuncName_ObjectAPI(property_name) +
+ "()[_j].getType()";
+ break;
+ case BASE_TYPE_UNION:
+ array_type = "int";
+ element_type =
+ WrapInNameSpace(*field.value.type.enum_def) + "Union";
+ to_array = WrapInNameSpace(*field.value.type.enum_def) +
+ "Union.pack(builder, _o." +
+ GenGetterFuncName_ObjectAPI(property_name) +
+ "()[_j])";
+ break;
+ case BASE_TYPE_UCHAR: // TODO this branch of the switch is due to
+ // inconsistent behavior in unsigned byte.
+ // Read further at Issue #6574.
+ array_type = "byte";
+ element_type = "int";
+ to_array = "(byte) _e";
+ break;
+ default:
+ gen_for_loop = false;
+ array_name =
+ "_o." + GenGetterFuncName_ObjectAPI(property_name) + "()";
+ array_type = GenTypeNameDest(field.value.type);
+ element_type = array_type;
+ to_array = "_e";
+ break;
+ }
+ code += " int _" + camel_name + " = 0;\n";
+ code += " if (_o." + GenGetterFuncName_ObjectAPI(property_name) +
+ "() != null) {\n";
+ if (gen_for_loop) {
+ code += " " + array_type + "[] " + array_name + " = new " +
+ array_type + "[_o." +
+ GenGetterFuncName_ObjectAPI(property_name) +
+ "().length];\n";
+ code += " int _j = 0;\n";
+ code += " for (" + element_type + " _e : _o." +
+ GenGetterFuncName_ObjectAPI(property_name) + "()) { ";
+ code += array_name + "[_j] = " + to_array + "; _j++;}\n";
+ }
+ code += " _" + camel_name + " = create" +
+ camel_name_with_first + "Vector(builder, " + array_name +
+ ");\n";
+ code += " }\n";
+ } else {
+ auto type_name = GenTypeGet(field.value.type);
+ auto element_type_name =
+ GenTypeGet_ObjectAPI(field.value.type, opts, true, true);
+ auto pack_method =
+ field.value.type.struct_def == nullptr
+ ? "builder.add" + GenMethod(field.value.type.VectorType()) +
+ "(_o" + camel_name_with_first + "[_j]);"
+ : type_name + ".pack(builder, _o" + camel_name_with_first +
+ "[_j]);";
+ code += " int _" + camel_name + " = 0;\n";
+ code += " " + element_type_name + "[] _o" +
+ camel_name_with_first + " = _o." +
+ GenGetterFuncName_ObjectAPI(field.name) + "();\n";
+ code += " if (_o" + camel_name_with_first + " != null) {\n";
+ code += " start" + camel_name_with_first +
+ "Vector(builder, _o" + camel_name_with_first +
+ ".length);\n";
+ code += " for (int _j = _o" + camel_name_with_first +
+ ".length - 1; _j >=0; _j--) { ";
+ code += pack_method + "}\n";
+ code += " _" + camel_name + " = builder.endVector();\n";
+ code += " }\n";
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ if (field.value.type.struct_def != nullptr) {
+ std::vector<FieldArrayLength> array_lengths;
+ FieldArrayLength tmp_array_length = {
+ field.name,
+ field.value.type.fixed_length,
+ };
+ array_lengths.push_back(tmp_array_length);
+ GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
+ array_lengths);
+ } else {
+ code += " " +
+ GenTypeGet_ObjectAPI(field.value.type, opts, false, true) +
+ " _" + camel_name + " = _o." +
+ GenGetterFuncName_ObjectAPI(field.name) + "();\n";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ code +=
+ " " +
+ GenTypeBasic(DestinationType(
+ field.value.type.enum_def->underlying_type, false)) +
+ " _" + camel_name + "Type = _o.get" + camel_name_with_first +
+ "() == null ? " + WrapInNameSpace(*field.value.type.enum_def) +
+ ".NONE : " + "_o.get" + camel_name_with_first + "().getType();\n";
+ code += " " + GenOffsetType() + " _" + camel_name + " = _o.get" +
+ camel_name_with_first + "() == null ? 0 : " +
+ WrapInNameSpace(*field.value.type.enum_def) +
+ "Union.pack(builder, _o.get" + camel_name_with_first +
+ "());\n";
+ break;
+ }
+ default: break;
+ }
+ }
+ if (struct_has_create) {
+ // Create
+ code += " return create" + struct_def.name + "(\n";
+ code += " builder";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto camel_name = ConvertCase(field.name, Case::kLowerCamel);
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ if (struct_def.fixed) {
+ GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
+ code_ptr,
+ " _" + camel_name + "_");
+ } else {
+ code += ",\n";
+ if (field.value.type.struct_def->fixed) {
+ if (opts.generate_object_based_api)
+ code += " _o." + camel_name;
+ else
+ // Seems like unreachable code
+ code += " " + GenTypeGet(field.value.type) +
+ ".Pack(builder, _o." + camel_name + ")";
+ } else {
+ code += " _" + field.name;
+ }
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ if (field.value.type.struct_def != nullptr) {
+ GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
+ code_ptr,
+ " _" + camel_name + "_");
+ } else {
+ code += ",\n";
+ code += " _" + camel_name;
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_UTYPE: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ code += ",\n";
+ code += " _" + camel_name;
+ break;
+ }
+ default: // scalar
+ code += ",\n";
+ code +=
+ " _o." + GenGetterFuncName_ObjectAPI(field.name) + "()";
+ break;
+ }
+ }
+ code += ");\n";
+ } else {
+ // Start, End
+ code += " start" + struct_def.name + "(builder);\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto camel_name = ConvertCase(field.name, Case::kLowerCamel);
+ auto camel_name_with_first = ConvertCase(field.name, Case::kUpperCamel);
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ if (field.value.type.struct_def->fixed) {
+ code += " add" + camel_name_with_first + "(builder, " +
+ GenTypeGet(field.value.type) + ".pack(builder, _o." +
+ GenGetterFuncName_ObjectAPI(field.name) + "()));\n";
+ } else {
+ code += " add" + camel_name_with_first + "(builder, _" +
+ field.name + ");\n";
+ }
+ break;
+ }
+ case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ code += " add" + camel_name_with_first + "(builder, _" +
+ camel_name + ");\n";
+ break;
+ }
+ case BASE_TYPE_UTYPE: break;
+ case BASE_TYPE_UNION: {
+ code += " add" + camel_name_with_first + "Type(builder, _" +
+ camel_name + "Type);\n";
+ code += " add" + camel_name_with_first + "(builder, _" +
+ camel_name + ");\n";
+ break;
+ }
+ // scalar
+ default: {
+ if (field.IsScalarOptional()) {
+ code += " if (_o." + GenGetterFuncName_ObjectAPI(field.name) +
+ "() != null) { add" + camel_name_with_first +
+ "(builder, _o." +
+ GenGetterFuncName_ObjectAPI(field.name) + "()); }\n";
+ } else {
+ code += " add" + camel_name_with_first + "(builder, _o." +
+ GenGetterFuncName_ObjectAPI(field.name) + "());\n";
+ }
+ break;
+ }
+ }
+ }
+ code += " return end" + struct_def.name + "(builder);\n";
+ }
+ code += " }\n";
+ }
+
+ void GenStructPackDecl_ObjectAPI(
+ const StructDef &struct_def, std::string *code_ptr,
+ std::vector<FieldArrayLength> &array_lengths) const {
+ auto &code = *code_ptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ auto is_array = IsArray(field.value.type);
+ const auto &field_type =
+ is_array ? field.value.type.VectorType() : field.value.type;
+ FieldArrayLength tmp_array_length = {
+ field.name,
+ field_type.fixed_length,
+ };
+ array_lengths.push_back(tmp_array_length);
+ if (field_type.struct_def != nullptr) {
+ GenStructPackDecl_ObjectAPI(*field_type.struct_def, code_ptr,
+ array_lengths);
+ } else {
+ std::vector<FieldArrayLength> array_only_lengths;
+ for (size_t i = 0; i < array_lengths.size(); ++i) {
+ if (array_lengths[i].length > 0) {
+ array_only_lengths.push_back(array_lengths[i]);
+ }
+ }
+ std::string name;
+ for (size_t i = 0; i < array_lengths.size(); ++i) {
+ name += "_" + ConvertCase(array_lengths[i].name, Case::kLowerCamel);
+ }
+ code += " " + GenTypeBasic(field_type);
+ if (array_only_lengths.size() > 0) {
+ for (size_t i = 0; i < array_only_lengths.size(); ++i) {
+ code += "[]";
+ }
+ code += " " + name + " = ";
+ code += "new " + GenTypeBasic(field_type) + "[";
+ for (size_t i = 0; i < array_only_lengths.size(); ++i) {
+ if (i != 0) { code += "]["; }
+ code += NumToString(array_only_lengths[i].length);
+ }
+ code += "];\n";
+ code += " ";
+ // initialize array
+ for (size_t i = 0; i < array_only_lengths.size(); ++i) {
+ auto idx = "idx" + NumToString(i);
+ code += "for (int " + idx + " = 0; " + idx + " < " +
+ NumToString(array_only_lengths[i].length) + "; ++" + idx +
+ ") {";
+ }
+ for (size_t i = 0; i < array_only_lengths.size(); ++i) {
+ auto idx = "idx" + NumToString(i);
+ if (i == 0) {
+ code += name + "[" + idx;
+ } else {
+ code += "][" + idx;
+ }
+ }
+ code += "] = _o";
+ for (size_t i = 0, j = 0; i < array_lengths.size(); ++i) {
+ code +=
+ "." + GenGetterFuncName_ObjectAPI(array_lengths[i].name) + "()";
+ if (array_lengths[i].length <= 0) continue;
+ code += "[idx" + NumToString(j++) + "]";
+ }
+ code += ";";
+ for (size_t i = 0; i < array_only_lengths.size(); ++i) {
+ code += "}";
+ }
+ } else {
+ code += " " + name + " = ";
+ code += "_o";
+ for (size_t i = 0; i < array_lengths.size(); ++i) {
+ code +=
+ "." + GenGetterFuncName_ObjectAPI(array_lengths[i].name) + "()";
+ }
+ code += ";";
+ }
+ code += "\n";
+ }
+ array_lengths.pop_back();
+ }
+ }
+
+ void GenStructPackCall_ObjectAPI(const StructDef &struct_def,
+ std::string *code_ptr,
+ std::string prefix) const {
+ auto &code = *code_ptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ if (field_type.struct_def != nullptr) {
+ GenStructPackCall_ObjectAPI(
+ *field_type.struct_def, code_ptr,
+ prefix + ConvertCase(field.name, Case::kLowerCamel) + "_");
+ } else {
+ code += ",\n";
+ code += prefix + ConvertCase(field.name, Case::kLowerCamel);
+ }
+ }
+ }
+
+ std::string ConvertPrimitiveTypeToObjectWrapper_ObjectAPI(
+ std::string type_name) const {
+ if (type_name == "boolean")
+ return "Boolean";
+ else if (type_name == "byte")
+ return "Byte";
+ else if (type_name == "char")
+ return "Character";
+ else if (type_name == "short")
+ return "Short";
+ else if (type_name == "int")
+ return "Integer";
+ else if (type_name == "long")
+ return "Long";
+ else if (type_name == "float")
+ return "Float";
+ else if (type_name == "double")
+ return "Double";
+ return type_name;
+ }
+
+ std::string GenTypeGet_ObjectAPI(flatbuffers::Type type,
+ const IDLOptions &opts, bool vectorelem,
+ bool wrap_in_namespace) const {
+ auto type_name = GenTypeNameDest(type);
+ // Replace to ObjectBaseAPI Type Name
+ switch (type.base_type) {
+ case BASE_TYPE_STRUCT: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ if (type.struct_def != nullptr) {
+ auto type_name_length = type.struct_def->name.length();
+ auto new_type_name =
+ GenTypeName_ObjectAPI(type.struct_def->name, opts);
+ type_name.replace(type_name.length() - type_name_length,
+ type_name_length, new_type_name);
+ } else if (type.element == BASE_TYPE_UNION) {
+ if (wrap_in_namespace) {
+ type_name = WrapInNameSpace(*type.enum_def) + "Union";
+ } else {
+ type_name = type.enum_def->name + "Union";
+ }
+ }
+ break;
+ }
+
+ case BASE_TYPE_UNION: {
+ if (wrap_in_namespace) {
+ type_name = WrapInNameSpace(*type.enum_def) + "Union";
+ } else {
+ type_name = type.enum_def->name + "Union";
+ }
+ break;
+ }
+ default: break;
+ }
+ if (vectorelem) { return type_name; }
+ switch (type.base_type) {
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ type_name = type_name + "[]";
+ break;
+ }
+ default: break;
+ }
+ return type_name;
+ }
+
+ std::string GenConcreteTypeGet_ObjectAPI(flatbuffers::Type type,
+ const IDLOptions &opts) const {
+ auto type_name = GenTypeNameDest(type);
+ // Replace to ObjectBaseAPI Type Name
+ switch (type.base_type) {
+ case BASE_TYPE_STRUCT: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ if (type.struct_def != nullptr) {
+ auto type_name_length = type.struct_def->name.length();
+ auto new_type_name =
+ GenTypeName_ObjectAPI(type.struct_def->name, opts);
+ type_name.replace(type_name.length() - type_name_length,
+ type_name_length, new_type_name);
+ } else if (type.element == BASE_TYPE_UNION) {
+ type_name = WrapInNameSpace(*type.enum_def) + "Union";
+ }
+ break;
+ }
+
+ case BASE_TYPE_UNION: {
+ type_name = WrapInNameSpace(*type.enum_def) + "Union";
+ break;
+ }
+ default: break;
+ }
+
+ switch (type.base_type) {
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ type_name = type_name + "[]";
+ break;
+ }
+ default: break;
+ }
+ return type_name;
+ }
+
+ void GenStruct_ObjectAPI(StructDef &struct_def, std::string *code_ptr,
+ const IDLOptions &opts) const {
+ if (struct_def.generated) return;
+ auto &code = *code_ptr;
+ if (struct_def.attributes.Lookup("private")) {
+ // For Java, we leave the enum unmarked to indicate package-private
+ } else {
+ code += "public ";
+ }
+
+ auto class_name = GenTypeName_ObjectAPI(struct_def.name, opts);
+ code += "class " + class_name;
+ code += " {\n";
+ // Generate Properties
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
+ if (field.value.type.element == BASE_TYPE_UTYPE) continue;
+ auto type_name =
+ GenTypeGet_ObjectAPI(field.value.type, opts, false, true);
+ if (field.IsScalarOptional())
+ type_name = ConvertPrimitiveTypeToObjectWrapper_ObjectAPI(type_name);
+ auto camel_name = ConvertCase(field.name, Case::kLowerCamel);
+ code += " private " + type_name + " " + camel_name + ";\n";
+ }
+ // Generate Java getters and setters
+ code += "\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
+ if (field.value.type.element == BASE_TYPE_UTYPE) continue;
+ auto type_name =
+ GenTypeGet_ObjectAPI(field.value.type, opts, false, true);
+ if (field.IsScalarOptional())
+ type_name = ConvertPrimitiveTypeToObjectWrapper_ObjectAPI(type_name);
+ auto camel_name = ConvertCase(field.name, Case::kLowerCamel);
+ code += " public " + type_name + " " +
+ GenGetterFuncName_ObjectAPI(field.name) + "() { return " +
+ camel_name + "; }\n\n";
+ std::string array_validation = "";
+ if (field.value.type.base_type == BASE_TYPE_ARRAY) {
+ array_validation =
+ "if (" + camel_name + " != null && " + camel_name +
+ ".length == " + NumToString(field.value.type.fixed_length) + ") ";
+ }
+ code += " public void " + GenSetterFuncName_ObjectAPI(field.name) + "(" +
+ type_name + " " + camel_name + ") { " + array_validation +
+ "this." + camel_name + " = " + camel_name + "; }\n\n";
+ }
+ // Generate Constructor
+ code += "\n";
+ code += " public " + class_name + "() {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
+ if (field.value.type.element == BASE_TYPE_UTYPE) continue;
+ code += " this." + ConvertCase(field.name, Case::kLowerCamel) + " = ";
+ auto type_name =
+ GenTypeGet_ObjectAPI(field.value.type, opts, false, true);
+ if (IsScalar(field.value.type.base_type)) {
+ if (field.IsScalarOptional()) {
+ code += "null;\n";
+ } else {
+ code += GenDefaultValue(field) + ";\n";
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ if (IsStruct(field.value.type)) {
+ code += "new " + type_name + "();\n";
+ } else {
+ code += "null;\n";
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ code += "new " + type_name.substr(0, type_name.length() - 1) +
+ NumToString(field.value.type.fixed_length) + "];\n";
+ break;
+ }
+ default: {
+ code += "null;\n";
+ break;
+ }
+ }
+ }
+ }
+ code += " }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
+ code += " public static " + class_name +
+ " deserializeFromBinary(byte[] fbBuffer) {\n";
+ code += " return " + struct_def.name + ".getRootAs" + struct_def.name +
+ "(ByteBuffer.wrap(fbBuffer)).unpack();\n";
+ code += " }\n";
+ code += " public byte[] serializeToBinary() {\n";
+ code += " FlatBufferBuilder fbb = new FlatBufferBuilder();\n";
+ code += " " + struct_def.name + ".finish" + struct_def.name +
+ "Buffer(fbb, " + struct_def.name + ".pack(fbb, this));\n";
+ code += " return fbb.sizedByteArray();\n";
+ code += " }\n";
+ }
+ code += "}\n\n";
+ }
+
// This tracks the current namespace used to determine if a type need to be
// prefixed by its namespace
const Namespace *cur_name_space_;
diff --git a/third_party/flatbuffers/src/idl_gen_js_ts.cpp b/third_party/flatbuffers/src/idl_gen_js_ts.cpp
deleted file mode 100644
index 42aea8e..0000000
--- a/third_party/flatbuffers/src/idl_gen_js_ts.cpp
+++ /dev/null
@@ -1,2189 +0,0 @@
-/*
- * Copyright 2014 Google Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// independent from idl_parser, since this code is not needed for most clients
-#include <algorithm>
-#include <cassert>
-#include <unordered_map>
-#include <unordered_set>
-
-#include "flatbuffers/code_generators.h"
-#include "flatbuffers/flatbuffers.h"
-#include "flatbuffers/idl.h"
-#include "flatbuffers/util.h"
-
-namespace flatbuffers {
-
-struct JsTsLanguageParameters {
- IDLOptions::Language language;
- std::string file_extension;
-};
-
-struct ReexportDescription {
- std::string symbol;
- std::string source_namespace;
- std::string target_namespace;
-};
-
-enum AnnotationType { kParam = 0, kType = 1, kReturns = 2 };
-
-// frc971 modification: We need to rename the `Object` class to `ObjectGenerated`
-// to avoid compilation errors with reserved keywords.
-#define WRAP_IN_NAMESPACE(...) \
- WrapInNameSpace(__VA_ARGS__, true)
-
-const JsTsLanguageParameters &GetJsLangParams(IDLOptions::Language lang) {
- static JsTsLanguageParameters js_language_parameters[] = {
- {
- IDLOptions::kJs,
- ".js",
- },
- {
- IDLOptions::kTs,
- ".ts",
- },
- };
-
- if (lang == IDLOptions::kJs) {
- return js_language_parameters[0];
- } else {
- FLATBUFFERS_ASSERT(lang == IDLOptions::kTs);
- return js_language_parameters[1];
- }
-}
-
-namespace jsts {
-// Iterate through all definitions we haven't generate code for (enums, structs,
-// and tables) and output them to a single file.
-class JsTsGenerator : public BaseGenerator {
- public:
- typedef std::unordered_set<std::string> imported_fileset;
- typedef std::unordered_multimap<std::string, ReexportDescription>
- reexport_map;
-
- JsTsGenerator(const Parser &parser, const std::string &path,
- const std::string &file_name)
- : BaseGenerator(parser, path, file_name, "", ".",
- parser.opts.lang == IDLOptions::kJs ? "js" : "ts"),
- lang_(GetJsLangParams(parser_.opts.lang)) {}
- // Iterate through all definitions we haven't generate code for (enums,
- // structs, and tables) and output them to a single file.
- bool generate() {
- imported_fileset imported_files;
- reexport_map reexports;
-
- std::string enum_code, struct_code, import_code, exports_code, code;
- generateEnums(&enum_code, &exports_code, reexports, imported_files);
- generateStructs(&struct_code, &exports_code, imported_files);
- generateImportDependencies(&import_code, imported_files);
- generateReexports(&import_code, reexports, imported_files);
-
- code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
-
- // Generate code for all the namespace declarations.
- GenNamespaces(&code, &exports_code);
-
- // Output the main declaration code from above.
- code += import_code;
-
- code += enum_code;
- code += struct_code;
-
- if (lang_.language == IDLOptions::kJs && !exports_code.empty() &&
- !parser_.opts.skip_js_exports) {
- if (parser_.opts.use_ES6_js_export_format)
- code += "// Exports for ECMAScript6 Modules\n";
- else
- code += "// Exports for Node.js and RequireJS\n";
- code += exports_code;
- }
-
- return SaveFile(GeneratedFileName(path_, file_name_, parser_.opts).c_str(),
- code, false);
- }
-
- private:
- JsTsLanguageParameters lang_;
-
- // Generate code for imports
- void generateImportDependencies(std::string *code_ptr,
- const imported_fileset &imported_files) {
- std::string &code = *code_ptr;
- for (auto it = imported_files.begin(); it != imported_files.end(); ++it) {
- const auto &file = *it;
- const auto basename =
- flatbuffers::StripPath(flatbuffers::StripExtension(file));
- if (basename != file_name_) { code += GenPrefixedImport(file, basename); }
- }
- }
-
- // Generate reexports, which might not have been explicitly imported using the
- // "export import" trick
- void generateReexports(std::string *code_ptr, const reexport_map &reexports,
- imported_fileset imported_files) {
- if (!parser_.opts.reexport_ts_modules ||
- lang_.language != IDLOptions::kTs) {
- return;
- }
-
- std::unordered_set<std::string> imported;
-
- std::string &code = *code_ptr;
- for (auto it = reexports.begin(); it != reexports.end(); ++it) {
- const auto &file = *it;
- const auto basename =
- flatbuffers::StripPath(flatbuffers::StripExtension(file.first));
- if (basename != file_name_ &&
- imported.find(file.second.symbol) == imported.end()) {
- if (imported_files.find(file.first) == imported_files.end()) {
- code += GenPrefixedImport(file.first, basename);
- imported_files.emplace(file.first);
- }
-
- if (!file.second.target_namespace.empty()) {
- code += "export namespace " + file.second.target_namespace + " { \n";
- }
- code += "export import " + file.second.symbol + " = ";
- code += GenFileNamespacePrefix(file.first) + ".";
- if (!file.second.source_namespace.empty()) {
- code += file.second.source_namespace + ".";
- }
- code += file.second.symbol + ";\n";
- if (!file.second.target_namespace.empty()) { code += "}\n"; }
-
- imported.emplace(file.second.symbol);
- }
- }
- }
-
- // Generate code for all enums.
- void generateEnums(std::string *enum_code_ptr, std::string *exports_code_ptr,
- reexport_map &reexports,
- imported_fileset &imported_files) {
- for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
- ++it) {
- auto &enum_def = **it;
- GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports,
- imported_files, false);
- GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports,
- imported_files, true);
- }
- }
-
- // Generate code for all structs.
- void generateStructs(std::string *decl_code_ptr,
- std::string *exports_code_ptr,
- imported_fileset &imported_files) {
- for (auto it = parser_.structs_.vec.begin();
- it != parser_.structs_.vec.end(); ++it) {
- auto &struct_def = **it;
- GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr,
- imported_files);
- }
- }
- void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) {
- if (lang_.language == IDLOptions::kTs &&
- parser_.opts.skip_flatbuffers_import) {
- return;
- }
-
- std::set<std::string> namespaces;
-
- for (auto it = parser_.namespaces_.begin(); it != parser_.namespaces_.end();
- ++it) {
- std::string namespace_so_far;
-
- // Gather all parent namespaces for this namespace
- for (auto component = (*it)->components.begin();
- component != (*it)->components.end(); ++component) {
- if (!namespace_so_far.empty()) { namespace_so_far += '.'; }
- namespace_so_far += *component;
- namespaces.insert(namespace_so_far);
- }
- }
-
- // Make sure parent namespaces come before child namespaces
- std::vector<std::string> sorted_namespaces(namespaces.begin(),
- namespaces.end());
- std::sort(sorted_namespaces.begin(), sorted_namespaces.end());
-
- // Emit namespaces in a form that Closure Compiler can optimize
- std::string &code = *code_ptr;
- std::string &exports = *exports_ptr;
-
- if (lang_.language == IDLOptions::kTs) {
- code += "import * as flatbuffers from 'flatbuffers';\n";
- }
-
- for (auto it = sorted_namespaces.begin(); it != sorted_namespaces.end();
- ++it) {
- if (lang_.language == IDLOptions::kTs) {
- if (it->find('.') == std::string::npos) { break; }
- } else {
- code += "/**\n * @const\n * @namespace\n */\n";
- if (it->find('.') == std::string::npos) {
- code += "var ";
- if (parser_.opts.use_goog_js_export_format) {
- exports += "goog.exportSymbol('" + *it + "', " + *it + ");\n";
- } else if (parser_.opts.use_ES6_js_export_format) {
- exports += "export {" + *it + "};\n";
- } else {
- exports += "this." + *it + " = " + *it + ";\n";
- }
- }
- code += *it + " = " + *it + " || {};\n\n";
- }
- }
- }
-
- // Generate a documentation comment, if available.
- static void GenDocComment(const std::vector<std::string> &dc,
- std::string *code_ptr,
- const std::string &extra_lines,
- const char *indent = nullptr) {
- if (dc.empty() && extra_lines.empty()) {
- // Don't output empty comment blocks with 0 lines of comment content.
- return;
- }
-
- std::string &code = *code_ptr;
- if (indent) code += indent;
- code += "/**\n";
- for (auto it = dc.begin(); it != dc.end(); ++it) {
- if (indent) code += indent;
- code += " *" + *it + "\n";
- }
- if (!extra_lines.empty()) {
- if (!dc.empty()) {
- if (indent) code += indent;
- code += " *\n";
- }
- if (indent) code += indent;
- std::string::size_type start = 0;
- for (;;) {
- auto end = extra_lines.find('\n', start);
- if (end != std::string::npos) {
- code += " * " + extra_lines.substr(start, end - start) + "\n";
- start = end + 1;
- } else {
- code += " * " + extra_lines.substr(start) + "\n";
- break;
- }
- }
- }
- if (indent) code += indent;
- code += " */\n";
- }
-
- static void GenDocComment(std::string *code_ptr,
- const std::string &extra_lines) {
- GenDocComment(std::vector<std::string>(), code_ptr, extra_lines);
- }
-
- std::string GenTypeAnnotation(AnnotationType annotation_type,
- const std::string &type_name,
- const std::string &arg_name,
- bool include_newline = true) {
- std::string result = "";
- switch (annotation_type) {
- case kParam: {
- result += "@param";
- break;
- }
- case kType: {
- if (lang_.language != IDLOptions::kTs) {
- result += "@type";
- } else {
- return "";
- }
- break;
- }
- case kReturns: {
- result += "@returns";
- break;
- }
- }
- switch (lang_.language) {
- case IDLOptions::kTs: {
- result += " " + type_name;
- break;
- }
- default: {
- result += " {" + type_name + "}";
- }
- }
- if (!arg_name.empty()) { result += " " + arg_name; }
- if (include_newline) { result += "\n"; }
-
- return result;
- }
-
- // Generate an enum declaration and an enum string lookup table.
- void GenEnum(EnumDef &enum_def, std::string *code_ptr,
- std::string *exports_ptr, reexport_map &reexports,
- imported_fileset &imported_files, bool reverse) {
- if (enum_def.generated) return;
- if (reverse && lang_.language == IDLOptions::kTs) return; // FIXME.
- std::string &code = *code_ptr;
- std::string &exports = *exports_ptr;
- GenDocComment(enum_def.doc_comment, code_ptr,
- reverse ? "@enum {string}" : "@enum {number}");
- std::string ns = GetNameSpace(enum_def);
- std::string enum_def_name = enum_def.name + (reverse ? "Name" : "");
- if (lang_.language == IDLOptions::kTs) {
- if (!ns.empty()) { code += "export namespace " + ns + "{\n"; }
- code += "export enum " + enum_def.name + "{\n";
- } else {
- if (enum_def.defined_namespace->components.empty()) {
- code += "var ";
- if (parser_.opts.use_goog_js_export_format) {
- exports += "goog.exportSymbol('" + enum_def_name + "', " +
- enum_def.name + ");\n";
- } else if (parser_.opts.use_ES6_js_export_format) {
- exports += "export {" + enum_def_name + "};\n";
- } else {
- exports += "this." + enum_def_name + " = " + enum_def_name + ";\n";
- }
- }
- code += WRAP_IN_NAMESPACE(enum_def) + (reverse ? "Name" : "") + " = {\n";
- }
- for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
- auto &ev = **it;
- if (!ev.doc_comment.empty()) {
- if (it != enum_def.Vals().begin()) { code += '\n'; }
- GenDocComment(ev.doc_comment, code_ptr, "", " ");
- }
-
- // Generate mapping between EnumName: EnumValue(int)
- if (reverse) {
- code += " '" + enum_def.ToString(ev) + "'";
- code += lang_.language == IDLOptions::kTs ? "= " : ": ";
- code += "'" + ev.name + "'";
- } else {
- code += " " + ev.name;
- code += lang_.language == IDLOptions::kTs ? "= " : ": ";
- code += enum_def.ToString(ev);
- }
-
- code += (it + 1) != enum_def.Vals().end() ? ",\n" : "\n";
-
- if (ev.union_type.struct_def) {
- ReexportDescription desc = { ev.union_type.struct_def->name,
- GetNameSpace(*ev.union_type.struct_def),
- GetNameSpace(enum_def) };
- reexports.insert(
- std::make_pair(ev.union_type.struct_def->file, std::move(desc)));
- }
- }
- code += "};";
-
- if (lang_.language == IDLOptions::kTs) {
- if (enum_def.is_union) {
- code += GenUnionConvFunc(enum_def.underlying_type, imported_files);
- }
- if (!ns.empty()) { code += "\n}"; }
- }
-
- code += "\n\n";
- }
-
- static std::string GenType(const Type &type) {
- switch (type.base_type) {
- case BASE_TYPE_BOOL:
- case BASE_TYPE_CHAR: return "Int8";
- case BASE_TYPE_UTYPE:
- case BASE_TYPE_UCHAR: return "Uint8";
- case BASE_TYPE_SHORT: return "Int16";
- case BASE_TYPE_USHORT: return "Uint16";
- case BASE_TYPE_INT: return "Int32";
- case BASE_TYPE_UINT: return "Uint32";
- case BASE_TYPE_LONG: return "Int64";
- case BASE_TYPE_ULONG: return "Uint64";
- case BASE_TYPE_FLOAT: return "Float32";
- case BASE_TYPE_DOUBLE: return "Float64";
- case BASE_TYPE_STRING: return "String";
- case BASE_TYPE_VECTOR: return GenType(type.VectorType());
- case BASE_TYPE_STRUCT: return type.struct_def->name;
- default: return "Table";
- }
- }
-
- std::string GenGetter(const Type &type, const std::string &arguments) {
- switch (type.base_type) {
- case BASE_TYPE_STRING: return GenBBAccess() + ".__string" + arguments;
- case BASE_TYPE_STRUCT: return GenBBAccess() + ".__struct" + arguments;
- case BASE_TYPE_UNION:
- if (!UnionHasStringType(*type.enum_def) ||
- lang_.language == IDLOptions::kJs) {
- return GenBBAccess() + ".__union" + arguments;
- }
- return GenBBAccess() + ".__union_with_string" + arguments;
- case BASE_TYPE_VECTOR: return GenGetter(type.VectorType(), arguments);
- default: {
- auto getter =
- GenBBAccess() + ".read" + MakeCamel(GenType(type)) + arguments;
- if (type.base_type == BASE_TYPE_BOOL) { getter = "!!" + getter; }
- if (type.enum_def) {
- getter = "/** " +
- GenTypeAnnotation(kType, WRAP_IN_NAMESPACE(*type.enum_def), "",
- false) +
- " */ (" + getter + ")";
- }
- return getter;
- }
- }
- }
-
- std::string GenBBAccess() const {
- return lang_.language == IDLOptions::kTs ? "this.bb!" : "this.bb";
- }
-
- std::string GenDefaultValue(const FieldDef &field, const std::string &context) {
- if (field.IsScalarOptional()) {
- return "null";
- }
-
- const auto &value = field.value;
- if (value.type.enum_def && value.type.base_type != BASE_TYPE_UNION &&
- value.type.base_type != BASE_TYPE_VECTOR) {
- if (auto val = value.type.enum_def->FindByValue(value.constant)) {
- if (lang_.language == IDLOptions::kTs) {
- return GenPrefixedTypeName(WRAP_IN_NAMESPACE(*value.type.enum_def),
- value.type.enum_def->file) +
- "." + val->name;
- } else {
- return WRAP_IN_NAMESPACE(*value.type.enum_def) + "." + val->name;
- }
- } else {
- return "/** " +
- GenTypeAnnotation(kType, WRAP_IN_NAMESPACE(*value.type.enum_def),
- "", false) +
- "} */ (" + value.constant + ")";
- }
- }
-
- switch (value.type.base_type) {
- case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
-
- case BASE_TYPE_STRING:
- case BASE_TYPE_UNION:
- case BASE_TYPE_STRUCT: {
- return "null";
- }
-
- case BASE_TYPE_VECTOR: return "[]";
-
- case BASE_TYPE_LONG:
- case BASE_TYPE_ULONG: {
- int64_t constant = StringToInt(value.constant.c_str());
- return context + ".createLong(" +
- NumToString(static_cast<int32_t>(constant)) + ", " +
- NumToString(static_cast<int32_t>(constant >> 32)) + ")";
- }
-
- default: return value.constant;
- }
- }
-
- std::string GenTypeName(const Type &type, bool input,
- bool allowNull = false) {
- if (!input) {
- if (IsString(type) || type.base_type == BASE_TYPE_STRUCT) {
- std::string name;
- if (IsString(type)) {
- name = "string|Uint8Array";
- } else {
- name = WRAP_IN_NAMESPACE(*type.struct_def);
- }
- return (allowNull) ? (name + "|null") : (name);
- }
- }
-
- switch (type.base_type) {
- case BASE_TYPE_BOOL: return (allowNull) ? ("boolean|null") : ("boolean");
- case BASE_TYPE_LONG:
- case BASE_TYPE_ULONG: return (allowNull) ? ("flatbuffers.Long|null") : ("flatbuffers.Long");
- default:
- if (IsScalar(type.base_type)) {
- if (type.enum_def) {
- const auto enum_name = WRAP_IN_NAMESPACE(*type.enum_def);
- return (allowNull) ? (enum_name + "|null") : (enum_name);
- }
-
- return (allowNull) ? ("number|null") : ("number");
- }
- return "flatbuffers.Offset";
- }
- }
-
- // Returns the method name for use with add/put calls.
- static std::string GenWriteMethod(const Type &type) {
- // Forward to signed versions since unsigned versions don't exist
- switch (type.base_type) {
- case BASE_TYPE_UTYPE:
- case BASE_TYPE_UCHAR: return GenWriteMethod(Type(BASE_TYPE_CHAR));
- case BASE_TYPE_USHORT: return GenWriteMethod(Type(BASE_TYPE_SHORT));
- case BASE_TYPE_UINT: return GenWriteMethod(Type(BASE_TYPE_INT));
- case BASE_TYPE_ULONG: return GenWriteMethod(Type(BASE_TYPE_LONG));
- default: break;
- }
-
- return IsScalar(type.base_type) ? MakeCamel(GenType(type))
- : (IsStruct(type) ? "Struct" : "Offset");
- }
-
- template<typename T> static std::string MaybeAdd(T value) {
- return value != 0 ? " + " + NumToString(value) : "";
- }
-
- template<typename T> static std::string MaybeScale(T value) {
- return value != 1 ? " * " + NumToString(value) : "";
- }
-
- static std::string GenFileNamespacePrefix(const std::string &file) {
- return "NS" + std::to_string(HashFnv1a<uint64_t>(file.c_str()));
- }
-
- std::string GenPrefixedImport(const std::string &full_file_name,
- const std::string &base_name) {
- // Either keep the include path as it was
- // or use only the base_name + kGeneratedFileNamePostfix
- std::string path;
- if (parser_.opts.keep_include_path) {
- auto it = parser_.included_files_.find(full_file_name);
- FLATBUFFERS_ASSERT(it != parser_.included_files_.end());
- path = flatbuffers::StripExtension(it->second) +
- parser_.opts.filename_suffix;
- } else {
- path = base_name + parser_.opts.filename_suffix;
- }
-
- // Add the include prefix and make the path always relative
- path = flatbuffers::ConCatPathFileName(parser_.opts.include_prefix, path);
- path = std::string(".") + kPathSeparator + path;
-
- return "import * as " + GenFileNamespacePrefix(full_file_name) +
- " from \"" + path + "\";\n";
- }
-
- // Adds a source-dependent prefix, for of import * statements.
- std::string GenPrefixedTypeName(const std::string &typeName,
- const std::string &file) {
- const auto basename =
- flatbuffers::StripPath(flatbuffers::StripExtension(file));
- if (basename == file_name_ || parser_.opts.generate_all) {
- return typeName;
- }
- return GenFileNamespacePrefix(file) + "." + typeName;
- }
-
- void GenStructArgs(const StructDef &struct_def, std::string *annotations,
- std::string *arguments, const std::string &nameprefix) {
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (IsStruct(field.value.type)) {
- // Generate arguments for a struct inside a struct. To ensure names
- // don't clash, and to make it obvious these arguments are constructing
- // a nested struct, prefix the name with the field name.
- GenStructArgs(*field.value.type.struct_def, annotations, arguments,
- nameprefix + field.name + "_");
- } else {
- *annotations +=
- GenTypeAnnotation(kParam, GenTypeName(field.value.type, true, field.optional),
- nameprefix + field.name);
- if (lang_.language == IDLOptions::kTs) {
- *arguments += ", " + nameprefix + field.name + ": " +
- GenTypeName(field.value.type, true, field.optional);
- } else {
- *arguments += ", " + nameprefix + field.name;
- }
- }
- }
- }
-
- static void GenStructBody(const StructDef &struct_def, std::string *body,
- const std::string &nameprefix) {
- *body += " builder.prep(";
- *body += NumToString(struct_def.minalign) + ", ";
- *body += NumToString(struct_def.bytesize) + ");\n";
-
- for (auto it = struct_def.fields.vec.rbegin();
- it != struct_def.fields.vec.rend(); ++it) {
- auto &field = **it;
- if (field.padding) {
- *body += " builder.pad(" + NumToString(field.padding) + ");\n";
- }
- if (IsStruct(field.value.type)) {
- // Generate arguments for a struct inside a struct. To ensure names
- // don't clash, and to make it obvious these arguments are constructing
- // a nested struct, prefix the name with the field name.
- GenStructBody(*field.value.type.struct_def, body,
- nameprefix + field.name + "_");
- } else {
- *body += " builder.write" + GenWriteMethod(field.value.type) + "(";
- if (field.value.type.base_type == BASE_TYPE_BOOL) { *body += "+"; }
- *body += nameprefix + field.name + ");\n";
- }
- }
- }
-
- std::string GenerateNewExpression(const std::string &object_name) {
- return "new " + object_name +
- (lang_.language == IDLOptions::kTs ? "()" : "");
- }
-
- void GenerateRootAccessor(StructDef &struct_def, std::string *code_ptr,
- std::string &code, std::string &object_name,
- bool size_prefixed) {
- if (!struct_def.fixed) {
- GenDocComment(code_ptr,
- GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb") +
- GenTypeAnnotation(kParam, object_name + "=", "obj") +
- GenTypeAnnotation(kReturns, object_name, "", false));
- std::string sizePrefixed("SizePrefixed");
- if (lang_.language == IDLOptions::kTs) {
- code += "static get" + (size_prefixed ? sizePrefixed : "") + "Root" +
- Verbose(struct_def, "As");
- code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name +
- "):" + object_name + " {\n";
- } else {
- code += object_name + ".get" + (size_prefixed ? sizePrefixed : "") +
- "Root" + Verbose(struct_def, "As");
- code += " = function(bb, obj) {\n";
- }
- if (size_prefixed) {
- code +=
- " bb.setPosition(bb.position() + "
- "flatbuffers.SIZE_PREFIX_LENGTH);\n";
- }
- code += " return (obj || " + GenerateNewExpression(object_name);
- code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
- code += "};\n\n";
- }
- }
-
- void GenerateFinisher(StructDef &struct_def, std::string *code_ptr,
- std::string &code, std::string &object_name,
- bool size_prefixed) {
- if (parser_.root_struct_def_ == &struct_def) {
- std::string sizePrefixed("SizePrefixed");
- GenDocComment(
- code_ptr,
- GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
- GenTypeAnnotation(kParam, "flatbuffers.Offset", "offset", false));
-
- if (lang_.language == IDLOptions::kTs) {
- code += "static finish" + (size_prefixed ? sizePrefixed : "") +
- Verbose(struct_def) + "Buffer";
- code += "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
- } else {
- code += object_name + ".finish" + (size_prefixed ? sizePrefixed : "") +
- Verbose(struct_def) + "Buffer";
- code += " = function(builder, offset) {\n";
- }
-
- code += " builder.finish(offset";
- if (!parser_.file_identifier_.empty()) {
- code += ", '" + parser_.file_identifier_ + "'";
- }
- if (size_prefixed) {
- if (parser_.file_identifier_.empty()) { code += ", undefined"; }
- code += ", true";
- }
- code += ");\n";
- code += "};\n\n";
- }
- }
-
- static std::string GetObjApiClassName(const StructDef &sd,
- const IDLOptions &opts) {
- return GetObjApiClassName(sd.name, opts);
- }
-
- static std::string GetObjApiClassName(const std::string &name,
- const IDLOptions &opts) {
- return opts.object_prefix + name + opts.object_suffix;
- }
-
- bool UnionHasStringType(const EnumDef &union_enum) {
- return std::any_of(union_enum.Vals().begin(), union_enum.Vals().end(),
- [](const EnumVal *ev) {
- return !(ev->IsZero()) &&
- (IsString(ev->union_type));
- });
- }
-
- std::string GenUnionGenericTypeTS(const EnumDef &union_enum) {
- return std::string("T") + (UnionHasStringType(union_enum) ? "|string" : "");
- }
-
- std::string GenUnionTypeTS(const EnumDef &union_enum,
- imported_fileset &imported_files) {
- std::string ret;
- std::set<std::string> type_list;
-
- for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end();
- ++it) {
- const auto &ev = **it;
- if (ev.IsZero()) { continue; }
-
- std::string type = "";
- if (IsString(ev.union_type)) {
- type = "string"; // no need to wrap string type in namespace
- } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
- if (!parser_.opts.generate_all) {
- imported_files.insert(ev.union_type.struct_def->file);
- }
-
- type = GenPrefixedTypeName(WRAP_IN_NAMESPACE(*(ev.union_type.struct_def)),
- ev.union_type.struct_def->file);
- } else {
- FLATBUFFERS_ASSERT(false);
- }
- type_list.insert(type);
- }
-
- for (auto it = type_list.begin(); it != type_list.end(); ++it) {
- ret += *it + ((std::next(it) == type_list.end()) ? "" : "|");
- }
-
- return ret;
- }
-
- // Generate a TS union type based on a union's enum
- std::string GenObjApiUnionTypeTS(const IDLOptions &opts,
- const EnumDef &union_enum) {
- std::string ret = "";
- std::set<std::string> type_list;
-
- for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end();
- ++it) {
- const auto &ev = **it;
- if (ev.IsZero()) { continue; }
-
- std::string type = "";
- if (IsString(ev.union_type)) {
- type = "string"; // no need to wrap string type in namespace
- } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
- type = GenPrefixedTypeName(
- GetObjApiClassName(WRAP_IN_NAMESPACE(*(ev.union_type.struct_def)),
- opts),
- union_enum.file);
- } else {
- FLATBUFFERS_ASSERT(false);
- }
- type_list.insert(type);
- }
-
- size_t totalPrinted = 0;
- for (auto it = type_list.begin(); it != type_list.end(); ++it) {
- ++totalPrinted;
- ret += *it + ((totalPrinted == type_list.size()) ? "" : "|");
- }
-
- return ret;
- }
-
- std::string GenUnionConvFuncName(const EnumDef &enum_def) {
- return "unionTo" + enum_def.name;
- }
-
- std::string GenUnionListConvFuncName(const EnumDef &enum_def) {
- return "unionListTo" + enum_def.name;
- }
-
- std::string GenUnionConvFunc(const Type &union_type,
- imported_fileset &imported_files) {
- if (union_type.enum_def) {
- const auto &enum_def = *union_type.enum_def;
-
- const auto valid_union_type = GenUnionTypeTS(enum_def, imported_files);
- const auto valid_union_type_with_null = valid_union_type + "|null";
-
- auto ret = "\n\nexport function " + GenUnionConvFuncName(enum_def) +
- "(\n type: " + enum_def.name +
- ",\n accessor: (obj:" + valid_union_type + ") => " +
- valid_union_type_with_null +
- "\n): " + valid_union_type_with_null + " {\n";
-
- if (!parser_.opts.generate_all) {
- imported_files.insert(union_type.enum_def->file);
- }
-
- const auto enum_type = GenPrefixedTypeName(
- WRAP_IN_NAMESPACE(*(union_type.enum_def)), union_type.enum_def->file);
- const auto &union_enum = *(union_type.enum_def);
-
- const auto union_enum_loop = [&](const std::string &accessor_str) {
- ret += " switch(" + enum_type + "[type]) {\n";
- ret += " case 'NONE': return null; \n";
-
- for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end();
- ++it) {
- const auto &ev = **it;
- if (ev.IsZero()) { continue; }
-
- ret += " case '" + ev.name + "': ";
-
- if (IsString(ev.union_type)) {
- ret += "return " + accessor_str + "'') as string;";
- } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
- const auto type = GenPrefixedTypeName(
- WRAP_IN_NAMESPACE(*(ev.union_type.struct_def)),
- ev.union_type.struct_def->file);
- ret += "return " + accessor_str + "new " + type + "())! as " +
- type + ";";
- } else {
- FLATBUFFERS_ASSERT(false);
- }
- ret += "\n";
- }
-
- ret += " default: return null;\n";
- ret += " }\n";
- };
-
- union_enum_loop("accessor(");
- ret += "}";
-
- ret += "\n\nexport function " + GenUnionListConvFuncName(enum_def) +
- "(\n type: " + enum_def.name +
- ", \n accessor: (index: number, obj:" + valid_union_type +
- ") => " + valid_union_type_with_null +
- ", \n index: number\n): " + valid_union_type_with_null + " {\n";
- union_enum_loop("accessor(index, ");
- ret += "}";
-
- return ret;
- }
- FLATBUFFERS_ASSERT(0);
- return "";
- }
-
- // Used for generating a short function that returns the correct class
- // based on union enum type. Assume the context is inside the non object api
- // type
- std::string GenUnionValTS(const std::string &field_name,
- const Type &union_type,
- const bool is_array = false) {
- if (union_type.enum_def) {
- const auto &enum_def = *union_type.enum_def;
- const auto enum_type =
- GenPrefixedTypeName(WRAP_IN_NAMESPACE(enum_def), enum_def.file);
- const std::string union_accessor = "this." + field_name;
-
- const auto union_has_string = UnionHasStringType(enum_def);
- const auto field_binded_method = "this." + field_name + ".bind(this)";
-
- std::string ret;
-
- if (!is_array) {
- const auto conversion_function =
- GenPrefixedTypeName(WRAP_IN_NAMESPACE(enum_def.defined_namespace,
- GenUnionConvFuncName(enum_def)),
- enum_def.file);
- const auto target_enum = "this." + field_name + "Type()";
-
- ret = "(() => {\n";
- ret += " let temp = " + conversion_function + "(" + target_enum +
- ", " + field_binded_method + ");\n";
- ret += " if(temp === null) { return null; }\n";
- ret += union_has_string
- ? " if(typeof temp === 'string') { return temp; }\n"
- : "";
- ret += " return temp.unpack()\n";
- ret += " })()";
- } else {
- const auto conversion_function = GenPrefixedTypeName(
- WRAP_IN_NAMESPACE(enum_def.defined_namespace,
- GenUnionListConvFuncName(enum_def)),
- enum_def.file);
- const auto target_enum_accesor = "this." + field_name + "Type";
- const auto target_enum_length = target_enum_accesor + "Length()";
-
- ret = "(() => {\n";
- ret += " let ret = [];\n";
- ret += " for(let targetEnumIndex = 0; targetEnumIndex < " +
- target_enum_length +
- "; "
- "++targetEnumIndex) {\n";
- ret += " let targetEnum = " + target_enum_accesor +
- "(targetEnumIndex);\n";
- ret += " if(targetEnum === null || " + enum_type +
- "[targetEnum!] === 'NONE') { "
- "continue; }\n\n";
- ret += " let temp = " + conversion_function + "(targetEnum, " +
- field_binded_method + ", targetEnumIndex);\n";
- ret += " if(temp === null) { continue; }\n";
- ret += union_has_string ? " if(typeof temp === 'string') { "
- "ret.push(temp); continue; }\n"
- : "";
- ret += " ret.push(temp.unpack());\n";
- ret += " }\n";
- ret += " return ret;\n";
- ret += " })()";
- }
-
- return ret;
- }
-
- FLATBUFFERS_ASSERT(0);
- return "";
- }
-
- static std::string GenNullCheckConditional(const std::string &nullCheckVar,
- const std::string &trueVal,
- const std::string &falseVal = "null") {
- return "(" + nullCheckVar + " !== null ? " + trueVal + " : " + falseVal +
- ")";
- }
-
- std::string GenStructMemberValueTS(const StructDef &struct_def,
- const std::string &prefix,
- const std::string &delimiter,
- const bool nullCheck = true) {
- std::string ret;
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
-
- const auto curr_member_accessor =
- prefix + "." + MakeCamel(field.name, false);
- if (IsStruct(field.value.type)) {
- ret += GenStructMemberValueTS(*field.value.type.struct_def,
- curr_member_accessor, delimiter);
- } else {
- if (nullCheck) {
- ret +=
- "(" + prefix + " === null ? 0 : " + curr_member_accessor + "!)";
- } else {
- ret += curr_member_accessor;
- }
- }
-
- if (std::next(it) != struct_def.fields.vec.end()) { ret += delimiter; }
- }
-
- return ret;
- }
-
- void GenObjApi(const Parser &parser, StructDef &struct_def,
- std::string &obj_api_unpack_func, std::string &obj_api_class,
- imported_fileset &imported_files) {
- const auto class_name = GetObjApiClassName(struct_def, parser.opts);
-
- std::string unpack_func =
- "\n/**\n * " + GenTypeAnnotation(kReturns, class_name, "") +
- " */\nunpack(): " + class_name + " {\n return new " + class_name +
- "(" + (struct_def.fields.vec.empty() ? "" : "\n");
- std::string unpack_to_func =
- "/**\n * " + GenTypeAnnotation(kParam, class_name, "_o") +
- " */\nunpackTo(_o: " + class_name + "): void {" +
- +(struct_def.fields.vec.empty() ? "" : "\n");
-
- std::string constructor_annotation = "/**\n * @constructor";
- constructor_annotation += (struct_def.fields.vec.empty() ? "" : "\n");
- std::string constructor_func = "constructor(";
- constructor_func += (struct_def.fields.vec.empty() ? "" : "\n");
-
- const auto has_create =
- struct_def.fixed || CanCreateFactoryMethod(struct_def);
-
- std::string pack_func_prototype =
- "/**\n * " +
- GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") + " * " +
- GenTypeAnnotation(kReturns, "flatbuffers.Offset", "") +
- " */\npack(builder:flatbuffers.Builder): flatbuffers.Offset {\n";
-
- std::string pack_func_offset_decl;
- std::string pack_func_create_call;
-
- const auto struct_name =
- GenPrefixedTypeName(WRAP_IN_NAMESPACE(struct_def), struct_def.file);
-
- if (has_create) {
- pack_func_create_call = " return " + struct_name + ".create" +
- Verbose(struct_def) + "(builder" +
- (struct_def.fields.vec.empty() ? "" : ",\n ");
- } else {
- pack_func_create_call = " " + struct_name + ".start(builder);\n";
- }
-
- if (struct_def.fixed) {
- // when packing struct, nested struct's members instead of the struct's
- // offset are used
- pack_func_create_call +=
- GenStructMemberValueTS(struct_def, "this", ",\n ", false) + "\n ";
- }
-
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
-
- const auto field_name = MakeCamel(field.name, false);
- const std::string field_binded_method =
- "this." + field_name + ".bind(this)";
-
- std::string field_val;
- std::string field_type;
- // a string that declares a variable containing the
- // offset for things that can't be generated inline
- // empty otw
- std::string field_offset_decl;
- // a string that contains values for things that can be created inline or
- // the variable name from field_offset_decl
- std::string field_offset_val;
- const auto field_default_val =
- GenDefaultValue(field, "flatbuffers");
-
- // Emit a scalar field
- const auto is_string = IsString(field.value.type);
- if (IsScalar(field.value.type.base_type) || is_string) {
- const auto has_null_default = is_string || HasNullDefault(field);
-
- if (field.value.type.enum_def) {
- if (!parser_.opts.generate_all) {
- imported_files.insert(field.value.type.enum_def->file);
- }
-
- field_type +=
- GenPrefixedTypeName(GenTypeName(field.value.type, false, has_null_default),
- field.value.type.enum_def->file);
- } else {
- field_type += GenTypeName(field.value.type, false, has_null_default);
- }
- field_val = "this." + field_name + "()";
-
- if (field.value.type.base_type != BASE_TYPE_STRING) {
- field_offset_val = "this." + field_name;
- } else {
- field_offset_decl = GenNullCheckConditional(
- "this." + field_name,
- "builder.createString(this." + field_name + "!)", "0");
- }
- }
-
- // Emit an object field
- else {
- auto is_vector = false;
- switch (field.value.type.base_type) {
- case BASE_TYPE_STRUCT: {
- const auto &sd = *field.value.type.struct_def;
- field_type += GenPrefixedTypeName(
- WRAP_IN_NAMESPACE(sd.defined_namespace,
- GetObjApiClassName(sd, parser.opts)),
- field.value.type.struct_def->file);
-
- const std::string field_accessor = "this." + field_name + "()";
- field_val = GenNullCheckConditional(field_accessor,
- field_accessor + "!.unpack()");
- field_offset_val = GenNullCheckConditional(
- "this." + field_name, "this." + field_name + "!.pack(builder)",
- "0");
-
- break;
- }
-
- case BASE_TYPE_VECTOR: {
- auto vectortype = field.value.type.VectorType();
- auto vectortypename = GenTypeName(vectortype, false);
- is_vector = true;
-
- field_type = "(";
-
- switch (vectortype.base_type) {
- case BASE_TYPE_STRUCT: {
- const auto &sd = *field.value.type.struct_def;
- field_type += GenPrefixedTypeName(
- WRAP_IN_NAMESPACE(sd.defined_namespace,
- GetObjApiClassName(sd, parser.opts)),
- field.value.type.struct_def->file);
- field_type += ")[]";
-
- field_val = GenBBAccess() + ".createObjList(" +
- field_binded_method + ", this." + field_name +
- "Length())";
-
- if (sd.fixed) {
- field_offset_decl =
- "builder.createStructOffsetList(this." + field_name +
- ", " +
- GenPrefixedTypeName(WRAP_IN_NAMESPACE(struct_def),
- struct_def.file) +
- ".start" + MakeCamel(field_name) + "Vector)";
- } else {
- field_offset_decl =
- GenPrefixedTypeName(WRAP_IN_NAMESPACE(struct_def),
- struct_def.file) +
- ".create" + MakeCamel(field_name) +
- "Vector(builder, builder.createObjectOffsetList(" +
- "this." + field_name + "))";
- }
-
- break;
- }
-
- case BASE_TYPE_STRING: {
- field_type += "string)[]";
- field_val = GenBBAccess() + ".createStringList(" +
- field_binded_method + ", this." + field_name +
- "Length())";
- field_offset_decl =
- GenPrefixedTypeName(WRAP_IN_NAMESPACE(struct_def),
- struct_def.file) +
- ".create" + MakeCamel(field_name) +
- "Vector(builder, builder.createObjectOffsetList(" +
- "this." + field_name + "))";
- break;
- }
-
- case BASE_TYPE_UNION: {
- field_type +=
- GenObjApiUnionTypeTS(parser.opts, *(vectortype.enum_def));
- field_type += ")[]";
- field_val = GenUnionValTS(field_name, vectortype, true);
-
- field_offset_decl =
- GenPrefixedTypeName(WRAP_IN_NAMESPACE(struct_def),
- struct_def.file) +
- ".create" + MakeCamel(field_name) +
- "Vector(builder, builder.createObjectOffsetList(" +
- "this." + field_name + "))";
-
- break;
- }
- default: {
- if (vectortype.enum_def) {
- if (!parser_.opts.generate_all) {
- imported_files.insert(vectortype.enum_def->file);
- }
-
- field_type +=
- GenPrefixedTypeName(GenTypeName(vectortype, false, HasNullDefault(field)),
- vectortype.enum_def->file);
- } else {
- field_type += vectortypename;
- }
- field_type += ")[]";
- field_val = GenBBAccess() + ".createScalarList(" +
- field_binded_method + ", this." + field_name +
- "Length())";
-
- field_offset_decl =
- GenPrefixedTypeName(WRAP_IN_NAMESPACE(struct_def),
- struct_def.file) +
- ".create" + MakeCamel(field_name) +
- "Vector(builder, this." + field_name + ")";
-
- break;
- }
- }
-
- break;
- }
-
- case BASE_TYPE_UNION: {
- if (!parser_.opts.generate_all) {
- imported_files.insert(field.value.type.enum_def->file);
- }
-
- field_type +=
- GenObjApiUnionTypeTS(parser.opts, *(field.value.type.enum_def));
-
- field_val = GenUnionValTS(field_name, field.value.type);
- field_offset_decl =
- "builder.createObjectOffset(this." + field_name + ")";
- break;
- }
-
- default: FLATBUFFERS_ASSERT(0); break;
- }
-
- // length 0 vector is simply empty instead of null
- field_type += is_vector ? "" : "|null";
- }
-
- if (!field_offset_decl.empty()) {
- field_offset_decl =
- " const " + field_name + " = " + field_offset_decl + ";";
- }
- if (field_offset_val.empty()) { field_offset_val = field_name; }
-
- unpack_func += " " + field_val;
- unpack_to_func += " _o." + field_name + " = " + field_val + ";";
-
- constructor_annotation +=
- " * " + GenTypeAnnotation(kParam, field_type, field_name, false);
- constructor_func += " public " + field_name + ": " + field_type + " = " +
- field_default_val;
-
- if (!struct_def.fixed) {
- if (!field_offset_decl.empty()) {
- pack_func_offset_decl += field_offset_decl + "\n";
- }
-
- if (has_create) {
- pack_func_create_call += field_offset_val;
- } else {
- pack_func_create_call += " " + struct_name + ".add" +
- MakeCamel(field.name) + "(builder, " +
- field_offset_val + ");\n";
- }
- }
-
- if (std::next(it) != struct_def.fields.vec.end()) {
- constructor_annotation += "\n";
- constructor_func += ",\n";
-
- if (!struct_def.fixed && has_create) {
- pack_func_create_call += ",\n ";
- }
-
- unpack_func += ",\n";
- unpack_to_func += "\n";
- } else {
- constructor_func += "\n";
- if (!struct_def.fixed) {
- pack_func_offset_decl += (pack_func_offset_decl.empty() ? "" : "\n");
- pack_func_create_call += "\n ";
- }
-
- unpack_func += "\n ";
- unpack_to_func += "\n";
- }
- }
-
- constructor_annotation += "\n */\n";
- constructor_func += "){};\n\n";
-
- if (has_create) {
- pack_func_create_call += ");";
- } else {
- pack_func_create_call += "return " + struct_name + ".end(builder);";
- }
-
- obj_api_class = "\nexport class " +
- GetObjApiClassName(struct_def, parser.opts) + " {\n";
-
- obj_api_class += constructor_annotation + constructor_func;
-
- obj_api_class += pack_func_prototype + pack_func_offset_decl +
- pack_func_create_call + "\n};";
-
- obj_api_class += "\n}\n";
-
- unpack_func += ");\n};";
- unpack_to_func += "};\n";
-
- obj_api_unpack_func = unpack_func + "\n\n" + unpack_to_func;
- }
-
- static bool CanCreateFactoryMethod(const StructDef &struct_def) {
- // to preserve backwards compatibility, we allow the first field to be a
- // struct
- return struct_def.fields.vec.size() < 2 ||
- std::all_of(std::begin(struct_def.fields.vec) + 1,
- std::end(struct_def.fields.vec),
- [](const FieldDef *f) -> bool {
- FLATBUFFERS_ASSERT(f != nullptr);
- return f->value.type.base_type != BASE_TYPE_STRUCT;
- });
- }
-
- // Generate an accessor struct with constructor for a flatbuffers struct.
- void GenStruct(const Parser &parser, StructDef &struct_def,
- std::string *code_ptr, std::string *exports_ptr,
- imported_fileset &imported_files) {
- if (struct_def.generated) return;
- std::string &code = *code_ptr;
- std::string &exports = *exports_ptr;
-
- std::string object_name;
- std::string object_namespace = GetNameSpace(struct_def);
-
- // Emit constructor
- if (lang_.language == IDLOptions::kTs) {
- object_name = struct_def.name;
- if (object_name == "Object") {
- object_name += "Generated";
- }
- GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
- if (!object_namespace.empty()) {
- code += "export namespace " + object_namespace + "{\n";
- }
- code += "export class " + struct_def.name;
- if (struct_def.name.compare("Object") == 0) {
- code += "Generated";
- }
- code += " {\n";
- if (lang_.language != IDLOptions::kTs) {
- code += " /**\n";
- code +=
- " * " + GenTypeAnnotation(kType, "flatbuffers.ByteBuffer", "");
- code += " */\n";
- }
- code += " bb: flatbuffers.ByteBuffer|null = null;\n";
- code += "\n";
- if (lang_.language != IDLOptions::kTs) {
- code += " /**\n";
- code += " * " + GenTypeAnnotation(kType, "number", "");
- code += " */\n";
- }
- code += " bb_pos:number = 0;\n";
- } else {
- bool isStatement = struct_def.defined_namespace->components.empty();
- object_name = WRAP_IN_NAMESPACE(struct_def);
- GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
- if (isStatement) {
- if (parser_.opts.use_goog_js_export_format) {
- exports += "goog.exportSymbol('" + struct_def.name + "', " +
- struct_def.name + ");\n";
- } else if (parser_.opts.use_ES6_js_export_format) {
- exports += "export {" + struct_def.name + "};\n";
- } else {
- exports +=
- "this." + struct_def.name + " = " + struct_def.name + ";\n";
- }
- code += "function " + object_name;
- } else {
- code += object_name + " = function";
- }
- code += "() {\n";
- code += " /**\n";
- code += " * " + GenTypeAnnotation(kType, "flatbuffers.ByteBuffer", "");
- code += " */\n";
- code += " this.bb = null;\n";
- code += "\n";
- code += " /**\n";
- code += " * " + GenTypeAnnotation(kType, "number", "");
- code += " */\n";
- code += " this.bb_pos = 0;\n";
- code += isStatement ? "}\n\n" : "};\n\n";
- }
-
- // Generate the __init method that sets the field in a pre-existing
- // accessor object. This is to allow object reuse.
- code += "/**\n";
- code += " * " + GenTypeAnnotation(kParam, "number", "i");
- code += " * " + GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb");
- code += " * " + GenTypeAnnotation(kReturns, object_name, "");
- code += " */\n";
-
- if (lang_.language == IDLOptions::kTs) {
- code +=
- "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name + " {\n";
- } else {
- code += object_name + ".prototype.__init = function(i, bb) {\n";
- }
-
- code += " this.bb_pos = i;\n";
- code += " this.bb = bb;\n";
- code += " return this;\n";
- code += "};\n\n";
-
- // Generate special accessors for the table that when used as the root of a
- // FlatBuffer
- GenerateRootAccessor(struct_def, code_ptr, code, object_name, false);
- GenerateRootAccessor(struct_def, code_ptr, code, object_name, true);
-
- // Generate the identifier check method
- if (!struct_def.fixed && parser_.root_struct_def_ == &struct_def &&
- !parser_.file_identifier_.empty()) {
- GenDocComment(code_ptr,
- GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb") +
- GenTypeAnnotation(kReturns, "boolean", "", false));
- if (lang_.language == IDLOptions::kTs) {
- code +=
- "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean "
- "{\n";
- } else {
- code += object_name + ".bufferHasIdentifier = function(bb) {\n";
- }
-
- code += " return bb.__has_identifier('" + parser_.file_identifier_;
- code += "');\n};\n\n";
- }
-
- // Emit field accessors
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
- auto offset_prefix =
- " var offset = " + GenBBAccess() + ".__offset(this.bb_pos, " +
- NumToString(field.value.offset) + ");\n return offset ? ";
-
- // Emit a scalar field
- const auto is_string = IsString(field.value.type);
- if (IsScalar(field.value.type.base_type) || is_string) {
- const auto has_null_default = is_string || HasNullDefault(field);
-
- GenDocComment(
- field.doc_comment, code_ptr,
- std::string(is_string
- ? GenTypeAnnotation(kParam, "flatbuffers.Encoding=",
- "optionalEncoding")
- : "") +
- GenTypeAnnotation(kReturns,
- GenTypeName(field.value.type, false, has_null_default),
- "", false));
- if (lang_.language == IDLOptions::kTs) {
- std::string prefix = MakeCamel(field.name, false) + "(";
- if (is_string) {
- code += prefix + "):string|null\n";
- code += prefix + "optionalEncoding:flatbuffers.Encoding" +
- "):" + GenTypeName(field.value.type, false, true) + "\n";
- code += prefix + "optionalEncoding?:any";
- } else {
- code += prefix;
- }
- if (field.value.type.enum_def) {
- code +=
- "):" +
- GenPrefixedTypeName(GenTypeName(field.value.type, false, field.optional),
- field.value.type.enum_def->file) +
- " {\n";
-
- if (!parser_.opts.generate_all) {
- imported_files.insert(field.value.type.enum_def->file);
- }
- } else {
- code += "):" + GenTypeName(field.value.type, false, has_null_default) + " {\n";
- }
- } else {
- code += object_name + ".prototype." + MakeCamel(field.name, false);
- code += " = function(";
- if (is_string) {
- code += "optionalEncoding";
- }
- code += ") {\n";
- }
-
- if (struct_def.fixed) {
- code +=
- " return " +
- GenGetter(field.value.type,
- "(this.bb_pos" + MaybeAdd(field.value.offset) + ")") +
- ";\n";
- } else {
- std::string index = "this.bb_pos + offset";
- if (is_string) {
- index += ", optionalEncoding";
- }
- code += offset_prefix +
- GenGetter(field.value.type, "(" + index + ")") + " : " +
- GenDefaultValue(field, GenBBAccess());
- code += ";\n";
- }
- }
-
- // Emit an object field
- else {
- switch (field.value.type.base_type) {
- case BASE_TYPE_STRUCT: {
- auto type = WRAP_IN_NAMESPACE(*field.value.type.struct_def);
- GenDocComment(
- field.doc_comment, code_ptr,
- GenTypeAnnotation(kParam, type + "=", "obj") +
- GenTypeAnnotation(kReturns, type + "|null", "", false));
- if (lang_.language == IDLOptions::kTs) {
- type =
- GenPrefixedTypeName(type, field.value.type.struct_def->file);
- code += MakeCamel(field.name, false);
- code += "(obj?:" + type + "):" + type + "|null {\n";
- } else {
- code +=
- object_name + ".prototype." + MakeCamel(field.name, false);
- code += " = function(obj) {\n";
- }
-
- if (struct_def.fixed) {
- code += " return (obj || " + GenerateNewExpression(type);
- code += ").__init(this.bb_pos";
- code +=
- MaybeAdd(field.value.offset) + ", " + GenBBAccess() + ");\n";
- } else {
- code += offset_prefix + "(obj || " + GenerateNewExpression(type) +
- ").__init(";
- code += field.value.type.struct_def->fixed
- ? "this.bb_pos + offset"
- : GenBBAccess() + ".__indirect(this.bb_pos + offset)";
- code += ", " + GenBBAccess() + ") : null;\n";
- }
-
- if (lang_.language == IDLOptions::kTs &&
- !parser_.opts.generate_all) {
- imported_files.insert(field.value.type.struct_def->file);
- }
-
- break;
- }
-
- case BASE_TYPE_VECTOR: {
- auto vectortype = field.value.type.VectorType();
- auto vectortypename = GenTypeName(vectortype, false);
-
- if (vectortype.enum_def) {
- vectortypename = GenPrefixedTypeName(vectortypename,
- vectortype.enum_def->file);
- }
-
- auto inline_size = InlineSize(vectortype);
- auto index = GenBBAccess() +
- ".__vector(this.bb_pos + offset) + index" +
- MaybeScale(inline_size);
- std::string args = GenTypeAnnotation(kParam, "number", "index");
- std::string ret_type;
- bool is_union = false;
- switch (vectortype.base_type) {
- case BASE_TYPE_STRUCT:
- args += GenTypeAnnotation(kParam, vectortypename + "=", "obj");
- ret_type = vectortypename;
- break;
- case BASE_TYPE_STRING:
- args += GenTypeAnnotation(
- kParam, "flatbuffers.Encoding=", "optionalEncoding");
- ret_type = vectortypename;
- break;
- case BASE_TYPE_UNION:
- args += GenTypeAnnotation(kParam, "flatbuffers.Table=", "obj");
- ret_type = "?flatbuffers.Table";
- is_union = true;
- break;
- default: ret_type = vectortypename;
- }
- GenDocComment(
- field.doc_comment, code_ptr,
- args + GenTypeAnnotation(kReturns, ret_type, "", false));
- if (lang_.language == IDLOptions::kTs) {
- std::string prefix = MakeCamel(field.name, false);
- if (is_union) { prefix += "<T extends flatbuffers.Table>"; }
- prefix += "(index: number";
- if (is_union) {
- const auto union_type =
- GenUnionGenericTypeTS(*(field.value.type.enum_def));
-
- vectortypename = union_type;
- code += prefix + ", obj:" + union_type;
- } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
- vectortypename = GenPrefixedTypeName(
- vectortypename, vectortype.struct_def->file);
- code += prefix + ", obj?:" + vectortypename;
-
- if (!parser_.opts.generate_all) {
- imported_files.insert(vectortype.struct_def->file);
- }
- } else if (IsString(vectortype)) {
- code += prefix + "):string\n";
- code += prefix + ",optionalEncoding:flatbuffers.Encoding" +
- "):" + vectortypename + "\n";
- code += prefix + ",optionalEncoding?:any";
- } else {
- code += prefix;
-
- if (vectortype.enum_def && !parser_.opts.generate_all) {
- imported_files.insert(vectortype.enum_def->file);
- }
- }
- code += "):" + vectortypename + "|null {\n";
- } else {
- code +=
- object_name + ".prototype." + MakeCamel(field.name, false);
- code += " = function(index";
- if (vectortype.base_type == BASE_TYPE_STRUCT || is_union) {
- code += ", obj";
- } else if (IsString(vectortype)) {
- code += ", optionalEncoding";
- }
- code += ") {\n";
- }
-
- if (vectortype.base_type == BASE_TYPE_STRUCT) {
- code += offset_prefix + "(obj || " +
- GenerateNewExpression(vectortypename);
- code += ").__init(";
- code += vectortype.struct_def->fixed
- ? index
- : GenBBAccess() + ".__indirect(" + index + ")";
- code += ", " + GenBBAccess() + ")";
- } else {
- if (is_union) {
- index = "obj, " + index;
- } else if (IsString(vectortype)) {
- index += ", optionalEncoding";
- }
- code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
- }
- code += " : ";
- if (field.value.type.element == BASE_TYPE_BOOL) {
- code += "false";
- } else if (field.value.type.element == BASE_TYPE_LONG ||
- field.value.type.element == BASE_TYPE_ULONG) {
- code += GenBBAccess() + ".createLong(0, 0)";
- } else if (IsScalar(field.value.type.element)) {
- if (field.value.type.enum_def) {
- code += "/** " +
- GenTypeAnnotation(
- kType, WRAP_IN_NAMESPACE(*field.value.type.enum_def),
- "", false) +
- " */ (" + field.value.constant + ")";
- } else {
- code += "0";
- }
- } else {
- code += "null";
- }
- code += ";\n";
- break;
- }
-
- case BASE_TYPE_UNION:
- GenDocComment(
- field.doc_comment, code_ptr,
- GenTypeAnnotation(kParam, "flatbuffers.Table", "obj") +
- GenTypeAnnotation(kReturns, "?flatbuffers.Table", "",
- false));
- if (lang_.language == IDLOptions::kTs) {
- code += MakeCamel(field.name, false);
-
- const auto &union_enum = *(field.value.type.enum_def);
- const auto union_type = GenUnionGenericTypeTS(union_enum);
- code += "<T extends flatbuffers.Table>(obj:" + union_type +
- "):" + union_type +
- "|null "
- "{\n";
- } else {
- code +=
- object_name + ".prototype." + MakeCamel(field.name, false);
- code += " = function(obj) {\n";
- }
-
- code += offset_prefix +
- GenGetter(field.value.type, "(obj, this.bb_pos + offset)") +
- " : null;\n";
- break;
-
- default: FLATBUFFERS_ASSERT(0);
- }
- }
- code += "};\n\n";
-
- if (parser_.opts.use_goog_js_export_format) {
- exports += "goog.exportProperty(" + object_name + ".prototype, '" +
- MakeCamel(field.name, false) + "', " + object_name +
- ".prototype." + MakeCamel(field.name, false) + ");\n";
- }
-
- // Adds the mutable scalar value to the output
- if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer &&
- !IsUnion(field.value.type)) {
- std::string annotations = GenTypeAnnotation(
- kParam, GenTypeName(field.value.type, true), "value");
- GenDocComment(
- code_ptr,
- annotations + GenTypeAnnotation(kReturns, "boolean", "", false));
-
- if (lang_.language == IDLOptions::kTs) {
- std::string type;
- if (field.value.type.enum_def) {
- if (!parser_.opts.generate_all) {
- imported_files.insert(field.value.type.enum_def->file);
- }
-
- type = GenPrefixedTypeName(GenTypeName(field.value.type, true),
- field.value.type.enum_def->file);
- } else {
- type = GenTypeName(field.value.type, true);
- }
-
- code += "mutate_" + field.name + "(value:" + type + "):boolean {\n";
- } else {
- code += object_name + ".prototype.mutate_" + field.name +
- " = function(value) {\n";
- }
-
- if (struct_def.fixed) {
- code += " " + GenBBAccess() + ".write" +
- MakeCamel(GenType(field.value.type)) + "(this.bb_pos + " +
- NumToString(field.value.offset) + ", ";
- } else {
- code += " var offset = " + GenBBAccess() +
- ".__offset(this.bb_pos, " + NumToString(field.value.offset) +
- ");\n\n";
- code += " if (offset === 0) {\n";
- code += " return false;\n";
- code += " }\n\n";
-
- // special case for bools, which are treated as uint8
- code += " " + GenBBAccess() + ".write" +
- MakeCamel(GenType(field.value.type)) +
- "(this.bb_pos + offset, ";
- if (field.value.type.base_type == BASE_TYPE_BOOL &&
- lang_.language == IDLOptions::kTs) {
- code += "+";
- }
- }
-
- code += "value);\n";
- code += " return true;\n";
- code += "};\n\n";
-
- if (parser_.opts.use_goog_js_export_format) {
- exports += "goog.exportProperty(" + object_name +
- ".prototype, 'mutate_" + field.name + "', " + object_name +
- ".prototype.mutate_" + field.name + ");\n";
- }
- }
-
- // Emit vector helpers
- if (IsVector(field.value.type)) {
- // Emit a length helper
- GenDocComment(code_ptr,
- GenTypeAnnotation(kReturns, "number", "", false));
- if (lang_.language == IDLOptions::kTs) {
- code += MakeCamel(field.name, false);
- code += "Length():number {\n" + offset_prefix;
- } else {
- code += object_name + ".prototype." + MakeCamel(field.name, false);
- code += "Length = function() {\n" + offset_prefix;
- }
-
- code +=
- GenBBAccess() + ".__vector_len(this.bb_pos + offset) : 0;\n};\n\n";
-
- if (parser_.opts.use_goog_js_export_format) {
- exports += "goog.exportProperty(" + object_name + ".prototype, '" +
- MakeCamel(field.name, false) + "Length', " + object_name +
- ".prototype." + MakeCamel(field.name, false) +
- "Length);\n";
- }
-
- // For scalar types, emit a typed array helper
- auto vectorType = field.value.type.VectorType();
- if (IsScalar(vectorType.base_type) && !IsLong(vectorType.base_type)) {
- GenDocComment(code_ptr, GenTypeAnnotation(
- kReturns, GenType(vectorType) + "Array",
- "", false));
-
- if (lang_.language == IDLOptions::kTs) {
- code += MakeCamel(field.name, false);
- code += "Array():" + GenType(vectorType) + "Array|null {\n" +
- offset_prefix;
- } else {
- code += object_name + ".prototype." + MakeCamel(field.name, false);
- code += "Array = function() {\n" + offset_prefix;
- }
-
- code += "new " + GenType(vectorType) + "Array(" + GenBBAccess() +
- ".bytes().buffer, " + GenBBAccess() +
- ".bytes().byteOffset + " + GenBBAccess() +
- ".__vector(this.bb_pos + offset), " + GenBBAccess() +
- ".__vector_len(this.bb_pos + offset)) : null;\n};\n\n";
-
- if (parser_.opts.use_goog_js_export_format) {
- exports += "goog.exportProperty(" + object_name + ".prototype, '" +
- MakeCamel(field.name, false) + "Array', " + object_name +
- ".prototype." + MakeCamel(field.name, false) +
- "Array);\n";
- }
- }
- }
- }
-
- // Emit the fully qualified name
- if (parser_.opts.generate_name_strings) {
- GenDocComment(code_ptr, GenTypeAnnotation(kReturns, "string", "", false));
- if (lang_.language == IDLOptions::kTs) {
- code += "static getFullyQualifiedName():string {\n";
- } else {
- code += object_name + ".getFullyQualifiedName = function() {\n";
- }
- code += " return '" + WRAP_IN_NAMESPACE(struct_def) + "';\n";
- code += "}\n\n";
- }
-
- // Emit the size of the struct.
- if (struct_def.fixed) {
- GenDocComment(code_ptr, GenTypeAnnotation(kReturns, "number", "", false));
- if (lang_.language == IDLOptions::kTs) {
- code += "static sizeOf():number {\n";
- } else {
- code += object_name + ".sizeOf = function() {\n";
- }
- code += " return " + NumToString(struct_def.bytesize) + ";\n";
- code += "}\n\n";
- }
-
- // Emit a factory constructor
- if (struct_def.fixed) {
- std::string annotations =
- GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder");
- std::string arguments;
- GenStructArgs(struct_def, &annotations, &arguments, "");
- GenDocComment(code_ptr, annotations + GenTypeAnnotation(
- kReturns, "flatbuffers.Offset",
- "", false));
-
- if (lang_.language == IDLOptions::kTs) {
- code += "static create" + Verbose(struct_def) +
- "(builder:flatbuffers.Builder";
- code += arguments + "):flatbuffers.Offset {\n";
- } else {
- code += object_name + ".create" + Verbose(struct_def);
- code += " = function(builder";
- code += arguments + ") {\n";
- }
-
- GenStructBody(struct_def, &code, "");
- code += " return builder.offset();\n};\n\n";
- } else {
- // Generate a method to start building a new object
- GenDocComment(code_ptr, GenTypeAnnotation(kParam, "flatbuffers.Builder",
- "builder", false));
-
- if (lang_.language == IDLOptions::kTs) {
- code += "static start" + Verbose(struct_def) +
- "(builder:flatbuffers.Builder) {\n";
- } else {
- code += object_name + ".start" + Verbose(struct_def);
- code += " = function(builder) {\n";
- }
-
- code += " builder.startObject(" +
- NumToString(struct_def.fields.vec.size()) + ");\n";
- code += "};\n\n";
-
- // Generate a set of static methods that allow table construction
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
- const auto argname = GetArgName(field);
-
- // Generate the field insertion method
- GenDocComment(
- code_ptr,
- GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
- GenTypeAnnotation(kParam, GenTypeName(field.value.type, true),
- argname, false));
-
- if (lang_.language == IDLOptions::kTs) {
- code += "static add" + MakeCamel(field.name);
- code += "(builder:flatbuffers.Builder, " + argname + ":" +
- GetArgType(field, false) + ") {\n";
- } else {
- code += object_name + ".add" + MakeCamel(field.name);
- code += " = function(builder, " + argname + ") {\n";
- }
-
- code += " builder.addField" + GenWriteMethod(field.value.type) + "(";
- code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
- if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; }
- code += argname + ", ";
- if (!IsScalar(field.value.type.base_type)) {
- code += "0";
- } else if (HasNullDefault(field)) {
- if (IsLong(field.value.type.base_type)) {
- code += "builder.createLong(0, 0)";
- } else {
- code += "0";
- }
- } else {
- if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; }
- code += GenDefaultValue(field, "builder");
- }
- code += ");\n};\n\n";
-
- if (IsVector(field.value.type)) {
- auto vector_type = field.value.type.VectorType();
- auto alignment = InlineAlignment(vector_type);
- auto elem_size = InlineSize(vector_type);
-
- // Generate a method to create a vector from a JavaScript array
- if (!IsStruct(vector_type)) {
- GenDocComment(
- code_ptr,
- GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
- GenTypeAnnotation(
- kParam,
- "Array.<" + GenTypeName(vector_type, true) + ">",
- "data") +
- GenTypeAnnotation(kReturns, "flatbuffers.Offset", "",
- false));
-
- if (lang_.language == IDLOptions::kTs) {
- const std::string sig_begin =
- "static create" + MakeCamel(field.name) +
- "Vector(builder:flatbuffers.Builder, data:";
- const std::string sig_end = "):flatbuffers.Offset";
- std::string type = GenTypeName(vector_type, true) + "[]";
- if (type == "number[]") {
- const auto &array_type = GenType(vector_type);
- // the old type should be deprecated in the future
- std::string type_old = "number[]|Uint8Array";
- std::string type_new = "number[]|" + array_type + "Array";
- if (type_old == type_new) {
- type = type_new;
- } else {
- // add function overloads
- code += sig_begin + type_new + sig_end + ";\n";
- code +=
- "/**\n * @deprecated This Uint8Array overload will "
- "be removed in the future.\n */\n";
- code += sig_begin + type_old + sig_end + ";\n";
- type = type_new + "|Uint8Array";
- }
- } else {
- if (vector_type.enum_def) {
- if (!parser_.opts.generate_all) {
- imported_files.insert(vector_type.enum_def->file);
- }
-
- type = GenPrefixedTypeName(type, vector_type.enum_def->file);
- }
- }
- code += sig_begin + type + sig_end + " {\n";
- } else {
- code += object_name + ".create" + MakeCamel(field.name);
- code += "Vector = function(builder, data) {\n";
- }
-
- code += " builder.startVector(" + NumToString(elem_size);
- code += ", data.length, " + NumToString(alignment) + ");\n";
- code += " for (var i = data.length - 1; i >= 0; i--) {\n";
- code += " builder.add" + GenWriteMethod(vector_type) + "(";
- if (vector_type.base_type == BASE_TYPE_BOOL) { code += "+"; }
- code += "data[i]);\n";
- code += " }\n";
- code += " return builder.endVector();\n";
- code += "};\n\n";
- }
-
- // Generate a method to start a vector, data to be added manually
- // after
- GenDocComment(
- code_ptr,
- GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
- GenTypeAnnotation(kParam, "number", "numElems", false));
-
- if (lang_.language == IDLOptions::kTs) {
- code += "static start" + MakeCamel(field.name);
- code += "Vector(builder:flatbuffers.Builder, numElems:number) {\n";
- } else {
- code += object_name + ".start" + MakeCamel(field.name);
- code += "Vector = function(builder, numElems) {\n";
- }
-
- code += " builder.startVector(" + NumToString(elem_size);
- code += ", numElems, " + NumToString(alignment) + ");\n";
- code += "};\n\n";
- }
- }
-
- // Generate a method to stop building a new object
- GenDocComment(
- code_ptr,
- GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
- GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false));
-
- if (lang_.language == IDLOptions::kTs) {
- code += "static end" + Verbose(struct_def);
- code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n";
- } else {
- code += object_name + ".end" + Verbose(struct_def);
- code += " = function(builder) {\n";
- }
-
- code += " var offset = builder.endObject();\n";
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (!field.deprecated && field.required) {
- code += " builder.requiredField(offset, ";
- code += NumToString(field.value.offset);
- code += "); // " + field.name + "\n";
- }
- }
- code += " return offset;\n";
- code += "};\n\n";
-
- // Generate the methods to complete buffer construction
- GenerateFinisher(struct_def, code_ptr, code, object_name, false);
- GenerateFinisher(struct_def, code_ptr, code, object_name, true);
-
- // Generate a convenient CreateX function
- if (CanCreateFactoryMethod(struct_def)) {
- if (lang_.language == IDLOptions::kJs) {
- std::string paramDoc =
- GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder");
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (field.deprecated) continue;
- paramDoc +=
- GenTypeAnnotation(kParam, GetArgType(field, true), GetArgName(field));
- }
- paramDoc +=
- GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false);
-
- GenDocComment(code_ptr, paramDoc);
- }
-
- if (lang_.language == IDLOptions::kTs) {
- code += "static create" + Verbose(struct_def);
- code += "(builder:flatbuffers.Builder";
- } else {
- code += object_name + ".create" + Verbose(struct_def);
- code += " = function(builder";
- }
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (field.deprecated) continue;
-
- if (lang_.language == IDLOptions::kTs) {
- code += ", " + GetArgName(field) + ":" + GetArgType(field, true);
- } else {
- code += ", " + GetArgName(field);
- }
- }
-
- if (lang_.language == IDLOptions::kTs) {
- std::string methodPrefix = struct_def.name;
- if (methodPrefix == "Object") {
- methodPrefix += "Generated";
- }
- code += "):flatbuffers.Offset {\n";
- code += " " + methodPrefix + ".start" + Verbose(struct_def) +
- "(builder);\n";
- } else {
- code += ") {\n";
- code += " " + object_name + ".start" + Verbose(struct_def) +
- "(builder);\n";
- }
-
- std::string methodPrefix =
- lang_.language == IDLOptions::kTs ? struct_def.name : object_name;
- if (methodPrefix == "Object") {
- methodPrefix += "Generated";
- }
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- const auto &field = **it;
- if (field.deprecated) continue;
-
- const auto arg_name = GetArgName(field);
-
- if (field.IsScalarOptional()) {
- code += " if (" + arg_name + " !== null)\n ";
- }
-
- code += " " + methodPrefix + ".add" + MakeCamel(field.name) + "(";
- code += "builder, " + arg_name + ");\n";
- }
-
- code += " return " + methodPrefix + ".end" + Verbose(struct_def) +
- "(builder);\n";
- code += "}\n";
- if (lang_.language == IDLOptions::kJs) code += "\n";
- }
- }
-
- if (!struct_def.fixed && parser_.services_.vec.size() != 0 &&
- lang_.language == IDLOptions::kTs) {
- auto name = Verbose(struct_def, "");
- code += "\n";
- code += "serialize():Uint8Array {\n";
- code += " return this.bb!.bytes();\n";
- code += "}\n";
-
- code += "\n";
- code += "static deserialize(buffer: Uint8Array):"+ name +" {\n";
- code += " return " + name + ".getRootAs" + name +
- "(new flatbuffers.ByteBuffer(buffer))\n";
- code += "}\n";
- }
-
- if (lang_.language == IDLOptions::kTs) {
- if (parser_.opts.generate_object_based_api) {
- std::string obj_api_class;
- std::string obj_api_unpack_func;
- GenObjApi(parser_, struct_def, obj_api_unpack_func, obj_api_class,
- imported_files);
-
- code += obj_api_unpack_func + "}\n" + obj_api_class;
- } else {
- code += "}\n";
- }
- if (!object_namespace.empty()) { code += "}\n"; }
- }
- }
-
- static bool HasNullDefault(const FieldDef &field) {
- return field.optional && field.value.constant == "null";
- }
-
- std::string GetArgType(const FieldDef &field, bool allowNull) {
- auto type_name = GenTypeName(field.value.type, true, allowNull && field.optional);
-
- if (field.value.type.enum_def) {
- if (IsScalar(field.value.type.base_type)) {
- return GenPrefixedTypeName(type_name, field.value.type.enum_def->file);
- }
- }
-
- return type_name;
- }
-
- static std::string GetArgName(const FieldDef &field) {
- auto argname = MakeCamel(field.name, false);
- if (!IsScalar(field.value.type.base_type)) { argname += "Offset"; }
-
- return argname;
- }
-
- std::string Verbose(const StructDef &struct_def, const char *prefix = "") {
- return parser_.opts.js_ts_short_names ? "" : prefix + struct_def.name;
- }
-}; // namespace jsts
-} // namespace jsts
-
-bool GenerateJSTS(const Parser &parser, const std::string &path,
- const std::string &file_name) {
- jsts::JsTsGenerator generator(parser, path, file_name);
- return generator.generate();
-}
-
-std::string JSTSMakeRule(const Parser &parser, const std::string &path,
- const std::string &file_name) {
- FLATBUFFERS_ASSERT(parser.opts.lang <= IDLOptions::kMAX);
-
- std::string filebase =
- flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
- jsts::JsTsGenerator generator(parser, path, file_name);
- std::string make_rule =
- generator.GeneratedFileName(path, filebase, parser.opts) + ": ";
-
- auto included_files = parser.GetIncludedFilesRecursive(file_name);
- for (auto it = included_files.begin(); it != included_files.end(); ++it) {
- make_rule += " " + *it;
- }
- return make_rule;
-}
-
-} // namespace flatbuffers
diff --git a/third_party/flatbuffers/src/idl_gen_json_schema.cpp b/third_party/flatbuffers/src/idl_gen_json_schema.cpp
index 76540d1..9ea37ae 100644
--- a/third_party/flatbuffers/src/idl_gen_json_schema.cpp
+++ b/third_party/flatbuffers/src/idl_gen_json_schema.cpp
@@ -49,10 +49,10 @@
return "\"type\" : \"integer\", \"minimum\" : " +
NumToString(std::numeric_limits<int8_t>::min()) +
", \"maximum\" : " +
- NumToString(std::numeric_limits<int8_t>::max()) + "\"";
+ NumToString(std::numeric_limits<int8_t>::max());
case BASE_TYPE_UCHAR:
return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" :" +
- NumToString(std::numeric_limits<uint8_t>::max()) + "\"";
+ NumToString(std::numeric_limits<uint8_t>::max());
case BASE_TYPE_SHORT:
return "\"type\" : \"integer\", \"minimum\" : " +
NumToString(std::numeric_limits<int16_t>::min()) +
@@ -166,9 +166,45 @@
return std::string(num_spaces, ' ');
}
+ std::string PrepareDescription(
+ const std::vector<std::string> &comment_lines) {
+ std::string comment;
+ for (auto line_iterator = comment_lines.cbegin();
+ line_iterator != comment_lines.cend(); ++line_iterator) {
+ const auto &comment_line = *line_iterator;
+
+ // remove leading and trailing spaces from comment line
+ const auto start = std::find_if(comment_line.begin(), comment_line.end(),
+ [](char c) { return !isspace(c); });
+ const auto end =
+ std::find_if(comment_line.rbegin(), comment_line.rend(), [](char c) {
+ return !isspace(c);
+ }).base();
+ if (start < end) {
+ comment.append(start, end);
+ } else {
+ comment.append(comment_line);
+ }
+
+ if (line_iterator + 1 != comment_lines.cend()) comment.append("\n");
+ }
+ if (!comment.empty()) {
+ std::string description;
+ if (EscapeString(comment.c_str(), comment.length(), &description, true,
+ true)) {
+ return description;
+ }
+ return "";
+ }
+ return "";
+ }
+
bool generate() {
code_ = "";
- if (parser_.root_struct_def_ == nullptr) { return false; }
+ if (parser_.root_struct_def_ == nullptr) {
+ std::cerr << "Error: Binary schema not generated, no root struct found\n";
+ return false;
+ }
code_ += "{" + NewLine();
code_ += Indent(1) +
"\"$schema\": \"https://json-schema.org/draft/2019-09/schema\"," +
@@ -193,21 +229,12 @@
const auto &structure = *s;
code_ += Indent(2) + "\"" + GenFullName(structure) + "\" : {" + NewLine();
code_ += Indent(3) + GenType("object") + "," + NewLine();
- std::string comment;
const auto &comment_lines = structure->doc_comment;
- for (auto comment_line = comment_lines.cbegin();
- comment_line != comment_lines.cend(); ++comment_line) {
- comment.append(*comment_line);
+ auto comment = PrepareDescription(comment_lines);
+ if (comment != "") {
+ code_ += Indent(3) + "\"description\" : " + comment + "," + NewLine();
}
- if (!comment.empty()) {
- std::string description;
- if (!EscapeString(comment.c_str(), comment.length(), &description, true,
- true)) {
- return false;
- }
- code_ +=
- Indent(3) + "\"description\" : " + description + "," + NewLine();
- }
+
code_ += Indent(3) + "\"properties\" : {" + NewLine();
const auto &properties = structure->fields.vec;
@@ -223,13 +250,19 @@
std::string deprecated_info = "";
if (property->deprecated) {
deprecated_info =
- "," + NewLine() + Indent(8) + "\"deprecated\" : true,";
+ "," + NewLine() + Indent(8) + "\"deprecated\" : true";
}
std::string typeLine = Indent(4) + "\"" + property->name + "\"";
typeLine += " : {" + NewLine() + Indent(8);
typeLine += GenType(property->value.type);
typeLine += arrayInfo;
typeLine += deprecated_info;
+ auto description = PrepareDescription(property->doc_comment);
+ if (description != "") {
+ typeLine +=
+ "," + NewLine() + Indent(8) + "\"description\" : " + description;
+ }
+
typeLine += NewLine() + Indent(7) + "}";
if (property != properties.back()) { typeLine.append(","); }
code_ += typeLine + NewLine();
@@ -239,7 +272,7 @@
std::vector<FieldDef *> requiredProperties;
std::copy_if(properties.begin(), properties.end(),
back_inserter(requiredProperties),
- [](FieldDef const *prop) { return prop->required; });
+ [](FieldDef const *prop) { return prop->IsRequired(); });
if (!requiredProperties.empty()) {
auto required_string(Indent(3) + "\"required\" : [");
for (auto req_prop = requiredProperties.cbegin();
@@ -268,8 +301,7 @@
}
bool save() const {
- const auto file_path =
- GeneratedFileName(path_, file_name_, parser_.opts);
+ const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts);
return SaveFile(file_path.c_str(), code_, false);
}
diff --git a/third_party/flatbuffers/src/idl_gen_kotlin.cpp b/third_party/flatbuffers/src/idl_gen_kotlin.cpp
index ed85b2c..fc55aeb 100644
--- a/third_party/flatbuffers/src/idl_gen_kotlin.cpp
+++ b/third_party/flatbuffers/src/idl_gen_kotlin.cpp
@@ -23,9 +23,6 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
-#if defined(FLATBUFFERS_CPP98_STL)
-# include <cctype>
-#endif // defined(FLATBUFFERS_CPP98_STL)
namespace flatbuffers {
@@ -49,10 +46,12 @@
// Escape Keywords
static std::string Esc(const std::string &name) {
for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
- if (name == keywords[i]) { return MakeCamel(name + "_", false); }
+ if (name == keywords[i]) {
+ return ConvertCase(name + "_", Case::kLowerCamel);
+ }
}
- return MakeCamel(name, false);
+ return ConvertCase(name, Case::kLowerCamel);
}
class KotlinGenerator : public BaseGenerator {
@@ -262,7 +261,6 @@
GenerateComment(enum_def.doc_comment, writer, &comment_config);
writer += "@Suppress(\"unused\")";
- writer += "@ExperimentalUnsignedTypes";
writer += "class " + Esc(enum_def.name) + " private constructor() {";
writer.IncrementIdentLevel();
@@ -341,7 +339,8 @@
case BASE_TYPE_UTYPE: return bb_var_name + ".get";
case BASE_TYPE_BOOL: return "0.toByte() != " + bb_var_name + ".get";
default:
- return bb_var_name + ".get" + MakeCamel(GenTypeBasic(type.base_type));
+ return bb_var_name + ".get" +
+ ConvertCase(GenTypeBasic(type.base_type), Case::kUpperCamel);
}
}
@@ -361,7 +360,9 @@
case BASE_TYPE_BOOL:
case BASE_TYPE_NONE:
case BASE_TYPE_UTYPE: return "bb.put";
- default: return "bb.put" + MakeCamel(GenTypeBasic(type.base_type));
+ default:
+ return "bb.put" +
+ ConvertCase(GenTypeBasic(type.base_type), Case::kUpperCamel);
}
}
return "";
@@ -398,7 +399,7 @@
(nameprefix + (field.name + "_")).c_str());
} else {
writer += std::string(", ") + nameprefix + "\\";
- writer += MakeCamel(field.name) + ": \\";
+ writer += ConvertCase(field.name, Case::kUpperCamel) + ": \\";
writer += GenTypeBasic(field.value.type.base_type) + "\\";
}
}
@@ -425,7 +426,8 @@
(nameprefix + (field.name + "_")).c_str());
} else {
writer.SetValue("type", GenMethod(field.value.type));
- writer.SetValue("argname", nameprefix + MakeCamel(field.name, false));
+ writer.SetValue("argname", nameprefix + ConvertCase(Esc(field.name),
+ Case::kLowerCamel));
writer.SetValue("cast", CastToSigned(field.value.type));
writer += "builder.put{{type}}({{argname}}{{cast}})";
}
@@ -463,7 +465,6 @@
writer.SetValue("superclass", fixed ? "Struct" : "Table");
writer += "@Suppress(\"unused\")";
- writer += "@ExperimentalUnsignedTypes";
writer += "class {{struct_name}} : {{superclass}}() {\n";
writer.IncrementIdentLevel();
@@ -494,7 +495,7 @@
// runtime.
GenerateFunOneLine(
writer, "validateVersion", "", "",
- [&]() { writer += "Constants.FLATBUFFERS_1_12_0()"; },
+ [&]() { writer += "Constants.FLATBUFFERS_2_0_0()"; },
options.gen_jvmstatic);
GenerateGetRootAsAccessors(Esc(struct_def.name), writer, options);
@@ -646,7 +647,7 @@
writer.IncrementIdentLevel();
for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
auto &field = **it;
- if (field.deprecated || !field.required) { continue; }
+ if (field.deprecated || !field.IsRequired()) { continue; }
writer.SetValue("offset", NumToString(field.value.offset));
writer += "builder.required(o, {{offset}})";
}
@@ -660,7 +661,8 @@
void GenerateCreateVectorField(FieldDef &field, CodeWriter &writer,
const IDLOptions options) const {
auto vector_type = field.value.type.VectorType();
- auto method_name = "create" + MakeCamel(Esc(field.name)) + "Vector";
+ auto method_name =
+ "create" + ConvertCase(Esc(field.name), Case::kUpperCamel) + "Vector";
auto params = "builder: FlatBufferBuilder, data: " +
GenTypeBasic(vector_type.base_type) + "Array";
writer.SetValue("size", NumToString(InlineSize(vector_type)));
@@ -692,8 +694,9 @@
writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
GenerateFunOneLine(
- writer, "start" + MakeCamel(Esc(field.name) + "Vector", true), params,
- "",
+ writer,
+ "start" + ConvertCase(Esc(field.name) + "Vector", Case::kUpperCamel),
+ params, "",
[&]() {
writer += "builder.startVector({{size}}, numElems, {{align}})";
},
@@ -703,14 +706,16 @@
void GenerateAddField(std::string field_pos, FieldDef &field,
CodeWriter &writer, const IDLOptions options) const {
auto field_type = GenTypeBasic(field.value.type.base_type);
- auto secondArg = MakeCamel(Esc(field.name), false) + ": " + field_type;
+ auto secondArg =
+ ConvertCase(Esc(field.name), Case::kLowerCamel) + ": " + field_type;
GenerateFunOneLine(
- writer, "add" + MakeCamel(Esc(field.name), true),
+ writer, "add" + ConvertCase(Esc(field.name), Case::kUpperCamel),
"builder: FlatBufferBuilder, " + secondArg, "",
[&]() {
auto method = GenMethod(field.value.type);
- writer.SetValue("field_name", MakeCamel(Esc(field.name), false));
+ writer.SetValue("field_name",
+ ConvertCase(Esc(field.name), Case::kLowerCamel));
writer.SetValue("method_name", method);
writer.SetValue("pos", field_pos);
writer.SetValue("default", GenFBBDefaultValue(field));
@@ -801,7 +806,7 @@
for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
- params << ", " << MakeCamel(Esc(field.name), false);
+ params << ", " << ConvertCase(Esc(field.name), Case::kLowerCamel);
if (!IsScalar(field.value.type.base_type)) {
params << "Offset: ";
} else {
@@ -827,10 +832,11 @@
auto base_type_size = SizeOf(field.value.type.base_type);
if (!field.deprecated &&
(!sortbysize || size == base_type_size)) {
- writer.SetValue("camel_field_name",
- MakeCamel(Esc(field.name), true));
- writer.SetValue("field_name",
- MakeCamel(Esc(field.name), false));
+ writer.SetValue(
+ "camel_field_name",
+ ConvertCase(Esc(field.name), Case::kUpperCamel));
+ writer.SetValue("field_name", ConvertCase(Esc(field.name),
+ Case::kLowerCamel));
// we wrap on null check for scalar optionals
writer += field.IsScalarOptional()
@@ -857,7 +863,7 @@
// Check if a buffer has the identifier.
if (parser_.root_struct_def_ != &struct_def || !file_identifier.length())
return;
- auto name = MakeCamel(Esc(struct_def.name), false);
+ auto name = ConvertCase(Esc(struct_def.name), Case::kLowerCamel);
GenerateFunOneLine(
writer, name + "BufferHasIdentifier", "_bb: ByteBuffer", "Boolean",
[&]() {
@@ -876,7 +882,7 @@
GenerateComment(field.doc_comment, writer, &comment_config);
- auto field_name = MakeCamel(Esc(field.name), false);
+ auto field_name = ConvertCase(Esc(field.name), Case::kLowerCamel);
auto field_type = GenTypeGet(field.value.type);
auto field_default_value = GenDefaultValue(field);
auto return_type = GetterReturnType(field);
@@ -1047,7 +1053,8 @@
auto &kfield = **kit;
if (kfield.key) {
auto qualified_name = WrapInNameSpace(sd);
- auto name = MakeCamel(Esc(field.name), false) + "ByKey";
+ auto name =
+ ConvertCase(Esc(field.name), Case::kLowerCamel) + "ByKey";
auto params = "key: " + GenTypeGet(kfield.value.type);
auto rtype = qualified_name + "?";
GenerateFun(writer, name, params, rtype, [&]() {
@@ -1140,7 +1147,7 @@
auto underlying_type = value_base_type == BASE_TYPE_VECTOR
? value_type.VectorType()
: value_type;
- auto name = "mutate" + MakeCamel(Esc(field.name), true);
+ auto name = "mutate" + ConvertCase(Esc(field.name), Case::kUpperCamel);
auto size = NumToString(InlineSize(underlying_type));
auto params = Esc(field.name) + ": " + GenTypeGet(underlying_type);
// A vector mutator also needs the index of the vector element it should
@@ -1343,8 +1350,8 @@
out << StructConstructorParams(*field.value.type.struct_def,
prefix + (Esc(field.name) + "_"));
} else {
- out << ", " << prefix << MakeCamel(Esc(field.name), false) << ": "
- << GenTypeBasic(field.value.type.base_type);
+ out << ", " << prefix << ConvertCase(Esc(field.name), Case::kLowerCamel)
+ << ": " << GenTypeBasic(field.value.type.base_type);
}
}
return out.str();
diff --git a/third_party/flatbuffers/src/idl_gen_lobster.cpp b/third_party/flatbuffers/src/idl_gen_lobster.cpp
index 4ebf8ca..c1e78ad 100644
--- a/third_party/flatbuffers/src/idl_gen_lobster.cpp
+++ b/third_party/flatbuffers/src/idl_gen_lobster.cpp
@@ -60,7 +60,10 @@
std::string GenTypeName(const Type &type) {
auto bits = NumToString(SizeOf(type.base_type) * 8);
- if (IsInteger(type.base_type)) return "int" + bits;
+ if (IsInteger(type.base_type)) {
+ if (IsUnsigned(type.base_type)) return "uint" + bits;
+ else return "int" + bits;
+ }
if (IsFloat(type.base_type)) return "float" + bits;
if (IsString(type)) return "string";
if (type.base_type == BASE_TYPE_STRUCT) return "table";
@@ -78,7 +81,7 @@
// Returns the method name for use with add/put calls.
std::string GenMethod(const Type &type) {
return IsScalar(type.base_type)
- ? MakeCamel(GenTypeBasic(type))
+ ? ConvertCase(GenTypeBasic(type), Case::kUpperCamel)
: (IsStruct(type) ? "Struct" : "UOffsetTRelative");
}
@@ -110,13 +113,13 @@
offsets + ")";
} else {
- auto defval = field.optional ? "0" : field.value.constant;
+ auto defval = field.IsOptional() ? "0" : field.value.constant;
acc = "buf_.flatbuffers_field_" + GenTypeName(field.value.type) +
"(pos_, " + offsets + ", " + defval + ")";
}
if (field.value.type.enum_def)
acc = NormalizedName(*field.value.type.enum_def) + "(" + acc + ")";
- if (field.optional)
+ if (field.IsOptional())
acc += ", buf_.flatbuffers_field_present(pos_, " + offsets + ")";
code += def + "():\n return " + acc + "\n";
return;
@@ -201,7 +204,7 @@
NormalizedName(field) + ":" + LobsterType(field.value.type) +
"):\n b_.Prepend" + GenMethod(field.value.type) + "Slot(" +
NumToString(offset) + ", " + NormalizedName(field);
- if (IsScalar(field.value.type.base_type) && !field.optional)
+ if (IsScalar(field.value.type.base_type) && !field.IsOptional())
code += ", " + field.value.constant;
code += ")\n return this\n";
}
@@ -212,7 +215,7 @@
if (field.deprecated) continue;
if (IsVector(field.value.type)) {
code += "def " + NormalizedName(struct_def) + "Start" +
- MakeCamel(NormalizedName(field)) +
+ ConvertCase(NormalizedName(field), Case::kUpperCamel) +
"Vector(b_:flatbuffers_builder, n_:int):\n b_.StartVector(";
auto vector_type = field.value.type.VectorType();
auto alignment = InlineAlignment(vector_type);
@@ -222,7 +225,7 @@
if (vector_type.base_type != BASE_TYPE_STRUCT ||
!vector_type.struct_def->fixed) {
code += "def " + NormalizedName(struct_def) + "Create" +
- MakeCamel(NormalizedName(field)) +
+ ConvertCase(NormalizedName(field), Case::kUpperCamel) +
"Vector(b_:flatbuffers_builder, v_:[" +
LobsterType(vector_type) + "]):\n b_.StartVector(" +
NumToString(elem_size) + ", v_.length, " +
diff --git a/third_party/flatbuffers/src/idl_gen_lua.cpp b/third_party/flatbuffers/src/idl_gen_lua.cpp
index 9788485..7be0015 100644
--- a/third_party/flatbuffers/src/idl_gen_lua.cpp
+++ b/third_party/flatbuffers/src/idl_gen_lua.cpp
@@ -124,6 +124,10 @@
code += "function " + NormalizedName(struct_def) + ".GetRootAs" +
NormalizedName(struct_def) + "(buf, offset)\n";
+ code += std::string(Indent) + "if type(buf) == \"string\" then\n";
+ code += std::string(Indent) + Indent +
+ "buf = flatbuffers.binaryArray.New(buf)\n";
+ code += std::string(Indent) + "end\n";
code += std::string(Indent) +
"local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)\n";
code += std::string(Indent) + "local o = " + NormalizedName(struct_def) +
@@ -150,7 +154,8 @@
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field)) + "Length()\n";
+ code +=
+ ConvertCase(NormalizedName(field), Case::kUpperCamel) + "Length()\n";
code += OffsetPrefix(field);
code +=
std::string(Indent) + Indent + "return " + SelfData + ":VectorLen(o)\n";
@@ -165,7 +170,7 @@
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
code += "()\n";
code += std::string(Indent) + "return " + getter;
code += std::string(SelfDataPos) + " + " + NumToString(field.value.offset) +
@@ -179,7 +184,7 @@
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
code += "()\n";
code += OffsetPrefix(field);
getter += std::string("o + ") + SelfDataPos + ")";
@@ -203,7 +208,7 @@
const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
code += "(obj)\n";
code += std::string(Indent) + "obj:Init(" + SelfDataBytes + ", " +
SelfDataPos + " + ";
@@ -218,7 +223,7 @@
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
code += "()\n";
code += OffsetPrefix(field);
if (field.value.type.struct_def->fixed) {
@@ -242,7 +247,7 @@
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
code += "()\n";
code += OffsetPrefix(field);
code +=
@@ -257,7 +262,7 @@
std::string *code_ptr) {
std::string &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field)) + "()\n";
+ code += ConvertCase(NormalizedName(field), Case::kUpperCamel) + "()\n";
code += OffsetPrefix(field);
// TODO(rw): this works and is not the good way to it:
@@ -288,7 +293,7 @@
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
code += "(j)\n";
code += OffsetPrefix(field);
code +=
@@ -317,7 +322,7 @@
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
code += "(j)\n";
code += OffsetPrefix(field);
code +=
@@ -335,6 +340,18 @@
code += EndFunc;
}
+ // Access a byte/ubyte vector as a string
+ void AccessByteVectorAsString(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
+ code += "AsString(start, stop)\n";
+ code += std::string(Indent) + "return " + SelfData + ":VectorAsString(" +
+ NumToString(field.value.offset) + ", start, stop)\n";
+ code += EndFunc;
+ }
+
// Begin the creator function signature.
void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
@@ -361,7 +378,7 @@
} else {
std::string &code = *code_ptr;
code += std::string(", ") + nameprefix;
- code += MakeCamel(NormalizedName(field), false);
+ code += ConvertCase(NormalizedName(field), Case::kLowerCamel);
}
}
}
@@ -393,7 +410,8 @@
} else {
code +=
std::string(Indent) + "builder:Prepend" + GenMethod(field) + "(";
- code += nameprefix + MakeCamel(NormalizedName(field), false) + ")\n";
+ code += nameprefix +
+ ConvertCase(NormalizedName(field), Case::kLowerCamel) + ")\n";
}
}
}
@@ -419,9 +437,9 @@
const size_t offset, std::string *code_ptr) {
std::string &code = *code_ptr;
code += "function " + NormalizedName(struct_def) + ".Add" +
- MakeCamel(NormalizedName(field));
+ ConvertCase(NormalizedName(field), Case::kUpperCamel);
code += "(builder, ";
- code += MakeCamel(NormalizedName(field), false);
+ code += ConvertCase(NormalizedName(field), Case::kLowerCamel);
code += ") ";
code += "builder:Prepend";
code += GenMethod(field) + "Slot(";
@@ -430,9 +448,9 @@
// if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
// code += "flatbuffers.N.UOffsetTFlags.py_type";
// code += "(";
- // code += MakeCamel(NormalizedName(field), false) + ")";
+ // code += ConvertCase(NormalizedName(field), Case::kLowerCamel) + ")";
// } else {
- code += MakeCamel(NormalizedName(field), false);
+ code += ConvertCase(NormalizedName(field), Case::kLowerCamel);
// }
code += ", " + field.value.constant;
code += ") end\n";
@@ -443,7 +461,7 @@
std::string *code_ptr) {
std::string &code = *code_ptr;
code += "function " + NormalizedName(struct_def) + ".Start";
- code += MakeCamel(NormalizedName(field));
+ code += ConvertCase(NormalizedName(field), Case::kUpperCamel);
code += "Vector(builder, numElems) return builder:StartVector(";
auto vector_type = field.value.type.VectorType();
auto alignment = InlineAlignment(vector_type);
@@ -495,6 +513,10 @@
GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
} else {
GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+ if (vectortype.base_type == BASE_TYPE_CHAR ||
+ vectortype.base_type == BASE_TYPE_UCHAR) {
+ AccessByteVectorAsString(struct_def, field, code_ptr);
+ }
}
break;
}
@@ -583,14 +605,14 @@
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
default:
return std::string(SelfData) + ":Get(flatbuffers.N." +
- MakeCamel(GenTypeGet(type)) + ", ";
+ ConvertCase(GenTypeGet(type), Case::kUpperCamel) + ", ";
}
}
// Returns the method name for use with add/put calls.
std::string GenMethod(const FieldDef &field) {
return IsScalar(field.value.type.base_type)
- ? MakeCamel(GenTypeBasic(field.value.type))
+ ? ConvertCase(GenTypeBasic(field.value.type), Case::kUpperCamel)
: (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
}
diff --git a/third_party/flatbuffers/src/idl_gen_php.cpp b/third_party/flatbuffers/src/idl_gen_php.cpp
index b986fe3..5896935 100644
--- a/third_party/flatbuffers/src/idl_gen_php.cpp
+++ b/third_party/flatbuffers/src/idl_gen_php.cpp
@@ -181,7 +181,7 @@
code += Indent + " * @return int\n";
code += Indent + " */\n";
code += Indent + "public function get";
- code += MakeCamel(field.name) + "Length()\n";
+ code += ConvertCase(field.name, Case::kUpperCamel) + "Length()\n";
code += Indent + "{\n";
code += Indent + Indent + "$o = $this->__offset(";
code += NumToString(field.value.offset) + ");\n";
@@ -198,7 +198,7 @@
code += Indent + " * @return string\n";
code += Indent + " */\n";
code += Indent + "public function get";
- code += MakeCamel(field.name) + "Bytes()\n";
+ code += ConvertCase(field.name, Case::kUpperCamel) + "Bytes()\n";
code += Indent + "{\n";
code += Indent + Indent + "return $this->__vector_as_bytes(";
code += NumToString(field.value.offset) + ");\n";
@@ -216,12 +216,12 @@
code += GenTypeGet(field.value.type) + "\n";
code += Indent + " */\n";
code += Indent + "public function " + getter;
- code += MakeCamel(field.name) + "()\n";
+ code += ConvertCase(field.name, Case::kUpperCamel) + "()\n";
code += Indent + "{\n";
code += Indent + Indent + "return ";
code += "$this->bb->get";
- code += MakeCamel(GenTypeGet(field.value.type));
+ code += ConvertCase(GenTypeGet(field.value.type), Case::kUpperCamel);
code += "($this->bb_pos + ";
code += NumToString(field.value.offset) + ")";
code += ";\n";
@@ -237,14 +237,15 @@
code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
code += Indent + " */\n";
code += Indent + "public function get";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "()\n";
code += Indent + "{\n";
code += Indent + Indent + "$o = $this->__offset(" +
NumToString(field.value.offset) + ");\n" + Indent + Indent +
"return $o != 0 ? ";
code += "$this->bb->get";
- code += MakeCamel(GenTypeGet(field.value.type)) + "($o + $this->bb_pos)";
+ code += ConvertCase(GenTypeGet(field.value.type), Case::kUpperCamel) +
+ "($o + $this->bb_pos)";
code += " : " + GenDefaultValue(field.value) + ";\n";
code += Indent + "}\n\n";
}
@@ -258,7 +259,7 @@
code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
code += Indent + " */\n";
code += Indent + "public function get";
- code += MakeCamel(field.name) + "()\n";
+ code += ConvertCase(field.name, Case::kUpperCamel) + "()\n";
code += Indent + "{\n";
code += Indent + Indent + "$obj = new ";
code += GenTypeGet(field.value.type) + "();\n";
@@ -274,11 +275,12 @@
std::string &code = *code_ptr;
code += Indent + "public function get";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "()\n";
code += Indent + "{\n";
code += Indent + Indent + "$obj = new ";
- code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
+ code +=
+ ConvertCase(GenTypeGet(field.value.type), Case::kUpperCamel) + "();\n";
code += Indent + Indent + "$o = $this->__offset(" +
NumToString(field.value.offset) + ");\n";
code += Indent + Indent;
@@ -296,7 +298,7 @@
void GetStringField(const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent + "public function get";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "()\n";
code += Indent + "{\n";
code += Indent + Indent + "$o = $this->__offset(" +
@@ -315,7 +317,7 @@
code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
code += Indent + " */\n";
code += Indent + "public function get";
- code += MakeCamel(field.name) + "($obj)\n";
+ code += ConvertCase(field.name, Case::kUpperCamel) + "($obj)\n";
code += Indent + "{\n";
code += Indent + Indent + "$o = $this->__offset(" +
NumToString(field.value.offset) + ");\n";
@@ -334,13 +336,14 @@
code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
code += Indent + " */\n";
code += Indent + "public function get";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "($j)\n";
code += Indent + "{\n";
code += Indent + Indent + "$o = $this->__offset(" +
NumToString(field.value.offset) + ");\n";
code += Indent + Indent + "$obj = new ";
- code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
+ code +=
+ ConvertCase(GenTypeGet(field.value.type), Case::kUpperCamel) + "();\n";
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT:
@@ -395,7 +398,7 @@
code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
code += Indent + " */\n";
code += Indent + "public function get";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "($j)\n";
code += Indent + "{\n";
code += Indent + Indent + "$o = $this->__offset(" +
@@ -408,7 +411,7 @@
code += GenDefaultValue(field.value) + ";\n";
} else {
code += Indent + Indent + "return $o != 0 ? $this->bb->get";
- code += MakeCamel(GenTypeGet(field.value.type));
+ code += ConvertCase(GenTypeGet(field.value.type), Case::kUpperCamel);
code += "($this->__vector($o) + $j * ";
code += NumToString(InlineSize(vectortype)) + ") : ";
code += GenDefaultValue(field.value) + ";\n";
@@ -427,7 +430,7 @@
code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
code += Indent + " */\n";
code += Indent + "public function get";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "($j, $obj)\n";
code += Indent + "{\n";
code += Indent + Indent + "$o = $this->__offset(" +
@@ -455,7 +458,7 @@
} else {
std::string &code = *code_ptr;
code += std::string(", $") + nameprefix;
- code += MakeCamel(field.name, false);
+ code += ConvertCase(field.name, Case::kLowerCamel);
}
}
}
@@ -480,7 +483,8 @@
(nameprefix + (field.name + "_")).c_str(), code_ptr);
} else {
code += Indent + Indent + "$builder->put" + GenMethod(field) + "($";
- code += nameprefix + MakeCamel(field.name, false) + ");\n";
+ code +=
+ nameprefix + ConvertCase(field.name, Case::kLowerCamel) + ");\n";
}
}
}
@@ -528,7 +532,8 @@
if (field.deprecated) continue;
code += Indent + Indent + "self::add";
- code += MakeCamel(field.name) + "($builder, $" + field.name + ");\n";
+ code += ConvertCase(field.name, Case::kUpperCamel) + "($builder, $" +
+ field.name + ");\n";
}
code += Indent + Indent + "$o = $builder->endObject();\n";
@@ -536,7 +541,7 @@
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
- if (!field.deprecated && field.required) {
+ if (!field.deprecated && field.IsRequired()) {
code += Indent + Indent + "$builder->required($o, ";
code += NumToString(field.value.offset);
code += "); // " + field.name + "\n";
@@ -557,16 +562,16 @@
code += Indent + " * @return void\n";
code += Indent + " */\n";
code += Indent + "public static function ";
- code += "add" + MakeCamel(field.name);
+ code += "add" + ConvertCase(field.name, Case::kUpperCamel);
code += "(FlatBufferBuilder $builder, ";
- code += "$" + MakeCamel(field.name, false);
+ code += "$" + ConvertCase(field.name, Case::kLowerCamel);
code += ")\n";
code += Indent + "{\n";
code += Indent + Indent + "$builder->add";
code += GenMethod(field) + "X(";
code += NumToString(offset) + ", ";
- code += "$" + MakeCamel(field.name, false);
+ code += "$" + ConvertCase(field.name, Case::kLowerCamel);
code += ", ";
if (field.value.type.base_type == BASE_TYPE_BOOL) {
@@ -591,7 +596,7 @@
code += Indent + " * @return int vector offset\n";
code += Indent + " */\n";
code += Indent + "public static function create";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "Vector(FlatBufferBuilder $builder, array $data)\n";
code += Indent + "{\n";
code += Indent + Indent + "$builder->startVector(";
@@ -603,7 +608,8 @@
if (IsScalar(field.value.type.VectorType().base_type)) {
code += Indent + Indent + Indent;
code += "$builder->put";
- code += MakeCamel(GenTypeBasic(field.value.type.VectorType()));
+ code += ConvertCase(GenTypeBasic(field.value.type.VectorType()),
+ Case::kUpperCamel);
code += "($data[$i]);\n";
} else {
code += Indent + Indent + Indent;
@@ -619,7 +625,7 @@
code += Indent + " * @return void\n";
code += Indent + " */\n";
code += Indent + "public static function start";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "Vector(FlatBufferBuilder $builder, $numElems)\n";
code += Indent + "{\n";
code += Indent + Indent + "$builder->startVector(";
@@ -645,7 +651,7 @@
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
- if (!field.deprecated && field.required) {
+ if (!field.deprecated && field.IsRequired()) {
code += Indent + Indent + "$builder->required($o, ";
code += NumToString(field.value.offset);
code += "); // " + field.name + "\n";
@@ -726,7 +732,7 @@
if (field.value.type.base_type == BASE_TYPE_UNION) {
std::string &code = *code_ptr;
code += Indent + "public static function add";
- code += MakeCamel(field.name);
+ code += ConvertCase(field.name, Case::kUpperCamel);
code += "(FlatBufferBuilder $builder, $offset)\n";
code += Indent + "{\n";
code += Indent + Indent + "$builder->addOffsetX(";
@@ -735,9 +741,7 @@
} else {
BuildFieldOfTable(field, offset, code_ptr);
}
- if (IsVector(field.value.type)) {
- BuildVectorOfTable(field, code_ptr);
- }
+ if (IsVector(field.value.type)) { BuildVectorOfTable(field, code_ptr); }
}
GetEndOffsetOnTable(struct_def, code_ptr);
@@ -855,7 +859,7 @@
// Returns the method name for use with add/put calls.
static std::string GenMethod(const FieldDef &field) {
return IsScalar(field.value.type.base_type)
- ? MakeCamel(GenTypeBasic(field.value.type))
+ ? ConvertCase(GenTypeBasic(field.value.type), Case::kUpperCamel)
: (IsStruct(field.value.type) ? "Struct" : "Offset");
}
diff --git a/third_party/flatbuffers/src/idl_gen_python.cpp b/third_party/flatbuffers/src/idl_gen_python.cpp
index 1260673..8426b6e 100644
--- a/third_party/flatbuffers/src/idl_gen_python.cpp
+++ b/third_party/flatbuffers/src/idl_gen_python.cpp
@@ -26,10 +26,42 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
+#include "namer.h"
namespace flatbuffers {
namespace python {
+std::set<std::string> PythonKeywords() {
+ return { "False", "None", "True", "and", "as", "assert",
+ "break", "class", "continue", "def", "del", "elif",
+ "else", "except", "finally", "for", "from", "global",
+ "if", "import", "in", "is", "lambda", "nonlocal",
+ "not", "or", "pass", "raise", "return", "try",
+ "while", "with", "yield" };
+}
+
+Namer::Config PythonDefaultConfig() {
+ return { /*types=*/Case::kKeep,
+ /*constants=*/Case::kScreamingSnake,
+ /*methods=*/Case::kUpperCamel,
+ /*functions=*/Case::kUpperCamel,
+ /*fields=*/Case::kLowerCamel,
+ /*variable=*/Case::kLowerCamel,
+ /*variants=*/Case::kKeep,
+ /*enum_variant_seperator=*/".",
+ /*namespaces=*/Case::kKeep, // Packages in python.
+ /*namespace_seperator=*/".",
+ /*object_prefix=*/"",
+ /*object_suffix=*/"T",
+ /*keyword_prefix=*/"",
+ /*keyword_suffix=*/"_",
+ /*filenames=*/Case::kKeep,
+ /*directories=*/Case::kKeep,
+ /*output_path=*/"",
+ /*filename_suffix=*/"",
+ /*filename_extension=*/".py" };
+}
+
// Hardcode spaces per indentation.
const CommentConfig def_comment = { nullptr, "#", nullptr };
const std::string Indent = " ";
@@ -40,20 +72,13 @@
const std::string &file_name)
: BaseGenerator(parser, path, file_name, "" /* not used */,
"" /* not used */, "py"),
- float_const_gen_("float('nan')", "float('inf')", "float('-inf')") {
- static const char *const keywords[] = {
- "False", "None", "True", "and", "as", "assert", "break",
- "class", "continue", "def", "del", "elif", "else", "except",
- "finally", "for", "from", "global", "if", "import", "in",
- "is", "lambda", "nonlocal", "not", "or", "pass", "raise",
- "return", "try", "while", "with", "yield"
- };
- keywords_.insert(std::begin(keywords), std::end(keywords));
- }
+ float_const_gen_("float('nan')", "float('inf')", "float('-inf')"),
+ namer_({ PythonDefaultConfig().WithFlagOptions(parser.opts, path),
+ PythonKeywords() }) {}
// Most field accessors need to retrieve and test the field offset first,
// this is the prefix code for that.
- std::string OffsetPrefix(const FieldDef &field) {
+ std::string OffsetPrefix(const FieldDef &field) const {
return "\n" + Indent + Indent +
"o = flatbuffers.number_types.UOffsetTFlags.py_type" +
"(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
@@ -61,85 +86,64 @@
}
// Begin a class declaration.
- void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ void BeginClass(const StructDef &struct_def, std::string *code_ptr) const {
auto &code = *code_ptr;
- code += "class " + NormalizedName(struct_def) + "(object):\n";
+ code += "class " + namer_.Type(struct_def.name) + "(object):\n";
code += Indent + "__slots__ = ['_tab']";
code += "\n\n";
}
// Begin enum code with a class declaration.
- void BeginEnum(const std::string &class_name, std::string *code_ptr) {
+ void BeginEnum(const EnumDef &enum_def, std::string *code_ptr) const {
auto &code = *code_ptr;
- code += "class " + class_name + "(object):\n";
- }
-
- std::string EscapeKeyword(const std::string &name) const {
- return keywords_.find(name) == keywords_.end() ? name : name + "_";
- }
-
- std::string NormalizedName(const Definition &definition) const {
- return EscapeKeyword(definition.name);
- }
-
- std::string NormalizedName(const EnumVal &ev) const {
- return EscapeKeyword(ev.name);
- }
-
- // Converts the name of a definition into upper Camel format.
- std::string MakeUpperCamel(const Definition &definition) const {
- return MakeCamel(NormalizedName(definition), true);
- }
-
- // Converts the name of a definition into lower Camel format.
- std::string MakeLowerCamel(const Definition &definition) const {
- auto name = MakeCamel(NormalizedName(definition), false);
- name[0] = CharToLower(name[0]);
- return name;
+ code += "class " + namer_.Type(enum_def.name) + "(object):\n";
}
// Starts a new line and then indents.
- std::string GenIndents(int num) {
+ std::string GenIndents(int num) const {
return "\n" + std::string(num * Indent.length(), ' ');
}
// A single enum member.
void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
code += Indent;
- code += NormalizedName(ev);
+ code += namer_.Variant(ev.name);
code += " = ";
code += enum_def.ToString(ev) + "\n";
}
- // End enum code.
- void EndEnum(std::string *code_ptr) {
- auto &code = *code_ptr;
- code += "\n";
- }
-
// Initialize a new struct or table from existing data.
void NewRootTypeFromBuffer(const StructDef &struct_def,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
+ const std::string struct_type = namer_.Type(struct_def.name);
code += Indent + "@classmethod\n";
code += Indent + "def GetRootAs";
- code += NormalizedName(struct_def);
- code += "(cls, buf, offset):";
+ code += "(cls, buf, offset=0):";
code += "\n";
code += Indent + Indent;
code += "n = flatbuffers.encode.Get";
code += "(flatbuffers.packer.uoffset, buf, offset)\n";
- code += Indent + Indent + "x = " + NormalizedName(struct_def) + "()\n";
+ code += Indent + Indent + "x = " + struct_type + "()\n";
code += Indent + Indent + "x.Init(buf, n + offset)\n";
code += Indent + Indent + "return x\n";
code += "\n";
+
+ // Add an alias with the old name
+ code += Indent + "@classmethod\n";
+ code += Indent + "def GetRootAs" + struct_type + "(cls, buf, offset=0):\n";
+ code +=
+ Indent + Indent +
+ "\"\"\"This method is deprecated. Please switch to GetRootAs.\"\"\"\n";
+ code += Indent + Indent + "return cls.GetRootAs(buf, offset)\n";
}
// Initialize an existing object with other data, to avoid an allocation.
- void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
+ void InitializeExisting(const StructDef &struct_def,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
@@ -150,11 +154,11 @@
// Get the length of a vector.
void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field)) + "Length(self";
+ code += namer_.Method(field.name) + "Length(self";
code += "):" + OffsetPrefix(field);
code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
code += Indent + Indent + "return 0\n\n";
@@ -162,11 +166,11 @@
// Determines whether a vector is none or not.
void GetVectorIsNone(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field)) + "IsNone(self";
+ code += namer_.Method(field.name) + "IsNone(self";
code += "):";
code += GenIndents(2) +
"o = flatbuffers.number_types.UOffsetTFlags.py_type" +
@@ -177,11 +181,12 @@
// Get the value of a struct's scalar.
void GetScalarFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
+ const FieldDef &field,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += namer_.Method(field.name);
code += "(self): return " + getter;
code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
code += NumToString(field.value.offset) + "))\n";
@@ -189,11 +194,11 @@
// Get the value of a table's scalar.
void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += namer_.Method(field.name);
code += "(self):";
code += OffsetPrefix(field);
getter += "o + self._tab.Pos)";
@@ -214,10 +219,11 @@
// Get a struct by initializing an existing struct.
// Specific to Struct.
void GetStructFieldOfStruct(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
+ const FieldDef &field,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += namer_.Method(field.name);
code += "(self, obj):\n";
code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
code += NumToString(field.value.offset) + ")";
@@ -226,11 +232,11 @@
// Get the value of a fixed size array.
void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
const auto vec_type = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += namer_.Method(field.name);
if (IsStruct(vec_type)) {
code += "(self, obj, i):\n";
code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
@@ -251,10 +257,10 @@
// Get a struct by initializing an existing struct.
// Specific to Table.
void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += namer_.Method(field.name);
code += "(self):";
code += OffsetPrefix(field);
if (field.value.type.struct_def->fixed) {
@@ -276,10 +282,10 @@
// Get the value of a string.
void GetStringField(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += namer_.Method(field.name);
code += "(self):";
code += OffsetPrefix(field);
code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
@@ -289,10 +295,10 @@
// Get the value of a union from an object.
void GetUnionField(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field)) + "(self):";
+ code += namer_.Method(field.name) + "(self):";
code += OffsetPrefix(field);
// TODO(rw): this works and is not the good way to it:
@@ -313,27 +319,33 @@
// Generate the package reference when importing a struct or enum from its
// module.
- std::string GenPackageReference(const Type &type) {
- Namespace *namespaces;
+ std::string GenPackageReference(const Type &type) const {
if (type.struct_def) {
- namespaces = type.struct_def->defined_namespace;
+ return GenPackageReference(*type.struct_def);
} else if (type.enum_def) {
- namespaces = type.enum_def->defined_namespace;
+ return GenPackageReference(*type.enum_def);
} else {
return "." + GenTypeGet(type);
}
-
- return namespaces->GetFullyQualifiedName(GenTypeGet(type));
+ }
+ std::string GenPackageReference(const EnumDef &enum_def) const {
+ return namer_.NamespacedType(enum_def.defined_namespace->components,
+ enum_def.name);
+ }
+ std::string GenPackageReference(const StructDef &struct_def) const {
+ return namer_.NamespacedType(struct_def.defined_namespace->components,
+ struct_def.name);
}
// Get the value of a vector's struct member.
void GetMemberOfVectorOfStruct(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
+ const FieldDef &field,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += namer_.Method(field.name);
code += "(self, j):" + OffsetPrefix(field);
code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
code += Indent + Indent + Indent;
@@ -357,12 +369,12 @@
// argument to conveniently set the zero value for the result.
void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field));
+ code += namer_.Method(field.name);
code += "(self, j):";
code += OffsetPrefix(field);
code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
@@ -382,7 +394,7 @@
// than iterating over the vector element by element.
void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
@@ -391,13 +403,13 @@
if (!(IsScalar(vectortype.base_type))) { return; }
GenReceiver(struct_def, code_ptr);
- code += MakeCamel(NormalizedName(field)) + "AsNumpy(self):";
+ code += namer_.Method(field.name) + "AsNumpy(self):";
code += OffsetPrefix(field);
code += Indent + Indent + Indent;
code += "return ";
code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
- code += MakeCamel(GenTypeGet(field.value.type));
+ code += namer_.Method(GenTypeGet(field.value.type));
code += "Flags, o)\n";
if (IsString(vectortype)) {
@@ -408,12 +420,51 @@
code += "\n";
}
+ std::string NestedFlatbufferType(std::string unqualified_name) const {
+ StructDef* nested_root = parser_.LookupStruct(unqualified_name);
+ std::string qualified_name;
+ if (nested_root == nullptr) {
+ qualified_name = namer_.NamespacedType(
+ parser_.current_namespace_->components, unqualified_name);
+ // Double check qualified name just to be sure it exists.
+ nested_root = parser_.LookupStruct(qualified_name);
+ }
+ FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
+ return qualified_name;
+ }
+
+ // Returns a nested flatbuffer as itself.
+ void GetVectorAsNestedFlatbuffer(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) const {
+ auto nested = field.attributes.Lookup("nested_flatbuffer");
+ if (!nested) { return; } // There is no nested flatbuffer.
+
+ const std::string unqualified_name = nested->constant;
+ const std::string qualified_name = NestedFlatbufferType(unqualified_name);
+
+ auto &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += namer_.Method(field.name) + "NestedRoot(self):";
+
+ code += OffsetPrefix(field);
+
+ code += Indent + Indent + Indent;
+ code += "from " + qualified_name + " import " + unqualified_name + "\n";
+ code += Indent + Indent + Indent + "return " + unqualified_name;
+ code += ".GetRootAs" + unqualified_name;
+ code += "(self._tab.Bytes, self._tab.Vector(o))\n";
+ code += Indent + Indent + "return 0\n";
+ code += "\n";
+ }
+
// Begin the creator function signature.
- void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
+ void BeginBuilderArgs(const StructDef &struct_def,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
code += "\n";
- code += "def Create" + NormalizedName(struct_def);
+ code += "def Create" + namer_.Type(struct_def.name);
code += "(builder";
}
@@ -423,7 +474,7 @@
const std::string nameprefix,
const std::string namesuffix, bool has_field_name,
const std::string fieldname_suffix,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
@@ -436,21 +487,21 @@
// a nested struct, prefix the name with the field name.
auto subprefix = nameprefix;
if (has_field_name) {
- subprefix += NormalizedName(field) + fieldname_suffix;
+ subprefix += namer_.Field(field.name) + fieldname_suffix;
}
StructBuilderArgs(*field.value.type.struct_def, subprefix, namesuffix,
has_field_name, fieldname_suffix, code_ptr);
} else {
auto &code = *code_ptr;
code += std::string(", ") + nameprefix;
- if (has_field_name) { code += MakeCamel(NormalizedName(field), false); }
+ if (has_field_name) { code += namer_.Field(field.name); }
code += namesuffix;
}
}
}
// End the creator function signature.
- void EndBuilderArgs(std::string *code_ptr) {
+ void EndBuilderArgs(std::string *code_ptr) const {
auto &code = *code_ptr;
code += "):\n";
}
@@ -459,7 +510,7 @@
// padding.
void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
std::string *code_ptr, size_t index = 0,
- bool in_array = false) {
+ bool in_array = false) const {
auto &code = *code_ptr;
std::string indent(index * 4, ' ');
code +=
@@ -475,9 +526,10 @@
code +=
indent + " builder.Pad(" + NumToString(field.padding) + ")\n";
if (IsStruct(field_type)) {
- StructBuilderBody(*field_type.struct_def,
- (nameprefix + (NormalizedName(field) + "_")).c_str(),
- code_ptr, index, in_array);
+ StructBuilderBody(
+ *field_type.struct_def,
+ (nameprefix + (namer_.Field(field.name) + "_")).c_str(), code_ptr,
+ index, in_array);
} else {
const auto index_var = "_idx" + NumToString(index);
if (IsArray(field_type)) {
@@ -489,12 +541,12 @@
if (IsStruct(type)) {
StructBuilderBody(
*field_type.struct_def,
- (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr,
+ (nameprefix + (namer_.Field(field.name) + "_")).c_str(), code_ptr,
index + 1, in_array);
} else {
code += IsArray(field_type) ? " " : "";
code += indent + " builder.Prepend" + GenMethod(field) + "(";
- code += nameprefix + MakeCamel(NormalizedName(field), false);
+ code += nameprefix + namer_.Variable(field.name);
size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
for (size_t i = 0; in_array && i < array_cnt; i++) {
code += "[_idx" + NumToString(i) + "-1]";
@@ -505,53 +557,76 @@
}
}
- void EndBuilderBody(std::string *code_ptr) {
+ void EndBuilderBody(std::string *code_ptr) const {
auto &code = *code_ptr;
code += " return builder.Offset()\n";
}
// Get the value of a table's starting offset.
- void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
+ void GetStartOfTable(const StructDef &struct_def,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- code += "def " + NormalizedName(struct_def) + "Start";
- code += "(builder): ";
+ const auto struct_type = namer_.Type(struct_def.name);
+ // Generate method with struct name.
+ code += "def " + struct_type + "Start(builder): ";
code += "builder.StartObject(";
code += NumToString(struct_def.fields.vec.size());
code += ")\n";
+
+ if (!parser_.opts.one_file) {
+ // Generate method without struct name.
+ code += "def Start(builder):\n";
+ code += Indent + "return " + struct_type + "Start(builder)\n";
+ }
}
// Set the value of a table's field.
void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
- const size_t offset, std::string *code_ptr) {
+ const size_t offset, std::string *code_ptr) const {
auto &code = *code_ptr;
- code += "def " + NormalizedName(struct_def) + "Add" +
- MakeCamel(NormalizedName(field));
+ const std::string field_var = namer_.Variable(field.name);
+ const std::string field_method = namer_.Method(field.name);
+
+ // Generate method with struct name.
+ code += "def " + namer_.Type(struct_def.name) + "Add" + field_method;
code += "(builder, ";
- code += MakeCamel(NormalizedName(field), false);
+ code += field_var;
code += "): ";
code += "builder.Prepend";
code += GenMethod(field) + "Slot(";
code += NumToString(offset) + ", ";
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
code += "flatbuffers.number_types.UOffsetTFlags.py_type";
- code += "(";
- code += MakeCamel(NormalizedName(field), false) + ")";
+ code += "(" + field_var + ")";
} else {
- code += MakeCamel(NormalizedName(field), false);
+ code += field_var;
}
code += ", ";
code += IsFloat(field.value.type.base_type)
? float_const_gen_.GenFloatConstant(field)
: field.value.constant;
code += ")\n";
+
+ if (!parser_.opts.one_file) {
+ // Generate method without struct name.
+ code += "def Add" + field_method + "(builder, " + field_var + "):\n";
+ code += Indent + "return " + namer_.Type(struct_def.name) + "Add" +
+ field_method;
+ code += "(builder, ";
+ code += field_var;
+ code += ")\n";
+ }
}
// Set the value of one of the members of a table's vector.
void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- code += "def " + NormalizedName(struct_def) + "Start";
- code += MakeCamel(NormalizedName(field));
+ const std::string struct_type = namer_.Type(struct_def.name);
+ const std::string field_method = namer_.Method(field.name);
+
+ // Generate method with struct name.
+ code += "def " + struct_type + "Start" + field_method;
code += "Vector(builder, numElems): return builder.StartVector(";
auto vector_type = field.value.type.VectorType();
auto alignment = InlineAlignment(vector_type);
@@ -559,26 +634,79 @@
code += NumToString(elem_size);
code += ", numElems, " + NumToString(alignment);
code += ")\n";
+
+ if (!parser_.opts.one_file) {
+ // Generate method without struct name.
+ code += "def Start" + field_method + "Vector(builder, numElems):\n";
+ code += Indent + "return " + struct_type + "Start";
+ code += field_method + "Vector(builder, numElems)\n";
+ }
+ }
+
+ // Set the value of one of the members of a table's vector and fills in the
+ // elements from a bytearray. This is for simplifying the use of nested
+ // flatbuffers.
+ void BuildVectorOfTableFromBytes(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) const {
+ auto nested = field.attributes.Lookup("nested_flatbuffer");
+ if (!nested) { return; } // There is no nested flatbuffer.
+
+ auto &code = *code_ptr;
+ const std::string field_method = namer_.Method(field.name);
+ const std::string struct_type = namer_.Type(struct_def.name);
+
+ // Generate method with struct and field name.
+ code += "def " + struct_type + "Make" + field_method;
+ code += "VectorFromBytes(builder, bytes):\n";
+ code += Indent + "builder.StartVector(";
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ code += NumToString(elem_size);
+ code += ", len(bytes), " + NumToString(alignment);
+ code += ")\n";
+ code += Indent + "builder.head = builder.head - len(bytes)\n";
+ code += Indent + "builder.Bytes[builder.head : builder.head + len(bytes)]";
+ code += " = bytes\n";
+ code += Indent + "return builder.EndVector()\n";
+
+ if (!parser_.opts.one_file) {
+ // Generate method without struct and field name.
+ code += "def Make" + field_method + "VectorFromBytes(builder, bytes):\n";
+ code += Indent + "return " + struct_type + "Make" + field_method +
+ "VectorFromBytes(builder, bytes)\n";
+ }
}
// Get the offset of the end of a table.
- void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
+ void GetEndOffsetOnTable(const StructDef &struct_def,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- code += "def " + NormalizedName(struct_def) + "End";
+
+ // Generate method with struct name.
+ code += "def " + namer_.Type(struct_def.name) + "End";
code += "(builder): ";
code += "return builder.EndObject()\n";
+
+ if (!parser_.opts.one_file) {
+ // Generate method without struct name.
+ code += "def End(builder):\n";
+ code +=
+ Indent + "return " + namer_.Type(struct_def.name) + "End(builder)";
+ }
}
// Generate the receiver for function signatures.
- void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
+ void GenReceiver(const StructDef &struct_def, std::string *code_ptr) const {
auto &code = *code_ptr;
- code += Indent + "# " + NormalizedName(struct_def) + "\n";
+ code += Indent + "# " + namer_.Type(struct_def.name) + "\n";
code += Indent + "def ";
}
// Generate a struct field, conditioned on its child type(s).
void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
GenComment(field.doc_comment, code_ptr, &def_comment, Indent.c_str());
if (IsScalar(field.value.type.base_type)) {
if (struct_def.fixed) {
@@ -607,6 +735,7 @@
} else {
GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
+ GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr);
}
break;
}
@@ -621,7 +750,8 @@
}
// Generate struct sizeof.
- void GenStructSizeOf(const StructDef &struct_def, std::string *code_ptr) {
+ void GenStructSizeOf(const StructDef &struct_def,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
code += Indent + "@classmethod\n";
code += Indent + "def SizeOf(cls):\n";
@@ -631,7 +761,8 @@
}
// Generate table constructors, conditioned on its members' types.
- void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
+ void GenTableBuilders(const StructDef &struct_def,
+ std::string *code_ptr) const {
GetStartOfTable(struct_def, code_ptr);
for (auto it = struct_def.fields.vec.begin();
@@ -643,6 +774,7 @@
BuildFieldOfTable(struct_def, field, offset, code_ptr);
if (IsVector(field.value.type)) {
BuildVectorOfTable(struct_def, field, code_ptr);
+ BuildVectorOfTableFromBytes(struct_def, field, code_ptr);
}
}
@@ -651,7 +783,7 @@
// Generate function to check for proper file identifier
void GenHasFileIdentifier(const StructDef &struct_def,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
std::string escapedID;
// In the event any of file_identifier characters are special(NULL, \, etc),
@@ -663,7 +795,7 @@
}
code += Indent + "@classmethod\n";
- code += Indent + "def " + NormalizedName(struct_def);
+ code += Indent + "def " + namer_.Type(struct_def.name);
code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):";
code += "\n";
code += Indent + Indent;
@@ -674,7 +806,7 @@
}
// Generates struct or table methods.
- void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) const {
if (struct_def.generated) return;
GenComment(struct_def.doc_comment, code_ptr, &def_comment);
@@ -712,23 +844,24 @@
}
void GenReceiverForObjectAPI(const StructDef &struct_def,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- code += GenIndents(1) + "# " + NormalizedName(struct_def) + "T";
+ code += GenIndents(1) + "# " + namer_.ObjectType(struct_def.name);
code += GenIndents(1) + "def ";
}
void BeginClassForObjectAPI(const StructDef &struct_def,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
code += "\n";
- code += "class " + NormalizedName(struct_def) + "T(object):";
+ code += "class " + namer_.ObjectType(struct_def.name) + "(object):";
code += "\n";
}
// Gets the accoresponding python builtin type of a BaseType for scalars and
// string.
- std::string GetBasePythonTypeForScalarAndString(const BaseType &base_type) {
+ std::string GetBasePythonTypeForScalarAndString(
+ const BaseType &base_type) const {
if (IsBool(base_type)) {
return "bool";
} else if (IsFloat(base_type)) {
@@ -743,7 +876,7 @@
}
}
- std::string GetDefaultValue(const FieldDef &field) {
+ std::string GetDefaultValue(const FieldDef &field) const {
BaseType base_type = field.value.type.base_type;
if (IsBool(base_type)) {
return field.value.constant == "0" ? "False" : "True";
@@ -759,7 +892,7 @@
void GenUnionInit(const FieldDef &field, std::string *field_types_ptr,
std::set<std::string> *import_list,
- std::set<std::string> *import_typing_list) {
+ std::set<std::string> *import_typing_list) const {
// Gets all possible types in the union.
import_typing_list->insert("Union");
auto &field_types = *field_types_ptr;
@@ -774,7 +907,7 @@
std::string field_type;
switch (ev.union_type.base_type) {
case BASE_TYPE_STRUCT:
- field_type = GenTypeGet(ev.union_type) + "T";
+ field_type = namer_.ObjectType(ev.union_type.struct_def->name);
if (parser_.opts.include_dependence_headers) {
auto package_reference = GenPackageReference(ev.union_type);
field_type = package_reference + "." + field_type;
@@ -794,45 +927,43 @@
// Gets the import lists for the union.
if (parser_.opts.include_dependence_headers) {
- // The package reference is generated based on enum_def, instead
- // of struct_def in field.type. That's why GenPackageReference() is
- // not used.
- Namespace *namespaces = field.value.type.enum_def->defined_namespace;
- auto package_reference = namespaces->GetFullyQualifiedName(
- MakeUpperCamel(*(field.value.type.enum_def)));
- auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
+ const auto package_reference =
+ GenPackageReference(*field.value.type.enum_def);
import_list->insert("import " + package_reference);
}
}
- void GenStructInit(const FieldDef &field, std::string *field_type_ptr,
+ void GenStructInit(const FieldDef &field, std::string *out_ptr,
std::set<std::string> *import_list,
- std::set<std::string> *import_typing_list) {
+ std::set<std::string> *import_typing_list) const {
import_typing_list->insert("Optional");
- auto &field_type = *field_type_ptr;
+ auto &output = *out_ptr;
+ const Type &type = field.value.type;
+ const std::string object_type = namer_.ObjectType(type.struct_def->name);
if (parser_.opts.include_dependence_headers) {
- auto package_reference = GenPackageReference(field.value.type);
- field_type = package_reference + "." + TypeName(field) + "T]";
+ auto package_reference = GenPackageReference(type);
+ output = package_reference + "." + object_type + "]";
import_list->insert("import " + package_reference);
} else {
- field_type = TypeName(field) + "T]";
+ output = object_type + "]";
}
- field_type = "Optional[" + field_type;
+ output = "Optional[" + output;
}
void GenVectorInit(const FieldDef &field, std::string *field_type_ptr,
std::set<std::string> *import_list,
- std::set<std::string> *import_typing_list) {
+ std::set<std::string> *import_typing_list) const {
import_typing_list->insert("List");
auto &field_type = *field_type_ptr;
- auto base_type = field.value.type.VectorType().base_type;
+ const Type &vector_type = field.value.type.VectorType();
+ const BaseType base_type = vector_type.base_type;
if (base_type == BASE_TYPE_STRUCT) {
- field_type = GenTypeGet(field.value.type.VectorType()) + "T]";
+ const std::string object_type =
+ namer_.ObjectType(GenTypeGet(vector_type));
+ field_type = object_type + "]";
if (parser_.opts.include_dependence_headers) {
- auto package_reference =
- GenPackageReference(field.value.type.VectorType());
- field_type = package_reference + "." +
- GenTypeGet(field.value.type.VectorType()) + "T]";
+ auto package_reference = GenPackageReference(vector_type);
+ field_type = package_reference + "." + object_type + "]";
import_list->insert("import " + package_reference);
}
field_type = "List[" + field_type;
@@ -843,7 +974,7 @@
}
void GenInitialize(const StructDef &struct_def, std::string *code_ptr,
- std::set<std::string> *import_list) {
+ std::set<std::string> *import_list) const {
std::string code;
std::set<std::string> import_typing_list;
for (auto it = struct_def.fields.vec.begin();
@@ -874,11 +1005,11 @@
break;
}
- auto default_value = GetDefaultValue(field);
+ const auto default_value = GetDefaultValue(field);
// Wrties the init statement.
- auto field_instance_name = MakeLowerCamel(field);
- code += GenIndents(2) + "self." + field_instance_name + " = " +
- default_value + " # type: " + field_type;
+ const auto field_field = namer_.Field(field.name);
+ code += GenIndents(2) + "self." + field_field + " = " + default_value +
+ " # type: " + field_type;
}
// Writes __init__ method.
@@ -914,46 +1045,44 @@
}
// Removes the import of the struct itself, if applied.
- auto package_reference =
- struct_def.defined_namespace->GetFullyQualifiedName(
- MakeUpperCamel(struct_def));
- auto struct_import = "import " + package_reference;
+ auto struct_import = "import " + GenPackageReference(struct_def);
import_list->erase(struct_import);
}
- void InitializeFromBuf(const StructDef &struct_def, std::string *code_ptr) {
+ void InitializeFromBuf(const StructDef &struct_def,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- auto instance_name = MakeLowerCamel(struct_def);
- auto struct_name = NormalizedName(struct_def);
+ const auto struct_var = namer_.Variable(struct_def.name);
+ const auto struct_type = namer_.Type(struct_def.name);
code += GenIndents(1) + "@classmethod";
code += GenIndents(1) + "def InitFromBuf(cls, buf, pos):";
- code += GenIndents(2) + instance_name + " = " + struct_name + "()";
- code += GenIndents(2) + instance_name + ".Init(buf, pos)";
- code += GenIndents(2) + "return cls.InitFromObj(" + instance_name + ")";
+ code += GenIndents(2) + struct_var + " = " + struct_type + "()";
+ code += GenIndents(2) + struct_var + ".Init(buf, pos)";
+ code += GenIndents(2) + "return cls.InitFromObj(" + struct_var + ")";
code += "\n";
}
void InitializeFromObjForObject(const StructDef &struct_def,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- auto instance_name = MakeLowerCamel(struct_def);
- auto struct_name = NormalizedName(struct_def);
+ const auto struct_var = namer_.Variable(struct_def.name);
+ const auto struct_object = namer_.ObjectType(struct_def.name);
code += GenIndents(1) + "@classmethod";
- code += GenIndents(1) + "def InitFromObj(cls, " + instance_name + "):";
- code += GenIndents(2) + "x = " + struct_name + "T()";
- code += GenIndents(2) + "x._UnPack(" + instance_name + ")";
+ code += GenIndents(1) + "def InitFromObj(cls, " + struct_var + "):";
+ code += GenIndents(2) + "x = " + struct_object + "()";
+ code += GenIndents(2) + "x._UnPack(" + struct_var + ")";
code += GenIndents(2) + "return x";
code += "\n";
}
void GenUnPackForStruct(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- auto struct_instance_name = MakeLowerCamel(struct_def);
- auto field_instance_name = MakeLowerCamel(field);
- auto field_accessor_name = MakeUpperCamel(field);
+ const auto struct_var = namer_.Variable(struct_def.name);
+ const auto field_field = namer_.Field(field.name);
+ const auto field_method = namer_.Method(field.name);
auto field_type = TypeName(field);
if (parser_.opts.include_dependence_headers) {
@@ -961,16 +1090,14 @@
field_type = package_reference + "." + TypeName(field);
}
- code += GenIndents(2) + "if " + struct_instance_name + "." +
- field_accessor_name + "(";
+ code += GenIndents(2) + "if " + struct_var + "." + field_method + "(";
// if field is a struct, we need to create an instance for it first.
if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
code += field_type + "()";
}
code += ") is not None:";
- code += GenIndents(3) + "self." + field_instance_name + " = " + field_type +
- "T.InitFromObj(" + struct_instance_name + "." +
- field_accessor_name + "(";
+ code += GenIndents(3) + "self." + field_field + " = " + field_type +
+ "T.InitFromObj(" + struct_var + "." + field_method + "(";
// A struct's accessor requires a struct buf instance.
if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
code += field_type + "()";
@@ -979,82 +1106,81 @@
}
void GenUnPackForUnion(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- auto field_instance_name = MakeLowerCamel(field);
- auto field_accessor_name = MakeUpperCamel(field);
- auto struct_instance_name = MakeLowerCamel(struct_def);
- auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
+ const auto field_field = namer_.Field(field.name);
+ const auto field_method = namer_.Method(field.name);
+ const auto struct_var = namer_.Variable(struct_def.name);
+ const EnumDef &enum_def = *field.value.type.enum_def;
+ auto union_type = namer_.Namespace(enum_def.name);
if (parser_.opts.include_dependence_headers) {
- Namespace *namespaces = field.value.type.enum_def->defined_namespace;
- auto package_reference = namespaces->GetFullyQualifiedName(
- MakeUpperCamel(*(field.value.type.enum_def)));
- union_name = package_reference + "." + union_name;
+ union_type = GenPackageReference(enum_def) + "." + union_type;
}
- code += GenIndents(2) + "self." + field_instance_name + " = " + union_name +
- "Creator(" + "self." + field_instance_name + "Type, " +
- struct_instance_name + "." + field_accessor_name + "())";
+ code += GenIndents(2) + "self." + field_field + " = " + union_type +
+ "Creator(" + "self." + field_field + "Type, " + struct_var + "." +
+ field_method + "())";
}
void GenUnPackForStructVector(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
+ const FieldDef &field,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- auto field_instance_name = MakeLowerCamel(field);
- auto field_accessor_name = MakeUpperCamel(field);
- auto struct_instance_name = MakeLowerCamel(struct_def);
+ const auto field_field = namer_.Field(field.name);
+ const auto field_method = namer_.Method(field.name);
+ const auto struct_var = namer_.Variable(struct_def.name);
- code += GenIndents(2) + "if not " + struct_instance_name + "." +
- field_accessor_name + "IsNone():";
- code += GenIndents(3) + "self." + field_instance_name + " = []";
- code += GenIndents(3) + "for i in range(" + struct_instance_name + "." +
- field_accessor_name + "Length()):";
+ code += GenIndents(2) + "if not " + struct_var + "." + field_method +
+ "IsNone():";
+ code += GenIndents(3) + "self." + field_field + " = []";
+ code += GenIndents(3) + "for i in range(" + struct_var + "." +
+ field_method + "Length()):";
- auto field_type_name = TypeName(field);
- auto one_instance = field_type_name + "_";
+ auto field_type = TypeName(field);
+ auto one_instance = field_type + "_";
one_instance[0] = CharToLower(one_instance[0]);
if (parser_.opts.include_dependence_headers) {
auto package_reference = GenPackageReference(field.value.type);
- field_type_name = package_reference + "." + TypeName(field);
+ field_type = package_reference + "." + TypeName(field);
}
- code += GenIndents(4) + "if " + struct_instance_name + "." +
- field_accessor_name + "(i) is None:";
- code += GenIndents(5) + "self." + field_instance_name + ".append(None)";
+ code += GenIndents(4) + "if " + struct_var + "." + field_method +
+ "(i) is None:";
+ code += GenIndents(5) + "self." + field_field + ".append(None)";
code += GenIndents(4) + "else:";
- code += GenIndents(5) + one_instance + " = " + field_type_name +
- "T.InitFromObj(" + struct_instance_name + "." +
- field_accessor_name + "(i))";
- code += GenIndents(5) + "self." + field_instance_name + ".append(" +
- one_instance + ")";
+ code += GenIndents(5) + one_instance + " = " + field_type +
+ "T.InitFromObj(" + struct_var + "." + field_method + "(i))";
+ code +=
+ GenIndents(5) + "self." + field_field + ".append(" + one_instance + ")";
}
void GenUnpackforScalarVectorHelper(const StructDef &struct_def,
const FieldDef &field,
- std::string *code_ptr, int indents) {
+ std::string *code_ptr,
+ int indents) const {
auto &code = *code_ptr;
- auto field_instance_name = MakeLowerCamel(field);
- auto field_accessor_name = MakeUpperCamel(field);
- auto struct_instance_name = MakeLowerCamel(struct_def);
+ const auto field_field = namer_.Field(field.name);
+ const auto field_method = namer_.Method(field.name);
+ const auto struct_var = namer_.Variable(struct_def.name);
- code += GenIndents(indents) + "self." + field_instance_name + " = []";
- code += GenIndents(indents) + "for i in range(" + struct_instance_name +
- "." + field_accessor_name + "Length()):";
- code += GenIndents(indents + 1) + "self." + field_instance_name +
- ".append(" + struct_instance_name + "." + field_accessor_name +
- "(i))";
+ code += GenIndents(indents) + "self." + field_field + " = []";
+ code += GenIndents(indents) + "for i in range(" + struct_var + "." +
+ field_method + "Length()):";
+ code += GenIndents(indents + 1) + "self." + field_field + ".append(" +
+ struct_var + "." + field_method + "(i))";
}
void GenUnPackForScalarVector(const StructDef &struct_def,
- const FieldDef &field, std::string *code_ptr) {
+ const FieldDef &field,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- auto field_instance_name = MakeLowerCamel(field);
- auto field_accessor_name = MakeUpperCamel(field);
- auto struct_instance_name = MakeLowerCamel(struct_def);
+ const auto field_field = namer_.Field(field.name);
+ const auto field_method = namer_.Method(field.name);
+ const auto struct_var = namer_.Variable(struct_def.name);
- code += GenIndents(2) + "if not " + struct_instance_name + "." +
- field_accessor_name + "IsNone():";
+ code += GenIndents(2) + "if not " + struct_var + "." + field_method +
+ "IsNone():";
// String does not have the AsNumpy method.
if (!(IsScalar(field.value.type.VectorType().base_type))) {
@@ -1067,23 +1193,23 @@
// If numpy exists, use the AsNumpy method to optimize the unpack speed.
code += GenIndents(3) + "else:";
- code += GenIndents(4) + "self." + field_instance_name + " = " +
- struct_instance_name + "." + field_accessor_name + "AsNumpy()";
+ code += GenIndents(4) + "self." + field_field + " = " + struct_var + "." +
+ field_method + "AsNumpy()";
}
void GenUnPackForScalar(const StructDef &struct_def, const FieldDef &field,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- auto field_instance_name = MakeLowerCamel(field);
- auto field_accessor_name = MakeUpperCamel(field);
- auto struct_instance_name = MakeLowerCamel(struct_def);
+ const auto field_field = namer_.Field(field.name);
+ const auto field_method = namer_.Method(field.name);
+ const auto struct_var = namer_.Variable(struct_def.name);
- code += GenIndents(2) + "self." + field_instance_name + " = " +
- struct_instance_name + "." + field_accessor_name + "()";
+ code += GenIndents(2) + "self." + field_field + " = " + struct_var + "." +
+ field_method + "()";
}
// Generates the UnPack method for the object class.
- void GenUnPack(const StructDef &struct_def, std::string *code_ptr) {
+ void GenUnPack(const StructDef &struct_def, std::string *code_ptr) const {
std::string code;
// Items that needs to be imported. No duplicate modules will be imported.
std::set<std::string> import_list;
@@ -1122,12 +1248,11 @@
// Writes import statements and code into the generated file.
auto &code_base = *code_ptr;
- auto struct_instance_name = MakeLowerCamel(struct_def);
- auto struct_name = MakeUpperCamel(struct_def);
+ const auto struct_var = namer_.Variable(struct_def.name);
GenReceiverForObjectAPI(struct_def, code_ptr);
- code_base += "_UnPack(self, " + struct_instance_name + "):";
- code_base += GenIndents(2) + "if " + struct_instance_name + " is None:";
+ code_base += "_UnPack(self, " + struct_var + "):";
+ code_base += GenIndents(2) + "if " + struct_var + " is None:";
code_base += GenIndents(3) + "return";
// Write the import statements.
@@ -1141,13 +1266,14 @@
code_base += "\n";
}
- void GenPackForStruct(const StructDef &struct_def, std::string *code_ptr) {
+ void GenPackForStruct(const StructDef &struct_def,
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- auto struct_name = MakeUpperCamel(struct_def);
+ const auto struct_fn = namer_.Function(struct_def.name);
GenReceiverForObjectAPI(struct_def, code_ptr);
code += "Pack(self, builder):";
- code += GenIndents(2) + "return Create" + struct_name + "(builder";
+ code += GenIndents(2) + "return Create" + struct_fn + "(builder";
StructBuilderArgs(struct_def,
/* nameprefix = */ "self.",
@@ -1160,67 +1286,61 @@
void GenPackForStructVectorField(const StructDef &struct_def,
const FieldDef &field,
std::string *code_prefix_ptr,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code_prefix = *code_prefix_ptr;
auto &code = *code_ptr;
- auto field_instance_name = MakeLowerCamel(field);
- auto struct_name = NormalizedName(struct_def);
- auto field_accessor_name = MakeUpperCamel(field);
+ const auto field_field = namer_.Field(field.name);
+ const auto struct_type = namer_.Type(struct_def.name);
+ const auto field_method = namer_.Method(field.name);
// Creates the field.
- code_prefix +=
- GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
if (field.value.type.struct_def->fixed) {
- code_prefix += GenIndents(3) + struct_name + "Start" +
- field_accessor_name + "Vector(builder, len(self." +
- field_instance_name + "))";
+ code_prefix += GenIndents(3) + struct_type + "Start" + field_method +
+ "Vector(builder, len(self." + field_field + "))";
code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
- field_instance_name + "))):";
+ field_field + "))):";
code_prefix +=
- GenIndents(4) + "self." + field_instance_name + "[i].Pack(builder)";
- code_prefix += GenIndents(3) + field_instance_name +
- " = builder.EndVector(len(self." + field_instance_name +
- "))";
+ GenIndents(4) + "self." + field_field + "[i].Pack(builder)";
+ code_prefix += GenIndents(3) + field_field + " = builder.EndVector()";
} else {
// If the vector is a struct vector, we need to first build accessor for
// each struct element.
- code_prefix += GenIndents(3) + field_instance_name + "list = []";
+ code_prefix += GenIndents(3) + field_field + "list = []";
code_prefix += GenIndents(3);
- code_prefix += "for i in range(len(self." + field_instance_name + ")):";
- code_prefix += GenIndents(4) + field_instance_name + "list.append(self." +
- field_instance_name + "[i].Pack(builder))";
+ code_prefix += "for i in range(len(self." + field_field + ")):";
+ code_prefix += GenIndents(4) + field_field + "list.append(self." +
+ field_field + "[i].Pack(builder))";
- code_prefix += GenIndents(3) + struct_name + "Start" +
- field_accessor_name + "Vector(builder, len(self." +
- field_instance_name + "))";
+ code_prefix += GenIndents(3) + struct_type + "Start" + field_method +
+ "Vector(builder, len(self." + field_field + "))";
code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
- field_instance_name + "))):";
+ field_field + "))):";
code_prefix += GenIndents(4) + "builder.PrependUOffsetTRelative" + "(" +
- field_instance_name + "list[i])";
- code_prefix += GenIndents(3) + field_instance_name +
- " = builder.EndVector(len(self." + field_instance_name +
- "))";
+ field_field + "list[i])";
+ code_prefix += GenIndents(3) + field_field + " = builder.EndVector()";
}
// Adds the field into the struct.
- code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
- code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
- "(builder, " + field_instance_name + ")";
+ code += GenIndents(2) + "if self." + field_field + " is not None:";
+ code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
+ field_field + ")";
}
void GenPackForScalarVectorFieldHelper(const StructDef &struct_def,
const FieldDef &field,
- std::string *code_ptr, int indents) {
+ std::string *code_ptr,
+ int indents) const {
auto &code = *code_ptr;
- auto field_instance_name = MakeLowerCamel(field);
- auto field_accessor_name = MakeUpperCamel(field);
- auto struct_name = NormalizedName(struct_def);
- auto vectortype = field.value.type.VectorType();
+ const auto field_field = namer_.Field(field.name);
+ const auto field_method = namer_.Method(field.name);
+ const auto struct_type = namer_.Type(struct_def.name);
+ const auto vectortype = field.value.type.VectorType();
- code += GenIndents(indents) + struct_name + "Start" + field_accessor_name +
- "Vector(builder, len(self." + field_instance_name + "))";
+ code += GenIndents(indents) + struct_type + "Start" + field_method +
+ "Vector(builder, len(self." + field_field + "))";
code += GenIndents(indents) + "for i in reversed(range(len(self." +
- field_instance_name + "))):";
+ field_field + "))):";
code += GenIndents(indents + 1) + "builder.Prepend";
std::string type_name;
@@ -1245,120 +1365,109 @@
void GenPackForScalarVectorField(const StructDef &struct_def,
const FieldDef &field,
std::string *code_prefix_ptr,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
auto &code_prefix = *code_prefix_ptr;
- auto field_instance_name = MakeLowerCamel(field);
- auto field_accessor_name = MakeUpperCamel(field);
- auto struct_name = NormalizedName(struct_def);
+ const auto field_field = namer_.Field(field.name);
+ const auto field_method = namer_.Method(field.name);
+ const auto struct_type = namer_.Type(struct_def.name);
// Adds the field into the struct.
- code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
- code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
- "(builder, " + field_instance_name + ")";
+ code += GenIndents(2) + "if self." + field_field + " is not None:";
+ code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
+ field_field + ")";
// Creates the field.
- code_prefix +=
- GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
// If the vector is a string vector, we need to first build accessor for
// each string element. And this generated code, needs to be
// placed ahead of code_prefix.
auto vectortype = field.value.type.VectorType();
if (IsString(vectortype)) {
- code_prefix += GenIndents(3) + MakeLowerCamel(field) + "list = []";
- code_prefix += GenIndents(3) + "for i in range(len(self." +
- field_instance_name + ")):";
- code_prefix += GenIndents(4) + MakeLowerCamel(field) +
- "list.append(builder.CreateString(self." +
- field_instance_name + "[i]))";
+ code_prefix += GenIndents(3) + field_field + "list = []";
+ code_prefix +=
+ GenIndents(3) + "for i in range(len(self." + field_field + ")):";
+ code_prefix += GenIndents(4) + field_field +
+ "list.append(builder.CreateString(self." + field_field +
+ "[i]))";
GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
- code_prefix += "(" + MakeLowerCamel(field) + "list[i])";
- code_prefix += GenIndents(3) + field_instance_name +
- " = builder.EndVector(len(self." + field_instance_name +
- "))";
+ code_prefix += "(" + field_field + "list[i])";
+ code_prefix += GenIndents(3) + field_field + " = builder.EndVector()";
return;
}
code_prefix += GenIndents(3) + "if np is not None and type(self." +
- field_instance_name + ") is np.ndarray:";
- code_prefix += GenIndents(4) + field_instance_name +
- " = builder.CreateNumpyVector(self." + field_instance_name +
- ")";
+ field_field + ") is np.ndarray:";
+ code_prefix += GenIndents(4) + field_field +
+ " = builder.CreateNumpyVector(self." + field_field + ")";
code_prefix += GenIndents(3) + "else:";
GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 4);
- code_prefix += "(self." + field_instance_name + "[i])";
- code_prefix += GenIndents(4) + field_instance_name +
- " = builder.EndVector(len(self." + field_instance_name +
- "))";
+ code_prefix += "(self." + field_field + "[i])";
+ code_prefix += GenIndents(4) + field_field + " = builder.EndVector()";
}
void GenPackForStructField(const StructDef &struct_def, const FieldDef &field,
std::string *code_prefix_ptr,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code_prefix = *code_prefix_ptr;
auto &code = *code_ptr;
- auto field_instance_name = MakeLowerCamel(field);
-
- auto field_accessor_name = MakeUpperCamel(field);
- auto struct_name = NormalizedName(struct_def);
+ const auto field_field = namer_.Field(field.name);
+ const auto field_method = namer_.Method(field.name);
+ const auto struct_type = namer_.Type(struct_def.name);
if (field.value.type.struct_def->fixed) {
// Pure struct fields need to be created along with their parent
// structs.
- code +=
- GenIndents(2) + "if self." + field_instance_name + " is not None:";
- code += GenIndents(3) + field_instance_name + " = self." +
- field_instance_name + ".Pack(builder)";
+ code += GenIndents(2) + "if self." + field_field + " is not None:";
+ code += GenIndents(3) + field_field + " = self." + field_field +
+ ".Pack(builder)";
} else {
// Tables need to be created before their parent structs are created.
- code_prefix +=
- GenIndents(2) + "if self." + field_instance_name + " is not None:";
- code_prefix += GenIndents(3) + field_instance_name + " = self." +
- field_instance_name + ".Pack(builder)";
- code +=
- GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
+ code_prefix += GenIndents(3) + field_field + " = self." + field_field +
+ ".Pack(builder)";
+ code += GenIndents(2) + "if self." + field_field + " is not None:";
}
- code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
- "(builder, " + field_instance_name + ")";
+ code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
+ field_field + ")";
}
void GenPackForUnionField(const StructDef &struct_def, const FieldDef &field,
std::string *code_prefix_ptr,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code_prefix = *code_prefix_ptr;
auto &code = *code_ptr;
- auto field_instance_name = MakeLowerCamel(field);
-
- auto field_accessor_name = MakeUpperCamel(field);
- auto struct_name = NormalizedName(struct_def);
+ const auto field_field = namer_.Field(field.name);
+ const auto field_method = namer_.Method(field.name);
+ const auto struct_type = namer_.Type(struct_def.name);
// TODO(luwa): TypeT should be moved under the None check as well.
- code_prefix +=
- GenIndents(2) + "if self." + field_instance_name + " is not None:";
- code_prefix += GenIndents(3) + field_instance_name + " = self." +
- field_instance_name + ".Pack(builder)";
- code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
- code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
- "(builder, " + field_instance_name + ")";
+ code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
+ code_prefix += GenIndents(3) + field_field + " = self." + field_field +
+ ".Pack(builder)";
+ code += GenIndents(2) + "if self." + field_field + " is not None:";
+ code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
+ field_field + ")";
}
- void GenPackForTable(const StructDef &struct_def, std::string *code_ptr) {
+ void GenPackForTable(const StructDef &struct_def,
+ std::string *code_ptr) const {
auto &code_base = *code_ptr;
std::string code, code_prefix;
- auto struct_instance_name = MakeLowerCamel(struct_def);
- auto struct_name = NormalizedName(struct_def);
+ const auto struct_var = namer_.Variable(struct_def.name);
+ const auto struct_type = namer_.Type(struct_def.name);
GenReceiverForObjectAPI(struct_def, code_ptr);
code_base += "Pack(self, builder):";
- code += GenIndents(2) + struct_name + "Start(builder)";
+ code += GenIndents(2) + struct_type + "Start(builder)";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
- auto field_accessor_name = MakeUpperCamel(field);
- auto field_instance_name = MakeLowerCamel(field);
+ const auto field_method = namer_.Method(field.name);
+ const auto field_field = namer_.Field(field.name);
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT: {
@@ -1383,37 +1492,34 @@
break;
}
case BASE_TYPE_STRING: {
- code_prefix += GenIndents(2) + "if self." + field_instance_name +
- " is not None:";
- code_prefix += GenIndents(3) + field_instance_name +
- " = builder.CreateString(self." + field_instance_name +
- ")";
- code += GenIndents(2) + "if self." + field_instance_name +
- " is not None:";
- code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
- "(builder, " + field_instance_name + ")";
+ code_prefix +=
+ GenIndents(2) + "if self." + field_field + " is not None:";
+ code_prefix += GenIndents(3) + field_field +
+ " = builder.CreateString(self." + field_field + ")";
+ code += GenIndents(2) + "if self." + field_field + " is not None:";
+ code += GenIndents(3) + struct_type + "Add" + field_method +
+ "(builder, " + field_field + ")";
break;
}
default:
// Generates code for scalar values. If the value equals to the
// default value, builder will automatically ignore it. So we don't
// need to check the value ahead.
- code += GenIndents(2) + struct_name + "Add" + field_accessor_name +
- "(builder, self." + field_instance_name + ")";
+ code += GenIndents(2) + struct_type + "Add" + field_method +
+ "(builder, self." + field_field + ")";
break;
}
}
- code += GenIndents(2) + struct_instance_name + " = " + struct_name +
- "End(builder)";
- code += GenIndents(2) + "return " + struct_instance_name;
+ code += GenIndents(2) + struct_var + " = " + struct_type + "End(builder)";
+ code += GenIndents(2) + "return " + struct_var;
code_base += code_prefix + code;
code_base += "\n";
}
void GenStructForObjectAPI(const StructDef &struct_def,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
if (struct_def.generated) return;
std::set<std::string> import_list;
@@ -1447,14 +1553,14 @@
}
void GenUnionCreatorForStruct(const EnumDef &enum_def, const EnumVal &ev,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- auto union_name = NormalizedName(enum_def);
- auto field_name = NormalizedName(ev);
- auto field_type = GenTypeGet(ev.union_type) + "T";
+ const auto union_type = namer_.Type(enum_def.name);
+ const auto variant = namer_.Variant(ev.name);
+ auto field_type = namer_.ObjectType(GenTypeGet(ev.union_type));
- code += GenIndents(1) + "if unionType == " + union_name + "()." +
- field_name + ":";
+ code += GenIndents(1) + "if unionType == " + union_type + "()." +
+ variant + ":";
if (parser_.opts.include_dependence_headers) {
auto package_reference = GenPackageReference(ev.union_type);
code += GenIndents(2) + "import " + package_reference;
@@ -1465,25 +1571,27 @@
}
void GenUnionCreatorForString(const EnumDef &enum_def, const EnumVal &ev,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
- auto union_name = NormalizedName(enum_def);
- auto field_name = NormalizedName(ev);
+ const auto union_type = namer_.Type(enum_def.name);
+ const auto variant = namer_.Variant(ev.name);
- code += GenIndents(1) + "if unionType == " + union_name + "()." +
- field_name + ":";
+ code += GenIndents(1) + "if unionType == " + union_type + "()." +
+ variant + ":";
code += GenIndents(2) + "tab = Table(table.Bytes, table.Pos)";
code += GenIndents(2) + "union = tab.String(table.Pos)";
code += GenIndents(2) + "return union";
}
// Creates an union object based on union type.
- void GenUnionCreator(const EnumDef &enum_def, std::string *code_ptr) {
+ void GenUnionCreator(const EnumDef &enum_def, std::string *code_ptr) const {
+ if (enum_def.generated) return;
+
auto &code = *code_ptr;
- auto union_name = MakeUpperCamel(enum_def);
+ const auto enum_fn = namer_.Function(enum_def.name);
code += "\n";
- code += "def " + union_name + "Creator(unionType, table):";
+ code += "def " + enum_fn + "Creator(unionType, table):";
code += GenIndents(1) + "from flatbuffers.table import Table";
code += GenIndents(1) + "if not isinstance(table, Table):";
code += GenIndents(2) + "return None";
@@ -1506,39 +1614,38 @@
}
// Generate enum declarations.
- void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ void GenEnum(const EnumDef &enum_def, std::string *code_ptr) const {
if (enum_def.generated) return;
GenComment(enum_def.doc_comment, code_ptr, &def_comment);
- BeginEnum(NormalizedName(enum_def), code_ptr);
+ BeginEnum(enum_def, code_ptr);
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
auto &ev = **it;
GenComment(ev.doc_comment, code_ptr, &def_comment, Indent.c_str());
EnumMember(enum_def, ev, code_ptr);
}
- EndEnum(code_ptr);
}
// Returns the function name that is able to read a value of the given type.
- std::string GenGetter(const Type &type) {
+ std::string GenGetter(const Type &type) const {
switch (type.base_type) {
case BASE_TYPE_STRING: return "self._tab.String(";
case BASE_TYPE_UNION: return "self._tab.Union(";
case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
default:
return "self._tab.Get(flatbuffers.number_types." +
- MakeCamel(GenTypeGet(type)) + "Flags, ";
+ namer_.Method(GenTypeGet(type)) + "Flags, ";
}
}
// Returns the method name for use with add/put calls.
- std::string GenMethod(const FieldDef &field) {
+ std::string GenMethod(const FieldDef &field) const {
return (IsScalar(field.value.type.base_type) || IsArray(field.value.type))
- ? MakeCamel(GenTypeBasic(field.value.type))
+ ? namer_.Method(GenTypeBasic(field.value.type))
: (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
}
- std::string GenTypeBasic(const Type &type) {
+ std::string GenTypeBasic(const Type &type) const {
// clang-format off
static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
@@ -1552,7 +1659,7 @@
: type.base_type];
}
- std::string GenTypePointer(const Type &type) {
+ std::string GenTypePointer(const Type &type) const {
switch (type.base_type) {
case BASE_TYPE_STRING: return "string";
case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
@@ -1563,16 +1670,17 @@
}
}
- std::string GenTypeGet(const Type &type) {
+ std::string GenTypeGet(const Type &type) const {
return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
}
- std::string TypeName(const FieldDef &field) {
+ std::string TypeName(const FieldDef &field) const {
return GenTypeGet(field.value.type);
}
// Create a struct with a builder and the struct's arguments.
- void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
+ void GenStructBuilder(const StructDef &struct_def,
+ std::string *code_ptr) const {
BeginBuilderArgs(struct_def, code_ptr);
StructBuilderArgs(struct_def,
/* nameprefix = */ "",
@@ -1586,13 +1694,21 @@
}
bool generate() {
- if (!generateEnums()) return false;
- if (!generateStructs()) return false;
+ std::string one_file_code;
+ if (!generateEnums(&one_file_code)) return false;
+ if (!generateStructs(&one_file_code)) return false;
+
+ if (parser_.opts.one_file) {
+ // Legacy file format uses keep casing.
+ return SaveType(file_name_ + "_generated.py", *parser_.current_namespace_,
+ one_file_code, true);
+ }
+
return true;
}
private:
- bool generateEnums() {
+ bool generateEnums(std::string *one_file_code) const {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
auto &enum_def = **it;
@@ -1601,12 +1717,19 @@
if (parser_.opts.generate_object_based_api & enum_def.is_union) {
GenUnionCreator(enum_def, &enumcode);
}
- if (!SaveType(enum_def, enumcode, false)) return false;
+
+ if (parser_.opts.one_file && !enumcode.empty()) {
+ *one_file_code += enumcode + "\n\n";
+ } else {
+ if (!SaveType(namer_.File(enum_def.name, SkipFile::Suffix),
+ *enum_def.defined_namespace, enumcode, false))
+ return false;
+ }
}
return true;
}
- bool generateStructs() {
+ bool generateStructs(std::string *one_file_code) const {
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
auto &struct_def = **it;
@@ -1615,14 +1738,21 @@
if (parser_.opts.generate_object_based_api) {
GenStructForObjectAPI(struct_def, &declcode);
}
- if (!SaveType(struct_def, declcode, true)) return false;
+
+ if (parser_.opts.one_file && !declcode.empty()) {
+ *one_file_code += declcode + "\n\n";
+ } else {
+ if (!SaveType(namer_.File(struct_def.name, SkipFile::Suffix),
+ *struct_def.defined_namespace, declcode, true))
+ return false;
+ }
}
return true;
}
// Begin by declaring namespace and imports.
void BeginFile(const std::string &name_space_name, const bool needs_imports,
- std::string *code_ptr) {
+ std::string *code_ptr) const {
auto &code = *code_ptr;
code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
code += "# namespace: " + name_space_name + "\n\n";
@@ -1634,30 +1764,32 @@
}
// Save out the generated code for a Python Table type.
- bool SaveType(const Definition &def, const std::string &classcode,
- bool needs_imports) {
+ bool SaveType(const std::string &defname, const Namespace &ns,
+ const std::string &classcode, bool needs_imports) const {
if (!classcode.length()) return true;
- std::string namespace_dir = path_;
- auto &namespaces = def.defined_namespace->components;
- for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
- if (it != namespaces.begin()) namespace_dir += kPathSeparator;
- namespace_dir += *it;
- std::string init_py_filename = namespace_dir + "/__init__.py";
- SaveFile(init_py_filename.c_str(), "", false);
+ std::string code = "";
+ BeginFile(LastNamespacePart(ns), needs_imports, &code);
+ code += classcode;
+
+ const std::string directories =
+ parser_.opts.one_file ? path_ : namer_.Directories(ns.components);
+ EnsureDirExists(directories);
+
+ for (size_t i = path_.size() + 1; i != std::string::npos;
+ i = directories.find(kPathSeparator, i + 1)) {
+ const std::string init_py =
+ directories.substr(0, i) + kPathSeparator + "__init__.py";
+ SaveFile(init_py.c_str(), "", false);
}
- std::string code = "";
- BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
- code += classcode;
- std::string filename =
- NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".py";
+ const std::string filename = directories + defname;
return SaveFile(filename.c_str(), code, false);
}
private:
- std::unordered_set<std::string> keywords_;
const SimpleFloatConstantGenerator float_const_gen_;
+ const Namer namer_;
};
} // namespace python
diff --git a/third_party/flatbuffers/src/idl_gen_rust.cpp b/third_party/flatbuffers/src/idl_gen_rust.cpp
index 3995a7f..17853a0 100644
--- a/third_party/flatbuffers/src/idl_gen_rust.cpp
+++ b/third_party/flatbuffers/src/idl_gen_rust.cpp
@@ -20,35 +20,119 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
+#include "namer.h"
namespace flatbuffers {
-// Convert a camelCaseIdentifier or CamelCaseIdentifier to a
-// snake_case_indentifier.
-std::string MakeSnakeCase(const std::string &in) {
- std::string s;
- for (size_t i = 0; i < in.length(); i++) {
- if (i == 0) {
- s += CharToLower(in[0]);
- } else if (in[i] == '_') {
- s += '_';
- } else if (!islower(in[i])) {
- // Prevent duplicate underscores for Upper_Snake_Case strings
- // and UPPERCASE strings.
- if (islower(in[i - 1])) { s += '_'; }
- s += CharToLower(in[i]);
- } else {
- s += in[i];
- }
- }
- return s;
+Namer::Config RustDefaultConfig() {
+ // Historical note: We've been using "keep" casing since the original
+ // implementation, presumably because Flatbuffers schema style and Rust style
+ // roughly align. We are not going to enforce proper casing since its an
+ // unnecessary breaking change.
+ return { /*types=*/Case::kKeep,
+ /*constants=*/Case::kScreamingSnake,
+ /*methods=*/Case::kSnake,
+ /*functions=*/Case::kSnake,
+ /*fields=*/Case::kKeep,
+ /*variables=*/Case::kUnknown, // Unused.
+ /*variants=*/Case::kKeep,
+ /*enum_variant_seperator=*/"::",
+ /*namespaces=*/Case::kSnake,
+ /*namespace_seperator=*/"::",
+ /*object_prefix=*/"",
+ /*object_suffix=*/"T",
+ /*keyword_prefix=*/"",
+ /*keyword_suffix=*/"_",
+ /*filenames=*/Case::kSnake,
+ /*directories=*/Case::kSnake,
+ /*output_path=*/"",
+ /*filename_suffix=*/"_generated",
+ /*filename_extension=*/".rs" };
}
-// Convert a string to all uppercase.
-std::string MakeUpper(const std::string &in) {
- std::string s;
- for (size_t i = 0; i < in.length(); i++) { s += CharToUpper(in[i]); }
- return s;
+std::set<std::string> RustKeywords() {
+ return {
+ // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
+ "as",
+ "break",
+ "const",
+ "continue",
+ "crate",
+ "else",
+ "enum",
+ "extern",
+ "false",
+ "fn",
+ "for",
+ "if",
+ "impl",
+ "in",
+ "let",
+ "loop",
+ "match",
+ "mod",
+ "move",
+ "mut",
+ "pub",
+ "ref",
+ "return",
+ "Self",
+ "self",
+ "static",
+ "struct",
+ "super",
+ "trait",
+ "true",
+ "type",
+ "unsafe",
+ "use",
+ "where",
+ "while",
+ // future possible keywords
+ "abstract",
+ "alignof",
+ "become",
+ "box",
+ "do",
+ "final",
+ "macro",
+ "offsetof",
+ "override",
+ "priv",
+ "proc",
+ "pure",
+ "sizeof",
+ "typeof",
+ "unsized",
+ "virtual",
+ "yield",
+ // other rust terms we should not use
+ "std",
+ "usize",
+ "isize",
+ "u8",
+ "i8",
+ "u16",
+ "i16",
+ "u32",
+ "i32",
+ "u64",
+ "i64",
+ "u128",
+ "i128",
+ "f32",
+ "f64",
+ // Terms that we use ourselves
+ "follow",
+ "push",
+ "size",
+ "alignment",
+ "to_little_endian",
+ "from_little_endian",
+ "ENUM_MAX",
+ "ENUM_MIN",
+ "ENUM_VALUES",
+ };
}
// Encapsulate all logical field types in this enum. This allows us to write
@@ -81,6 +165,10 @@
ftVectorOfTable = 14,
ftVectorOfString = 15,
ftVectorOfUnionValue = 16,
+
+ ftArrayOfBuiltin = 17,
+ ftArrayOfEnum = 18,
+ ftArrayOfStruct = 19,
};
// Convert a Type to a FullType (exhaustive).
@@ -127,6 +215,23 @@
FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
}
}
+ } else if (IsArray(type)) {
+ switch (GetFullType(type.VectorType())) {
+ case ftInteger:
+ case ftFloat:
+ case ftBool: {
+ return ftArrayOfBuiltin;
+ }
+ case ftStruct: {
+ return ftArrayOfStruct;
+ }
+ case ftEnumKey: {
+ return ftArrayOfEnum;
+ }
+ default: {
+ FLATBUFFERS_ASSERT(false && "Unsupported type for fixed array");
+ }
+ }
} else if (type.enum_def != nullptr) {
if (type.enum_def->is_union) {
if (type.base_type == BASE_TYPE_UNION) {
@@ -157,30 +262,78 @@
return ftBool;
}
-// If the second parameter is false then wrap the first with Option<...>
-std::string WrapInOptionIfNotRequired(std::string s, bool required) {
- if (required) {
- return s;
- } else {
- return "Option<" + s + ">";
- }
-}
-
-// If the second parameter is false then add .unwrap()
-std::string AddUnwrapIfRequired(std::string s, bool required) {
- if (required) {
- return s + ".unwrap()";
- } else {
- return s;
- }
-}
-
bool IsBitFlagsEnum(const EnumDef &enum_def) {
return enum_def.attributes.Lookup("bit_flags") != nullptr;
}
-bool IsBitFlagsEnum(const FieldDef &field) {
- EnumDef* ed = field.value.type.enum_def;
- return ed && IsBitFlagsEnum(*ed);
+
+// TableArgs make required non-scalars "Option<_>".
+// TODO(cneo): Rework how we do defaults and stuff.
+bool IsOptionalToBuilder(const FieldDef &field) {
+ return field.IsOptional() || !IsScalar(field.value.type.base_type);
+}
+
+bool GenerateRustModuleRootFile(const Parser &parser,
+ const std::string &output_dir) {
+ if (!parser.opts.rust_module_root_file) {
+ // Don't generate a root file when generating one file. This isn't an error
+ // so return true.
+ return true;
+ }
+ Namer namer(RustDefaultConfig().WithFlagOptions(parser.opts, output_dir),
+ RustKeywords());
+ // We gather the symbols into a tree of namespaces (which are rust mods) and
+ // generate a file that gathers them all.
+ struct Module {
+ std::map<std::string, Module> sub_modules;
+ std::vector<std::string> generated_files;
+ // Add a symbol into the tree.
+ void Insert(const Namer &namer, const Definition *s) {
+ const Definition &symbol = *s;
+ Module *current_module = this;
+ for (auto it = symbol.defined_namespace->components.begin();
+ it != symbol.defined_namespace->components.end(); it++) {
+ std::string ns_component = namer.Namespace(*it);
+ current_module = ¤t_module->sub_modules[ns_component];
+ }
+ current_module->generated_files.push_back(
+ namer.File(symbol.name, SkipFile::Extension));
+ }
+ // Recursively create the importer file.
+ void GenerateImports(CodeWriter &code) {
+ for (auto it = sub_modules.begin(); it != sub_modules.end(); it++) {
+ code += "pub mod " + it->first + " {";
+ code.IncrementIdentLevel();
+ code += "use super::*;";
+ it->second.GenerateImports(code);
+ code.DecrementIdentLevel();
+ code += "} // " + it->first;
+ }
+ for (auto it = generated_files.begin(); it != generated_files.end();
+ it++) {
+ code += "mod " + *it + ";";
+ code += "pub use self::" + *it + "::*;";
+ }
+ }
+ };
+ Module root_module;
+ for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
+ it++) {
+ root_module.Insert(namer, *it);
+ }
+ for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
+ it++) {
+ root_module.Insert(namer, *it);
+ }
+ CodeWriter code(" ");
+ // TODO(caspern): Move generated warning out of BaseGenerator.
+ code +=
+ "// Automatically generated by the Flatbuffers compiler. "
+ "Do not modify.";
+ root_module.GenerateImports(code);
+ const bool success =
+ SaveFile((output_dir + "mod.rs").c_str(), code.ToString(), false);
+ code.Clear();
+ return success;
}
namespace rust {
@@ -190,50 +343,79 @@
RustGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
: BaseGenerator(parser, path, file_name, "", "::", "rs"),
- cur_name_space_(nullptr) {
- const char *keywords[] = {
- // list taken from:
- // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
- //
- // we write keywords one per line so that we can easily compare them with
- // changes to that webpage in the future.
-
- // currently-used keywords
- "as", "break", "const", "continue", "crate", "else", "enum", "extern",
- "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod",
- "move", "mut", "pub", "ref", "return", "Self", "self", "static", "struct",
- "super", "trait", "true", "type", "unsafe", "use", "where", "while",
-
- // future possible keywords
- "abstract", "alignof", "become", "box", "do", "final", "macro",
- "offsetof", "override", "priv", "proc", "pure", "sizeof", "typeof",
- "unsized", "virtual", "yield",
-
- // other rust terms we should not use
- "std", "usize", "isize", "u8", "i8", "u16", "i16", "u32", "i32", "u64",
- "i64", "u128", "i128", "f32", "f64",
-
- // These are terms the code generator can implement on types.
- //
- // In Rust, the trait resolution rules (as described at
- // https://github.com/rust-lang/rust/issues/26007) mean that, as long
- // as we impl table accessors as inherent methods, we'll never create
- // conflicts with these keywords. However, that's a fairly nuanced
- // implementation detail, and how we implement methods could change in
- // the future. as a result, we proactively block these out as reserved
- // words.
- "follow", "push", "size", "alignment", "to_little_endian",
- "from_little_endian", nullptr,
-
- // used by Enum constants
- "ENUM_MAX", "ENUM_MIN", "ENUM_VALUES",
- };
- for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+ cur_name_space_(nullptr),
+ namer_({ RustDefaultConfig().WithFlagOptions(parser.opts, path),
+ RustKeywords() }) {
+ // TODO: Namer flag overrides should be in flatc or flatc_main.
+ code_.SetPadding(" ");
}
+ bool generate() {
+ if (!parser_.opts.rust_module_root_file) {
+ return GenerateOneFile();
+ } else {
+ return GenerateIndividualFiles();
+ }
+ }
+
+ template<typename T>
+ bool GenerateSymbols(const SymbolTable<T> &symbols,
+ std::function<void(const T &)> gen_symbol) {
+ for (auto it = symbols.vec.begin(); it != symbols.vec.end(); it++) {
+ const T &symbol = **it;
+ if (symbol.generated) continue;
+ code_.Clear();
+ code_ += "// " + std::string(FlatBuffersGeneratedWarning());
+ code_ += "extern crate flatbuffers;";
+ code_ += "use std::mem;";
+ code_ += "use std::cmp::Ordering;";
+ if (parser_.opts.rust_serialize) {
+ code_ += "extern crate serde;";
+ code_ +=
+ "use self::serde::ser::{Serialize, Serializer, SerializeStruct};";
+ }
+ code_ += "use self::flatbuffers::{EndianScalar, Follow};";
+ code_ += "use super::*;";
+ cur_name_space_ = symbol.defined_namespace;
+ gen_symbol(symbol);
+
+ const std::string directories =
+ namer_.Directories(symbol.defined_namespace->components);
+ EnsureDirExists(directories);
+ const std::string file_path = directories + namer_.File(symbol.name);
+ const bool save_success =
+ SaveFile(file_path.c_str(), code_.ToString(), /*binary=*/false);
+ if (!save_success) return false;
+ }
+ return true;
+ }
+
+ bool GenerateIndividualFiles() {
+ code_.Clear();
+ // Don't bother with imports. Use absolute paths everywhere.
+ return GenerateSymbols<EnumDef>(
+ parser_.enums_, [&](const EnumDef &e) { this->GenEnum(e); }) &&
+ GenerateSymbols<StructDef>(
+ parser_.structs_, [&](const StructDef &s) {
+ if (s.fixed) {
+ this->GenStruct(s);
+ } else {
+ this->GenTable(s);
+ if (this->parser_.opts.generate_object_based_api) {
+ this->GenTableObject(s);
+ }
+ }
+ if (this->parser_.root_struct_def_ == &s) {
+ this->GenRootTableFuncs(s);
+ }
+ });
+ }
+
+ // Generates code organized by .fbs files. This is broken legacy behavior
+ // that does not work with multiple fbs files with shared namespaces.
// Iterate through all definitions we haven't generated code for (enums,
// structs, and tables) and output them to a single file.
- bool generate() {
+ bool GenerateOneFile() {
code_.Clear();
code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
@@ -257,8 +439,7 @@
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
const auto &enum_def = **it;
- if (enum_def.defined_namespace != ns) { continue; }
- if (!enum_def.generated) {
+ if (enum_def.defined_namespace == ns && !enum_def.generated) {
SetNameSpace(enum_def.defined_namespace);
GenEnum(enum_def);
}
@@ -268,8 +449,8 @@
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
const auto &struct_def = **it;
- if (struct_def.defined_namespace != ns) { continue; }
- if (struct_def.fixed && !struct_def.generated) {
+ if (struct_def.defined_namespace == ns && struct_def.fixed &&
+ !struct_def.generated) {
SetNameSpace(struct_def.defined_namespace);
GenStruct(struct_def);
}
@@ -279,10 +460,13 @@
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
const auto &struct_def = **it;
- if (struct_def.defined_namespace != ns) { continue; }
- if (!struct_def.fixed && !struct_def.generated) {
+ if (struct_def.defined_namespace == ns && !struct_def.fixed &&
+ !struct_def.generated) {
SetNameSpace(struct_def.defined_namespace);
GenTable(struct_def);
+ if (parser_.opts.generate_object_based_api) {
+ GenTableObject(struct_def);
+ }
}
}
@@ -304,8 +488,6 @@
private:
CodeWriter code_;
- std::set<std::string> keywords_;
-
// This tracks the current namespace so we can insert namespace declarations.
const Namespace *cur_name_space_;
@@ -344,18 +526,13 @@
return false;
}
- std::string EscapeKeyword(const std::string &name) const {
- return keywords_.find(name) == keywords_.end() ? name : name + "_";
+ std::string NamespacedNativeName(const Definition &def) {
+ return WrapInNameSpace(def.defined_namespace, namer_.ObjectType(def.name));
}
- std::string Name(const Definition &def) const {
- return EscapeKeyword(def.name);
- }
-
- std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
-
std::string WrapInNameSpace(const Definition &def) const {
- return WrapInNameSpace(def.defined_namespace, Name(def));
+ return WrapInNameSpace(def.defined_namespace,
+ namer_.EscapeKeyword(def.name));
}
std::string WrapInNameSpace(const Namespace *ns,
const std::string &name) const {
@@ -364,19 +541,6 @@
return prefix + name;
}
- // Determine the namespace traversal needed from the Rust crate root.
- // This may be useful in the future for referring to included files, but is
- // currently unused.
- std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const {
- std::stringstream stream;
-
- stream << "::";
- for (auto d = dst->components.begin(); d != dst->components.end(); ++d) {
- stream << MakeSnakeCase(*d) + "::";
- }
- return stream.str();
- }
-
// Determine the relative namespace traversal needed to reference one
// namespace from another namespace. This is useful because it does not force
// the user to have a particular file layout. (If we output absolute
@@ -394,32 +558,25 @@
// example: f(A, D::E) -> super::D::E
// does not include leaf object (typically a struct type).
- size_t i = 0;
std::stringstream stream;
-
- auto s = src->components.begin();
- auto d = dst->components.begin();
- for (;;) {
- if (s == src->components.end()) { break; }
- if (d == dst->components.end()) { break; }
- if (*s != *d) { break; }
- ++s;
- ++d;
- ++i;
- }
-
- for (; s != src->components.end(); ++s) { stream << "super::"; }
- for (; d != dst->components.end(); ++d) {
- stream << MakeSnakeCase(*d) + "::";
- }
+ size_t common = 0;
+ std::vector<std::string> s, d;
+ if (src) s = src->components;
+ if (dst) d = dst->components;
+ while (common < s.size() && common < d.size() && s[common] == d[common])
+ common++;
+ // If src namespace is empty, this must be an absolute path.
+ for (size_t i = common; i < s.size(); i++) stream << "super::";
+ for (size_t i = common; i < d.size(); i++)
+ stream << namer_.Namespace(d[i]) + "::";
return stream.str();
}
// Generate a comment from the schema.
void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
- std::string text;
- ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
- code_ += text + "\\";
+ for (auto it = dc.begin(); it != dc.end(); it++) {
+ code_ += std::string(prefix) + "///" + *it;
+ }
}
// Return a Rust type from the table in idl.h.
@@ -486,6 +643,12 @@
case ftUnionKey: {
return GetTypeBasic(type);
}
+ case ftArrayOfBuiltin:
+ case ftArrayOfEnum:
+ case ftArrayOfStruct: {
+ return "[" + GetTypeGet(type.VectorType()) + "; " +
+ NumToString(type.fixed_length) + "]";
+ }
case ftTable: {
return WrapInNameSpace(type.struct_def->defined_namespace,
type.struct_def->name) +
@@ -499,36 +662,38 @@
}
std::string GetEnumValue(const EnumDef &enum_def,
- const EnumVal &enum_val) const {
- return Name(enum_def) + "::" + Name(enum_val);
+ const EnumVal &enum_val) const {
+ return namer_.EnumVariant(enum_def.name, enum_val.name);
}
// 1 suffix since old C++ can't figure out the overload.
void ForAllEnumValues1(const EnumDef &enum_def,
- std::function<void(const EnumVal&)> cb) {
+ std::function<void(const EnumVal &)> cb) {
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
const auto &ev = **it;
- code_.SetValue("VARIANT", Name(ev));
+ code_.SetValue("VARIANT", namer_.Variant(ev.name));
code_.SetValue("VALUE", enum_def.ToString(ev));
+ code_.IncrementIdentLevel();
cb(ev);
+ code_.DecrementIdentLevel();
}
}
void ForAllEnumValues(const EnumDef &enum_def, std::function<void()> cb) {
- std::function<void(const EnumVal&)> wrapped = [&](const EnumVal& unused) {
- (void) unused;
- cb();
- };
- ForAllEnumValues1(enum_def, wrapped);
+ std::function<void(const EnumVal &)> wrapped = [&](const EnumVal &unused) {
+ (void)unused;
+ cb();
+ };
+ ForAllEnumValues1(enum_def, wrapped);
}
// Generate an enum declaration,
// an enum string lookup table,
// an enum match function,
// and an enum array of values
void GenEnum(const EnumDef &enum_def) {
- code_.SetValue("ENUM_NAME", Name(enum_def));
+ code_.SetValue("ENUM_TY", namer_.Type(enum_def.name));
code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
- code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
- code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
+ code_.SetValue("ENUM_NAMESPACE", namer_.Namespace(enum_def.name));
+ code_.SetValue("ENUM_CONSTANT", namer_.Constant(enum_def.name));
const EnumVal *minv = enum_def.MinValue();
const EnumVal *maxv = enum_def.MaxValue();
FLATBUFFERS_ASSERT(minv && maxv);
@@ -536,193 +701,381 @@
code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
if (IsBitFlagsEnum(enum_def)) {
- // Defer to the convenient and canonical bitflags crate. We declare it in a
- // module to #allow camel case constants in a smaller scope. This matches
- // Flatbuffers c-modeled enums where variants are associated constants but
- // in camel case.
+ // Defer to the convenient and canonical bitflags crate. We declare it in
+ // a module to #allow camel case constants in a smaller scope. This
+ // matches Flatbuffers c-modeled enums where variants are associated
+ // constants but in camel case.
code_ += "#[allow(non_upper_case_globals)]";
- code_ += "mod bitflags_{{ENUM_NAME_SNAKE}} {";
+ code_ += "mod bitflags_{{ENUM_NAMESPACE}} {";
code_ += " flatbuffers::bitflags::bitflags! {";
GenComment(enum_def.doc_comment, " ");
- code_ += " pub struct {{ENUM_NAME}}: {{BASE_TYPE}} {";
- ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
- this->GenComment(ev.doc_comment, " ");
- code_ += " const {{VARIANT}} = {{VALUE}};";
+ code_ += " #[derive(Default)]";
+ code_ += " pub struct {{ENUM_TY}}: {{BASE_TYPE}} {";
+ ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
+ this->GenComment(ev.doc_comment, " ");
+ code_ += " const {{VARIANT}} = {{VALUE}};";
});
code_ += " }";
code_ += " }";
code_ += "}";
- code_ += "pub use self::bitflags_{{ENUM_NAME_SNAKE}}::{{ENUM_NAME}};";
+ code_ += "pub use self::bitflags_{{ENUM_NAMESPACE}}::{{ENUM_TY}};";
code_ += "";
- // Generate Follow and Push so we can serialize and stuff.
- code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
- code_ += " type Inner = Self;";
- code_ += " #[inline]";
- code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
- code_ += " let bits = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc);";
- code_ += " unsafe { Self::from_bits_unchecked(bits) }";
- code_ += " }";
- code_ += "}";
+ code_.SetValue("FROM_BASE", "unsafe { Self::from_bits_unchecked(b) }");
+ code_.SetValue("INTO_BASE", "self.bits()");
+ } else {
+ // Normal, c-modelled enums.
+ // Deprecated associated constants;
+ const std::string deprecation_warning =
+ "#[deprecated(since = \"2.0.0\", note = \"Use associated constants"
+ " instead. This will no longer be generated in 2021.\")]";
+ code_ += deprecation_warning;
+ code_ +=
+ "pub const ENUM_MIN_{{ENUM_CONSTANT}}: {{BASE_TYPE}}"
+ " = {{ENUM_MIN_BASE_VALUE}};";
+ code_ += deprecation_warning;
+ code_ +=
+ "pub const ENUM_MAX_{{ENUM_CONSTANT}}: {{BASE_TYPE}}"
+ " = {{ENUM_MAX_BASE_VALUE}};";
+ auto num_fields = NumToString(enum_def.size());
+ code_ += deprecation_warning;
+ code_ += "#[allow(non_camel_case_types)]";
+ code_ += "pub const ENUM_VALUES_{{ENUM_CONSTANT}}: [{{ENUM_TY}}; " +
+ num_fields + "] = [";
+ ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
+ code_ += namer_.EnumVariant(enum_def.name, ev.name) + ",";
+ });
+ code_ += "];";
code_ += "";
- code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
- code_ += " type Output = {{ENUM_NAME}};";
- code_ += " #[inline]";
- code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
- code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
- "(dst, self.bits());";
+
+ GenComment(enum_def.doc_comment);
+ // Derive Default to be 0. flatc enforces this when the enum
+ // is put into a struct, though this isn't documented behavior, it is
+ // needed to derive defaults in struct objects.
+ code_ +=
+ "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, "
+ "Default)]";
+ code_ += "#[repr(transparent)]";
+ code_ += "pub struct {{ENUM_TY}}(pub {{BASE_TYPE}});";
+ code_ += "#[allow(non_upper_case_globals)]";
+ code_ += "impl {{ENUM_TY}} {";
+ ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
+ this->GenComment(ev.doc_comment);
+ code_ += "pub const {{VARIANT}}: Self = Self({{VALUE}});";
+ });
+ code_ += "";
+ // Generate Associated constants
+ code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};";
+ code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};";
+ code_ += " pub const ENUM_VALUES: &'static [Self] = &[";
+ ForAllEnumValues(enum_def, [&]() { code_ += " Self::{{VARIANT}},"; });
+ code_ += " ];";
+ code_ += " /// Returns the variant's name or \"\" if unknown.";
+ code_ += " pub fn variant_name(self) -> Option<&'static str> {";
+ code_ += " match self {";
+ ForAllEnumValues(enum_def, [&]() {
+ code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),";
+ });
+ code_ += " _ => None,";
code_ += " }";
- code_ += "}";
- code_ += "";
- code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
- code_ += " #[inline]";
- code_ += " fn to_little_endian(self) -> Self {";
- code_ += " let bits = {{BASE_TYPE}}::to_le(self.bits());";
- code_ += " unsafe { Self::from_bits_unchecked(bits) }";
- code_ += " }";
- code_ += " #[inline]";
- code_ += " fn from_little_endian(self) -> Self {";
- code_ += " let bits = {{BASE_TYPE}}::from_le(self.bits());";
- code_ += " unsafe { Self::from_bits_unchecked(bits) }";
code_ += " }";
code_ += "}";
- code_ += "";
- return;
+
+ // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>".
+ code_ += "impl std::fmt::Debug for {{ENUM_TY}} {";
+ code_ +=
+ " fn fmt(&self, f: &mut std::fmt::Formatter) ->"
+ " std::fmt::Result {";
+ code_ += " if let Some(name) = self.variant_name() {";
+ code_ += " f.write_str(name)";
+ code_ += " } else {";
+ code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))";
+ code_ += " }";
+ code_ += " }";
+ code_ += "}";
+
+ code_.SetValue("FROM_BASE", "Self(b)");
+ code_.SetValue("INTO_BASE", "self.0");
}
- // Deprecated associated constants;
- code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
- " instead. This will no longer be generated in 2021.\")]";
- code_ += "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
- " = {{ENUM_MIN_BASE_VALUE}};";
- code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
- " instead. This will no longer be generated in 2021.\")]";
- code_ += "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
- " = {{ENUM_MAX_BASE_VALUE}};";
- auto num_fields = NumToString(enum_def.size());
- code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
- " instead. This will no longer be generated in 2021.\")]";
- code_ += "#[allow(non_camel_case_types)]";
- code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " +
- num_fields + "] = [";
- ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
- code_ += " " + GetEnumValue(enum_def, ev) + ",";
- });
- code_ += "];";
- code_ += "";
-
- GenComment(enum_def.doc_comment);
- code_ +=
- "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]";
- code_ += "#[repr(transparent)]";
- code_ += "pub struct {{ENUM_NAME}}(pub {{BASE_TYPE}});";
- code_ += "#[allow(non_upper_case_globals)]";
- code_ += "impl {{ENUM_NAME}} {";
- ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
- this->GenComment(ev.doc_comment, " ");
- code_ += " pub const {{VARIANT}}: Self = Self({{VALUE}});";
- });
- code_ += "";
- // Generate Associated constants
- code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};";
- code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};";
- code_ += " pub const ENUM_VALUES: &'static [Self] = &[";
- ForAllEnumValues(enum_def, [&](){
- code_ += " Self::{{VARIANT}},";
- });
- code_ += " ];";
- code_ += " /// Returns the variant's name or \"\" if unknown.";
- code_ += " pub fn variant_name(self) -> Option<&'static str> {";
- code_ += " match self {";
- ForAllEnumValues(enum_def, [&](){
- code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),";
- });
- code_ += " _ => None,";
- code_ += " }";
- code_ += " }";
- code_ += "}";
-
- // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>".
- code_ += "impl std::fmt::Debug for {{ENUM_NAME}} {";
- code_ += " fn fmt(&self, f: &mut std::fmt::Formatter) ->"
- " std::fmt::Result {";
- code_ += " if let Some(name) = self.variant_name() {";
- code_ += " f.write_str(name)";
- code_ += " } else {";
- code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))";
- code_ += " }";
- code_ += " }";
- code_ += "}";
+ // Implement serde::Serialize
+ if (parser_.opts.rust_serialize) {
+ code_ += "impl Serialize for {{ENUM_TY}} {";
+ code_ +=
+ " fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
+ code_ += " where";
+ code_ += " S: Serializer,";
+ code_ += " {";
+ if (IsBitFlagsEnum(enum_def)) {
+ code_ += " serializer.serialize_u32(self.bits() as u32)";
+ } else {
+ code_ +=
+ " serializer.serialize_unit_variant(\"{{ENUM_TY}}\", self.0 "
+ "as "
+ "u32, self.variant_name().unwrap())";
+ }
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ }
// Generate Follow and Push so we can serialize and stuff.
- code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
+ code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_TY}} {";
code_ += " type Inner = Self;";
code_ += " #[inline]";
code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
- code_ += " Self(flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc))";
+ code_ += " let b = unsafe {";
+ code_ += " flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc)";
+ code_ += " };";
+ code_ += " {{FROM_BASE}}";
code_ += " }";
code_ += "}";
code_ += "";
- code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
- code_ += " type Output = {{ENUM_NAME}};";
+ code_ += "impl flatbuffers::Push for {{ENUM_TY}} {";
+ code_ += " type Output = {{ENUM_TY}};";
code_ += " #[inline]";
code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
- code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
- "(dst, self.0);";
+ code_ +=
+ " unsafe { flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
+ "(dst, {{INTO_BASE}}); }";
code_ += " }";
code_ += "}";
code_ += "";
- code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
+ code_ += "impl flatbuffers::EndianScalar for {{ENUM_TY}} {";
code_ += " #[inline]";
code_ += " fn to_little_endian(self) -> Self {";
- code_ += " Self({{BASE_TYPE}}::to_le(self.0))";
+ code_ += " let b = {{BASE_TYPE}}::to_le({{INTO_BASE}});";
+ code_ += " {{FROM_BASE}}";
code_ += " }";
code_ += " #[inline]";
+ code_ += " #[allow(clippy::wrong_self_convention)]";
code_ += " fn from_little_endian(self) -> Self {";
- code_ += " Self({{BASE_TYPE}}::from_le(self.0))";
+ code_ += " let b = {{BASE_TYPE}}::from_le({{INTO_BASE}});";
+ code_ += " {{FROM_BASE}}";
code_ += " }";
code_ += "}";
code_ += "";
+ // Generate verifier - deferring to the base type.
+ code_ += "impl<'a> flatbuffers::Verifiable for {{ENUM_TY}} {";
+ code_ += " #[inline]";
+ code_ += " fn run_verifier(";
+ code_ += " v: &mut flatbuffers::Verifier, pos: usize";
+ code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
+ code_ += " use self::flatbuffers::Verifiable;";
+ code_ += " {{BASE_TYPE}}::run_verifier(v, pos)";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ // Enums are basically integers.
+ code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{ENUM_TY}} {}";
+
if (enum_def.is_union) {
- // Generate tyoesafe offset(s) for unions
- code_.SetValue("NAME", Name(enum_def));
- code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
- code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
+ // Generate typesafe offset(s) for unions
+ code_.SetValue("UNION_TYPE", namer_.Type(enum_def.name));
+ code_ += "pub struct {{UNION_TYPE}}UnionTableOffset {}";
+ code_ += "";
+ if (parser_.opts.generate_object_based_api) { GenUnionObject(enum_def); }
}
}
+ // TODO(cneo): dedup Object versions from non object versions.
+ void ForAllUnionObjectVariantsBesidesNone(const EnumDef &enum_def,
+ std::function<void()> cb) {
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &enum_val = **it;
+ if (enum_val.union_type.base_type == BASE_TYPE_NONE) continue;
+ code_.SetValue("VARIANT_NAME", namer_.Variant(enum_val.name));
+ // For legacy reasons, enum variants are Keep case while enum native
+ // variants are UpperCamel case.
+ code_.SetValue(
+ "NATIVE_VARIANT",
+ ConvertCase(namer_.EscapeKeyword(enum_val.name), Case::kUpperCamel));
+ code_.SetValue("U_ELEMENT_NAME", namer_.Method(enum_val.name));
+ code_.SetValue("U_ELEMENT_TABLE_TYPE",
+ NamespacedNativeName(*enum_val.union_type.struct_def));
+ code_.IncrementIdentLevel();
+ cb();
+ code_.DecrementIdentLevel();
+ }
+ }
+ void GenUnionObject(const EnumDef &enum_def) {
+ code_.SetValue("ENUM_TY", namer_.Type(enum_def.name));
+ code_.SetValue("ENUM_FN", namer_.Function(enum_def.name));
+ code_.SetValue("ENUM_OTY", namer_.ObjectType(enum_def.name));
+
+ // Generate native union.
+ code_ += "#[allow(clippy::upper_case_acronyms)]"; // NONE's spelling is
+ // intended.
+ code_ += "#[non_exhaustive]";
+ code_ += "#[derive(Debug, Clone, PartialEq)]";
+ code_ += "pub enum {{ENUM_OTY}} {";
+ code_ += " NONE,";
+ ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
+ code_ += "{{NATIVE_VARIANT}}(Box<{{U_ELEMENT_TABLE_TYPE}}>),";
+ });
+ code_ += "}";
+ // Generate Default (NONE).
+ code_ += "impl Default for {{ENUM_OTY}} {";
+ code_ += " fn default() -> Self {";
+ code_ += " Self::NONE";
+ code_ += " }";
+ code_ += "}";
+
+ // Generate native union methods.
+ code_ += "impl {{ENUM_OTY}} {";
+
+ // Get flatbuffers union key.
+ // TODO(cneo): add docstrings?
+ code_ += " pub fn {{ENUM_FN}}_type(&self) -> {{ENUM_TY}} {";
+ code_ += " match self {";
+ code_ += " Self::NONE => {{ENUM_TY}}::NONE,";
+ ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
+ code_ +=
+ " Self::{{NATIVE_VARIANT}}(_) => {{ENUM_TY}}::"
+ "{{VARIANT_NAME}},";
+ });
+ code_ += " }";
+ code_ += " }";
+ // Pack flatbuffers union value
+ code_ +=
+ " pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder)"
+ " -> Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>"
+ " {";
+ code_ += " match self {";
+ code_ += " Self::NONE => None,";
+ ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
+ code_ += " Self::{{NATIVE_VARIANT}}(v) => \\";
+ code_ += "Some(v.pack(fbb).as_union_value()),";
+ });
+ code_ += " }";
+ code_ += " }";
+
+ // Generate some accessors;
+ ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
+ // Move accessor.
+ code_ +=
+ "/// If the union variant matches, return the owned "
+ "{{U_ELEMENT_TABLE_TYPE}}, setting the union to NONE.";
+ code_ +=
+ "pub fn take_{{U_ELEMENT_NAME}}(&mut self) -> "
+ "Option<Box<{{U_ELEMENT_TABLE_TYPE}}>> {";
+ code_ += " if let Self::{{NATIVE_VARIANT}}(_) = self {";
+ code_ += " let v = std::mem::replace(self, Self::NONE);";
+ code_ += " if let Self::{{NATIVE_VARIANT}}(w) = v {";
+ code_ += " Some(w)";
+ code_ += " } else {";
+ code_ += " unreachable!()";
+ code_ += " }";
+ code_ += " } else {";
+ code_ += " None";
+ code_ += " }";
+ code_ += "}";
+ // Immutable reference accessor.
+ code_ +=
+ "/// If the union variant matches, return a reference to the "
+ "{{U_ELEMENT_TABLE_TYPE}}.";
+ code_ +=
+ "pub fn as_{{U_ELEMENT_NAME}}(&self) -> "
+ "Option<&{{U_ELEMENT_TABLE_TYPE}}> {";
+ code_ +=
+ " if let Self::{{NATIVE_VARIANT}}(v) = self "
+ "{ Some(v.as_ref()) } else { None }";
+ code_ += "}";
+ // Mutable reference accessor.
+ code_ +=
+ "/// If the union variant matches, return a mutable reference"
+ " to the {{U_ELEMENT_TABLE_TYPE}}.";
+ code_ +=
+ "pub fn as_{{U_ELEMENT_NAME}}_mut(&mut self) -> "
+ "Option<&mut {{U_ELEMENT_TABLE_TYPE}}> {";
+ code_ +=
+ " if let Self::{{NATIVE_VARIANT}}(v) = self "
+ "{ Some(v.as_mut()) } else { None }";
+ code_ += "}";
+ });
+ code_ += "}"; // End union methods impl.
+ }
+
std::string GetFieldOffsetName(const FieldDef &field) {
- return "VT_" + MakeUpper(Name(field));
+ // FIXME: VT_FIELD_NAME is not screaming snake case by legacy mistake.
+ // but changing this is probably a breaking change.
+ return "VT_" +
+ ConvertCase(namer_.EscapeKeyword(field.name), Case::kAllUpper);
}
- std::string GetDefaultScalarValue(const FieldDef &field) {
+ enum DefaultContext { kBuilder, kAccessor, kObject };
+ std::string GetDefaultValue(const FieldDef &field,
+ const DefaultContext context) {
+ if (context == kBuilder) {
+ // Builders and Args structs model nonscalars "optional" even if they're
+ // required or have defaults according to the schema. I guess its because
+ // WIPOffset is not nullable.
+ if (!IsScalar(field.value.type.base_type) || field.IsOptional()) {
+ return "None";
+ }
+ } else {
+ // This for defaults in objects.
+ // Unions have a NONE variant instead of using Rust's None.
+ if (field.IsOptional() && !IsUnion(field.value.type)) { return "None"; }
+ }
switch (GetFullType(field.value.type)) {
case ftInteger:
case ftFloat: {
- return field.optional ? "None" : field.value.constant;
+ return field.value.constant;
}
case ftBool: {
- return field.optional ? "None"
- : field.value.constant == "0" ? "false" : "true";
+ return field.value.constant == "0" ? "false" : "true";
}
case ftUnionKey:
case ftEnumKey: {
- if (field.optional) {
- return "None";
- }
auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
- assert(ev);
- return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
- GetEnumValue(*field.value.type.enum_def, *ev));
+ if (!ev) return "Default::default()"; // Bitflags enum.
+ return WrapInNameSpace(
+ field.value.type.enum_def->defined_namespace,
+ namer_.EnumVariant(field.value.type.enum_def->name, ev->name));
+ }
+ case ftUnionValue: {
+ return ObjectFieldType(field, true) + "::NONE";
+ }
+ case ftString: {
+ // Required fields do not have defaults defined by the schema, but we
+ // need one for Rust's Default trait so we use empty string. The usual
+ // value of field.value.constant is `0`, which is non-sensical except
+ // maybe to c++ (nullptr == 0).
+ // TODO: Escape strings?
+ const std::string defval =
+ field.IsRequired() ? "\"\"" : "\"" + field.value.constant + "\"";
+ if (context == kObject) return defval + ".to_string()";
+ if (context == kAccessor) return "&" + defval;
+ FLATBUFFERS_ASSERT(false);
+ return "INVALID_CODE_GENERATION";
}
- // All pointer-ish types have a default value of None, because they are
- // wrapped in Option.
- default: {
- return "None";
+ case ftArrayOfStruct:
+ case ftArrayOfEnum:
+ case ftArrayOfBuiltin:
+ case ftVectorOfBool:
+ case ftVectorOfFloat:
+ case ftVectorOfInteger:
+ case ftVectorOfString:
+ case ftVectorOfStruct:
+ case ftVectorOfTable:
+ case ftVectorOfEnumKey:
+ case ftVectorOfUnionValue:
+ case ftStruct:
+ case ftTable: {
+ // We only support empty vectors which matches the defaults for
+ // &[T] and Vec<T> anyway.
+ //
+ // For required structs and tables fields, we defer to their object API
+ // defaults. This works so long as there's nothing recursive happening,
+ // but `table Infinity { i: Infinity (required); }` does compile.
+ return "Default::default()";
}
}
+ FLATBUFFERS_ASSERT(false);
+ return "INVALID_CODE_GENERATION";
}
// Create the return type for fields in the *BuilderArgs structs that are
@@ -739,30 +1092,38 @@
std::string TableBuilderArgsDefnType(const FieldDef &field,
const std::string &lifetime) {
const Type &type = field.value.type;
+ auto WrapOption = [&](std::string s) {
+ return IsOptionalToBuilder(field) ? "Option<" + s + ">" : s;
+ };
+ auto WrapVector = [&](std::string ty) {
+ return WrapOption("flatbuffers::WIPOffset<flatbuffers::Vector<" +
+ lifetime + ", " + ty + ">>");
+ };
+ auto WrapUOffsetsVector = [&](std::string ty) {
+ return WrapVector("flatbuffers::ForwardsUOffset<" + ty + ">");
+ };
switch (GetFullType(type)) {
case ftInteger:
case ftFloat:
case ftBool: {
- const auto typname = GetTypeBasic(type);
- return field.optional ? "Option<" + typname + ">" : typname;
+ return WrapOption(GetTypeBasic(type));
}
case ftStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "Option<&" + lifetime + " " + typname + ">";
+ return WrapOption("&" + lifetime + " " + typname);
}
case ftTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime +
- ">>>";
+ return WrapOption("flatbuffers::WIPOffset<" + typname + "<" + lifetime +
+ ">>");
}
case ftString: {
- return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
+ return WrapOption("flatbuffers::WIPOffset<&" + lifetime + " str>");
}
case ftEnumKey:
case ftUnionKey: {
- const auto typname = WrapInNameSpace(*type.enum_def);
- return field.optional ? "Option<" + typname + ">" : typname;
+ return WrapOption(WrapInNameSpace(*type.enum_def));
}
case ftUnionValue: {
return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
@@ -772,41 +1133,121 @@
case ftVectorOfBool:
case ftVectorOfFloat: {
const auto typname = GetTypeBasic(type.VectorType());
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", " + typname + ">>>";
+ return WrapVector(typname);
}
case ftVectorOfEnumKey: {
const auto typname = WrapInNameSpace(*type.enum_def);
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", " + typname + ">>>";
+ return WrapVector(typname);
}
case ftVectorOfStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", " + typname + ">>>";
+ return WrapVector(typname);
}
case ftVectorOfTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
- ">>>>>";
+ return WrapUOffsetsVector(typname + "<" + lifetime + ">");
}
case ftVectorOfString: {
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>>";
+ return WrapUOffsetsVector("&" + lifetime + " str");
}
case ftVectorOfUnionValue: {
- const auto typname =
- WrapInNameSpace(*type.enum_def) + "UnionTableOffset";
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", flatbuffers::ForwardsUOffset<"
- "flatbuffers::Table<" +
- lifetime + ">>>>";
+ return WrapUOffsetsVector("flatbuffers::Table<" + lifetime + ">");
+ }
+ case ftArrayOfEnum:
+ case ftArrayOfStruct:
+ case ftArrayOfBuiltin: {
+ FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
+ return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
}
}
return "INVALID_CODE_GENERATION"; // for return analysis
}
+ std::string ObjectFieldType(const FieldDef &field, bool in_a_table) {
+ const Type &type = field.value.type;
+ std::string ty;
+ switch (GetFullType(type)) {
+ case ftInteger:
+ case ftBool:
+ case ftFloat: {
+ ty = GetTypeBasic(type);
+ break;
+ }
+ case ftString: {
+ ty = "String";
+ break;
+ }
+ case ftStruct: {
+ ty = NamespacedNativeName(*type.struct_def);
+ break;
+ }
+ case ftTable: {
+ // Since Tables can contain themselves, Box is required to avoid
+ // infinite types.
+ ty = "Box<" + NamespacedNativeName(*type.struct_def) + ">";
+ break;
+ }
+ case ftUnionKey: {
+ // There is no native "UnionKey", natively, unions are rust enums with
+ // newtype-struct-variants.
+ return "INVALID_CODE_GENERATION";
+ }
+ case ftUnionValue: {
+ ty = NamespacedNativeName(*type.enum_def);
+ break;
+ }
+ case ftEnumKey: {
+ ty = WrapInNameSpace(*type.enum_def);
+ break;
+ }
+ // Vectors are in tables and are optional
+ case ftVectorOfEnumKey: {
+ ty = "Vec<" + WrapInNameSpace(*type.VectorType().enum_def) + ">";
+ break;
+ }
+ case ftVectorOfInteger:
+ case ftVectorOfBool:
+ case ftVectorOfFloat: {
+ ty = "Vec<" + GetTypeBasic(type.VectorType()) + ">";
+ break;
+ }
+ case ftVectorOfString: {
+ ty = "Vec<String>";
+ break;
+ }
+ case ftVectorOfTable:
+ case ftVectorOfStruct: {
+ ty = NamespacedNativeName(*type.VectorType().struct_def);
+ ty = "Vec<" + ty + ">";
+ break;
+ }
+ case ftVectorOfUnionValue: {
+ FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
+ return "INVALID_CODE_GENERATION"; // OH NO!
+ }
+ case ftArrayOfEnum: {
+ ty = "[" + WrapInNameSpace(*type.VectorType().enum_def) + "; " +
+ NumToString(type.fixed_length) + "]";
+ break;
+ }
+ case ftArrayOfStruct: {
+ ty = "[" + NamespacedNativeName(*type.VectorType().struct_def) + "; " +
+ NumToString(type.fixed_length) + "]";
+ break;
+ }
+ case ftArrayOfBuiltin: {
+ ty = "[" + GetTypeBasic(type.VectorType()) + "; " +
+ NumToString(type.fixed_length) + "]";
+ break;
+ }
+ }
+ if (in_a_table && !IsUnion(type) && field.IsOptional()) {
+ return "Option<" + ty + ">";
+ } else {
+ return ty;
+ }
+ }
+
std::string TableBuilderArgsAddFuncType(const FieldDef &field,
const std::string &lifetime) {
const Type &type = field.value.type;
@@ -844,7 +1285,8 @@
", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + lifetime +
">>>";
}
- case ftEnumKey: {
+ case ftEnumKey:
+ case ftUnionKey: {
const auto typname = WrapInNameSpace(*type.enum_def);
return typname;
}
@@ -864,13 +1306,24 @@
case ftString: {
return "flatbuffers::WIPOffset<&" + lifetime + " str>";
}
- case ftUnionKey: {
- const auto typname = WrapInNameSpace(*type.enum_def);
- return typname;
- }
case ftUnionValue: {
return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
}
+ case ftArrayOfBuiltin: {
+ const auto typname = GetTypeBasic(type.VectorType());
+ return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
+ NumToString(type.fixed_length) + ">";
+ }
+ case ftArrayOfEnum: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
+ NumToString(type.fixed_length) + ">";
+ }
+ case ftArrayOfStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
+ NumToString(type.fixed_length) + ">";
+ }
}
return "INVALID_CODE_GENERATION"; // for return analysis
@@ -884,16 +1337,16 @@
case ftBool:
case ftFloat: {
const auto typname = GetTypeBasic(field.value.type);
- return (field.optional ? "self.fbb_.push_slot_always::<"
- : "self.fbb_.push_slot::<") +
+ return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
+ : "self.fbb_.push_slot::<") +
typname + ">";
}
case ftEnumKey:
case ftUnionKey: {
const auto underlying_typname = GetTypeBasic(type);
- return (field.optional ?
- "self.fbb_.push_slot_always::<" :
- "self.fbb_.push_slot::<") + underlying_typname + ">";
+ return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
+ : "self.fbb_.push_slot::<") +
+ underlying_typname + ">";
}
case ftStruct: {
@@ -918,6 +1371,12 @@
case ftVectorOfUnionValue: {
return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
}
+ case ftArrayOfEnum:
+ case ftArrayOfStruct:
+ case ftArrayOfBuiltin: {
+ FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
+ return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
+ }
}
return "INVALID_CODE_GENERATION"; // for return analysis
}
@@ -925,73 +1384,64 @@
std::string GenTableAccessorFuncReturnType(const FieldDef &field,
const std::string &lifetime) {
const Type &type = field.value.type;
+ const auto WrapOption = [&](std::string s) {
+ return field.IsOptional() ? "Option<" + s + ">" : s;
+ };
switch (GetFullType(field.value.type)) {
case ftInteger:
case ftFloat:
case ftBool: {
- const auto typname = GetTypeBasic(type);
- return field.optional ? "Option<" + typname + ">" : typname;
+ return WrapOption(GetTypeBasic(type));
}
case ftStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired("&" + lifetime + " " + typname,
- field.required);
+ return WrapOption("&" + lifetime + " " + typname);
}
case ftTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">",
- field.required);
+ return WrapOption(typname + "<" + lifetime + ">");
}
case ftEnumKey:
case ftUnionKey: {
- const auto typname = WrapInNameSpace(*type.enum_def);
- return field.optional ? "Option<" + typname + ">" : typname;
+ return WrapOption(WrapInNameSpace(*type.enum_def));
}
case ftUnionValue: {
- return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">",
- field.required);
+ return WrapOption("flatbuffers::Table<" + lifetime + ">");
}
case ftString: {
- return WrapInOptionIfNotRequired("&" + lifetime + " str",
- field.required);
+ return WrapOption("&" + lifetime + " str");
}
case ftVectorOfInteger:
case ftVectorOfBool:
case ftVectorOfFloat: {
const auto typname = GetTypeBasic(type.VectorType());
- if (IsOneByte(type.VectorType().base_type)) {
- return WrapInOptionIfNotRequired(
- "&" + lifetime + " [" + typname + "]", field.required);
- }
- return WrapInOptionIfNotRequired(
- "flatbuffers::Vector<" + lifetime + ", " + typname + ">",
- field.required);
+ const auto vector_type =
+ IsOneByte(type.VectorType().base_type)
+ ? "&" + lifetime + " [" + typname + "]"
+ : "flatbuffers::Vector<" + lifetime + ", " + typname + ">";
+ return WrapOption(vector_type);
}
case ftVectorOfEnumKey: {
const auto typname = WrapInNameSpace(*type.enum_def);
- return WrapInOptionIfNotRequired(
- "flatbuffers::Vector<" + lifetime + ", " + typname + ">",
- field.required);
+ return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname +
+ ">");
}
case ftVectorOfStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]",
- field.required);
+ return WrapOption("&" + lifetime + " [" + typname + "]");
}
case ftVectorOfTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime +
- ", flatbuffers::ForwardsUOffset<" +
- typname + "<" + lifetime + ">>>",
- field.required);
+ return WrapOption("flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<" + typname + "<" +
+ lifetime + ">>>");
}
case ftVectorOfString: {
- return WrapInOptionIfNotRequired(
- "flatbuffers::Vector<" + lifetime +
- ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>",
- field.required);
+ return WrapOption("flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<&" + lifetime +
+ " str>>");
}
case ftVectorOfUnionValue: {
FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
@@ -999,177 +1449,166 @@
// Into trait to convert tables to typesafe union values.
return "INVALID_CODE_GENERATION"; // for return analysis
}
+ case ftArrayOfEnum:
+ case ftArrayOfStruct:
+ case ftArrayOfBuiltin: {
+ FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
+ return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
+ }
}
return "INVALID_CODE_GENERATION"; // for return analysis
}
- std::string GenTableAccessorFuncBody(const FieldDef &field,
- const std::string &lifetime,
- const std::string &offset_prefix) {
- const std::string offset_name =
- offset_prefix + "::" + GetFieldOffsetName(field);
- const Type &type = field.value.type;
+ std::string FollowType(const Type &type, const std::string &lifetime) {
+ // IsVector... This can be made iterative?
- switch (GetFullType(field.value.type)) {
+ const auto WrapForwardsUOffset = [](std::string ty) -> std::string {
+ return "flatbuffers::ForwardsUOffset<" + ty + ">";
+ };
+ const auto WrapVector = [&](std::string ty) -> std::string {
+ return "flatbuffers::Vector<" + lifetime + ", " + ty + ">";
+ };
+ const auto WrapArray = [&](std::string ty, uint16_t length) -> std::string {
+ return "flatbuffers::Array<" + lifetime + ", " + ty + ", " +
+ NumToString(length) + ">";
+ };
+ switch (GetFullType(type)) {
case ftInteger:
case ftFloat:
case ftBool: {
- const auto typname = GetTypeBasic(type);
- if (field.optional) {
- return "self._tab.get::<" + typname + ">(" + offset_name + ", None)";
- } else {
- const auto default_value = GetDefaultScalarValue(field);
- return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" +
- default_value + ")).unwrap()";
- }
+ return GetTypeBasic(type);
}
case ftStruct: {
- const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired(
- "self._tab.get::<" + typname + ">(" + offset_name + ", None)",
- field.required);
- }
- case ftTable: {
- const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<" + typname + "<" +
- lifetime + ">>>(" + offset_name + ", None)",
- field.required);
- }
- case ftUnionValue: {
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Table<" +
- lifetime + ">>>(" + offset_name + ", None)",
- field.required);
+ return WrapInNameSpace(*type.struct_def);
}
case ftUnionKey:
case ftEnumKey: {
- const std::string typname = WrapInNameSpace(*type.enum_def);
- const std::string default_value = GetDefaultScalarValue(field);
- if (field.optional) {
- return "self._tab.get::<" + typname + ">(" + offset_name + ", None)";
- } else {
- return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" +
- default_value + ")).unwrap()";
- }
+ return WrapInNameSpace(*type.enum_def);
+ }
+ case ftTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapForwardsUOffset(typname);
+ }
+ case ftUnionValue: {
+ return WrapForwardsUOffset("flatbuffers::Table<" + lifetime + ">");
}
case ftString: {
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" +
- offset_name + ", None)",
- field.required);
+ return WrapForwardsUOffset("&str");
}
-
case ftVectorOfInteger:
case ftVectorOfBool:
case ftVectorOfFloat: {
const auto typname = GetTypeBasic(type.VectorType());
- std::string s =
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<" +
- lifetime + ", " + typname + ">>>(" + offset_name + ", None)";
- // single-byte values are safe to slice
- if (IsOneByte(type.VectorType().base_type)) {
- s += ".map(|v| v.safe_slice())";
- }
- return AddUnwrapIfRequired(s, field.required);
+ return WrapForwardsUOffset(WrapVector(typname));
}
case ftVectorOfEnumKey: {
- const auto typname = WrapInNameSpace(*type.enum_def);
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<" +
- lifetime + ", " + typname + ">>>(" + offset_name + ", None)",
- field.required);
+ const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
+ return WrapForwardsUOffset(WrapVector(typname));
}
case ftVectorOfStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<" +
- typname + ">>>(" + offset_name +
- ", None).map(|v| v.safe_slice() )",
- field.required);
+ return WrapForwardsUOffset(WrapVector(typname));
}
case ftVectorOfTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" +
- typname + "<" + lifetime + ">>>>>(" + offset_name + ", None)",
- field.required);
+ return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(typname)));
}
case ftVectorOfString: {
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" +
- lifetime + " str>>>>(" + offset_name + ", None)",
- field.required);
+ return WrapForwardsUOffset(
+ WrapVector(WrapForwardsUOffset("&" + lifetime + " str")));
}
case ftVectorOfUnionValue: {
FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
return "INVALID_CODE_GENERATION"; // for return analysis
}
+ case ftArrayOfEnum: {
+ const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
+ return WrapArray(typname, type.fixed_length);
+ }
+ case ftArrayOfStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapArray(typname, type.fixed_length);
+ }
+ case ftArrayOfBuiltin: {
+ const auto typname = GetTypeBasic(type.VectorType());
+ return WrapArray(typname, type.fixed_length);
+ }
}
return "INVALID_CODE_GENERATION"; // for return analysis
}
- bool TableFieldReturnsOption(const FieldDef &field) {
- if (field.optional) return true;
- switch (GetFullType(field.value.type)) {
- case ftInteger:
- case ftFloat:
- case ftBool:
- case ftEnumKey:
- case ftUnionKey: return false;
- default: return true;
- }
+ std::string GenTableAccessorFuncBody(const FieldDef &field,
+ const std::string &lifetime) {
+ const std::string vt_offset = GetFieldOffsetName(field);
+ const std::string typname = FollowType(field.value.type, lifetime);
+ // Default-y fields (scalars so far) are neither optional nor required.
+ const std::string default_value =
+ !(field.IsOptional() || field.IsRequired())
+ ? "Some(" + GetDefaultValue(field, kAccessor) + ")"
+ : "None";
+ const std::string unwrap = field.IsOptional() ? "" : ".unwrap()";
+
+ const auto t = GetFullType(field.value.type);
+
+ // TODO(caspern): Shouldn't 1byte VectorOfEnumKey be slice too?
+ const std::string safe_slice =
+ (t == ftVectorOfStruct ||
+ ((t == ftVectorOfBool || t == ftVectorOfFloat ||
+ t == ftVectorOfInteger) &&
+ IsOneByte(field.value.type.VectorType().base_type)))
+ ? ".map(|v| v.safe_slice())"
+ : "";
+
+ return "self._tab.get::<" + typname + ">({{STRUCT_TY}}::" + vt_offset +
+ ", " + default_value + ")" + safe_slice + unwrap;
}
// Generates a fully-qualified name getter for use with --gen-name-strings
void GenFullyQualifiedNameGetter(const StructDef &struct_def,
const std::string &name) {
- code_ += " pub const fn get_fully_qualified_name() -> &'static str {";
- code_ += " \"" +
- struct_def.defined_namespace->GetFullyQualifiedName(name) + "\"";
- code_ += " }";
+ const std::string fully_qualified_name =
+ struct_def.defined_namespace->GetFullyQualifiedName(name);
+ code_ += " pub const fn get_fully_qualified_name() -> &'static str {";
+ code_ += " \"" + fully_qualified_name + "\"";
+ code_ += " }";
code_ += "";
}
void ForAllUnionVariantsBesidesNone(
- const EnumDef &def,
- std::function<void(const EnumVal &ev)> cb
- ) {
+ const EnumDef &def, std::function<void(const EnumVal &ev)> cb) {
FLATBUFFERS_ASSERT(def.is_union);
for (auto it = def.Vals().begin(); it != def.Vals().end(); ++it) {
- const EnumVal & ev = **it;
+ const EnumVal &ev = **it;
// TODO(cneo): Can variants be deprecated, should we skip them?
if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
+ code_.SetValue("U_ELEMENT_ENUM_TYPE",
+ WrapInNameSpace(def.defined_namespace,
+ namer_.EnumVariant(def.name, ev.name)));
code_.SetValue(
- "U_ELEMENT_ENUM_TYPE",
- WrapInNameSpace(def.defined_namespace, GetEnumValue(def, ev)));
- code_.SetValue("U_ELEMENT_TABLE_TYPE",
+ "U_ELEMENT_TABLE_TYPE",
WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
ev.union_type.struct_def->name));
- code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
+ code_.SetValue("U_ELEMENT_NAME", namer_.Function(ev.name));
cb(ev);
}
}
- void ForAllTableFields(
- const StructDef &struct_def,
- std::function<void(const FieldDef&)> cb, bool reversed=false) {
+ void ForAllTableFields(const StructDef &struct_def,
+ std::function<void(const FieldDef &)> cb,
+ bool reversed = false) {
// TODO(cneo): Remove `reversed` overload. It's only here to minimize the
// diff when refactoring to the `ForAllX` helper functions.
- auto go = [&](const FieldDef& field) {
+ auto go = [&](const FieldDef &field) {
if (field.deprecated) return;
code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
- code_.SetValue("FIELD_NAME", Name(field));
- code_.SetValue("DEFAULT_VALUE", GetDefaultScalarValue(field));
+ code_.SetValue("FIELD", namer_.Field(field.name));
+ code_.SetValue("BLDR_DEF_VAL", GetDefaultValue(field, kBuilder));
+ code_.SetValue("DISCRIMINANT", namer_.Method(field.name) + "_type");
+ code_.IncrementIdentLevel();
cb(field);
+ code_.DecrementIdentLevel();
};
const auto &fields = struct_def.fields.vec;
if (reversed) {
@@ -1181,84 +1620,194 @@
// Generate an accessor struct, builder struct, and create function for a
// table.
void GenTable(const StructDef &struct_def) {
- code_.SetValue("STRUCT_NAME", Name(struct_def));
- code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
- code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
+ code_.SetValue("STRUCT_TY", namer_.Type(struct_def.name));
+ code_.SetValue("STRUCT_FN", namer_.Function(struct_def.name));
// Generate an offset type, the base type, the Follow impl, and the
// init_from_table impl.
- code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
+ code_ += "pub enum {{STRUCT_TY}}Offset {}";
code_ += "#[derive(Copy, Clone, PartialEq)]";
code_ += "";
GenComment(struct_def.doc_comment);
- code_ += "pub struct {{STRUCT_NAME}}<'a> {";
+ code_ += "pub struct {{STRUCT_TY}}<'a> {";
code_ += " pub _tab: flatbuffers::Table<'a>,";
code_ += "}";
code_ += "";
- code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
- code_ += " type Inner = {{STRUCT_NAME}}<'a>;";
- code_ += " #[inline]";
- code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
- code_ += " Self { _tab: flatbuffers::Table { buf, loc } }";
- code_ += " }";
+ code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_TY}}<'a> {";
+ code_ += " type Inner = {{STRUCT_TY}}<'a>;";
+ code_ += " #[inline]";
+ code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+ code_ += " Self { _tab: flatbuffers::Table { buf, loc } }";
+ code_ += " }";
code_ += "}";
code_ += "";
- code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
+ code_ += "impl<'a> {{STRUCT_TY}}<'a> {";
+
+ // Generate field id constants.
+ ForAllTableFields(struct_def, [&](const FieldDef &unused) {
+ (void)unused;
+ code_ +=
+ "pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
+ "{{OFFSET_VALUE}};";
+ });
+ code_ += "";
if (parser_.opts.generate_name_strings) {
GenFullyQualifiedNameGetter(struct_def, struct_def.name);
}
- code_ += " #[inline]";
+ code_ += " #[inline]";
code_ +=
- " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
+ " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
"Self {";
- code_ += " {{STRUCT_NAME}} {";
- code_ += " _tab: table,";
- code_ += " }";
- code_ += " }";
+ code_ += " {{STRUCT_TY}} { _tab: table }";
+ code_ += " }";
// Generate a convenient create* function that uses the above builder
// to create a table in one function call.
code_.SetValue("MAYBE_US", struct_def.fields.vec.size() == 0 ? "_" : "");
code_.SetValue("MAYBE_LT",
TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
- code_ += " #[allow(unused_mut)]";
- code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
- code_ +=
- " _fbb: "
- "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
- code_ +=
- " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
- " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
+ code_ += " #[allow(unused_mut)]";
+ code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
+ code_ += " _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
+ code_ += " {{MAYBE_US}}args: &'args {{STRUCT_TY}}Args{{MAYBE_LT}}";
+ code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_TY}}<'bldr>> {";
- code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
+ code_ += " let mut builder = {{STRUCT_TY}}Builder::new(_fbb);";
for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
size; size /= 2) {
- ForAllTableFields(struct_def, [&](const FieldDef &field) {
- if (struct_def.sortbysize && size != SizeOf(field.value.type.base_type))
- return;
- if (TableFieldReturnsOption(field)) {
- code_ +=
- " if let Some(x) = args.{{FIELD_NAME}} "
- "{ builder.add_{{FIELD_NAME}}(x); }";
- } else {
- code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
- }
- }, /*reverse=*/true);
+ ForAllTableFields(
+ struct_def,
+ [&](const FieldDef &field) {
+ if (struct_def.sortbysize &&
+ size != SizeOf(field.value.type.base_type))
+ return;
+ if (IsOptionalToBuilder(field)) {
+ code_ +=
+ " if let Some(x) = args.{{FIELD}} "
+ "{ builder.add_{{FIELD}}(x); }";
+ } else {
+ code_ += " builder.add_{{FIELD}}(args.{{FIELD}});";
+ }
+ },
+ /*reverse=*/true);
}
- code_ += " builder.finish()";
- code_ += " }";
+ code_ += " builder.finish()";
+ code_ += " }";
code_ += "";
+ // Generate Object API Packer function.
+ if (parser_.opts.generate_object_based_api) {
+ // TODO(cneo): Replace more for loops with ForAllX stuff.
+ // TODO(cneo): Manage indentation with IncrementIdentLevel?
+ code_.SetValue("STRUCT_OTY", namer_.ObjectType(struct_def.name));
+ code_ += " pub fn unpack(&self) -> {{STRUCT_OTY}} {";
+ ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
+ const Type &type = field.value.type;
+ switch (GetFullType(type)) {
+ case ftInteger:
+ case ftBool:
+ case ftFloat:
+ case ftEnumKey: {
+ code_ += " let {{FIELD}} = self.{{FIELD}}();";
+ return;
+ }
+ case ftUnionKey: return;
+ case ftUnionValue: {
+ const auto &enum_def = *type.enum_def;
+ code_.SetValue("ENUM_TY", WrapInNameSpace(enum_def));
+ code_.SetValue("NATIVE_ENUM_NAME", NamespacedNativeName(enum_def));
+ code_ += " let {{FIELD}} = match self.{{FIELD}}_type() {";
+ code_ += " {{ENUM_TY}}::NONE => {{NATIVE_ENUM_NAME}}::NONE,";
+ ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
+ code_ +=
+ " {{ENUM_TY}}::{{VARIANT_NAME}} => "
+ "{{NATIVE_ENUM_NAME}}::{{NATIVE_VARIANT}}(Box::new(";
+ code_ += " self.{{FIELD}}_as_{{U_ELEMENT_NAME}}()";
+ code_ +=
+ " .expect(\"Invalid union table, "
+ "expected `{{ENUM_TY}}::{{VARIANT_NAME}}`.\")";
+ code_ += " .unpack()";
+ code_ += " )),";
+ });
+ // Maybe we shouldn't throw away unknown discriminants?
+ code_ += " _ => {{NATIVE_ENUM_NAME}}::NONE,";
+ code_ += " };";
+ return;
+ }
+ // The rest of the types need special handling based on if the field
+ // is optional or not.
+ case ftString: {
+ code_.SetValue("EXPR", "x.to_string()");
+ break;
+ }
+ case ftStruct: {
+ code_.SetValue("EXPR", "x.unpack()");
+ break;
+ }
+ case ftTable: {
+ code_.SetValue("EXPR", "Box::new(x.unpack())");
+ break;
+ }
+ case ftVectorOfInteger:
+ case ftVectorOfBool: {
+ if (IsOneByte(type.VectorType().base_type)) {
+ // 1 byte stuff is viewed w/ slice instead of flatbuffer::Vector
+ // and thus needs to be cloned out of the slice.
+ code_.SetValue("EXPR", "x.to_vec()");
+ break;
+ }
+ code_.SetValue("EXPR", "x.into_iter().collect()");
+ break;
+ }
+ case ftVectorOfFloat:
+ case ftVectorOfEnumKey: {
+ code_.SetValue("EXPR", "x.into_iter().collect()");
+ break;
+ }
+ case ftVectorOfString: {
+ code_.SetValue("EXPR", "x.iter().map(|s| s.to_string()).collect()");
+ break;
+ }
+ case ftVectorOfStruct:
+ case ftVectorOfTable: {
+ code_.SetValue("EXPR", "x.iter().map(|t| t.unpack()).collect()");
+ break;
+ }
+ case ftVectorOfUnionValue: {
+ FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
+ return;
+ }
+ case ftArrayOfEnum:
+ case ftArrayOfStruct:
+ case ftArrayOfBuiltin: {
+ FLATBUFFERS_ASSERT(false &&
+ "arrays are not supported within tables");
+ return;
+ }
+ }
+ if (field.IsOptional()) {
+ code_ += " let {{FIELD}} = self.{{FIELD}}().map(|x| {";
+ code_ += " {{EXPR}}";
+ code_ += " });";
+ } else {
+ code_ += " let {{FIELD}} = {";
+ code_ += " let x = self.{{FIELD}}();";
+ code_ += " {{EXPR}}";
+ code_ += " };";
+ }
+ });
+ code_ += " {{STRUCT_OTY}} {";
+ ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
+ code_ += " {{FIELD}},";
+ });
+ code_ += " }";
+ code_ += " }";
+ }
- // Generate field id constants.
- ForAllTableFields(struct_def, [&](const FieldDef &unused){
- (void) unused;
- code_ += " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
- "{{OFFSET_VALUE}};";
- });
if (struct_def.fields.vec.size() > 0) code_ += "";
// Generate the accessors. Each has one of two forms:
@@ -1272,18 +1821,15 @@
// pub fn name(&'a self) -> user_facing_type {
// self._tab.get::<internal_type>(offset, defaultval).unwrap()
// }
- const auto offset_prefix = Name(struct_def);
ForAllTableFields(struct_def, [&](const FieldDef &field) {
code_.SetValue("RETURN_TYPE",
GenTableAccessorFuncReturnType(field, "'a"));
- code_.SetValue("FUNC_BODY",
- GenTableAccessorFuncBody(field, "'a", offset_prefix));
- this->GenComment(field.doc_comment, " ");
- code_ += " #[inline]";
- code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
- code_ += " {{FUNC_BODY}}";
- code_ += " }";
+ this->GenComment(field.doc_comment);
+ code_ += "#[inline]";
+ code_ += "pub fn {{FIELD}}(&self) -> {{RETURN_TYPE}} {";
+ code_ += " " + GenTableAccessorFuncBody(field, "'a");
+ code_ += "}";
// Generate a comparison function for this field if it is a key.
if (field.key) { GenKeyFieldMethods(field); }
@@ -1301,99 +1847,214 @@
FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
code_.SetValue("NESTED", WrapInNameSpace(*nested_root));
- code_ +=
- " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> \\";
- if (field.required) {
+ code_ += "pub fn {{FIELD}}_nested_flatbuffer(&'a self) -> \\";
+ if (field.IsRequired()) {
code_ += "{{NESTED}}<'a> {";
- code_ += " let data = self.{{FIELD_NAME}}();";
- code_ += " use flatbuffers::Follow;";
- code_ += " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
- "::follow(data, 0)";
+ code_ += " let data = self.{{FIELD}}();";
+ code_ += " use flatbuffers::Follow;";
+ code_ +=
+ " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
+ "::follow(data, 0)";
} else {
code_ += "Option<{{NESTED}}<'a>> {";
- code_ += " self.{{FIELD_NAME}}().map(|data| {";
- code_ += " use flatbuffers::Follow;";
- code_ += " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
- "::follow(data, 0)";
- code_ += " })";
+ code_ += " self.{{FIELD}}().map(|data| {";
+ code_ += " use flatbuffers::Follow;";
+ code_ +=
+ " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
+ "::follow(data, 0)";
+ code_ += " })";
}
- code_ += " }";
+ code_ += "}";
}
});
// Explicit specializations for union accessors
ForAllTableFields(struct_def, [&](const FieldDef &field) {
if (field.value.type.base_type != BASE_TYPE_UNION) return;
- code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
ForAllUnionVariantsBesidesNone(
- *field.value.type.enum_def, [&](const EnumVal &unused){
- (void) unused;
- code_ += " #[inline]";
- code_ += " #[allow(non_snake_case)]";
- code_ +=
- " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
- "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
- // If the user defined schemas name a field that clashes with a
- // language reserved word, flatc will try to escape the field name by
- // appending an underscore. This works well for most cases, except
- // one. When generating union accessors (and referring to them
- // internally within the code generated here), an extra underscore
- // will be appended to the name, causing build failures.
- //
- // This only happens when unions have members that overlap with
- // language reserved words.
- //
- // To avoid this problem the type field name is used unescaped here:
- code_ +=
- " if self.{{FIELD_TYPE_FIELD_NAME}}_type() == "
- "{{U_ELEMENT_ENUM_TYPE}} {";
+ *field.value.type.enum_def, [&](const EnumVal &unused) {
+ (void)unused;
+ code_ += "#[inline]";
+ code_ += "#[allow(non_snake_case)]";
+ code_ +=
+ "pub fn {{FIELD}}_as_{{U_ELEMENT_NAME}}(&self) -> "
+ "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
+ // If the user defined schemas name a field that clashes with a
+ // language reserved word, flatc will try to escape the field name
+ // by appending an underscore. This works well for most cases,
+ // except one. When generating union accessors (and referring to
+ // them internally within the code generated here), an extra
+ // underscore will be appended to the name, causing build failures.
+ //
+ // This only happens when unions have members that overlap with
+ // language reserved words.
+ //
+ // To avoid this problem the type field name is used unescaped here:
+ code_ +=
+ " if self.{{DISCRIMINANT}}() == {{U_ELEMENT_ENUM_TYPE}} {";
- // The following logic is not tested in the integration test,
- // as of April 10, 2020
- if (field.required) {
- code_ += " let u = self.{{FIELD_NAME}}();";
- code_ += " Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
- } else {
- code_ +=
- " self.{{FIELD_NAME}}().map("
- "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)";
- }
- code_ += " } else {";
- code_ += " None";
- code_ += " }";
- code_ += " }";
- code_ += "";
-
- });
+ // The following logic is not tested in the integration test,
+ // as of April 10, 2020
+ if (field.IsRequired()) {
+ code_ += " let u = self.{{FIELD}}();";
+ code_ += " Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
+ } else {
+ code_ +=
+ " self.{{FIELD}}().map("
+ "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)";
+ }
+ code_ += " } else {";
+ code_ += " None";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ });
});
code_ += "}"; // End of table impl.
code_ += "";
+ // Generate Verifier;
+ code_ += "impl flatbuffers::Verifiable for {{STRUCT_TY}}<'_> {";
+ code_ += " #[inline]";
+ code_ += " fn run_verifier(";
+ code_ += " v: &mut flatbuffers::Verifier, pos: usize";
+ code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
+ code_ += " use self::flatbuffers::Verifiable;";
+ code_ += " v.visit_table(pos)?\\";
+ // Escape newline and insert it onthe next line so we can end the builder
+ // with a nice semicolon.
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ if (GetFullType(field.value.type) == ftUnionKey) return;
+
+ code_.SetValue("IS_REQ", field.IsRequired() ? "true" : "false");
+ if (GetFullType(field.value.type) != ftUnionValue) {
+ // All types besides unions.
+ code_.SetValue("TY", FollowType(field.value.type, "'_"));
+ code_ +=
+ "\n .visit_field::<{{TY}}>(\"{{FIELD}}\", "
+ "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\";
+ return;
+ }
+ // Unions.
+ const EnumDef &union_def = *field.value.type.enum_def;
+ code_.SetValue("UNION_TYPE", WrapInNameSpace(union_def));
+ code_.SetValue("UNION_TYPE_OFFSET_NAME",
+ GetFieldOffsetName(field) + "_TYPE");
+ code_ +=
+ "\n .visit_union::<{{UNION_TYPE}}, _>("
+ "\"{{FIELD}}_type\", Self::{{UNION_TYPE_OFFSET_NAME}}, "
+ "\"{{FIELD}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, "
+ "|key, v, pos| {";
+ code_ += " match key {";
+ ForAllUnionVariantsBesidesNone(union_def, [&](const EnumVal &unused) {
+ (void)unused;
+ code_ +=
+ " {{U_ELEMENT_ENUM_TYPE}} => v.verify_union_variant::"
+ "<flatbuffers::ForwardsUOffset<{{U_ELEMENT_TABLE_TYPE}}>>("
+ "\"{{U_ELEMENT_ENUM_TYPE}}\", pos),";
+ });
+ code_ += " _ => Ok(()),";
+ code_ += " }";
+ code_ += " })?\\";
+ });
+ code_ += "\n .finish();";
+ code_ += " Ok(())";
+ code_ += " }";
+ code_ += "}";
+
// Generate an args struct:
code_.SetValue("MAYBE_LT",
TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
- code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
+ code_ += "pub struct {{STRUCT_TY}}Args{{MAYBE_LT}} {";
ForAllTableFields(struct_def, [&](const FieldDef &field) {
code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
- code_ += " pub {{FIELD_NAME}}: {{PARAM_TYPE}},";
+ code_ += " pub {{FIELD}}: {{PARAM_TYPE}},";
});
code_ += "}";
// Generate an impl of Default for the *Args type:
- code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
- code_ += " #[inline]";
- code_ += " fn default() -> Self {";
- code_ += " {{STRUCT_NAME}}Args {";
+ code_ += "impl<'a> Default for {{STRUCT_TY}}Args{{MAYBE_LT}} {";
+ code_ += " #[inline]";
+ code_ += " fn default() -> Self {";
+ code_ += " {{STRUCT_TY}}Args {";
ForAllTableFields(struct_def, [&](const FieldDef &field) {
- code_ += " {{FIELD_NAME}}: {{DEFAULT_VALUE}},\\";
- code_ += field.required ? " // required field" : "";
+ code_ += " {{FIELD}}: {{BLDR_DEF_VAL}},\\";
+ code_ += field.IsRequired() ? " // required field" : "";
});
- code_ += " }";
code_ += " }";
+ code_ += " }";
code_ += "}";
+ code_ += "";
+
+ // Implement serde::Serialize
+ if (parser_.opts.rust_serialize) {
+ const auto numFields = struct_def.fields.vec.size();
+ code_.SetValue("NUM_FIELDS", NumToString(numFields));
+ code_ += "impl Serialize for {{STRUCT_TY}}<'_> {";
+ code_ +=
+ " fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
+ code_ += " where";
+ code_ += " S: Serializer,";
+ code_ += " {";
+ if (numFields == 0) {
+ code_ +=
+ " let s = serializer.serialize_struct(\"{{STRUCT_TY}}\", 0)?;";
+ } else {
+ code_ +=
+ " let mut s = serializer.serialize_struct(\"{{STRUCT_TY}}\", "
+ "{{NUM_FIELDS}})?;";
+ }
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ const Type &type = field.value.type;
+ if (IsUnion(type)) {
+ if (type.base_type == BASE_TYPE_UNION) {
+ const auto &enum_def = *type.enum_def;
+ code_.SetValue("ENUM_TY", WrapInNameSpace(enum_def));
+ code_.SetValue("FIELD", namer_.Field(field.name));
+
+ code_ += " match self.{{FIELD}}_type() {";
+ code_ += " {{ENUM_TY}}::NONE => (),";
+ ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
+ code_.SetValue("FIELD", namer_.Field(field.name));
+ code_ += " {{ENUM_TY}}::{{VARIANT_NAME}} => {";
+ code_ +=
+ " let f = "
+ "self.{{FIELD}}_as_{{U_ELEMENT_NAME}}()";
+ code_ +=
+ " .expect(\"Invalid union table, expected "
+ "`{{ENUM_TY}}::{{VARIANT_NAME}}`.\");";
+ code_ += " s.serialize_field(\"{{FIELD}}\", &f)?;";
+ code_ += " }";
+ });
+ code_ += " _ => unimplemented!(),";
+ code_ += " }";
+ } else {
+ code_ +=
+ " s.serialize_field(\"{{FIELD}}\", "
+ "&self.{{FIELD}}())?;";
+ }
+ } else {
+ if (field.IsOptional()) {
+ code_ += " if let Some(f) = self.{{FIELD}}() {";
+ code_ += " s.serialize_field(\"{{FIELD}}\", &f)?;";
+ code_ += " } else {";
+ code_ += " s.skip_field(\"{{FIELD}}\")?;";
+ code_ += " }";
+ } else {
+ code_ +=
+ " s.serialize_field(\"{{FIELD}}\", "
+ "&self.{{FIELD}}())?;";
+ }
+ }
+ });
+ code_ += " s.end()";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ }
// Generate a builder struct:
- code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
+ code_ += "pub struct {{STRUCT_TY}}Builder<'a: 'b, 'b> {";
code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
code_ +=
" start_: flatbuffers::WIPOffset<"
@@ -1401,7 +2062,7 @@
code_ += "}";
// Generate builder functions:
- code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
+ code_ += "impl<'a: 'b, 'b> {{STRUCT_TY}}Builder<'a, 'b> {";
ForAllTableFields(struct_def, [&](const FieldDef &field) {
const bool is_scalar = IsScalar(field.value.type.base_type);
std::string offset = GetFieldOffsetName(field);
@@ -1416,30 +2077,32 @@
// fn add_x(x_: type) {
// fbb_.push_slot_always::<type>(offset, x_);
// }
- code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
+ code_.SetValue("FIELD_OFFSET",
+ namer_.Type(struct_def.name) + "::" + offset);
code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
- code_ += " #[inline]";
- code_ += " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
- "{{FIELD_TYPE}}) {";
- if (is_scalar && !field.optional) {
+ code_ += "#[inline]";
+ code_ +=
+ "pub fn add_{{FIELD}}(&mut self, {{FIELD}}: "
+ "{{FIELD_TYPE}}) {";
+ if (is_scalar && !field.IsOptional()) {
code_ +=
- " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
- "{{DEFAULT_VALUE}});";
+ " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD}}, "
+ "{{BLDR_DEF_VAL}});";
} else {
- code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
+ code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD}});";
}
- code_ += " }";
+ code_ += "}";
});
// Struct initializer (all fields required);
code_ += " #[inline]";
code_ +=
" pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
- "{{STRUCT_NAME}}Builder<'a, 'b> {";
+ "{{STRUCT_TY}}Builder<'a, 'b> {";
code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
code_ += " let start = _fbb.start_table();";
- code_ += " {{STRUCT_NAME}}Builder {";
+ code_ += " {{STRUCT_TY}}Builder {";
code_ += " fbb_: _fbb,";
code_ += " start_: start,";
code_ += " }";
@@ -1449,53 +2112,56 @@
code_ += " #[inline]";
code_ +=
" pub fn finish(self) -> "
- "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
+ "flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>> {";
code_ += " let o = self.fbb_.end_table(self.start_);";
ForAllTableFields(struct_def, [&](const FieldDef &field) {
- if (!field.required) return;
+ if (!field.IsRequired()) return;
code_ +=
- " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
- "\"{{FIELD_NAME}}\");";
+ " self.fbb_.required(o, {{STRUCT_TY}}::{{OFFSET_NAME}},"
+ "\"{{FIELD}}\");";
});
code_ += " flatbuffers::WIPOffset::new(o.value())";
code_ += " }";
code_ += "}";
code_ += "";
- code_ += "impl std::fmt::Debug for {{STRUCT_NAME}}<'_> {";
- code_ += " fn fmt(&self, f: &mut std::fmt::Formatter<'_>"
- ") -> std::fmt::Result {";
- code_ += " let mut ds = f.debug_struct(\"{{STRUCT_NAME}}\");";
+ code_ += "impl std::fmt::Debug for {{STRUCT_TY}}<'_> {";
+ code_ +=
+ " fn fmt(&self, f: &mut std::fmt::Formatter<'_>"
+ ") -> std::fmt::Result {";
+ code_ += " let mut ds = f.debug_struct(\"{{STRUCT_TY}}\");";
ForAllTableFields(struct_def, [&](const FieldDef &field) {
if (GetFullType(field.value.type) == ftUnionValue) {
// Generate a match statement to handle unions properly.
code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
- code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
- code_.SetValue("UNION_ERR", "&\"InvalidFlatbuffer: Union discriminant"
- " does not match value.\"");
+ code_.SetValue("UNION_ERR",
+ "&\"InvalidFlatbuffer: Union discriminant"
+ " does not match value.\"");
- code_ += " match self.{{FIELD_NAME}}_type() {";
- ForAllUnionVariantsBesidesNone(*field.value.type.enum_def,
- [&](const EnumVal &unused){
- (void) unused;
- code_ += " {{U_ELEMENT_ENUM_TYPE}} => {";
- code_ += " if let Some(x) = self.{{FIELD_TYPE_FIELD_NAME}}_as_"
- "{{U_ELEMENT_NAME}}() {";
- code_ += " ds.field(\"{{FIELD_NAME}}\", &x)";
- code_ += " } else {";
- code_ += " ds.field(\"{{FIELD_NAME}}\", {{UNION_ERR}})";
- code_ += " }";
- code_ += " },";
- });
- code_ += " _ => { ";
- code_ += " let x: Option<()> = None;";
- code_ += " ds.field(\"{{FIELD_NAME}}\", &x)";
- code_ += " },";
- code_ += " };";
+ code_ += " match self.{{DISCRIMINANT}}() {";
+ ForAllUnionVariantsBesidesNone(
+ *field.value.type.enum_def, [&](const EnumVal &unused) {
+ (void)unused;
+ code_ += " {{U_ELEMENT_ENUM_TYPE}} => {";
+ code_ +=
+ " if let Some(x) = "
+ "self.{{FIELD}}_as_"
+ "{{U_ELEMENT_NAME}}() {";
+ code_ += " ds.field(\"{{FIELD}}\", &x)";
+ code_ += " } else {";
+ code_ += " ds.field(\"{{FIELD}}\", {{UNION_ERR}})";
+ code_ += " }";
+ code_ += " },";
+ });
+ code_ += " _ => {";
+ code_ += " let x: Option<()> = None;";
+ code_ += " ds.field(\"{{FIELD}}\", &x)";
+ code_ += " },";
+ code_ += " };";
} else {
// Most fields.
- code_ += " ds.field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}());";
+ code_ += " ds.field(\"{{FIELD}}\", &self.{{FIELD}}());";
}
});
code_ += " ds.finish()";
@@ -1503,97 +2169,355 @@
code_ += "}";
}
+ void GenTableObject(const StructDef &table) {
+ code_.SetValue("STRUCT_OTY", namer_.ObjectType(table.name));
+ code_.SetValue("STRUCT_TY", namer_.Type(table.name));
+
+ // Generate the native object.
+ code_ += "#[non_exhaustive]";
+ code_ += "#[derive(Debug, Clone, PartialEq)]";
+ code_ += "pub 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.
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
+ code_ += "pub {{FIELD}}: {{FIELD_OTY}},";
+ });
+ code_ += "}";
+
+ code_ += "impl Default for {{STRUCT_OTY}} {";
+ code_ += " fn default() -> Self {";
+ code_ += " Self {";
+ ForAllObjectTableFields(table, [&](const FieldDef &field) {
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
+ std::string default_value = GetDefaultValue(field, kObject);
+ code_ += " {{FIELD}}: " + default_value + ",";
+ });
+ code_ += " }";
+ code_ += " }";
+ code_ += "}";
+
+ // TODO(cneo): Generate defaults for Native tables. However, since structs
+ // may be required, they, and therefore enums need defaults.
+
+ // Generate pack function.
+ code_ += "impl {{STRUCT_OTY}} {";
+ code_ += " pub fn pack<'b>(";
+ code_ += " &self,";
+ code_ += " _fbb: &mut flatbuffers::FlatBufferBuilder<'b>";
+ code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_TY}}<'b>> {";
+ // First we generate variables for each field and then later assemble them
+ // using "StructArgs" to more easily manage ownership of the builder.
+ ForAllObjectTableFields(table, [&](const FieldDef &field) {
+ const Type &type = field.value.type;
+ switch (GetFullType(type)) {
+ case ftInteger:
+ case ftBool:
+ case ftFloat:
+ case ftEnumKey: {
+ code_ += " let {{FIELD}} = self.{{FIELD}};";
+ return;
+ }
+ case ftUnionKey: return; // Generate union type with union value.
+ case ftUnionValue: {
+ code_.SetValue("ENUM_METHOD",
+ namer_.Method(field.value.type.enum_def->name));
+ code_ +=
+ " let {{FIELD}}_type = "
+ "self.{{FIELD}}.{{ENUM_METHOD}}_type();";
+ code_ += " let {{FIELD}} = self.{{FIELD}}.pack(_fbb);";
+ return;
+ }
+ // The rest of the types require special casing around optionalness
+ // due to "required" annotation.
+ case ftString: {
+ MapNativeTableField(field, "_fbb.create_string(x)");
+ return;
+ }
+ case ftStruct: {
+ // Hold the struct in a variable so we can reference it.
+ if (field.IsRequired()) {
+ code_ += " let {{FIELD}}_tmp = Some(self.{{FIELD}}.pack());";
+ } else {
+ code_ +=
+ " let {{FIELD}}_tmp = self.{{FIELD}}"
+ ".as_ref().map(|x| x.pack());";
+ }
+ code_ += " let {{FIELD}} = {{FIELD}}_tmp.as_ref();";
+
+ return;
+ }
+ case ftTable: {
+ MapNativeTableField(field, "x.pack(_fbb)");
+ return;
+ }
+ case ftVectorOfEnumKey:
+ case ftVectorOfInteger:
+ case ftVectorOfBool:
+ case ftVectorOfFloat: {
+ MapNativeTableField(field, "_fbb.create_vector(x)");
+ return;
+ }
+ case ftVectorOfStruct: {
+ MapNativeTableField(
+ field,
+ "let w: Vec<_> = x.iter().map(|t| t.pack()).collect();"
+ "_fbb.create_vector(&w)");
+ return;
+ }
+ case ftVectorOfString: {
+ // TODO(cneo): create_vector* should be more generic to avoid
+ // allocations.
+
+ MapNativeTableField(
+ field,
+ "let w: Vec<_> = x.iter().map(|s| s.as_ref()).collect();"
+ "_fbb.create_vector_of_strings(&w)");
+ return;
+ }
+ case ftVectorOfTable: {
+ MapNativeTableField(
+ field,
+ "let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();"
+ "_fbb.create_vector(&w)");
+ return;
+ }
+ case ftVectorOfUnionValue: {
+ FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
+ return;
+ }
+ case ftArrayOfEnum:
+ case ftArrayOfStruct:
+ case ftArrayOfBuiltin: {
+ FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
+ return;
+ }
+ }
+ });
+ code_ += " {{STRUCT_TY}}::create(_fbb, &{{STRUCT_TY}}Args{";
+ ForAllObjectTableFields(table, [&](const FieldDef &field) {
+ (void)field; // Unused.
+ code_ += " {{FIELD}},";
+ });
+ code_ += " })";
+ code_ += " }";
+ code_ += "}";
+ }
+ void ForAllObjectTableFields(const StructDef &table,
+ std::function<void(const FieldDef &)> cb) {
+ const std::vector<FieldDef *> &v = table.fields.vec;
+ for (auto it = v.begin(); it != v.end(); it++) {
+ const FieldDef &field = **it;
+ if (field.deprecated) continue;
+ code_.SetValue("FIELD", namer_.Field(field.name));
+ code_.SetValue("FIELD_OTY", ObjectFieldType(field, true));
+ code_.IncrementIdentLevel();
+ cb(field);
+ code_.DecrementIdentLevel();
+ }
+ }
+ void MapNativeTableField(const FieldDef &field, const std::string &expr) {
+ if (field.IsOptional()) {
+ code_ += " let {{FIELD}} = self.{{FIELD}}.as_ref().map(|x|{";
+ code_ += " " + expr;
+ code_ += " });";
+ } else {
+ // For some reason Args has optional types for required fields.
+ // TODO(cneo): Fix this... but its a breaking change?
+ code_ += " let {{FIELD}} = Some({";
+ code_ += " let x = &self.{{FIELD}};";
+ code_ += " " + expr;
+ code_ += " });";
+ }
+ }
+
// Generate functions to compare tables and structs by key. This function
// must only be called if the field key is defined.
void GenKeyFieldMethods(const FieldDef &field) {
FLATBUFFERS_ASSERT(field.key);
code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
+ code_.SetValue("REF", IsString(field.value.type) ? "" : "&");
- code_ += " #[inline]";
+ code_ += "#[inline]";
code_ +=
- " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
- " bool {";
- code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
- code_ += " }";
+ "pub fn key_compare_less_than(&self, o: &{{STRUCT_TY}}) -> "
+ "bool {";
+ code_ += " self.{{FIELD}}() < o.{{FIELD}}()";
+ code_ += "}";
code_ += "";
- code_ += " #[inline]";
+ code_ += "#[inline]";
code_ +=
- " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
- " ::std::cmp::Ordering {";
- code_ += " let key = self.{{FIELD_NAME}}();";
- code_ += " key.cmp(&val)";
- code_ += " }";
+ "pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
+ "::std::cmp::Ordering {";
+ code_ += " let key = self.{{FIELD}}();";
+ code_ += " key.cmp({{REF}}val)";
+ code_ += "}";
}
// Generate functions for accessing the root table object. This function
// must only be called if the root table is defined.
void GenRootTableFuncs(const StructDef &struct_def) {
FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
- auto name = Name(struct_def);
-
- code_.SetValue("STRUCT_NAME", name);
- code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
- code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
+ code_.SetValue("STRUCT_TY", namer_.Type(struct_def.name));
+ code_.SetValue("STRUCT_FN", namer_.Function(struct_def.name));
+ code_.SetValue("STRUCT_CONST", namer_.Constant(struct_def.name));
// The root datatype accessors:
code_ += "#[inline]";
code_ +=
- "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
- " -> {{STRUCT_NAME}}<'a> {";
- code_ += " flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)";
+ "#[deprecated(since=\"2.0.0\", "
+ "note=\"Deprecated in favor of `root_as...` methods.\")]";
+ code_ +=
+ "pub fn get_root_as_{{STRUCT_FN}}<'a>(buf: &'a [u8])"
+ " -> {{STRUCT_TY}}<'a> {";
+ code_ +=
+ " unsafe { flatbuffers::root_unchecked::<{{STRUCT_TY}}"
+ "<'a>>(buf) }";
code_ += "}";
code_ += "";
code_ += "#[inline]";
code_ +=
- "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
- "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
+ "#[deprecated(since=\"2.0.0\", "
+ "note=\"Deprecated in favor of `root_as...` methods.\")]";
code_ +=
- " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
- "(buf)";
+ "pub fn get_size_prefixed_root_as_{{STRUCT_FN}}"
+ "<'a>(buf: &'a [u8]) -> {{STRUCT_TY}}<'a> {";
+ code_ +=
+ " unsafe { flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_TY}}"
+ "<'a>>(buf) }";
code_ += "}";
code_ += "";
+ // Default verifier root fns.
+ code_ += "#[inline]";
+ code_ += "/// Verifies that a buffer of bytes contains a `{{STRUCT_TY}}`";
+ code_ += "/// and returns it.";
+ code_ += "/// Note that verification is still experimental and may not";
+ code_ += "/// catch every error, or be maximally performant. For the";
+ code_ += "/// previous, unchecked, behavior use";
+ code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
+ code_ +=
+ "pub fn root_as_{{STRUCT_FN}}(buf: &[u8]) "
+ "-> Result<{{STRUCT_TY}}, flatbuffers::InvalidFlatbuffer> {";
+ code_ += " flatbuffers::root::<{{STRUCT_TY}}>(buf)";
+ code_ += "}";
+ code_ += "#[inline]";
+ code_ += "/// Verifies that a buffer of bytes contains a size prefixed";
+ code_ += "/// `{{STRUCT_TY}}` and returns it.";
+ code_ += "/// Note that verification is still experimental and may not";
+ code_ += "/// catch every error, or be maximally performant. For the";
+ code_ += "/// previous, unchecked, behavior use";
+ code_ += "/// `size_prefixed_root_as_{{STRUCT_FN}}_unchecked`.";
+ code_ +=
+ "pub fn size_prefixed_root_as_{{STRUCT_FN}}"
+ "(buf: &[u8]) -> Result<{{STRUCT_TY}}, "
+ "flatbuffers::InvalidFlatbuffer> {";
+ code_ += " flatbuffers::size_prefixed_root::<{{STRUCT_TY}}>(buf)";
+ code_ += "}";
+ // Verifier with options root fns.
+ code_ += "#[inline]";
+ code_ += "/// Verifies, with the given options, that a buffer of bytes";
+ code_ += "/// contains a `{{STRUCT_TY}}` and returns it.";
+ code_ += "/// Note that verification is still experimental and may not";
+ code_ += "/// catch every error, or be maximally performant. For the";
+ code_ += "/// previous, unchecked, behavior use";
+ code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
+ code_ += "pub fn root_as_{{STRUCT_FN}}_with_opts<'b, 'o>(";
+ code_ += " opts: &'o flatbuffers::VerifierOptions,";
+ code_ += " buf: &'b [u8],";
+ code_ +=
+ ") -> Result<{{STRUCT_TY}}<'b>, flatbuffers::InvalidFlatbuffer>"
+ " {";
+ code_ += " flatbuffers::root_with_opts::<{{STRUCT_TY}}<'b>>(opts, buf)";
+ code_ += "}";
+ code_ += "#[inline]";
+ code_ += "/// Verifies, with the given verifier options, that a buffer of";
+ code_ += "/// bytes contains a size prefixed `{{STRUCT_TY}}` and returns";
+ code_ += "/// it. Note that verification is still experimental and may not";
+ code_ += "/// catch every error, or be maximally performant. For the";
+ code_ += "/// previous, unchecked, behavior use";
+ code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
+ code_ +=
+ "pub fn size_prefixed_root_as_{{STRUCT_FN}}_with_opts"
+ "<'b, 'o>(";
+ code_ += " opts: &'o flatbuffers::VerifierOptions,";
+ code_ += " buf: &'b [u8],";
+ code_ +=
+ ") -> Result<{{STRUCT_TY}}<'b>, flatbuffers::InvalidFlatbuffer>"
+ " {";
+ code_ +=
+ " flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_TY}}"
+ "<'b>>(opts, buf)";
+ code_ += "}";
+ // Unchecked root fns.
+ code_ += "#[inline]";
+ code_ +=
+ "/// Assumes, without verification, that a buffer of bytes "
+ "contains a {{STRUCT_TY}} and returns it.";
+ code_ += "/// # Safety";
+ code_ +=
+ "/// Callers must trust the given bytes do indeed contain a valid"
+ " `{{STRUCT_TY}}`.";
+ code_ +=
+ "pub unsafe fn root_as_{{STRUCT_FN}}_unchecked"
+ "(buf: &[u8]) -> {{STRUCT_TY}} {";
+ code_ += " flatbuffers::root_unchecked::<{{STRUCT_TY}}>(buf)";
+ code_ += "}";
+ code_ += "#[inline]";
+ code_ +=
+ "/// Assumes, without verification, that a buffer of bytes "
+ "contains a size prefixed {{STRUCT_TY}} and returns it.";
+ code_ += "/// # Safety";
+ code_ +=
+ "/// Callers must trust the given bytes do indeed contain a valid"
+ " size prefixed `{{STRUCT_TY}}`.";
+ code_ +=
+ "pub unsafe fn size_prefixed_root_as_{{STRUCT_FN}}"
+ "_unchecked(buf: &[u8]) -> {{STRUCT_TY}} {";
+ code_ +=
+ " flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_TY}}>"
+ "(buf)";
+ code_ += "}";
if (parser_.file_identifier_.length()) {
// Declare the identifier
// (no lifetime needed as constants have static lifetimes by default)
- code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &str\\";
+ code_ += "pub const {{STRUCT_CONST}}_IDENTIFIER: &str\\";
code_ += " = \"" + parser_.file_identifier_ + "\";";
code_ += "";
// Check if a buffer has the identifier.
code_ += "#[inline]";
- code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
+ code_ += "pub fn {{STRUCT_FN}}_buffer_has_identifier\\";
code_ += "(buf: &[u8]) -> bool {";
code_ += " flatbuffers::buffer_has_identifier(buf, \\";
- code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false)";
+ code_ += "{{STRUCT_CONST}}_IDENTIFIER, false)";
code_ += "}";
code_ += "";
code_ += "#[inline]";
- code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
+ code_ += "pub fn {{STRUCT_FN}}_size_prefixed\\";
code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
code_ += " flatbuffers::buffer_has_identifier(buf, \\";
- code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true)";
+ code_ += "{{STRUCT_CONST}}_IDENTIFIER, true)";
code_ += "}";
code_ += "";
}
if (parser_.file_extension_.length()) {
// Return the extension
- code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &str = \\";
+ code_ += "pub const {{STRUCT_CONST}}_EXTENSION: &str = \\";
code_ += "\"" + parser_.file_extension_ + "\";";
code_ += "";
}
// Finish a buffer with a given root object:
- code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
code_ += "#[inline]";
- code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
+ code_ += "pub fn finish_{{STRUCT_FN}}_buffer<'a, 'b>(";
code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
- code_ += " root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
+ code_ += " root: flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>>) {";
if (parser_.file_identifier_.length()) {
- code_ += " fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
+ code_ += " fbb.finish(root, Some({{STRUCT_CONST}}_IDENTIFIER));";
} else {
code_ += " fbb.finish(root, None);";
}
@@ -1601,14 +2525,14 @@
code_ += "";
code_ += "#[inline]";
code_ +=
- "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
+ "pub fn finish_size_prefixed_{{STRUCT_FN}}_buffer"
"<'a, 'b>("
"fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
- "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
+ "root: flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>>) {";
if (parser_.file_identifier_.length()) {
code_ +=
" fbb.finish_size_prefixed(root, "
- "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
+ "Some({{STRUCT_CONST}}_IDENTIFIER));";
} else {
code_ += " fbb.finish_size_prefixed(root, None);";
}
@@ -1638,16 +2562,24 @@
*code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
}
- void ForAllStructFields(
- const StructDef &struct_def,
- std::function<void(const FieldDef &field)> cb
- ) {
+ void ForAllStructFields(const StructDef &struct_def,
+ std::function<void(const FieldDef &field)> cb) {
+ size_t offset_to_field = 0;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
- code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("FIELD_OTY", ObjectFieldType(field, false));
+ code_.SetValue("FIELD", namer_.Field(field.name));
+ code_.SetValue("FIELD_OFFSET", NumToString(offset_to_field));
+ code_.SetValue(
+ "REF",
+ IsStruct(field.value.type) || IsArray(field.value.type) ? "&" : "");
+ code_.IncrementIdentLevel();
cb(field);
+ code_.DecrementIdentLevel();
+ const size_t size = InlineSize(field.value.type);
+ offset_to_field += size + field.padding;
}
}
// Generate an accessor struct with constructor for a flatbuffers struct.
@@ -1657,121 +2589,146 @@
// platforms.
GenComment(struct_def.doc_comment);
code_.SetValue("ALIGN", NumToString(struct_def.minalign));
- code_.SetValue("STRUCT_NAME", Name(struct_def));
+ code_.SetValue("STRUCT_TY", namer_.Type(struct_def.name));
+ code_.SetValue("STRUCT_SIZE", NumToString(struct_def.bytesize));
- code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
- code_ += "#[repr(C, align({{ALIGN}}))]";
-
+ // We represent Flatbuffers-structs in Rust-u8-arrays since the data may be
+ // of the wrong endianness and alignment 1.
+ //
// PartialEq is useful to derive because we can correctly compare structs
// for equality by just comparing their underlying byte data. This doesn't
// hold for PartialOrd/Ord.
+ code_ += "// struct {{STRUCT_TY}}, aligned to {{ALIGN}}";
+ code_ += "#[repr(transparent)]";
code_ += "#[derive(Clone, Copy, PartialEq)]";
- code_ += "pub struct {{STRUCT_NAME}} {";
-
- int padding_id = 0;
- ForAllStructFields(struct_def, [&](const FieldDef &field) {
- code_ += " {{FIELD_NAME}}_: {{FIELD_TYPE}},";
- if (field.padding) {
- std::string padding;
- GenPadding(field, &padding, &padding_id, PaddingDefinition);
- code_ += padding;
- }
- });
- code_ += "} // pub struct {{STRUCT_NAME}}";
+ code_ += "pub struct {{STRUCT_TY}}(pub [u8; {{STRUCT_SIZE}}]);";
+ code_ += "impl Default for {{STRUCT_TY}} { ";
+ code_ += " fn default() -> Self { ";
+ code_ += " Self([0; {{STRUCT_SIZE}}])";
+ code_ += " }";
+ code_ += "}";
// Debug for structs.
- code_ += "impl std::fmt::Debug for {{STRUCT_NAME}} {";
- code_ += " fn fmt(&self, f: &mut std::fmt::Formatter"
- ") -> std::fmt::Result {";
- code_ += " f.debug_struct(\"{{STRUCT_NAME}}\")";
+ code_ += "impl std::fmt::Debug for {{STRUCT_TY}} {";
+ code_ +=
+ " fn fmt(&self, f: &mut std::fmt::Formatter"
+ ") -> std::fmt::Result {";
+ code_ += " f.debug_struct(\"{{STRUCT_TY}}\")";
ForAllStructFields(struct_def, [&](const FieldDef &unused) {
- (void) unused;
- code_ += " .field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}())";
+ (void)unused;
+ code_ += " .field(\"{{FIELD}}\", &self.{{FIELD}}())";
});
code_ += " .finish()";
code_ += " }";
code_ += "}";
code_ += "";
-
// Generate impls for SafeSliceAccess (because all structs are endian-safe),
// Follow for the value type, Follow for the reference type, Push for the
// value type, and Push for the reference type.
- code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
- code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
- code_ += " type Inner = &'a {{STRUCT_NAME}};";
+ code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{STRUCT_TY}} {}";
+ code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_TY}} {}";
+ code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_TY}} {";
+ code_ += " type Inner = &'a {{STRUCT_TY}};";
code_ += " #[inline]";
code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
- code_ += " <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
+ code_ += " <&'a {{STRUCT_TY}}>::follow(buf, loc)";
code_ += " }";
code_ += "}";
- code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
- code_ += " type Inner = &'a {{STRUCT_NAME}};";
+ code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_TY}} {";
+ code_ += " type Inner = &'a {{STRUCT_TY}};";
code_ += " #[inline]";
code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
- code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
+ code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_TY}}>(buf, loc)";
code_ += " }";
code_ += "}";
- code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
- code_ += " type Output = {{STRUCT_NAME}};";
+ code_ += "impl<'b> flatbuffers::Push for {{STRUCT_TY}} {";
+ code_ += " type Output = {{STRUCT_TY}};";
code_ += " #[inline]";
code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
code_ += " let src = unsafe {";
code_ +=
" ::std::slice::from_raw_parts("
- "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
+ "self as *const {{STRUCT_TY}} as *const u8, Self::size())";
code_ += " };";
code_ += " dst.copy_from_slice(src);";
code_ += " }";
code_ += "}";
- code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
- code_ += " type Output = {{STRUCT_NAME}};";
+ code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_TY}} {";
+ code_ += " type Output = {{STRUCT_TY}};";
code_ += "";
code_ += " #[inline]";
code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
code_ += " let src = unsafe {";
code_ +=
" ::std::slice::from_raw_parts("
- "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
+ "*self as *const {{STRUCT_TY}} as *const u8, Self::size())";
code_ += " };";
code_ += " dst.copy_from_slice(src);";
code_ += " }";
code_ += "}";
code_ += "";
+
+ // Generate verifier: Structs are simple so presence and alignment are
+ // all that need to be checked.
+ code_ += "impl<'a> flatbuffers::Verifiable for {{STRUCT_TY}} {";
+ code_ += " #[inline]";
+ code_ += " fn run_verifier(";
+ code_ += " v: &mut flatbuffers::Verifier, pos: usize";
+ code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
+ code_ += " use self::flatbuffers::Verifiable;";
+ code_ += " v.in_buffer::<Self>(pos)";
+ code_ += " }";
+ code_ += "}";
code_ += "";
+ // Implement serde::Serialize
+ if (parser_.opts.rust_serialize) {
+ const auto numFields = struct_def.fields.vec.size();
+ code_.SetValue("NUM_FIELDS", NumToString(numFields));
+ code_ += "impl Serialize for {{STRUCT_TY}} {";
+ code_ +=
+ " fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
+ code_ += " where";
+ code_ += " S: Serializer,";
+ code_ += " {";
+ if (numFields == 0) {
+ code_ +=
+ " let s = serializer.serialize_struct(\"{{STRUCT_TY}}\", 0)?;";
+ } else {
+ code_ +=
+ " let mut s = serializer.serialize_struct(\"{{STRUCT_TY}}\", "
+ "{{NUM_FIELDS}})?;";
+ }
+ ForAllStructFields(struct_def, [&](const FieldDef &unused) {
+ (void)unused;
+ code_ +=
+ " s.serialize_field(\"{{FIELD}}\", "
+ "&self.{{FIELD}}())?;";
+ });
+ code_ += " s.end()";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ }
+
// Generate a constructor that takes all fields as arguments.
- code_ += "impl {{STRUCT_NAME}} {";
- // TODO(cneo): Stop generating args on one line. Make it simpler.
- bool first_arg = true;
- code_ += " pub fn new(\\";
- ForAllStructFields(struct_def, [&](const FieldDef &field) {
- if (first_arg) first_arg = false; else code_ += ", \\";
- code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
- code_ += "_{{FIELD_NAME}}: {{REF}}{{FIELD_TYPE}}\\";
+ code_ += "impl<'a> {{STRUCT_TY}} {";
+ code_ += " #[allow(clippy::too_many_arguments)]";
+ code_ += " pub fn new(";
+ ForAllStructFields(struct_def, [&](const FieldDef &unused) {
+ (void)unused;
+ code_ += " {{FIELD}}: {{REF}}{{FIELD_TYPE}},";
});
- code_ += ") -> Self {";
- code_ += " {{STRUCT_NAME}} {";
-
- ForAllStructFields(struct_def, [&](const FieldDef &field) {
- const bool is_struct = IsStruct(field.value.type);
- code_.SetValue("DEREF", is_struct ? "*" : "");
- code_.SetValue("TO_LE", is_struct ? "" : ".to_little_endian()");
- code_ += " {{FIELD_NAME}}_: {{DEREF}}_{{FIELD_NAME}}{{TO_LE}},";
+ code_ += " ) -> Self {";
+ code_ += " let mut s = Self([0; {{STRUCT_SIZE}}]);";
+ ForAllStructFields(struct_def, [&](const FieldDef &unused) {
+ (void)unused;
+ code_ += " s.set_{{FIELD}}({{FIELD}});";
});
- code_ += "";
-
- // TODO(cneo): Does this padding even work? Why after all the fields?
- padding_id = 0;
- ForAllStructFields(struct_def, [&](const FieldDef &field) {
- if (field.padding) {
- std::string padding;
- GenPadding(field, &padding, &padding_id, PaddingInitializer);
- code_ += " " + padding;
- }
- });
- code_ += " }";
+ code_ += " s";
code_ += " }";
+ code_ += "";
if (parser_.opts.generate_name_strings) {
GenFullyQualifiedNameGetter(struct_def, struct_def.name);
@@ -1779,26 +2736,155 @@
// Generate accessor methods for the struct.
ForAllStructFields(struct_def, [&](const FieldDef &field) {
- const bool is_struct = IsStruct(field.value.type);
- code_.SetValue("REF", is_struct ? "&" : "");
- code_.SetValue("FROM_LE", is_struct ? "" : ".from_little_endian()");
-
- this->GenComment(field.doc_comment, " ");
- code_ += " pub fn {{FIELD_NAME}}(&self) -> {{REF}}{{FIELD_TYPE}} {";
- code_ += " {{REF}}self.{{FIELD_NAME}}_{{FROM_LE}}";
- code_ += " }";
+ this->GenComment(field.doc_comment);
+ // Getter.
+ if (IsStruct(field.value.type)) {
+ code_ += "pub fn {{FIELD}}(&self) -> &{{FIELD_TYPE}} {";
+ code_ +=
+ " unsafe {"
+ " &*(self.0[{{FIELD_OFFSET}}..].as_ptr() as *const"
+ " {{FIELD_TYPE}}) }";
+ } else if (IsArray(field.value.type)) {
+ code_.SetValue("ARRAY_SIZE",
+ NumToString(field.value.type.fixed_length));
+ code_.SetValue("ARRAY_ITEM", GetTypeGet(field.value.type.VectorType()));
+ code_ +=
+ "pub fn {{FIELD}}(&'a self) -> "
+ "flatbuffers::Array<'a, {{ARRAY_ITEM}}, {{ARRAY_SIZE}}> {";
+ code_ += " flatbuffers::Array::follow(&self.0, {{FIELD_OFFSET}})";
+ } else {
+ code_ += "pub fn {{FIELD}}(&self) -> {{FIELD_TYPE}} {";
+ code_ +=
+ " let mut mem = core::mem::MaybeUninit::"
+ "<{{FIELD_TYPE}}>::uninit();";
+ code_ += " unsafe {";
+ code_ += " core::ptr::copy_nonoverlapping(";
+ code_ += " self.0[{{FIELD_OFFSET}}..].as_ptr(),";
+ code_ += " mem.as_mut_ptr() as *mut u8,";
+ code_ += " core::mem::size_of::<{{FIELD_TYPE}}>(),";
+ code_ += " );";
+ code_ += " mem.assume_init()";
+ code_ += " }.from_little_endian()";
+ }
+ code_ += "}\n";
+ // Setter.
+ if (IsStruct(field.value.type)) {
+ code_.SetValue("FIELD_SIZE", NumToString(InlineSize(field.value.type)));
+ code_ += "#[allow(clippy::identity_op)]"; // If FIELD_OFFSET=0.
+ code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {";
+ code_ +=
+ " self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}} + {{FIELD_SIZE}}]"
+ ".copy_from_slice(&x.0)";
+ } else if (IsArray(field.value.type)) {
+ if (GetFullType(field.value.type) == ftArrayOfBuiltin) {
+ code_.SetValue("ARRAY_ITEM",
+ GetTypeGet(field.value.type.VectorType()));
+ code_.SetValue(
+ "ARRAY_ITEM_SIZE",
+ NumToString(InlineSize(field.value.type.VectorType())));
+ code_ +=
+ "pub fn set_{{FIELD}}(&mut self, items: &{{FIELD_TYPE}}) "
+ "{";
+ code_ +=
+ " flatbuffers::emplace_scalar_array(&mut self.0, "
+ "{{FIELD_OFFSET}}, items);";
+ } else {
+ code_.SetValue("FIELD_SIZE",
+ NumToString(InlineSize(field.value.type)));
+ code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {";
+ code_ += " unsafe {";
+ code_ += " std::ptr::copy(";
+ code_ += " x.as_ptr() as *const u8,";
+ code_ += " self.0.as_mut_ptr().add({{FIELD_OFFSET}}),";
+ code_ += " {{FIELD_SIZE}},";
+ code_ += " );";
+ code_ += " }";
+ }
+ } else {
+ code_ += "pub fn set_{{FIELD}}(&mut self, x: {{FIELD_TYPE}}) {";
+ code_ += " let x_le = x.to_little_endian();";
+ code_ += " unsafe {";
+ code_ += " core::ptr::copy_nonoverlapping(";
+ code_ += " &x_le as *const {{FIELD_TYPE}} as *const u8,";
+ code_ += " self.0[{{FIELD_OFFSET}}..].as_mut_ptr(),";
+ code_ += " core::mem::size_of::<{{FIELD_TYPE}}>(),";
+ code_ += " );";
+ code_ += " }";
+ }
+ code_ += "}\n";
// Generate a comparison function for this field if it is a key.
if (field.key) { GenKeyFieldMethods(field); }
});
- code_ += "}";
+
+ // Generate Object API unpack method.
+ if (parser_.opts.generate_object_based_api) {
+ code_.SetValue("STRUCT_OTY", namer_.ObjectType(struct_def.name));
+ code_ += " pub fn unpack(&self) -> {{STRUCT_OTY}} {";
+ code_ += " {{STRUCT_OTY}} {";
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
+ if (IsArray(field.value.type)) {
+ if (GetFullType(field.value.type) == ftArrayOfStruct) {
+ code_ +=
+ " {{FIELD}}: { let {{FIELD}} = "
+ "self.{{FIELD}}(); flatbuffers::array_init(|i| "
+ "{{FIELD}}.get(i).unpack()) },";
+ } else {
+ code_ += " {{FIELD}}: self.{{FIELD}}().into(),";
+ }
+ } else {
+ std::string unpack = IsStruct(field.value.type) ? ".unpack()" : "";
+ code_ += " {{FIELD}}: self.{{FIELD}}()" + unpack + ",";
+ }
+ });
+ code_ += " }";
+ code_ += " }";
+ }
+
+ code_ += "}"; // End impl Struct methods.
code_ += "";
+
+ // Generate Struct Object.
+ if (parser_.opts.generate_object_based_api) {
+ // Struct declaration
+ code_ += "#[derive(Debug, Clone, PartialEq, Default)]";
+ code_ += "pub struct {{STRUCT_OTY}} {";
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
+ (void)field; // unused.
+ code_ += "pub {{FIELD}}: {{FIELD_OTY}},";
+ });
+ code_ += "}";
+ // The `pack` method that turns the native struct into its Flatbuffers
+ // counterpart.
+ code_ += "impl {{STRUCT_OTY}} {";
+ code_ += " pub fn pack(&self) -> {{STRUCT_TY}} {";
+ code_ += " {{STRUCT_TY}}::new(";
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
+ if (IsStruct(field.value.type)) {
+ code_ += " &self.{{FIELD}}.pack(),";
+ } else if (IsArray(field.value.type)) {
+ if (GetFullType(field.value.type) == ftArrayOfStruct) {
+ code_ +=
+ " &flatbuffers::array_init(|i| "
+ "self.{{FIELD}}[i].pack()),";
+ } else {
+ code_ += " &self.{{FIELD}},";
+ }
+ } else {
+ code_ += " self.{{FIELD}},";
+ }
+ });
+ code_ += " )";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ }
}
void GenNamespaceImports(const int white_spaces) {
- if (white_spaces == 0) {
- code_ += "#![allow(unused_imports, dead_code)]";
- }
+ // DO not use global attributes (i.e. #![...]) since it interferes
+ // with users who include! generated files.
+ // See: https://github.com/google/flatbuffers/issues/6261
std::string indent = std::string(white_spaces, ' ');
code_ += "";
if (!parser_.opts.generate_all) {
@@ -1808,15 +2894,30 @@
auto noext = flatbuffers::StripExtension(it->second);
auto basename = flatbuffers::StripPath(noext);
- code_ += indent + "use crate::" + basename + "_generated::*;";
+ if (parser_.opts.include_prefix.empty()) {
+ code_ += indent + "use crate::" + basename +
+ parser_.opts.filename_suffix + "::*;";
+ } else {
+ auto prefix = parser_.opts.include_prefix;
+ prefix.pop_back();
+
+ code_ += indent + "use crate::" + prefix + "::" + basename +
+ parser_.opts.filename_suffix + "::*;";
+ }
}
}
-
code_ += indent + "use std::mem;";
code_ += indent + "use std::cmp::Ordering;";
code_ += "";
+ if (parser_.opts.rust_serialize) {
+ code_ += indent + "extern crate serde;";
+ code_ +=
+ indent +
+ "use self::serde::ser::{Serialize, Serializer, SerializeStruct};";
+ code_ += "";
+ }
code_ += indent + "extern crate flatbuffers;";
- code_ += indent + "use self::flatbuffers::EndianScalar;";
+ code_ += indent + "use self::flatbuffers::{EndianScalar, Follow};";
}
// Set up the correct namespace. This opens a namespace if the current
@@ -1853,7 +2954,7 @@
// in the previous example, E, then F, then G are opened
for (auto j = common_prefix_size; j != new_size; ++j) {
code_ += "#[allow(unused_imports, dead_code)]";
- code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
+ code_ += "pub mod " + namer_.Namespace(ns->components[j]) + " {";
// Generate local namespace imports.
GenNamespaceImports(2);
}
@@ -1861,6 +2962,9 @@
cur_name_space_ = ns;
}
+
+ private:
+ Namer namer_;
};
} // namespace rust
diff --git a/third_party/flatbuffers/src/idl_gen_swift.cpp b/third_party/flatbuffers/src/idl_gen_swift.cpp
index 084bafe..c3c322f 100644
--- a/third_party/flatbuffers/src/idl_gen_swift.cpp
+++ b/third_party/flatbuffers/src/idl_gen_swift.cpp
@@ -127,6 +127,7 @@
"unowned",
"weak",
"willSet",
+ "Void",
nullptr,
};
for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
@@ -153,17 +154,7 @@
const auto &struct_def = **it;
if (struct_def.fixed && !struct_def.generated) {
GenStructReader(struct_def);
- if (parser_.opts.generate_object_based_api) {
- GenObjectAPI(struct_def);
- }
- }
- }
-
- for (auto it = parser_.structs_.vec.begin();
- it != parser_.structs_.vec.end(); ++it) {
- const auto &struct_def = **it;
- if (struct_def.fixed && !struct_def.generated) {
- GenStructWriter(struct_def);
+ GenMutableStructReader(struct_def);
}
}
@@ -188,6 +179,168 @@
code_ += "\n// MARK: - {{MARKVALUE}}\n";
}
+ // MARK: - Generating structs
+
+ // Generates the reader for swift
+ void GenStructReader(const StructDef &struct_def) {
+ auto is_private_access = struct_def.attributes.Lookup("private");
+ code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
+ GenComment(struct_def.doc_comment);
+ code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def));
+ code_ +=
+ "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: NativeStruct, Verifiable, "
+ "FlatbuffersInitializable\\";
+ if (parser_.opts.generate_object_based_api) code_ += ", NativeObject\\";
+ code_ += " {";
+ code_ += "";
+ Indent();
+ code_ += ValidateFunc();
+ code_ += "";
+ int padding_id = 0;
+ std::string constructor = "";
+ std::vector<std::string> base_constructor;
+ std::vector<std::string> main_constructor;
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ if (!constructor.empty()) constructor += ", ";
+
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ if (IsEnum(field.value.type)) {
+ code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
+ }
+ code_.SetValue("VALUETYPE", type);
+ GenComment(field.doc_comment);
+ std::string valueType =
+ IsEnum(field.value.type) ? "{{BASEVALUE}}" : "{{VALUETYPE}}";
+ code_ += "private var _{{VALUENAME}}: " + valueType;
+ auto accessing_value = IsEnum(field.value.type) ? ".value" : "";
+ auto is_bool = IsBool(field.value.type.base_type);
+ auto base_value = IsStruct(field.value.type) ? (type + "()")
+ : is_bool ? ("0" == field.value.constant ? "false" : "true")
+ : field.value.constant;
+
+ main_constructor.push_back("_" + name + " = " + name + accessing_value);
+ base_constructor.push_back("_" + name + " = " + base_value);
+
+ if (field.padding) { GenPadding(field, &padding_id); }
+ constructor += name + ": " + type;
+ }
+ code_ += "";
+ BuildStructConstructor(struct_def);
+ BuildObjectConstructor(main_constructor, constructor);
+ BuildObjectConstructor(base_constructor, "");
+
+ if (parser_.opts.generate_object_based_api)
+ GenerateObjectAPIStructConstructor(struct_def);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", type);
+ GenComment(field.doc_comment);
+ if (!IsEnum(field.value.type)) {
+ code_ += GenReaderMainBody() + "_{{VALUENAME}} }";
+ } else if (IsEnum(field.value.type)) {
+ code_ +=
+ GenReaderMainBody() + "{{VALUETYPE}}(rawValue: _{{VALUENAME}})! }";
+ }
+ }
+ code_ += "";
+ code_ +=
+ "public static func verify<T>(_ verifier: inout Verifier, at position: "
+ "Int, of type: T.Type) throws where T: Verifiable {";
+ Indent();
+ code_ +=
+ "try verifier.inBuffer(position: position, of: {{STRUCTNAME}}.self)";
+ Outdent();
+ code_ += "}";
+ Outdent();
+ code_ += "}\n";
+ if (parser_.opts.gen_json_coders) GenerateJSONEncodingAPIs(struct_def);
+ }
+
+ void BuildStructConstructor(const StructDef &struct_def) {
+ code_ += "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) {";
+ Indent();
+ code_ += "let {{ACCESS}} = Struct(bb: bb, position: o)";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto name = Name(field);
+ auto type = field.value.type;
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", GenType(type));
+ code_.SetValue("OFFSET", NumToString(field.value.offset));
+ if (IsScalar(type.base_type)) {
+ if (IsEnum(type))
+ code_.SetValue("VALUETYPE", GenTypeBasic(field.value.type, false));
+ code_ +=
+ "_{{VALUENAME}} = {{ACCESS}}.readBuffer(of: {{VALUETYPE}}.self, "
+ "at: {{OFFSET}})";
+ } else {
+ code_ +=
+ "_{{VALUENAME}} = {{VALUETYPE}}({{ACCESS}}.bb, o: "
+ "{{ACCESS}}.postion + {{OFFSET}})";
+ }
+ }
+ Outdent();
+ code_ += "}\n";
+ }
+
+ void GenMutableStructReader(const StructDef &struct_def) {
+ GenObjectHeader(struct_def);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto offset = NumToString(field.value.offset);
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ if (IsEnum(field.value.type)) {
+ code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
+ }
+ code_.SetValue("VALUETYPE", type);
+ code_.SetValue("OFFSET", offset);
+ if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type)) {
+ code_ +=
+ GenReaderMainBody() + "return " + GenReader("VALUETYPE") + " }";
+ } else if (IsEnum(field.value.type)) {
+ code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
+ code_ += GenReaderMainBody() + "return " +
+ GenEnumConstructor("{{OFFSET}}") + "?? " +
+ GenEnumDefaultValue(field) + " }";
+ } else if (IsStruct(field.value.type)) {
+ code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
+ code_ += GenReaderMainBody() + "return " +
+ GenConstructor("{{ACCESS}}.postion + {{OFFSET}}");
+ }
+ if (parser_.opts.mutable_buffer && !IsStruct(field.value.type))
+ code_ += GenMutate("{{OFFSET}}", "", IsEnum(field.value.type));
+ }
+
+ if (parser_.opts.generate_object_based_api) {
+ GenerateObjectAPIExtensionHeader(NameWrappedInNameSpace(struct_def));
+ code_ += "return builder.create(struct: obj)";
+ Outdent();
+ code_ += "}";
+ }
+ Outdent();
+ code_ += "}\n";
+ }
+
// Generates the create function for swift
void GenStructWriter(const StructDef &struct_def) {
auto is_private_access = struct_def.attributes.Lookup("private");
@@ -203,12 +356,11 @@
std::string func_header = "";
GenerateStructArgs(struct_def, &func_header, "", "");
code_ += func_header.substr(0, func_header.size() - 2) + "\\";
- code_ += ") -> Offset<UOffset> {";
+ code_ += ") -> Offset {";
Indent();
code_ +=
"builder.createStructOf(size: {{STRUCTNAME}}.size, alignment: "
"{{STRUCTNAME}}.alignment)";
- GenerateStructBody(struct_def, "");
code_ += "return builder.endStruct()";
Outdent();
code_ += "}\n";
@@ -216,27 +368,6 @@
code_ += "}\n";
}
- void GenerateStructBody(const StructDef &struct_def,
- const std::string &nameprefix, int offset = 0) {
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
- auto name = nameprefix + Name(field);
- const auto &field_type = field.value.type;
- auto type = GenTypeBasic(field_type, false);
- if (IsStruct(field.value.type)) {
- GenerateStructBody(*field_type.struct_def, (nameprefix + field.name),
- static_cast<int>(field.value.offset));
- } else {
- auto off = NumToString(offset + field.value.offset);
- code_ += "builder.reverseAdd(v: " + name +
- (field_type.enum_def ? ".rawValue" : "") +
- ", postion: " + off + ")";
- }
- }
- }
-
void GenerateStructArgs(const StructDef &struct_def, std::string *code_ptr,
const std::string &nameprefix,
const std::string &object_name,
@@ -275,65 +406,23 @@
}
}
- void GenObjectHeader(const StructDef &struct_def) {
- GenComment(struct_def.doc_comment);
- code_.SetValue("SHORT_STRUCTNAME", Name(struct_def));
- code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def));
- code_.SetValue("PROTOCOL",
- struct_def.fixed ? "Readable" : "FlatBufferObject");
- code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
- code_ += "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: {{PROTOCOL}}\\";
- if (!struct_def.fixed && parser_.opts.generate_object_based_api)
- code_ += ", ObjectAPI\\";
- code_ += " {\n";
- Indent();
- code_ += ValidateFunc();
- code_ +=
- "{{ACCESS_TYPE}} var __buffer: ByteBuffer! { return {{ACCESS}}.bb }";
- code_ += "private var {{ACCESS}}: {{OBJECTTYPE}}\n";
- if (struct_def.fixed) {
- code_.SetValue("BYTESIZE", NumToString(struct_def.bytesize));
- code_.SetValue("MINALIGN", NumToString(struct_def.minalign));
- code_ += "{{ACCESS_TYPE}} static var size = {{BYTESIZE}}";
- code_ += "{{ACCESS_TYPE}} static var alignment = {{MINALIGN}}";
- } else {
- if (parser_.file_identifier_.length()) {
- code_.SetValue("FILENAME", parser_.file_identifier_);
- code_ +=
- "{{ACCESS_TYPE}} static func finish(_ fbb: inout "
- "FlatBufferBuilder, end: "
- "Offset<UOffset>, prefix: Bool = false) { fbb.finish(offset: end, "
- "fileId: "
- "\"{{FILENAME}}\", addPrefix: prefix) }";
- }
- code_ +=
- "{{ACCESS_TYPE}} static func getRootAs{{SHORT_STRUCTNAME}}(bb: "
- "ByteBuffer) -> "
- "{{STRUCTNAME}} { return {{STRUCTNAME}}(Table(bb: bb, position: "
- "Int32(bb.read(def: UOffset.self, position: bb.reader)) + "
- "Int32(bb.reader))) }\n";
- code_ += "private init(_ t: Table) { {{ACCESS}} = t }";
- }
- code_ +=
- "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = "
- "{{OBJECTTYPE}}(bb: "
- "bb, position: o) }";
- code_ += "";
- }
+ // MARK: - Table Generator
// Generates the reader for swift
void GenTable(const StructDef &struct_def) {
auto is_private_access = struct_def.attributes.Lookup("private");
code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
-
GenObjectHeader(struct_def);
GenTableAccessors(struct_def);
GenTableReader(struct_def);
GenTableWriter(struct_def);
if (parser_.opts.generate_object_based_api)
GenerateObjectAPITableExtension(struct_def);
+ code_ += "";
+ GenerateVerifier(struct_def);
Outdent();
code_ += "}\n";
+ if (parser_.opts.gen_json_coders) GenerateJSONEncodingAPIs(struct_def);
}
// Generates the reader for swift
@@ -358,51 +447,47 @@
}
}
- void GenerateObjectAPIExtensionHeader() {
- code_ += "\n";
- code_ += "{{ACCESS_TYPE}} mutating func unpack() -> " +
- ObjectAPIName("{{STRUCTNAME}}") + " {";
- Indent();
- code_ += "return " + ObjectAPIName("{{STRUCTNAME}}") + "(&self)";
- Outdent();
- code_ += "}";
- code_ +=
- "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
- "obj: "
- "inout " +
- ObjectAPIName("{{STRUCTNAME}}") + "?) -> Offset<UOffset> {";
- Indent();
- code_ += "guard var obj = obj else { return Offset<UOffset>() }";
- code_ += "return pack(&builder, obj: &obj)";
- Outdent();
- code_ += "}";
- code_ += "";
- code_ +=
- "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
- "obj: "
- "inout " +
- ObjectAPIName("{{STRUCTNAME}}") + ") -> Offset<UOffset> {";
- Indent();
- }
+ void GenObjectHeader(const StructDef &struct_def) {
+ GenComment(struct_def.doc_comment);
- void GenerateObjectAPIStructExtension(const StructDef &struct_def) {
- GenerateObjectAPIExtensionHeader();
- std::string code;
- GenerateStructArgs(struct_def, &code, "", "", "obj", true);
- code_ += "return create{{SHORT_STRUCTNAME}}(builder: &builder, \\";
- code_ += code.substr(0, code.size() - 2) + "\\";
- code_ += ")";
- Outdent();
- code_ += "}";
- }
-
- void GenTableReader(const StructDef &struct_def) {
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
- GenTableReaderFields(field);
+ code_.SetValue("SHORT_STRUCTNAME", Name(struct_def));
+ code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def));
+ code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
+ code_.SetValue("MUTABLE", struct_def.fixed ? Mutable() : "");
+ code_ +=
+ "{{ACCESS_TYPE}} struct {{STRUCTNAME}}{{MUTABLE}}: FlatBufferObject\\";
+ if (!struct_def.fixed) code_ += ", Verifiable\\";
+ if (!struct_def.fixed && parser_.opts.generate_object_based_api)
+ code_ += ", ObjectAPIPacker\\";
+ code_ += " {\n";
+ Indent();
+ code_ += ValidateFunc();
+ code_ +=
+ "{{ACCESS_TYPE}} var __buffer: ByteBuffer! { return {{ACCESS}}.bb }";
+ code_ += "private var {{ACCESS}}: {{OBJECTTYPE}}\n";
+ if (!struct_def.fixed) {
+ if (parser_.file_identifier_.length()) {
+ code_.SetValue("FILENAME", parser_.file_identifier_);
+ code_ +=
+ "{{ACCESS_TYPE}} static func finish(_ fbb: inout "
+ "FlatBufferBuilder, end: "
+ "Offset, prefix: Bool = false) { fbb.finish(offset: end, "
+ "fileId: "
+ "\"{{FILENAME}}\", addPrefix: prefix) }";
+ }
+ code_ +=
+ "{{ACCESS_TYPE}} static func getRootAs{{SHORT_STRUCTNAME}}(bb: "
+ "ByteBuffer) -> "
+ "{{STRUCTNAME}} { return {{STRUCTNAME}}(Table(bb: bb, position: "
+ "Int32(bb.read(def: UOffset.self, position: bb.reader)) + "
+ "Int32(bb.reader))) }\n";
+ code_ += "private init(_ t: Table) { {{ACCESS}} = t }";
}
+ code_ +=
+ "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = "
+ "{{OBJECTTYPE}}(bb: "
+ "bb, position: o) }";
+ code_ += "";
}
void GenTableWriter(const StructDef &struct_def) {
@@ -423,17 +508,16 @@
auto &field = **it;
if (field.deprecated) continue;
if (field.key) key_field = &field;
- if (field.required)
+ if (field.IsRequired())
require_fields.push_back(NumToString(field.value.offset));
- GenTableWriterFields(field, &create_func_body, &create_func_header,
- should_generate_create);
+ GenTableWriterFields(field, &create_func_body, &create_func_header);
}
code_ +=
"{{ACCESS_TYPE}} static func end{{SHORT_STRUCTNAME}}(_ fbb: inout "
"FlatBufferBuilder, "
"start: "
- "UOffset) -> Offset<UOffset> { let end = Offset<UOffset>(offset: "
+ "UOffset) -> Offset { let end = Offset(offset: "
"fbb.endTable(at: start))\\";
if (require_fields.capacity() != 0) {
std::string fields = "";
@@ -455,7 +539,7 @@
}
code_ += "";
Outdent();
- code_ += ") -> Offset<UOffset> {";
+ code_ += ") -> Offset {";
Indent();
code_ += "let __start = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&fbb)";
for (auto it = create_func_body.begin(); it < create_func_body.end();
@@ -477,8 +561,8 @@
code_ +=
"{{ACCESS_TYPE}} static func "
- "sortVectorOf{{SHORT_VALUENAME}}(offsets:[Offset<UOffset>], "
- "_ fbb: inout FlatBufferBuilder) -> Offset<UOffset> {";
+ "sortVectorOf{{SHORT_VALUENAME}}(offsets:[Offset], "
+ "_ fbb: inout FlatBufferBuilder) -> Offset {";
Indent();
code_ += spacing + "var off = offsets";
code_ +=
@@ -495,24 +579,22 @@
void GenTableWriterFields(const FieldDef &field,
std::vector<std::string> *create_body,
- std::vector<std::string> *create_header,
- bool &contains_structs) {
+ std::vector<std::string> *create_header) {
std::string builder_string = ", _ fbb: inout FlatBufferBuilder) { ";
auto &create_func_body = *create_body;
auto &create_func_header = *create_header;
auto name = Name(field);
auto type = GenType(field.value.type);
- bool opt_scalar = field.optional && IsScalar(field.value.type.base_type);
+ auto opt_scalar =
+ field.IsOptional() && IsScalar(field.value.type.base_type);
auto nullable_type = opt_scalar ? type + "?" : type;
code_.SetValue("VALUENAME", name);
code_.SetValue("VALUETYPE", nullable_type);
code_.SetValue("OFFSET", name);
code_.SetValue("CONSTANT", field.value.constant);
std::string check_if_vector =
- (IsVector(field.value.type) ||
- IsArray(field.value.type))
- ? "VectorOf("
- : "(";
+ (IsVector(field.value.type) || IsArray(field.value.type)) ? "VectorOf("
+ : "(";
auto body = "add" + check_if_vector + name + ": ";
code_ += "{{ACCESS_TYPE}} static func " + body + "\\";
@@ -526,17 +608,18 @@
code_ +=
"{{VALUETYPE}}" + builder_string + "fbb.add(element: {{VALUENAME}}\\";
- code_ += field.optional ? (optional_enum + "\\")
- : (is_enum + ", def: {{CONSTANT}}\\");
+ code_ += field.IsOptional() ? (optional_enum + "\\")
+ : (is_enum + ", def: {{CONSTANT}}\\");
code_ += ", at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
auto default_value =
IsEnum(field.value.type)
- ? (field.optional ? "nil" : GenEnumDefaultValue(field))
+ ? (field.IsOptional() ? "nil" : GenEnumDefaultValue(field))
: field.value.constant;
- create_func_header.push_back("" + name + ": " + nullable_type + " = " +
- (field.optional ? "nil" : default_value));
+ create_func_header.push_back(
+ "" + name + ": " + nullable_type + " = " +
+ (field.IsOptional() ? "nil" : default_value));
return;
}
@@ -545,64 +628,69 @@
"0" == field.value.constant ? "false" : "true";
code_.SetValue("CONSTANT", default_value);
- code_.SetValue("VALUETYPE", field.optional ? "Bool?" : "Bool");
+ code_.SetValue("VALUETYPE", field.IsOptional() ? "Bool?" : "Bool");
code_ += "{{VALUETYPE}}" + builder_string +
"fbb.add(element: {{VALUENAME}},\\";
- code_ += field.optional ? "\\" : " def: {{CONSTANT}},";
+ code_ += field.IsOptional() ? "\\" : " def: {{CONSTANT}},";
code_ += " at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
- create_func_header.push_back(name + ": " + nullable_type + " = " +
- (field.optional ? "nil" : default_value));
+ create_func_header.push_back(
+ name + ": " + nullable_type + " = " +
+ (field.IsOptional() ? "nil" : default_value));
return;
}
if (IsStruct(field.value.type)) {
- contains_structs = false;
- auto struct_type = "Offset<UOffset>?";
- auto camel_case_name = "structOf" + MakeCamel(name, true);
- auto reader_type =
- "fbb.add(structOffset: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
- auto create_struct = "guard {{VALUENAME}} != nil else { return }; ";
- code_ += struct_type + builder_string + create_struct + reader_type;
+ auto create_struct =
+ "guard let {{VALUENAME}} = {{VALUENAME}} else { return };"
+ " fbb.create(struct: {{VALUENAME}}, position: "
+ "{{TABLEOFFSET}}.{{OFFSET}}.p) }";
+ code_ += type + "?" + builder_string + create_struct;
+ /// Optional hard coded since structs are always optional
+ create_func_header.push_back(name + ": " + type + "? = nil");
return;
}
- auto offset_type = IsString(field.value.type)
- ? "Offset<String>"
- : "Offset<UOffset>";
auto camel_case_name =
- (IsVector(field.value.type) ||
- IsArray(field.value.type)
- ? "vectorOf"
- : "offsetOf") +
- MakeCamel(name, true);
+ ConvertCase(name, Case::kLowerCamel) +
+ (IsVector(field.value.type) || IsArray(field.value.type)
+ ? "VectorOffset"
+ : "Offset");
create_func_header.push_back(camel_case_name + " " + name + ": " +
- offset_type + " = Offset()");
+ "Offset = Offset()");
auto reader_type =
IsStruct(field.value.type) && field.value.type.struct_def->fixed
? "structOffset: {{TABLEOFFSET}}.{{OFFSET}}.p) }"
: "offset: {{VALUENAME}}, at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
- code_ += offset_type + builder_string + "fbb.add(" + reader_type;
+ code_ += "Offset" + builder_string + "fbb.add(" + reader_type;
auto vectortype = field.value.type.VectorType();
if ((vectortype.base_type == BASE_TYPE_STRUCT &&
field.value.type.struct_def->fixed) &&
- (IsVector(field.value.type) ||
- IsArray(field.value.type))) {
+ (IsVector(field.value.type) || IsArray(field.value.type))) {
auto field_name = NameWrappedInNameSpace(*vectortype.struct_def);
- code_ += "public static func startVectorOf" + MakeCamel(name, true) +
+ code_ += "public static func startVectorOf" +
+ ConvertCase(name, Case::kUpperCamel) +
"(_ size: Int, in builder: inout "
"FlatBufferBuilder) {";
Indent();
- code_ += "builder.startVectorOfStructs(count: size, size: " + field_name +
- ".size, "
- "alignment: " +
- field_name + ".alignment)";
+ code_ += "builder.startVector(size * MemoryLayout<" + field_name +
+ ">.size, elementSize: MemoryLayout<" + field_name +
+ ">.alignment)";
Outdent();
code_ += "}";
}
}
+ void GenTableReader(const StructDef &struct_def) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ GenTableReaderFields(field);
+ }
+ }
+
void GenTableReaderFields(const FieldDef &field) {
auto offset = NumToString(field.value.offset);
auto name = Name(field);
@@ -611,7 +699,8 @@
code_.SetValue("VALUETYPE", type);
code_.SetValue("OFFSET", name);
code_.SetValue("CONSTANT", field.value.constant);
- bool opt_scalar = field.optional && IsScalar(field.value.type.base_type);
+ bool opt_scalar =
+ field.IsOptional() && IsScalar(field.value.type.base_type);
std::string def_Val = opt_scalar ? "nil" : "{{CONSTANT}}";
std::string optional = opt_scalar ? "?" : "";
auto const_string = "return o == 0 ? " + def_Val + " : ";
@@ -626,7 +715,8 @@
if (IsBool(field.value.type.base_type)) {
std::string default_value =
- "0" == field.value.constant ? "false" : "true";
+ field.IsOptional() ? "nil"
+ : ("0" == field.value.constant ? "false" : "true");
code_.SetValue("CONSTANT", default_value);
code_.SetValue("VALUETYPE", "Bool");
code_ += GenReaderMainBody(optional) + "\\";
@@ -638,7 +728,8 @@
}
if (IsEnum(field.value.type)) {
- auto default_value = field.optional ? "nil" : GenEnumDefaultValue(field);
+ auto default_value =
+ field.IsOptional() ? "nil" : GenEnumDefaultValue(field);
code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
code_ += GenReaderMainBody(optional) + "\\";
code_ += GenOffset() + "return o == 0 ? " + default_value + " : " +
@@ -648,13 +739,19 @@
return;
}
- std::string is_required = field.required ? "!" : "?";
- auto required_reader = field.required ? "return " : const_string;
+ std::string is_required = field.IsRequired() ? "!" : "?";
+ auto required_reader = field.IsRequired() ? "return " : const_string;
if (IsStruct(field.value.type) && field.value.type.struct_def->fixed) {
code_.SetValue("VALUETYPE", GenType(field.value.type));
code_.SetValue("CONSTANT", "nil");
code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader +
+ "{{ACCESS}}.readBuffer(of: {{VALUETYPE}}.self, at: o) }";
+ code_.SetValue("VALUENAME",
+ "mutable" + ConvertCase(name, Case::kUpperCamel));
+ code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
+ code_.SetValue("CONSTANT", "nil");
+ code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader +
GenConstructor("o + {{ACCESS}}.postion");
return;
}
@@ -667,9 +764,10 @@
GenConstructor(GenIndirect("o + {{ACCESS}}.postion"));
break;
- case BASE_TYPE_STRING:
+ case BASE_TYPE_STRING: {
+ auto default_string = "\"" + field.value.constant + "\"";
code_.SetValue("VALUETYPE", GenType(field.value.type));
- code_.SetValue("CONSTANT", "nil");
+ code_.SetValue("CONSTANT", field.IsDefault() ? default_string : "nil");
code_ += GenReaderMainBody(is_required) + GenOffset() +
required_reader + "{{ACCESS}}.string(at: o) }";
code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}SegmentArray: [UInt8]" +
@@ -677,15 +775,14 @@
" { return "
"{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) }";
break;
-
+ }
case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
- case BASE_TYPE_VECTOR:
- GenTableReaderVectorFields(field, const_string);
- break;
+ case BASE_TYPE_VECTOR: GenTableReaderVectorFields(field); break;
case BASE_TYPE_UNION:
code_.SetValue("CONSTANT", "nil");
code_ +=
- "{{ACCESS_TYPE}} func {{VALUENAME}}<T: FlatBufferObject>(type: "
+ "{{ACCESS_TYPE}} func {{VALUENAME}}<T: "
+ "FlatbuffersInitializable>(type: "
"T.Type) -> T" +
is_required + " { " + GenOffset() + required_reader +
"{{ACCESS}}.union(o) }";
@@ -694,33 +791,33 @@
}
}
- void GenTableReaderVectorFields(const FieldDef &field,
- const std::string &const_string) {
+ void GenTableReaderVectorFields(const FieldDef &field) {
+ std::string const_string = "return o == 0 ? {{CONSTANT}} : ";
auto vectortype = field.value.type.VectorType();
code_.SetValue("SIZE", NumToString(InlineSize(vectortype)));
code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}Count: Int32 { " + GenOffset() +
- const_string + "{{ACCESS}}.vector(count: o) }";
- code_.SetValue("CONSTANT", IsScalar(vectortype.base_type) == true
- ? field.value.constant
- : "nil");
+ "return o == 0 ? 0 : {{ACCESS}}.vector(count: o) }";
+ code_.SetValue("CONSTANT",
+ IsScalar(vectortype.base_type) == true ? "0" : "nil");
auto nullable = IsScalar(vectortype.base_type) == true ? "" : "?";
nullable = IsEnum(vectortype) == true ? "?" : nullable;
+
if (vectortype.base_type != BASE_TYPE_UNION) {
code_ += GenArrayMainBody(nullable) + GenOffset() + "\\";
} else {
code_ +=
- "{{ACCESS_TYPE}} func {{VALUENAME}}<T: FlatBufferObject>(at index: "
+ "{{ACCESS_TYPE}} func {{VALUENAME}}<T: FlatbuffersInitializable>(at "
+ "index: "
"Int32, type: T.Type) -> T? { " +
GenOffset() + "\\";
}
if (IsBool(vectortype.base_type)) {
code_.SetValue("CONSTANT", field.value.offset == 0 ? "false" : "true");
- code_.SetValue("VALUETYPE", "Byte");
+ code_.SetValue("VALUETYPE", "Bool");
}
- if (!IsEnum(vectortype))
- code_ +=
- const_string + (IsBool(vectortype.base_type) ? "0 != " : "") + "\\";
+
+ if (!IsEnum(vectortype)) code_ += const_string + "\\";
if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) &&
!IsBool(field.value.type.base_type)) {
@@ -733,9 +830,18 @@
if (parser_.opts.mutable_buffer) code_ += GenMutateArray();
return;
}
+
if (vectortype.base_type == BASE_TYPE_STRUCT &&
field.value.type.struct_def->fixed) {
- code_ += GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}");
+ code_ +=
+ "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
+ "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
+ code_.SetValue("VALUENAME",
+ "mutable" + ConvertCase(Name(field), Case::kUpperCamel));
+ code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
+ code_ += GenArrayMainBody(nullable) + GenOffset() + const_string +
+ GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}");
+
return;
}
@@ -778,6 +884,272 @@
}
}
+ void GenerateCodingKeys(const StructDef &struct_def) {
+ code_ += "enum CodingKeys: String, CodingKey {";
+ Indent();
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto name = Name(field);
+
+ code_.SetValue("RAWVALUENAME", field.name);
+ code_.SetValue("VALUENAME", name);
+ code_ += "case {{VALUENAME}} = \"{{RAWVALUENAME}}\"";
+ }
+ Outdent();
+ code_ += "}";
+ }
+
+ void GenerateEncoderUnionBody(const FieldDef &field) {
+ EnumDef &union_def = *field.value.type.enum_def;
+ auto is_vector = field.value.type.base_type == BASE_TYPE_VECTOR ||
+ field.value.type.base_type == BASE_TYPE_ARRAY;
+ if (field.value.type.base_type == BASE_TYPE_UTYPE ||
+ (is_vector &&
+ field.value.type.VectorType().base_type == BASE_TYPE_UTYPE))
+ return;
+ if (is_vector) {
+ code_ +=
+ "var enumsEncoder = container.nestedUnkeyedContainer(forKey: "
+ ".{{VALUENAME}}Type)";
+ code_ +=
+ "var contentEncoder = container.nestedUnkeyedContainer(forKey: "
+ ".{{VALUENAME}})";
+ code_ += "for index in 0..<{{VALUENAME}}Count {";
+ Indent();
+ code_ +=
+ "guard let type = {{VALUENAME}}Type(at: index) else { continue }";
+ code_ += "try enumsEncoder.encode(type)";
+ code_ += "switch type {";
+ for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+
+ auto name = Name(ev);
+ auto type = GenType(ev.union_type);
+ code_.SetValue("KEY", name);
+ code_.SetValue("VALUETYPE", type);
+ if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
+ code_ += "case .{{KEY}}:";
+ Indent();
+ code_ += "let _v = {{VALUENAME}}(at: index, type: {{VALUETYPE}}.self)";
+ code_ += "try contentEncoder.encode(_v)";
+ Outdent();
+ }
+ code_ += "default: break;";
+ code_ += "}";
+ Outdent();
+ code_ += "}";
+ return;
+ }
+
+ code_ += "switch {{VALUENAME}}Type {";
+ for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+
+ auto name = Name(ev);
+ auto type = GenType(ev.union_type);
+ code_.SetValue("KEY", name);
+ code_.SetValue("VALUETYPE", type);
+ if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
+ code_ += "case .{{KEY}}:";
+ Indent();
+ code_ += "let _v = {{VALUENAME}}(type: {{VALUETYPE}}.self)";
+ code_ += "try container.encodeIfPresent(_v, forKey: .{{VALUENAME}})";
+ Outdent();
+ }
+ code_ += "default: break;";
+ code_ += "}";
+ }
+
+ void GenerateEncoderBody(const StructDef &struct_def) {
+ code_ += "var container = encoder.container(keyedBy: CodingKeys.self)";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto name = Name(field);
+ auto type = field.value.type;
+
+ auto is_non_union_vector =
+ (field.value.type.base_type == BASE_TYPE_ARRAY ||
+ field.value.type.base_type == BASE_TYPE_VECTOR) &&
+ field.value.type.VectorType().base_type != BASE_TYPE_UTYPE;
+
+ code_.SetValue("RAWVALUENAME", field.name);
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("CONSTANT", field.value.constant);
+ bool should_indent = true;
+ if (is_non_union_vector) {
+ code_ += "if {{VALUENAME}}Count > 0 {";
+ } else if (IsEnum(type) && !field.IsOptional()) {
+ code_.SetValue("CONSTANT", GenEnumDefaultValue(field));
+ code_ += "if {{VALUENAME}} != {{CONSTANT}} {";
+ } else if (IsScalar(type.base_type) && !IsEnum(type) &&
+ !IsBool(type.base_type) && !field.IsOptional()) {
+ code_ += "if {{VALUENAME}} != {{CONSTANT}} {";
+ } else if (IsBool(type.base_type) && !field.IsOptional()) {
+ std::string default_value =
+ "0" == field.value.constant ? "false" : "true";
+ code_.SetValue("CONSTANT", default_value);
+ code_ += "if {{VALUENAME}} != {{CONSTANT}} {";
+ } else {
+ should_indent = false;
+ }
+ if (should_indent) Indent();
+
+ if (IsUnion(type) && !IsEnum(type)) {
+ GenerateEncoderUnionBody(field);
+ } else if (is_non_union_vector &&
+ (!IsScalar(type.VectorType().base_type) ||
+ IsEnum(type.VectorType()))) {
+ code_ +=
+ "var contentEncoder = container.nestedUnkeyedContainer(forKey: "
+ ".{{VALUENAME}})";
+ code_ += "for index in 0..<{{VALUENAME}}Count {";
+ Indent();
+ code_ += "guard let type = {{VALUENAME}}(at: index) else { continue }";
+ code_ += "try contentEncoder.encode(type)";
+ Outdent();
+ code_ += "}";
+ } else {
+ code_ +=
+ "try container.encodeIfPresent({{VALUENAME}}, forKey: "
+ ".{{VALUENAME}})";
+ }
+ if (should_indent) Outdent();
+
+ if (is_non_union_vector ||
+ (IsScalar(type.base_type) && !field.IsOptional())) {
+ code_ += "}";
+ }
+ }
+ }
+
+ void GenerateJSONEncodingAPIs(const StructDef &struct_def) {
+ code_ += "extension {{STRUCTNAME}}: Encodable {";
+ Indent();
+ code_ += "";
+ if (struct_def.fields.vec.empty() == false) GenerateCodingKeys(struct_def);
+
+ code_ += "public func encode(to encoder: Encoder) throws {";
+ Indent();
+ if (struct_def.fields.vec.empty() == false) GenerateEncoderBody(struct_def);
+ Outdent();
+ code_ += "}";
+ Outdent();
+ code_ += "}";
+ code_ += "";
+ }
+
+ void GenerateVerifier(const StructDef &struct_def) {
+ code_ +=
+ "public static func verify<T>(_ verifier: inout Verifier, at position: "
+ "Int, of type: T.Type) throws where T: Verifiable {";
+ Indent();
+ code_ += "var _v = try verifier.visitTable(at: position)";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto offset = NumToString(field.value.offset);
+ auto name = Name(field);
+
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", GenerateVerifierType(field));
+ code_.SetValue("OFFSET", name);
+ code_.SetValue("ISREQUIRED", field.IsRequired() ? "true" : "false");
+
+ if (IsUnion(field.value.type)) {
+ GenerateUnionTypeVerifier(field);
+ continue;
+ }
+
+ code_ +=
+ "try _v.visit(field: {{TABLEOFFSET}}.{{OFFSET}}.p, fieldName: "
+ "\"{{VALUENAME}}\", required: {{ISREQUIRED}}, type: "
+ "{{VALUETYPE}}.self)";
+ }
+ code_ += "_v.finish()";
+ Outdent();
+ code_ += "}";
+ }
+
+ void GenerateUnionTypeVerifier(const FieldDef &field) {
+ auto is_vector = IsVector(field.value.type) || IsArray(field.value.type);
+ if (field.value.type.base_type == BASE_TYPE_UTYPE ||
+ (is_vector &&
+ field.value.type.VectorType().base_type == BASE_TYPE_UTYPE))
+ return;
+ EnumDef &union_def = *field.value.type.enum_def;
+ code_.SetValue("VALUETYPE", NameWrappedInNameSpace(union_def));
+ code_.SetValue("FUNCTION_NAME", is_vector ? "visitUnionVector" : "visit");
+ code_ +=
+ "try _v.{{FUNCTION_NAME}}(unionKey: {{TABLEOFFSET}}.{{OFFSET}}Type.p, "
+ "unionField: {{TABLEOFFSET}}.{{OFFSET}}.p, unionKeyName: "
+ "\"{{VALUENAME}}Type\", fieldName: \"{{VALUENAME}}\", required: "
+ "{{ISREQUIRED}}, completion: { (verifier, key: {{VALUETYPE}}, pos) in";
+ Indent();
+ code_ += "switch key {";
+ for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+
+ auto name = Name(ev);
+ auto type = GenType(ev.union_type);
+ code_.SetValue("KEY", name);
+ code_.SetValue("VALUETYPE", type);
+ code_ += "case .{{KEY}}:";
+ Indent();
+ if (ev.union_type.base_type == BASE_TYPE_NONE) {
+ code_ += "break // NOTE - SWIFT doesnt support none";
+ } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ code_ +=
+ "try ForwardOffset<String>.verify(&verifier, at: pos, of: "
+ "String.self)";
+ } else {
+ code_.SetValue("MAINTYPE", ev.union_type.struct_def->fixed
+ ? type
+ : "ForwardOffset<" + type + ">");
+ code_ +=
+ "try {{MAINTYPE}}.verify(&verifier, at: pos, of: "
+ "{{VALUETYPE}}.self)";
+ }
+ Outdent();
+ }
+ code_ += "}";
+ Outdent();
+ code_ += "})";
+ }
+
+ std::string GenerateVerifierType(const FieldDef &field) {
+ auto type = field.value.type;
+ auto is_vector = IsVector(type) || IsArray(type);
+
+ if (is_vector) {
+ auto vector_type = field.value.type.VectorType();
+ return "ForwardOffset<Vector<" +
+ GenerateNestedVerifierTypes(vector_type) + ", " +
+ GenType(vector_type) + ">>";
+ }
+
+ return GenerateNestedVerifierTypes(field.value.type);
+ }
+
+ std::string GenerateNestedVerifierTypes(const Type &type) {
+ auto string_type = GenType(type);
+
+ if (IsScalar(type.base_type)) { return string_type; }
+
+ if (IsString(type)) { return "ForwardOffset<" + string_type + ">"; }
+
+ if (type.struct_def && type.struct_def->fixed) { return string_type; }
+
+ return "ForwardOffset<" + string_type + ">";
+ }
+
void GenByKeyFunctions(const FieldDef &key_field) {
code_.SetValue("TYPE", GenType(key_field.value.type));
code_ +=
@@ -788,54 +1160,27 @@
"{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }";
}
- // Generates the reader for swift
- void GenStructReader(const StructDef &struct_def) {
- auto is_private_access = struct_def.attributes.Lookup("private");
- code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
-
- GenObjectHeader(struct_def);
- for (auto it = struct_def.fields.vec.begin();
- it != struct_def.fields.vec.end(); ++it) {
- auto &field = **it;
- if (field.deprecated) continue;
- auto offset = NumToString(field.value.offset);
- auto name = Name(field);
- auto type = GenType(field.value.type);
- code_.SetValue("VALUENAME", name);
- code_.SetValue("VALUETYPE", type);
- code_.SetValue("OFFSET", offset);
- GenComment(field.doc_comment);
- if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type)) {
- code_ +=
- GenReaderMainBody() + "return " + GenReader("VALUETYPE") + " }";
- if (parser_.opts.mutable_buffer) code_ += GenMutate("{{OFFSET}}", "");
- } else if (IsEnum(field.value.type)) {
- code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
- code_ += GenReaderMainBody() + "return " +
- GenEnumConstructor("{{OFFSET}}") + "?? " +
- GenEnumDefaultValue(field) + " }";
- } else if (IsStruct(field.value.type)) {
- code_.SetValue("VALUETYPE", GenType(field.value.type));
- code_ += GenReaderMainBody() + "return " +
- GenConstructor("{{ACCESS}}.postion + {{OFFSET}}");
- }
- }
- if (parser_.opts.generate_object_based_api)
- GenerateObjectAPIStructExtension(struct_def);
- Outdent();
- code_ += "}\n";
- }
-
void GenEnum(const EnumDef &enum_def) {
if (enum_def.generated) return;
auto is_private_access = enum_def.attributes.Lookup("private");
+ code_.SetValue("ENUM_TYPE",
+ enum_def.is_union ? "UnionEnum" : "Enum, Verifiable");
code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
code_.SetValue("ENUM_NAME", NameWrappedInNameSpace(enum_def));
code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
GenComment(enum_def.doc_comment);
- code_ += "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, Enum { ";
+ code_ +=
+ "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, {{ENUM_TYPE}} {";
Indent();
code_ += "{{ACCESS_TYPE}} typealias T = {{BASE_TYPE}}";
+ if (enum_def.is_union) {
+ code_ += "";
+ code_ += "{{ACCESS_TYPE}} init?(value: T) {";
+ Indent();
+ code_ += "self.init(rawValue: value)";
+ Outdent();
+ code_ += "}\n";
+ }
code_ +=
"{{ACCESS_TYPE}} static var byteSize: Int { return "
"MemoryLayout<{{BASE_TYPE}}>.size "
@@ -850,17 +1195,20 @@
GenComment(ev.doc_comment);
code_ += "case {{KEY}} = {{VALUE}}";
}
- code_ += "\n";
+ code_ += "";
AddMinOrMaxEnumValue(Name(*enum_def.MaxValue()), "max");
AddMinOrMaxEnumValue(Name(*enum_def.MinValue()), "min");
Outdent();
code_ += "}\n";
+ if (parser_.opts.gen_json_coders) EnumEncoder(enum_def);
+ code_ += "";
if (parser_.opts.generate_object_based_api && enum_def.is_union) {
code_ += "{{ACCESS_TYPE}} struct {{ENUM_NAME}}Union {";
Indent();
code_ += "{{ACCESS_TYPE}} var type: {{ENUM_NAME}}";
- code_ += "{{ACCESS_TYPE}} var value: NativeTable?";
- code_ += "{{ACCESS_TYPE}} init(_ v: NativeTable?, type: {{ENUM_NAME}}) {";
+ code_ += "{{ACCESS_TYPE}} var value: NativeObject?";
+ code_ +=
+ "{{ACCESS_TYPE}} init(_ v: NativeObject?, type: {{ENUM_NAME}}) {";
Indent();
code_ += "self.type = type";
code_ += "self.value = v";
@@ -868,7 +1216,7 @@
code_ += "}";
code_ +=
"{{ACCESS_TYPE}} func pack(builder: inout FlatBufferBuilder) -> "
- "Offset<UOffset> {";
+ "Offset {";
Indent();
BuildUnionEnumSwitchCaseWritter(enum_def);
Outdent();
@@ -878,9 +1226,82 @@
}
}
+ void EnumEncoder(const EnumDef &enum_def) {
+ code_ += "extension {{ENUM_NAME}}: Encodable {";
+ Indent();
+ code_ += "{{ACCESS_TYPE}} func encode(to encoder: Encoder) throws {";
+ Indent();
+ code_ += "var container = encoder.singleValueContainer()";
+ code_ += "switch self {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+ auto name = Name(ev);
+ code_.SetValue("KEY", name);
+ code_.SetValue("RAWKEY", ev.name);
+ code_ += "case .{{KEY}}: try container.encode(\"{{RAWKEY}}\")";
+ }
+ code_ += "}";
+ Outdent();
+ code_ += "}";
+ Outdent();
+ code_ += "}";
+ }
+
+ // MARK: - Object API
+
+ void GenerateObjectAPIExtensionHeader(std::string name) {
+ code_ += "\n";
+ code_ += "{{ACCESS_TYPE}} mutating func unpack() -> " + name + " {";
+ Indent();
+ code_ += "return " + name + "(&self)";
+ Outdent();
+ code_ += "}";
+ code_ +=
+ "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
+ "obj: "
+ "inout " +
+ name + "?) -> Offset {";
+ Indent();
+ code_ += "guard var obj = obj else { return Offset() }";
+ code_ += "return pack(&builder, obj: &obj)";
+ Outdent();
+ code_ += "}";
+ code_ += "";
+ code_ +=
+ "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
+ "obj: "
+ "inout " +
+ name + ") -> Offset {";
+ Indent();
+ }
+
+ void GenerateObjectAPIStructConstructor(const StructDef &struct_def) {
+ code_ +=
+ "{{ACCESS_TYPE}} init(_ _t: inout {{STRUCTNAME}}" + Mutable() + ") {";
+ Indent();
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ if (IsStruct(field.value.type)) {
+ code_ += "var _v{{VALUENAME}} = _t.{{VALUENAME}}";
+ code_ += "_{{VALUENAME}} = _v{{VALUENAME}}.unpack()";
+ continue;
+ }
+ std::string is_enum = IsEnum(field.value.type) ? ".value" : "";
+ code_ += "_{{VALUENAME}} = _t.{{VALUENAME}}" + is_enum;
+ }
+ Outdent();
+ code_ += "}\n";
+ }
+
void GenObjectAPI(const StructDef &struct_def) {
code_ += "{{ACCESS_TYPE}} class " + ObjectAPIName("{{STRUCTNAME}}") +
- ": NativeTable {\n";
+ ": NativeObject {\n";
std::vector<std::string> buffer_constructor;
std::vector<std::string> base_constructor;
Indent();
@@ -892,10 +1313,9 @@
base_constructor);
}
code_ += "";
- BuildObjectAPIConstructor(
- buffer_constructor,
- "_ _t: inout " + NameWrappedInNameSpace(struct_def));
- BuildObjectAPIConstructor(base_constructor);
+ BuildObjectConstructor(buffer_constructor,
+ "_ _t: inout " + NameWrappedInNameSpace(struct_def));
+ BuildObjectConstructor(base_constructor);
if (!struct_def.fixed)
code_ +=
"{{ACCESS_TYPE}} func serialize() -> ByteBuffer { return "
@@ -906,7 +1326,7 @@
}
void GenerateObjectAPITableExtension(const StructDef &struct_def) {
- GenerateObjectAPIExtensionHeader();
+ GenerateObjectAPIExtensionHeader(ObjectAPIName("{{STRUCTNAME}}"));
std::vector<std::string> unpack_body;
std::string builder = ", &builder)";
for (auto it = struct_def.fields.vec.begin();
@@ -916,8 +1336,7 @@
auto name = Name(field);
auto type = GenType(field.value.type);
std::string check_if_vector =
- (IsVector(field.value.type) ||
- IsArray(field.value.type))
+ (IsVector(field.value.type) || IsArray(field.value.type))
? "VectorOf("
: "(";
std::string body = "add" + check_if_vector + name + ": ";
@@ -944,16 +1363,13 @@
if (field.value.type.struct_def &&
field.value.type.struct_def->fixed) {
// This is a Struct (IsStruct), not a table. We create
- // UnsafeMutableRawPointer in this case.
+ // a native swift object in this case.
std::string code;
GenerateStructArgs(*field.value.type.struct_def, &code, "", "",
"$0", true);
code = code.substr(0, code.size() - 2);
- unpack_body.push_back(
- "{{STRUCTNAME}}." + body + "obj." + name + ".map { " +
- NameWrappedInNameSpace(*field.value.type.struct_def) +
- ".create" + Name(*field.value.type.struct_def) +
- "(builder: &builder, " + code + ") }" + builder);
+ unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." + name +
+ builder);
} else {
code_ += "let __" + name + " = " + type +
".pack(&builder, obj: &obj." + name + ")";
@@ -965,12 +1381,11 @@
case BASE_TYPE_STRING: {
unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
builder);
- if (field.required) {
+ if (field.IsRequired()) {
code_ +=
"let __" + name + " = builder.create(string: obj." + name + ")";
} else {
- BuildingOptionalObjects(name, "String",
- "builder.create(string: s)");
+ BuildingOptionalObjects(name, "builder.create(string: s)");
}
break;
}
@@ -996,7 +1411,7 @@
auto vectortype = field.value.type.VectorType();
switch (vectortype.base_type) {
case BASE_TYPE_UNION: {
- code_ += "var __" + name + "__: [Offset<UOffset>] = []";
+ code_ += "var __" + name + "__: [Offset] = []";
code_ += "for i in obj." + name + " {";
Indent();
code_ += "guard let off = i?.pack(builder: &builder) else { continue }";
@@ -1013,7 +1428,7 @@
case BASE_TYPE_STRUCT: {
if (field.value.type.struct_def &&
!field.value.type.struct_def->fixed) {
- code_ += "var __" + name + "__: [Offset<UOffset>] = []";
+ code_ += "var __" + name + "__: [Offset] = []";
code_ += "for var i in obj." + name + " {";
Indent();
code_ +=
@@ -1023,8 +1438,9 @@
code_ += "let __" + name + " = builder.createVector(ofOffsets: __" +
name + "__)";
} else {
- code_ += "{{STRUCTNAME}}.startVectorOf" + MakeCamel(name, true) +
- "(obj." + name + ".count, in: &builder)";
+ code_ += "{{STRUCTNAME}}.startVectorOf" +
+ ConvertCase(name, Case::kUpperCamel) + "(obj." + name +
+ ".count, in: &builder)";
std::string code;
GenerateStructArgs(*field.value.type.struct_def, &code, "", "", "_o",
true);
@@ -1032,13 +1448,10 @@
code_ += "for i in obj." + name + " {";
Indent();
code_ += "guard let _o = i else { continue }";
- code_ += NameWrappedInNameSpace(*field.value.type.struct_def) +
- ".create" + Name(*field.value.type.struct_def) +
- "(builder: &builder, " + code + ")";
+ code_ += "builder.create(struct: _o)";
Outdent();
code_ += "}";
- code_ += "let __" + name +
- " = builder.endVectorOfStructs(count: obj." + name +
+ code_ += "let __" + name + " = builder.endVector(len: obj." + name +
".count)";
}
break;
@@ -1056,23 +1469,22 @@
}
void BuildingOptionalObjects(const std::string &name,
- const std::string &object_type,
const std::string &body_front) {
- code_ += "let __" + name + ": Offset<" + object_type + ">";
+ code_ += "let __" + name + ": Offset";
code_ += "if let s = obj." + name + " {";
Indent();
code_ += "__" + name + " = " + body_front;
Outdent();
code_ += "} else {";
Indent();
- code_ += "__" + name + " = Offset<" + object_type + ">()";
+ code_ += "__" + name + " = Offset()";
Outdent();
code_ += "}";
code_ += "";
}
- void BuildObjectAPIConstructor(const std::vector<std::string> &body,
- const std::string &header = "") {
+ void BuildObjectConstructor(const std::vector<std::string> &body,
+ const std::string &header = "") {
code_.SetValue("HEADER", header);
code_ += "{{ACCESS_TYPE}} init({{HEADER}}) {";
Indent();
@@ -1089,24 +1501,29 @@
auto type = GenType(field.value.type);
code_.SetValue("VALUENAME", name);
code_.SetValue("VALUETYPE", type);
- std::string is_required = field.required ? "" : "?";
+ std::string is_required = field.IsRequired() ? "" : "?";
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT: {
type = GenType(field.value.type, true);
code_.SetValue("VALUETYPE", type);
- buffer_constructor.push_back("var __" + name + " = _t." + name);
auto optional =
(field.value.type.struct_def && field.value.type.struct_def->fixed);
std::string question_mark =
- (field.required || (optional && is_fixed) ? "" : "?");
+ (field.IsRequired() || (optional && is_fixed) ? "" : "?");
code_ +=
"{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + question_mark;
- buffer_constructor.push_back("" + name + " = __" + name +
- (field.required ? "!" : question_mark) +
- ".unpack()");
base_constructor.push_back("" + name + " = " + type + "()");
+
+ if (field.value.type.struct_def->fixed) {
+ buffer_constructor.push_back("" + name + " = _t." + name);
+ } else {
+ buffer_constructor.push_back("var __" + name + " = _t." + name);
+ buffer_constructor.push_back(
+ "" + name + " = __" + name +
+ (field.IsRequired() ? "!" : question_mark) + ".unpack()");
+ }
break;
}
case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
@@ -1118,7 +1535,17 @@
case BASE_TYPE_STRING: {
code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: String" + is_required;
buffer_constructor.push_back(name + " = _t." + name);
- if (field.required) base_constructor.push_back(name + " = \"\"");
+
+ if (field.IsRequired()) {
+ std::string default_value =
+ field.IsDefault() ? field.value.constant : "";
+ base_constructor.push_back(name + " = \"" + default_value + "\"");
+ break;
+ }
+ if (field.IsDefault() && !field.IsRequired()) {
+ std::string value = field.IsDefault() ? field.value.constant : "nil";
+ base_constructor.push_back(name + " = \"" + value + "\"");
+ }
break;
}
case BASE_TYPE_UTYPE: break;
@@ -1129,12 +1556,12 @@
}
default: {
buffer_constructor.push_back(name + " = _t." + name);
- std::string nullable = field.optional ? "?" : "";
+ std::string nullable = field.IsOptional() ? "?" : "";
if (IsScalar(field.value.type.base_type) &&
!IsBool(field.value.type.base_type) && !IsEnum(field.value.type)) {
code_ +=
"{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + nullable;
- if (!field.optional)
+ if (!field.IsOptional())
base_constructor.push_back(name + " = " + field.value.constant);
break;
}
@@ -1152,7 +1579,7 @@
code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: Bool" + nullable;
std::string default_value =
"0" == field.value.constant ? "false" : "true";
- if (!field.optional)
+ if (!field.IsOptional())
base_constructor.push_back(name + " = " + default_value);
}
}
@@ -1176,10 +1603,15 @@
case BASE_TYPE_STRUCT: {
code_.SetValue("VALUETYPE", GenType(vectortype, true));
code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}?]";
- buffer_constructor.push_back(indentation + "var __v_ = _t." + name +
- "(at: index)");
- buffer_constructor.push_back(indentation + name +
- ".append(__v_?.unpack())");
+ if (!vectortype.struct_def->fixed) {
+ buffer_constructor.push_back(indentation + "var __v_ = _t." + name +
+ "(at: index)");
+ buffer_constructor.push_back(indentation + name +
+ ".append(__v_?.unpack())");
+ } else {
+ buffer_constructor.push_back(indentation + name + ".append(_t." +
+ name + "(at: index))");
+ }
break;
}
case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
@@ -1193,9 +1625,9 @@
}
case BASE_TYPE_UTYPE: break;
default: {
- code_.SetValue("VALUETYPE", (IsString(vectortype)
- ? "String?"
- : GenType(vectortype)));
+ code_.SetValue(
+ "VALUETYPE",
+ (IsString(vectortype) ? "String?" : GenType(vectortype)));
code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}]";
if (IsEnum(vectortype) && vectortype.base_type != BASE_TYPE_UNION) {
@@ -1223,15 +1655,12 @@
auto field = **it;
auto ev_name = Name(field);
auto type = GenType(field.union_type);
-
- if (field.union_type.base_type == BASE_TYPE_NONE ||
- IsString(field.union_type)) {
- continue;
- }
+ auto is_struct = IsStruct(field.union_type) ? type + Mutable() : type;
+ if (field.union_type.base_type == BASE_TYPE_NONE) { continue; }
code_ += "case ." + ev_name + ":";
Indent();
code_ += "var __obj = value as? " + GenType(field.union_type, true);
- code_ += "return " + type + ".pack(&builder, obj: &__obj)";
+ code_ += "return " + is_struct + ".pack(&builder, obj: &__obj)";
Outdent();
}
code_ += "default: return Offset()";
@@ -1254,19 +1683,18 @@
for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) {
auto field = **it;
auto ev_name = Name(field);
- if (field.union_type.base_type == BASE_TYPE_NONE ||
- IsString(field.union_type)) {
- continue;
- }
+ if (field.union_type.base_type == BASE_TYPE_NONE) { continue; }
+ auto type = IsStruct(field.union_type)
+ ? GenType(field.union_type) + Mutable()
+ : GenType(field.union_type);
buffer_constructor.push_back(indentation + "case ." + ev_name + ":");
buffer_constructor.push_back(
- indentation + " var _v = _t." + name + (is_vector ? "" : "(") +
- vector_reader + (is_vector ? ", " : "") +
- "type: " + GenType(field.union_type) + ".self)");
+ indentation + " var _v = _t." + name + (is_vector ? "" : "(") +
+ vector_reader + (is_vector ? ", " : "") + "type: " + type + ".self)");
auto constructor =
field_name + "Union(_v?.unpack(), type: ." + ev_name + ")";
buffer_constructor.push_back(
- indentation + " " + name +
+ indentation + " " + name +
(is_vector ? ".append(" + constructor + ")" : " = " + constructor));
}
buffer_constructor.push_back(indentation + "default: break");
@@ -1330,6 +1758,19 @@
code_ += "}";
}
+ inline void GenPadding(const FieldDef &field, int *id) {
+ if (field.padding) {
+ for (int i = 0; i < 4; i++) {
+ if (static_cast<int>(field.padding) & (1 << i)) {
+ auto bits = (1 << i) * 8;
+ code_ += "private let padding" + NumToString((*id)++) + "__: UInt" +
+ NumToString(bits) + " = 0";
+ }
+ }
+ FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
+ }
+ }
+
void GenComment(const std::vector<std::string> &dc) {
if (dc.begin() == dc.end()) {
// Don't output empty comment blocks with 0 lines of comment content.
@@ -1377,7 +1818,9 @@
auto &value = field.value;
FLATBUFFERS_ASSERT(value.type.enum_def);
auto &enum_def = *value.type.enum_def;
- auto enum_val = enum_def.FindByValue(value.constant);
+ // Vector of enum defaults are always "[]" which never works.
+ const std::string constant = IsVector(value.type) ? "0" : value.constant;
+ auto enum_val = enum_def.FindByValue(constant);
std::string name;
if (enum_val) {
name = Name(*enum_val);
@@ -1393,7 +1836,7 @@
}
std::string ValidateFunc() {
- return "static func validateVersion() { FlatBuffersVersion_1_12_0() }";
+ return "static func validateVersion() { FlatBuffersVersion_2_0_0() }";
}
std::string GenType(const Type &type,
@@ -1411,14 +1854,14 @@
case BASE_TYPE_VECTOR: return GenType(type.VectorType());
case BASE_TYPE_STRUCT: {
auto &struct_ = *type.struct_def;
- if (should_consider_suffix) {
+ if (should_consider_suffix && !struct_.fixed) {
return WrapInNameSpace(struct_.defined_namespace,
ObjectAPIName(Name(struct_)));
}
return WrapInNameSpace(struct_.defined_namespace, Name(struct_));
}
case BASE_TYPE_UNION:
- default: return "FlatBufferObject";
+ default: return "FlatbuffersInitializable";
}
}
@@ -1463,16 +1906,18 @@
return keywords_.find(name) == keywords_.end() ? name : name + "_";
}
+ std::string Mutable() const { return "_Mutable"; }
+
std::string Name(const EnumVal &ev) const {
auto name = ev.name;
if (isupper(name.front())) {
std::transform(name.begin(), name.end(), name.begin(), CharToLower);
}
- return EscapeKeyword(MakeCamel(name, false));
+ return EscapeKeyword(ConvertCase(name, Case::kLowerCamel));
}
std::string Name(const Definition &def) const {
- return EscapeKeyword(MakeCamel(def.name, false));
+ return EscapeKeyword(ConvertCase(def.name, Case::kLowerCamel));
}
};
} // namespace swift
diff --git a/third_party/flatbuffers/src/idl_gen_text.cpp b/third_party/flatbuffers/src/idl_gen_text.cpp
index e4d2182..805e934 100644
--- a/third_party/flatbuffers/src/idl_gen_text.cpp
+++ b/third_party/flatbuffers/src/idl_gen_text.cpp
@@ -264,12 +264,18 @@
FLATBUFFERS_ASSERT(IsStruct(fd.value.type) || IsArray(fd.value.type));
val = reinterpret_cast<const Struct *>(table)->GetStruct<const void *>(
fd.value.offset);
- } else if (fd.flexbuffer) {
+ } else if (fd.flexbuffer && opts.json_nested_flexbuffers) {
+ // We could verify this FlexBuffer before access, but since this sits
+ // inside a FlatBuffer that we don't know wether it has been verified or
+ // not, there is little point making this part safer than the parent..
+ // The caller should really be verifying the whole.
+ // If the whole buffer is corrupt, we likely crash before we even get
+ // here.
auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
auto root = flexbuffers::GetRoot(vec->data(), vec->size());
root.ToString(true, opts.strict_json, text);
return true;
- } else if (fd.nested_flatbuffer) {
+ } else if (fd.nested_flatbuffer && opts.json_nested_flatbuffers) {
auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
auto root = GetRoot<Table>(vec->data());
return GenStruct(*fd.nested_flatbuffer, root, indent);
@@ -292,7 +298,7 @@
it != struct_def.fields.vec.end(); ++it) {
FieldDef &fd = **it;
auto is_present = struct_def.fixed || table->CheckField(fd.value.offset);
- auto output_anyway = opts.output_default_scalars_in_json &&
+ auto output_anyway = (opts.output_default_scalars_in_json || fd.key) &&
IsScalar(fd.value.type.base_type) && !fd.deprecated;
if (is_present || output_anyway) {
if (fieldout++) { AddComma(); }
diff --git a/third_party/flatbuffers/src/idl_gen_ts.cpp b/third_party/flatbuffers/src/idl_gen_ts.cpp
new file mode 100644
index 0000000..b97154c
--- /dev/null
+++ b/third_party/flatbuffers/src/idl_gen_ts.cpp
@@ -0,0 +1,1829 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+#include <algorithm>
+#include <cassert>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+struct ImportDefinition {
+ std::string name;
+ std::string import_statement;
+ std::string export_statement;
+ std::string bare_file_path;
+ std::string rel_file_path;
+ const Definition *dependent = nullptr;
+ const Definition *dependency = nullptr;
+};
+
+enum AnnotationType { kParam = 0, kType = 1, kReturns = 2 };
+
+namespace ts {
+// Iterate through all definitions we haven't generate code for (enums, structs,
+// and tables) and output them to a single file.
+class TsGenerator : public BaseGenerator {
+ public:
+ typedef std::map<std::string, ImportDefinition> import_set;
+
+ TsGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", ".", "ts") {
+ // clang-format off
+
+ // List of keywords retrieved from here:
+ // https://github.com/microsoft/TypeScript/issues/2536
+ // One per line to ease comparisons to that list are easier
+ static const char *const keywords[] = {
+ "argument",
+ "break",
+ "case",
+ "catch",
+ "class",
+ "const",
+ "continue",
+ "debugger",
+ "default",
+ "delete",
+ "do",
+ "else",
+ "enum",
+ "export",
+ "extends",
+ "false",
+ "finally",
+ "for",
+ "function",
+ "if",
+ "import",
+ "in",
+ "instanceof",
+ "new",
+ "null",
+ "Object",
+ "return",
+ "super",
+ "switch",
+ "this",
+ "throw",
+ "true",
+ "try",
+ "typeof",
+ "var",
+ "void",
+ "while",
+ "with",
+ "as",
+ "implements",
+ "interface",
+ "let",
+ "package",
+ "private",
+ "protected",
+ "public",
+ "static",
+ "yield",
+ nullptr,
+ // clang-format on
+ };
+
+ for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+ }
+ bool generate() {
+ if (parser_.opts.ts_flat_file && parser_.opts.generate_all) {
+ // Not implemented; warning message should have beem emitted by flatc.
+ return false;
+ }
+ generateEnums();
+ generateStructs();
+ generateEntry();
+ return true;
+ }
+
+ // Save out the generated code for a single class while adding
+ // declaration boilerplate.
+ bool SaveType(const Definition &definition, const std::string &classcode,
+ import_set &imports, import_set &bare_imports) {
+ if (!classcode.length()) return true;
+
+ std::string code;
+
+ if (!parser_.opts.ts_flat_file) {
+ code += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ for (auto it = bare_imports.begin(); it != bare_imports.end(); it++) {
+ code += it->second.import_statement + "\n";
+ }
+ if (!bare_imports.empty()) code += "\n";
+
+ for (auto it = imports.begin(); it != imports.end(); it++) {
+ if (it->second.dependency != &definition) {
+ code += it->second.import_statement + "\n";
+ }
+ }
+ if (!imports.empty()) code += "\n\n";
+ }
+
+ code += classcode;
+ auto filename =
+ NamespaceDir(*definition.defined_namespace, true) +
+ ConvertCase(definition.name, Case::kDasher, Case::kUpperCamel) + ".ts";
+ if (parser_.opts.ts_flat_file) {
+ flat_file_ += code;
+ flat_file_definitions_.insert(&definition);
+ return true;
+ } else {
+ return SaveFile(filename.c_str(), code, false);
+ }
+ }
+
+ private:
+ std::unordered_set<std::string> keywords_;
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : name + "_";
+ }
+
+ import_set imports_all_;
+
+ // The following three members are used when generating typescript code into a
+ // single file rather than creating separate files for each type.
+
+ // flat_file_ contains the aggregated contents of the file prior to being
+ // written to disk.
+ std::string flat_file_;
+ // flat_file_definitions_ tracks which types have been written to flat_file_.
+ std::unordered_set<const Definition *> flat_file_definitions_;
+ // This maps from import names to types to import.
+ std::map<std::string, std::map<std::string, std::string>>
+ flat_file_import_declarations_;
+
+ // Generate code for all enums.
+ void generateEnums() {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ import_set bare_imports;
+ import_set imports;
+ std::string enumcode;
+ auto &enum_def = **it;
+ GenEnum(enum_def, &enumcode, imports, false);
+ GenEnum(enum_def, &enumcode, imports, true);
+ SaveType(enum_def, enumcode, imports, bare_imports);
+ imports_all_.insert(imports.begin(), imports.end());
+ }
+ }
+
+ // Generate code for all structs.
+ void generateStructs() {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ import_set bare_imports;
+ import_set imports;
+ AddImport(bare_imports, "* as flatbuffers", "flatbuffers");
+ auto &struct_def = **it;
+ std::string declcode;
+ GenStruct(parser_, struct_def, &declcode, imports);
+ SaveType(struct_def, declcode, imports, bare_imports);
+ imports_all_.insert(imports.begin(), imports.end());
+ }
+ }
+
+ // Generate code for a single entry point module.
+ void generateEntry() {
+ std::string code;
+ if (parser_.opts.ts_flat_file) {
+ code += "import * as flatbuffers from 'flatbuffers';\n";
+ for (const auto &it : flat_file_import_declarations_) {
+ // Note that we do end up generating an import for ourselves, which
+ // should generally be harmless.
+ // TODO: Make it so we don't generate a self-import; this will also
+ // require modifying AddImport to ensure that we don't use
+ // namespace-prefixed names anywhere...
+ std::string file = it.first;
+ if (file.empty()) {
+ continue;
+ }
+ std::string noext = flatbuffers::StripExtension(file);
+ std::string basename = flatbuffers::StripPath(noext);
+ std::string include_file = GeneratedFileName(
+ parser_.opts.include_prefix,
+ parser_.opts.keep_include_path ? noext : basename, parser_.opts);
+ // TODO: what is the right behavior when different include flags are
+ // specified here? Should we always be adding the "./" for a relative
+ // path or turn it off if --include-prefix is specified, or something
+ // else?
+ std::string include_name = "./" + flatbuffers::StripExtension(include_file);
+ code += "import {";
+ for (const auto &pair : it.second) {
+ code += EscapeKeyword(pair.first) + " as " +
+ EscapeKeyword(pair.second) + ", ";
+ }
+ code.resize(code.size() - 2);
+ code += "} from '" + include_name + "';\n";
+ }
+ code += "\n\n";
+ code += flat_file_;
+ const std::string filename =
+ GeneratedFileName(path_, file_name_, parser_.opts);
+ SaveFile(filename.c_str(), code, false);
+ } else {
+ for (auto it = imports_all_.begin(); it != imports_all_.end(); it++) {
+ code += it->second.export_statement + "\n";
+ }
+ std::string path = "./" + path_ + file_name_ + ".ts";
+ SaveFile(path.c_str(), code, false);
+ }
+ }
+
+ // Generate a documentation comment, if available.
+ static void GenDocComment(const std::vector<std::string> &dc,
+ std::string *code_ptr,
+ const char *indent = nullptr) {
+ if (dc.empty()) {
+ // Don't output empty comment blocks with 0 lines of comment content.
+ return;
+ }
+
+ std::string &code = *code_ptr;
+ if (indent) code += indent;
+ code += "/**\n";
+ for (auto it = dc.begin(); it != dc.end(); ++it) {
+ if (indent) code += indent;
+ code += " *" + *it + "\n";
+ }
+ if (indent) code += indent;
+ code += " */\n";
+ }
+
+ static void GenDocComment(std::string *code_ptr) {
+ GenDocComment(std::vector<std::string>(), code_ptr);
+ }
+
+ // Generate an enum declaration and an enum string lookup table.
+ void GenEnum(EnumDef &enum_def, std::string *code_ptr, import_set &imports,
+ bool reverse) {
+ if (enum_def.generated) return;
+ if (reverse) return; // FIXME.
+ std::string &code = *code_ptr;
+ GenDocComment(enum_def.doc_comment, code_ptr);
+ code += "export enum " + EscapeKeyword(enum_def.name) + "{\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ if (!ev.doc_comment.empty()) {
+ if (it != enum_def.Vals().begin()) { code += '\n'; }
+ GenDocComment(ev.doc_comment, code_ptr, " ");
+ }
+
+ const std::string escaped_name = EscapeKeyword(ev.name);
+
+ // Generate mapping between EnumName: EnumValue(int)
+ if (reverse) {
+ code += " '" + enum_def.ToString(ev) + "'";
+ code += " = ";
+ code += "'" + escaped_name + "'";
+ } else {
+ code += " " + escaped_name;
+ code += " = ";
+ // Unfortunately, because typescript does not support bigint enums,
+ // for 64-bit enums, we instead map the enum names to strings.
+ switch (enum_def.underlying_type.base_type) {
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG: {
+ code += "'" + enum_def.ToString(ev) + "'";
+ break;
+ }
+ default: code += enum_def.ToString(ev);
+ }
+ }
+
+ code += (it + 1) != enum_def.Vals().end() ? ",\n" : "\n";
+ }
+ code += "}";
+
+ if (enum_def.is_union) {
+ code += GenUnionConvFunc(enum_def.underlying_type, imports);
+ }
+
+ code += "\n\n";
+ }
+
+ static std::string GenType(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_BOOL:
+ case BASE_TYPE_CHAR: return "Int8";
+ case BASE_TYPE_UTYPE:
+ case BASE_TYPE_UCHAR: return "Uint8";
+ case BASE_TYPE_SHORT: return "Int16";
+ case BASE_TYPE_USHORT: return "Uint16";
+ case BASE_TYPE_INT: return "Int32";
+ case BASE_TYPE_UINT: return "Uint32";
+ case BASE_TYPE_LONG: return "Int64";
+ case BASE_TYPE_ULONG: return "Uint64";
+ case BASE_TYPE_FLOAT: return "Float32";
+ case BASE_TYPE_DOUBLE: return "Float64";
+ case BASE_TYPE_STRING: return "String";
+ case BASE_TYPE_VECTOR: return GenType(type.VectorType());
+ case BASE_TYPE_STRUCT: return type.struct_def->name;
+ default: return "flatbuffers.Table";
+ }
+ }
+
+ std::string GenGetter(const Type &type, const std::string &arguments) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return GenBBAccess() + ".__string" + arguments;
+ case BASE_TYPE_STRUCT: return GenBBAccess() + ".__struct" + arguments;
+ case BASE_TYPE_UNION:
+ if (!UnionHasStringType(*type.enum_def)) {
+ return GenBBAccess() + ".__union" + arguments;
+ }
+ return GenBBAccess() + ".__union_with_string" + arguments;
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType(), arguments);
+ default: {
+ auto getter = GenBBAccess() + ".read" +
+ ConvertCase(GenType(type), Case::kUpperCamel) + arguments;
+ if (type.base_type == BASE_TYPE_BOOL) { getter = "!!" + getter; }
+ return getter;
+ }
+ }
+ }
+
+ std::string GenBBAccess() const { return "this.bb!"; }
+
+ std::string GenDefaultValue(const FieldDef &field, import_set &imports) {
+ if (field.IsScalarOptional()) { return "null"; }
+
+ const auto &value = field.value;
+ if (value.type.enum_def && value.type.base_type != BASE_TYPE_UNION &&
+ value.type.base_type != BASE_TYPE_VECTOR) {
+ // If the value is an enum with a 64-bit base type, we have to just
+ // return the bigint value directly since typescript does not support
+ // enums with bigint backing types.
+ switch (value.type.base_type) {
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG: {
+ return "BigInt('" + value.constant + "')";
+ }
+ default: {
+ if (auto val = value.type.enum_def->FindByValue(value.constant)) {
+ return EscapeKeyword(AddImport(imports, *value.type.enum_def,
+ *value.type.enum_def)) +
+ "." + EscapeKeyword(val->name);
+ } else {
+ return value.constant;
+ }
+ }
+ }
+ }
+
+ switch (value.type.base_type) {
+ case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
+
+ case BASE_TYPE_STRING:
+ case BASE_TYPE_UNION:
+ case BASE_TYPE_STRUCT: {
+ return "null";
+ }
+
+ case BASE_TYPE_VECTOR: return "[]";
+
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG: {
+ return "BigInt('" + value.constant + "')";
+ }
+
+ default: return value.constant;
+ }
+ }
+
+ std::string GenTypeName(import_set &imports, const Definition &owner,
+ const Type &type, bool input,
+ bool allowNull = false) {
+ if (!input) {
+ if (IsString(type) || type.base_type == BASE_TYPE_STRUCT) {
+ std::string name;
+ if (IsString(type)) {
+ name = "string|Uint8Array";
+ } else {
+ name = EscapeKeyword(AddImport(imports, owner, *type.struct_def));
+ }
+ return allowNull ? (name + "|null") : name;
+ }
+ }
+
+ switch (type.base_type) {
+ case BASE_TYPE_BOOL: return allowNull ? "boolean|null" : "boolean";
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG: return allowNull ? "bigint|null" : "bigint";
+ default:
+ if (IsScalar(type.base_type)) {
+ if (type.enum_def) {
+ const auto enum_name = AddImport(imports, owner, *type.enum_def);
+ return allowNull ? (enum_name + "|null") : enum_name;
+ }
+ return allowNull ? "number|null" : "number";
+ }
+ return "flatbuffers.Offset";
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ static std::string GenWriteMethod(const Type &type) {
+ // Forward to signed versions since unsigned versions don't exist
+ switch (type.base_type) {
+ case BASE_TYPE_UTYPE:
+ case BASE_TYPE_UCHAR: return GenWriteMethod(Type(BASE_TYPE_CHAR));
+ case BASE_TYPE_USHORT: return GenWriteMethod(Type(BASE_TYPE_SHORT));
+ case BASE_TYPE_UINT: return GenWriteMethod(Type(BASE_TYPE_INT));
+ case BASE_TYPE_ULONG: return GenWriteMethod(Type(BASE_TYPE_LONG));
+ default: break;
+ }
+
+ return IsScalar(type.base_type)
+ ? ConvertCase(GenType(type), Case::kUpperCamel)
+ : (IsStruct(type) ? "Struct" : "Offset");
+ }
+
+ template<typename T> static std::string MaybeAdd(T value) {
+ return value != 0 ? " + " + NumToString(value) : "";
+ }
+
+ template<typename T> static std::string MaybeScale(T value) {
+ return value != 1 ? " * " + NumToString(value) : "";
+ }
+
+ void GenStructArgs(import_set &imports, const StructDef &struct_def,
+ std::string *arguments, const std::string &nameprefix) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ GenStructArgs(imports, *field.value.type.struct_def, arguments,
+ nameprefix + field.name + "_");
+ } else {
+ *arguments += ", " + nameprefix + field.name + ": " +
+ GenTypeName(imports, field, field.value.type, true,
+ field.IsOptional());
+ }
+ }
+ }
+
+ static void GenStructBody(const StructDef &struct_def, std::string *body,
+ const std::string &nameprefix) {
+ *body += " builder.prep(";
+ *body += NumToString(struct_def.minalign) + ", ";
+ *body += NumToString(struct_def.bytesize) + ");\n";
+
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (field.padding) {
+ *body += " builder.pad(" + NumToString(field.padding) + ");\n";
+ }
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ GenStructBody(*field.value.type.struct_def, body,
+ nameprefix + field.name + "_");
+ } else {
+ *body += " builder.write" + GenWriteMethod(field.value.type) + "(";
+ if (field.value.type.base_type == BASE_TYPE_BOOL) { *body += "+"; }
+ *body += nameprefix + field.name + ");\n";
+ }
+ }
+ }
+
+ std::string GenerateNewExpression(const std::string &object_name) {
+ return "new " + EscapeKeyword(object_name) + "()";
+ }
+
+ void GenerateRootAccessor(StructDef &struct_def, std::string *code_ptr,
+ std::string &code, const std::string &object_name,
+ bool size_prefixed) {
+ if (!struct_def.fixed) {
+ GenDocComment(code_ptr);
+ std::string sizePrefixed("SizePrefixed");
+ code += "static get" + (size_prefixed ? sizePrefixed : "") + "Root" +
+ GetPrefixedName(struct_def, "As");
+ code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name +
+ "):" + object_name + " {\n";
+ if (size_prefixed) {
+ code +=
+ " bb.setPosition(bb.position() + "
+ "flatbuffers.SIZE_PREFIX_LENGTH);\n";
+ }
+ code += " return (obj || " + GenerateNewExpression(object_name);
+ code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
+ code += "}\n\n";
+ }
+ }
+
+ void GenerateFinisher(StructDef &struct_def, std::string *code_ptr,
+ std::string &code, bool size_prefixed) {
+ if (parser_.root_struct_def_ == &struct_def) {
+ std::string sizePrefixed("SizePrefixed");
+ GenDocComment(code_ptr);
+
+ code += "static finish" + (size_prefixed ? sizePrefixed : "") +
+ GetPrefixedName(struct_def) + "Buffer";
+ code += "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
+ code += " builder.finish(offset";
+ if (!parser_.file_identifier_.empty()) {
+ code += ", '" + parser_.file_identifier_ + "'";
+ }
+ if (size_prefixed) {
+ if (parser_.file_identifier_.empty()) { code += ", undefined"; }
+ code += ", true";
+ }
+ code += ");\n";
+ code += "}\n\n";
+ }
+ }
+
+ static std::string GetObjApiClassName(const StructDef &sd,
+ const IDLOptions &opts) {
+ return GetObjApiClassName(sd.name, opts);
+ }
+
+ static std::string GetObjApiClassName(const std::string &name,
+ const IDLOptions &opts) {
+ return opts.object_prefix + name + opts.object_suffix;
+ }
+
+ bool UnionHasStringType(const EnumDef &union_enum) {
+ return std::any_of(union_enum.Vals().begin(), union_enum.Vals().end(),
+ [](const EnumVal *ev) {
+ return !ev->IsZero() && IsString(ev->union_type);
+ });
+ }
+
+ std::string GenUnionGenericTypeTS(const EnumDef &union_enum) {
+ // TODO: make it work without any
+ // return std::string("T") + (UnionHasStringType(union_enum) ? "|string" :
+ // "");
+ return std::string("any") +
+ (UnionHasStringType(union_enum) ? "|string" : "");
+ }
+
+ std::string GenUnionTypeTS(const EnumDef &union_enum, import_set &imports) {
+ std::string ret;
+ std::set<std::string> type_list;
+
+ for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ std::string type = "";
+ if (IsString(ev.union_type)) {
+ type = "string"; // no need to wrap string type in namespace
+ } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ type = AddImport(imports, union_enum, *ev.union_type.struct_def);
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ type_list.insert(type);
+ }
+
+ for (auto it = type_list.begin(); it != type_list.end(); ++it) {
+ ret += *it + ((std::next(it) == type_list.end()) ? "" : "|");
+ }
+
+ return ret;
+ }
+
+ std::string AddImport(import_set &imports, const Definition &dependent,
+ const StructDef &dependency) {
+ std::string ns;
+ const auto &depc_comps = dependency.defined_namespace->components;
+ for (auto it = depc_comps.begin(); it != depc_comps.end(); it++) {
+ ns += *it;
+ }
+ std::string unique_name = ns + dependency.name;
+ std::string import_name = dependency.name;
+ std::string long_import_name;
+ if (imports.find(unique_name) != imports.end())
+ return imports.find(unique_name)->second.name;
+ for (auto it = imports.begin(); it != imports.end(); it++) {
+ if (it->second.name == import_name) {
+ long_import_name = ns + import_name;
+ break;
+ }
+ }
+
+ if (parser_.opts.ts_flat_file) {
+ std::string file = dependency.declaration_file == nullptr
+ ? dependency.file
+ : dependency.declaration_file->substr(2);
+ file = RelativeToRootPath(StripFileName(AbsolutePath(dependent.file)),
+ dependency.file).substr(2);
+ long_import_name = ns + import_name;
+ flat_file_import_declarations_[file][import_name] = long_import_name;
+ if (parser_.opts.generate_object_based_api) {
+ flat_file_import_declarations_[file][import_name + "T"] = long_import_name + "T";
+ }
+ }
+
+ std::string import_statement;
+ std::string export_statement;
+ import_statement += "import { ";
+ export_statement += "export { ";
+ std::string symbols_expression;
+ if (long_import_name.empty()) {
+ symbols_expression += EscapeKeyword(import_name);
+ if (parser_.opts.generate_object_based_api)
+ symbols_expression += ", " + import_name + "T";
+ } else {
+ symbols_expression += EscapeKeyword(dependency.name) + " as " +
+ EscapeKeyword(long_import_name);
+ if (parser_.opts.generate_object_based_api)
+ symbols_expression +=
+ ", " + dependency.name + "T as " + long_import_name + "T";
+ }
+ import_statement += symbols_expression + " } from '";
+ export_statement += symbols_expression + " } from '";
+ std::string bare_file_path;
+ std::string rel_file_path;
+ const auto &dep_comps = dependent.defined_namespace->components;
+ for (size_t i = 0; i < dep_comps.size(); i++)
+ rel_file_path += i == 0 ? ".." : (kPathSeparator + std::string(".."));
+ if (dep_comps.size() == 0) rel_file_path += ".";
+ for (auto it = depc_comps.begin(); it != depc_comps.end(); it++)
+ bare_file_path +=
+ kPathSeparator + ConvertCase(*it, Case::kDasher, Case::kUpperCamel);
+ bare_file_path +=
+ kPathSeparator +
+ ConvertCase(dependency.name, Case::kDasher, Case::kUpperCamel);
+ rel_file_path += bare_file_path;
+ import_statement += rel_file_path + "';";
+ export_statement += "." + bare_file_path + "';";
+ ImportDefinition import;
+ import.name = long_import_name.empty() ? import_name : long_import_name;
+ import.bare_file_path = bare_file_path;
+ import.rel_file_path = rel_file_path;
+ import.import_statement = import_statement;
+ import.export_statement = export_statement;
+ import.dependency = &dependency;
+ import.dependent = &dependent;
+ imports.insert(std::make_pair(unique_name, import));
+ return import.name;
+ }
+
+ // TODO: largely (but not identical) duplicated code from above couln't find a
+ // good way to refactor
+ std::string AddImport(import_set &imports, const Definition &dependent,
+ const EnumDef &dependency) {
+ std::string ns;
+ const auto &depc_comps = dependency.defined_namespace->components;
+ for (auto it = depc_comps.begin(); it != depc_comps.end(); it++) {
+ ns += *it;
+ }
+ std::string unique_name = ns + dependency.name;
+ std::string import_name = EscapeKeyword(dependency.name);
+ std::string long_import_name;
+ if (imports.find(unique_name) != imports.end()) {
+ return imports.find(unique_name)->second.name;
+ }
+ for (auto it = imports.begin(); it != imports.end(); it++) {
+ if (it->second.name == import_name) {
+ long_import_name = ns + import_name;
+ break;
+ }
+ }
+
+ if (parser_.opts.ts_flat_file) {
+ std::string file = dependency.declaration_file == nullptr
+ ? dependency.file
+ : dependency.declaration_file->substr(2);
+ file = RelativeToRootPath(StripFileName(AbsolutePath(dependent.file)),
+ dependency.file).substr(2);
+ long_import_name = ns + import_name;
+ flat_file_import_declarations_[file][import_name] = long_import_name;
+ }
+
+ std::string import_statement;
+ std::string export_statement;
+ import_statement += "import { ";
+ export_statement += "export { ";
+ std::string symbols_expression;
+ if (long_import_name.empty())
+ symbols_expression += import_name;
+ else
+ symbols_expression += EscapeKeyword(dependency.name) + " as " +
+ EscapeKeyword(long_import_name);
+ if (dependency.is_union) {
+ symbols_expression += ", unionTo" + import_name;
+ symbols_expression += ", unionListTo" + import_name;
+ }
+ import_statement += symbols_expression + " } from '";
+ export_statement += symbols_expression + " } from '";
+ std::string bare_file_path;
+ std::string rel_file_path;
+ const auto &dep_comps = dependent.defined_namespace->components;
+ for (size_t i = 0; i < dep_comps.size(); i++)
+ rel_file_path += i == 0 ? ".." : (kPathSeparator + std::string(".."));
+ if (dep_comps.size() == 0) rel_file_path += ".";
+ for (auto it = depc_comps.begin(); it != depc_comps.end(); it++)
+ bare_file_path +=
+ kPathSeparator + ConvertCase(*it, Case::kDasher, Case::kUpperCamel);
+ bare_file_path +=
+ kPathSeparator +
+ ConvertCase(dependency.name, Case::kDasher, Case::kUpperCamel);
+ rel_file_path += bare_file_path;
+ import_statement += rel_file_path + "';";
+ export_statement += "." + bare_file_path + "';";
+ ImportDefinition import;
+ import.name = long_import_name.empty() ? import_name : long_import_name;
+ import.bare_file_path = bare_file_path;
+ import.rel_file_path = rel_file_path;
+ import.import_statement = import_statement;
+ import.export_statement = export_statement;
+ import.dependency = &dependency;
+ import.dependent = &dependent;
+ imports.insert(std::make_pair(unique_name, import));
+ return import.name;
+ }
+
+ void AddImport(import_set &imports, std::string import_name,
+ std::string fileName) {
+ ImportDefinition import;
+ import.name = import_name;
+ import.import_statement =
+ "import " + import_name + " from '" + fileName + "';";
+ imports.insert(std::make_pair(import_name, import));
+ }
+
+ // Generate a TS union type based on a union's enum
+ std::string GenObjApiUnionTypeTS(import_set &imports, const IDLOptions &opts,
+ const EnumDef &union_enum) {
+ std::string ret = "";
+ std::set<std::string> type_list;
+
+ for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ std::string type = "";
+ if (IsString(ev.union_type)) {
+ type = "string"; // no need to wrap string type in namespace
+ } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ type = GetObjApiClassName(
+ AddImport(imports, union_enum, *ev.union_type.struct_def), opts);
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ type_list.insert(type);
+ }
+
+ size_t totalPrinted = 0;
+ for (auto it = type_list.begin(); it != type_list.end(); ++it) {
+ ++totalPrinted;
+ ret += *it + ((totalPrinted == type_list.size()) ? "" : "|");
+ }
+
+ return ret;
+ }
+
+ std::string GenUnionConvFuncName(const EnumDef &enum_def) {
+ return "unionTo" + enum_def.name;
+ }
+
+ std::string GenUnionListConvFuncName(const EnumDef &enum_def) {
+ return "unionListTo" + enum_def.name;
+ }
+
+ std::string GenUnionConvFunc(const Type &union_type, import_set &imports) {
+ if (union_type.enum_def) {
+ const auto &enum_def = *union_type.enum_def;
+
+ const auto valid_union_type = GenUnionTypeTS(enum_def, imports);
+ const auto valid_union_type_with_null = valid_union_type + "|null";
+
+ auto ret = "\n\nexport function " + GenUnionConvFuncName(enum_def) +
+ "(\n type: " + enum_def.name +
+ ",\n accessor: (obj:" + valid_union_type + ") => " +
+ valid_union_type_with_null +
+ "\n): " + valid_union_type_with_null + " {\n";
+
+ const auto enum_type = AddImport(imports, enum_def, enum_def);
+
+ const auto union_enum_loop = [&](const std::string &accessor_str) {
+ ret += " switch(" + enum_type + "[type]) {\n";
+ ret += " case 'NONE': return null; \n";
+
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ ret += " case '" + ev.name + "': ";
+
+ if (IsString(ev.union_type)) {
+ ret += "return " + accessor_str + "'') as string;";
+ } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ const auto type =
+ AddImport(imports, enum_def, *ev.union_type.struct_def);
+ ret += "return " + accessor_str + "new " + type + "())! as " +
+ type + ";";
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ ret += "\n";
+ }
+
+ ret += " default: return null;\n";
+ ret += " }\n";
+ };
+
+ union_enum_loop("accessor(");
+ ret += "}";
+
+ ret += "\n\nexport function " + GenUnionListConvFuncName(enum_def) +
+ "(\n type: " + enum_def.name +
+ ", \n accessor: (index: number, obj:" + valid_union_type +
+ ") => " + valid_union_type_with_null +
+ ", \n index: number\n): " + valid_union_type_with_null + " {\n";
+ union_enum_loop("accessor(index, ");
+ ret += "}";
+
+ return ret;
+ }
+ FLATBUFFERS_ASSERT(0);
+ return "";
+ }
+
+ // Used for generating a short function that returns the correct class
+ // based on union enum type. Assume the context is inside the non object api
+ // type
+ std::string GenUnionValTS(import_set &imports, const std::string &field_name,
+ const Type &union_type,
+ const bool is_array = false) {
+ if (union_type.enum_def) {
+ const auto &enum_def = *union_type.enum_def;
+ const auto enum_type = AddImport(imports, enum_def, enum_def);
+ const std::string union_accessor = "this." + field_name;
+
+ const auto union_has_string = UnionHasStringType(enum_def);
+ const auto field_binded_method = "this." + field_name + ".bind(this)";
+
+ std::string ret;
+
+ if (!is_array) {
+ const auto conversion_function = GenUnionConvFuncName(enum_def);
+ const auto target_enum = "this." + field_name + "Type()";
+
+ ret = "(() => {\n";
+ ret += " let temp = " + conversion_function + "(" + target_enum +
+ ", " + field_binded_method + ");\n";
+ ret += " if(temp === null) { return null; }\n";
+ ret += union_has_string
+ ? " if(typeof temp === 'string') { return temp; }\n"
+ : "";
+ ret += " return temp.unpack()\n";
+ ret += " })()";
+ } else {
+ const auto conversion_function = GenUnionListConvFuncName(enum_def);
+ const auto target_enum_accesor = "this." + field_name + "Type";
+ const auto target_enum_length = target_enum_accesor + "Length()";
+
+ ret = "(() => {\n";
+ ret += " let ret = [];\n";
+ ret += " for(let targetEnumIndex = 0; targetEnumIndex < " +
+ target_enum_length +
+ "; "
+ "++targetEnumIndex) {\n";
+ ret += " let targetEnum = " + target_enum_accesor +
+ "(targetEnumIndex);\n";
+ ret += " if(targetEnum === null || " + enum_type +
+ "[targetEnum!] === 'NONE') { "
+ "continue; }\n\n";
+ ret += " let temp = " + conversion_function + "(targetEnum, " +
+ field_binded_method + ", targetEnumIndex);\n";
+ ret += " if(temp === null) { continue; }\n";
+ ret += union_has_string ? " if(typeof temp === 'string') { "
+ "ret.push(temp); continue; }\n"
+ : "";
+ ret += " ret.push(temp.unpack());\n";
+ ret += " }\n";
+ ret += " return ret;\n";
+ ret += " })()";
+ }
+
+ return ret;
+ }
+
+ FLATBUFFERS_ASSERT(0);
+ return "";
+ }
+
+ static std::string GenNullCheckConditional(
+ const std::string &nullCheckVar, const std::string &trueVal,
+ const std::string &falseVal = "null") {
+ return "(" + nullCheckVar + " !== null ? " + trueVal + " : " + falseVal +
+ ")";
+ }
+
+ std::string GenStructMemberValueTS(const StructDef &struct_def,
+ const std::string &prefix,
+ const std::string &delimiter,
+ const bool nullCheck = true) {
+ std::string ret;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+
+ const auto curr_member_accessor =
+ prefix + "." + ConvertCase(field.name, Case::kLowerCamel);
+ if (IsStruct(field.value.type)) {
+ ret += GenStructMemberValueTS(*field.value.type.struct_def,
+ curr_member_accessor, delimiter);
+ } else {
+ if (nullCheck) {
+ ret +=
+ "(" + prefix + " === null ? 0 : " + curr_member_accessor + "!)";
+ } else {
+ ret += curr_member_accessor;
+ }
+ }
+
+ if (std::next(it) != struct_def.fields.vec.end()) { ret += delimiter; }
+ }
+
+ return ret;
+ }
+
+ void GenObjApi(const Parser &parser, StructDef &struct_def,
+ std::string &obj_api_unpack_func, std::string &obj_api_class,
+ import_set &imports) {
+ const auto class_name = GetObjApiClassName(struct_def, parser.opts);
+
+ std::string unpack_func = "\nunpack(): " + class_name +
+ " {\n return new " + class_name + "(" +
+ (struct_def.fields.vec.empty() ? "" : "\n");
+ std::string unpack_to_func = "\nunpackTo(_o: " + class_name + "): void {" +
+ +(struct_def.fields.vec.empty() ? "" : "\n");
+
+ std::string constructor_func = "constructor(";
+ constructor_func += (struct_def.fields.vec.empty() ? "" : "\n");
+
+ const auto has_create =
+ struct_def.fixed || CanCreateFactoryMethod(struct_def);
+
+ std::string pack_func_prototype =
+ "\npack(builder:flatbuffers.Builder): flatbuffers.Offset {\n";
+
+ std::string pack_func_offset_decl;
+ std::string pack_func_create_call;
+
+ const auto struct_name =
+ EscapeKeyword(AddImport(imports, struct_def, struct_def));
+
+ if (has_create) {
+ pack_func_create_call = " return " + struct_name + ".create" +
+ GetPrefixedName(struct_def) + "(builder" +
+ (struct_def.fields.vec.empty() ? "" : ",\n ");
+ } else {
+ pack_func_create_call = " " + struct_name + ".start" +
+ GetPrefixedName(struct_def) + "(builder);\n";
+ }
+
+ if (struct_def.fixed) {
+ // when packing struct, nested struct's members instead of the struct's
+ // offset are used
+ pack_func_create_call +=
+ GenStructMemberValueTS(struct_def, "this", ",\n ", false) + "\n ";
+ }
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ const auto field_name = ConvertCase(field.name, Case::kLowerCamel);
+ const auto field_name_escaped = EscapeKeyword(field_name);
+ const std::string field_binded_method =
+ "this." + field_name + ".bind(this)";
+
+ std::string field_val;
+ std::string field_type;
+ // a string that declares a variable containing the
+ // offset for things that can't be generated inline
+ // empty otw
+ std::string field_offset_decl;
+ // a string that contains values for things that can be created inline or
+ // the variable name from field_offset_decl
+ std::string field_offset_val;
+ const auto field_default_val = GenDefaultValue(field, imports);
+
+ // Emit a scalar field
+ const auto is_string = IsString(field.value.type);
+ if (IsScalar(field.value.type.base_type) || is_string) {
+ const auto has_null_default = is_string || HasNullDefault(field);
+
+ field_type += GenTypeName(imports, field, field.value.type, false,
+ has_null_default);
+ field_val = "this." + field_name + "()";
+
+ if (field.value.type.base_type != BASE_TYPE_STRING) {
+ field_offset_val = "this." + field_name_escaped;
+ } else {
+ field_offset_decl = GenNullCheckConditional(
+ "this." + field_name_escaped,
+ "builder.createString(this." + field_name_escaped + "!)", "0");
+ }
+ }
+
+ // Emit an object field
+ else {
+ auto is_vector = false;
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ const auto &sd = *field.value.type.struct_def;
+ field_type += GetObjApiClassName(AddImport(imports, struct_def, sd),
+ parser.opts);
+
+ const std::string field_accessor =
+ "this." + field_name_escaped + "()";
+ field_val = GenNullCheckConditional(field_accessor,
+ field_accessor + "!.unpack()");
+ auto packing = GenNullCheckConditional(
+ "this." + field_name_escaped,
+ "this." + field_name_escaped + "!.pack(builder)",
+ "0");
+
+ if (sd.fixed) {
+ field_offset_val = std::move(packing);
+ } else {
+ field_offset_decl = std::move(packing);
+ }
+
+ break;
+ }
+
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ auto vectortypename =
+ GenTypeName(imports, struct_def, vectortype, false);
+ is_vector = true;
+
+ field_type = "(";
+
+ switch (vectortype.base_type) {
+ case BASE_TYPE_STRUCT: {
+ const auto &sd = *field.value.type.struct_def;
+ field_type += GetObjApiClassName(
+ AddImport(imports, struct_def, sd), parser.opts);
+ field_type += ")[]";
+
+ field_val = GenBBAccess() + ".createObjList(" +
+ field_binded_method + ", this." + field_name +
+ "Length())";
+
+ if (sd.fixed) {
+ field_offset_decl =
+ "builder.createStructOffsetList(this." +
+ field_name_escaped + ", " +
+ EscapeKeyword(
+ AddImport(imports, struct_def, struct_def)) +
+ ".start" + ConvertCase(field_name, Case::kUpperCamel) +
+ "Vector)";
+ } else {
+ field_offset_decl =
+ EscapeKeyword(
+ AddImport(imports, struct_def, struct_def)) +
+ ".create" + ConvertCase(field_name, Case::kUpperCamel) +
+ "Vector(builder, builder.createObjectOffsetList(" +
+ "this." + field_name_escaped + "))";
+ }
+
+ break;
+ }
+
+ case BASE_TYPE_STRING: {
+ field_type += "string)[]";
+ field_val = GenBBAccess() + ".createScalarList(" +
+ field_binded_method + ", this." + field_name +
+ "Length())";
+ field_offset_decl =
+ EscapeKeyword(AddImport(imports, struct_def, struct_def)) +
+ ".create" + ConvertCase(field_name, Case::kUpperCamel) +
+ "Vector(builder, builder.createObjectOffsetList(" +
+ "this." + field_name_escaped + "))";
+ break;
+ }
+
+ case BASE_TYPE_UNION: {
+ field_type += GenObjApiUnionTypeTS(imports, parser.opts,
+ *(vectortype.enum_def));
+ field_type += ")[]";
+ field_val =
+ GenUnionValTS(imports, field_name, vectortype, true);
+
+ field_offset_decl =
+ EscapeKeyword(AddImport(imports, struct_def, struct_def)) +
+ ".create" + ConvertCase(field_name, Case::kUpperCamel) +
+ "Vector(builder, builder.createObjectOffsetList(" +
+ "this." + field_name_escaped + "))";
+
+ break;
+ }
+ default: {
+ if (vectortype.enum_def) {
+ field_type += GenTypeName(imports, struct_def, vectortype,
+ false, HasNullDefault(field));
+ } else {
+ field_type += vectortypename;
+ }
+ field_type += ")[]";
+ field_val = GenBBAccess() + ".createScalarList(" +
+ field_binded_method + ", this." + field_name +
+ "Length())";
+
+ field_offset_decl =
+ EscapeKeyword(AddImport(imports, struct_def, struct_def)) +
+ ".create" + ConvertCase(field_name, Case::kUpperCamel) +
+ "Vector(builder, this." + field_name_escaped + ")";
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case BASE_TYPE_UNION: {
+ field_type += GenObjApiUnionTypeTS(imports, parser.opts,
+ *(field.value.type.enum_def));
+
+ field_val = GenUnionValTS(imports, field_name, field.value.type);
+ field_offset_decl =
+ "builder.createObjectOffset(this." + field_name_escaped + ")";
+ break;
+ }
+
+ default: FLATBUFFERS_ASSERT(0); break;
+ }
+
+ // length 0 vector is simply empty instead of null
+ field_type += is_vector ? "" : "|null";
+ }
+
+ if (!field_offset_decl.empty()) {
+ field_offset_decl =
+ " const " + field_name_escaped + " = " + field_offset_decl + ";";
+ }
+ if (field_offset_val.empty()) { field_offset_val = field_name_escaped; }
+
+ unpack_func += " " + field_val;
+ unpack_to_func += " _o." + field_name_escaped + " = " + field_val + ";";
+
+ // FIXME: if field_type and field_name_escaped are identical, then
+ // this generates invalid typescript.
+ constructor_func += " public " + field_name_escaped + ": " + field_type +
+ " = " +
+ field_default_val;
+
+ if (!struct_def.fixed) {
+ if (!field_offset_decl.empty()) {
+ pack_func_offset_decl += field_offset_decl + "\n";
+ }
+
+ if (has_create) {
+ pack_func_create_call += field_offset_val;
+ } else {
+ if (field.IsScalarOptional()) {
+ pack_func_create_call += " if (" + field_offset_val + " !== null)\n ";
+ }
+ pack_func_create_call += " " + struct_name + ".add" +
+ ConvertCase(field.name, Case::kUpperCamel) +
+ "(builder, " + field_offset_val + ");\n";
+ }
+ }
+
+ if (std::next(it) != struct_def.fields.vec.end()) {
+ constructor_func += ",\n";
+
+ if (!struct_def.fixed && has_create) {
+ pack_func_create_call += ",\n ";
+ }
+
+ unpack_func += ",\n";
+ unpack_to_func += "\n";
+ } else {
+ constructor_func += "\n";
+ if (!struct_def.fixed) {
+ pack_func_offset_decl += (pack_func_offset_decl.empty() ? "" : "\n");
+ pack_func_create_call += "\n ";
+ }
+
+ unpack_func += "\n ";
+ unpack_to_func += "\n";
+ }
+ }
+
+ constructor_func += "){}\n\n";
+
+ if (has_create) {
+ pack_func_create_call += ");";
+ } else {
+ pack_func_create_call += "return " + struct_name + ".end" +
+ GetPrefixedName(struct_def) + "(builder);";
+ }
+
+ obj_api_class = "\nexport class " +
+ GetObjApiClassName(struct_def, parser.opts) + " {\n";
+
+ obj_api_class += constructor_func;
+ obj_api_class += pack_func_prototype + pack_func_offset_decl +
+ pack_func_create_call + "\n}";
+
+ obj_api_class += "\n}\n";
+
+ unpack_func += ");\n}";
+ unpack_to_func += "}\n";
+
+ obj_api_unpack_func = unpack_func + "\n\n" + unpack_to_func;
+ }
+
+ static bool CanCreateFactoryMethod(const StructDef &struct_def) {
+ // to preserve backwards compatibility, we allow the first field to be a
+ // struct
+ return struct_def.fields.vec.size() < 2 ||
+ std::all_of(std::begin(struct_def.fields.vec) + 1,
+ std::end(struct_def.fields.vec),
+ [](const FieldDef *f) -> bool {
+ FLATBUFFERS_ASSERT(f != nullptr);
+ return f->value.type.base_type != BASE_TYPE_STRUCT;
+ });
+ }
+
+ // Generate an accessor struct with constructor for a flatbuffers struct.
+ void GenStruct(const Parser &parser, StructDef &struct_def,
+ std::string *code_ptr, import_set &imports) {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+
+ std::string object_name;
+ std::string object_namespace = GetNameSpace(struct_def);
+
+ // Emit constructor
+ object_name = EscapeKeyword(struct_def.name);
+ GenDocComment(struct_def.doc_comment, code_ptr);
+ code += "export class " + object_name;
+ code += " {\n";
+ code += " bb: flatbuffers.ByteBuffer|null = null;\n";
+ code += " bb_pos = 0;\n";
+
+ // Generate the __init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ code +=
+ "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name + " {\n";
+ code += " this.bb_pos = i;\n";
+ code += " this.bb = bb;\n";
+ code += " return this;\n";
+ code += "}\n\n";
+
+ // Generate special accessors for the table that when used as the root of a
+ // FlatBuffer
+ GenerateRootAccessor(struct_def, code_ptr, code, object_name, false);
+ GenerateRootAccessor(struct_def, code_ptr, code, object_name, true);
+
+ // Generate the identifier check method
+ if (!struct_def.fixed && parser_.root_struct_def_ == &struct_def &&
+ !parser_.file_identifier_.empty()) {
+ GenDocComment(code_ptr);
+ code +=
+ "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean "
+ "{\n";
+ code += " return bb.__has_identifier('" + parser_.file_identifier_;
+ code += "');\n}\n\n";
+ }
+
+ // Emit field accessors
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto offset_prefix =
+ " const offset = " + GenBBAccess() + ".__offset(this.bb_pos, " +
+ NumToString(field.value.offset) + ");\n return offset ? ";
+
+ // Emit a scalar field
+ const auto is_string = IsString(field.value.type);
+ if (IsScalar(field.value.type.base_type) || is_string) {
+ const auto has_null_default = is_string || HasNullDefault(field);
+
+ GenDocComment(field.doc_comment, code_ptr);
+ std::string prefix = ConvertCase(field.name, Case::kLowerCamel) + "(";
+ if (is_string) {
+ code += prefix + "):string|null\n";
+ code +=
+ prefix + "optionalEncoding:flatbuffers.Encoding" + "):" +
+ GenTypeName(imports, struct_def, field.value.type, false, true) +
+ "\n";
+ code += prefix + "optionalEncoding?:any";
+ } else {
+ code += prefix;
+ }
+ if (field.value.type.enum_def) {
+ code += "):" +
+ GenTypeName(imports, struct_def, field.value.type, false,
+ field.IsOptional()) +
+ " {\n";
+ } else {
+ code += "):" +
+ GenTypeName(imports, struct_def, field.value.type, false,
+ has_null_default) +
+ " {\n";
+ }
+
+ if (struct_def.fixed) {
+ code +=
+ " return " +
+ GenGetter(field.value.type,
+ "(this.bb_pos" + MaybeAdd(field.value.offset) + ")") +
+ ";\n";
+ } else {
+ std::string index = "this.bb_pos + offset";
+ if (is_string) { index += ", optionalEncoding"; }
+ code += offset_prefix +
+ GenGetter(field.value.type, "(" + index + ")") + " : " +
+ GenDefaultValue(field, imports);
+ code += ";\n";
+ }
+ }
+
+ // Emit an object field
+ else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ const auto type = EscapeKeyword(
+ AddImport(imports, struct_def, *field.value.type.struct_def));
+ GenDocComment(field.doc_comment, code_ptr);
+ code += ConvertCase(field.name, Case::kLowerCamel);
+ code += "(obj?:" + type + "):" + type + "|null {\n";
+
+ if (struct_def.fixed) {
+ code += " return (obj || " + GenerateNewExpression(type);
+ code += ").__init(this.bb_pos";
+ code +=
+ MaybeAdd(field.value.offset) + ", " + GenBBAccess() + ");\n";
+ } else {
+ code += offset_prefix + "(obj || " + GenerateNewExpression(type) +
+ ").__init(";
+ code += field.value.type.struct_def->fixed
+ ? "this.bb_pos + offset"
+ : GenBBAccess() + ".__indirect(this.bb_pos + offset)";
+ code += ", " + GenBBAccess() + ") : null;\n";
+ }
+
+ break;
+ }
+
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ auto vectortypename =
+ GenTypeName(imports, struct_def, vectortype, false);
+ auto inline_size = InlineSize(vectortype);
+ auto index = GenBBAccess() +
+ ".__vector(this.bb_pos + offset) + index" +
+ MaybeScale(inline_size);
+ std::string ret_type;
+ bool is_union = false;
+ switch (vectortype.base_type) {
+ case BASE_TYPE_STRUCT: ret_type = vectortypename; break;
+ case BASE_TYPE_STRING: ret_type = vectortypename; break;
+ case BASE_TYPE_UNION:
+ ret_type = "?flatbuffers.Table";
+ is_union = true;
+ break;
+ default: ret_type = vectortypename;
+ }
+ GenDocComment(field.doc_comment, code_ptr);
+ std::string prefix = ConvertCase(field.name, Case::kLowerCamel);
+ // TODO: make it work without any
+ // if (is_union) { prefix += "<T extends flatbuffers.Table>"; }
+ if (is_union) { prefix += ""; }
+ prefix += "(index: number";
+ if (is_union) {
+ const auto union_type =
+ GenUnionGenericTypeTS(*(field.value.type.enum_def));
+
+ vectortypename = union_type;
+ code += prefix + ", obj:" + union_type;
+ } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += prefix + ", obj?:" + vectortypename;
+ } else if (IsString(vectortype)) {
+ code += prefix + "):string\n";
+ code += prefix + ",optionalEncoding:flatbuffers.Encoding" +
+ "):" + vectortypename + "\n";
+ code += prefix + ",optionalEncoding?:any";
+ } else {
+ code += prefix;
+ }
+ code += "):" + vectortypename + "|null {\n";
+
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += offset_prefix + "(obj || " +
+ GenerateNewExpression(vectortypename);
+ code += ").__init(";
+ code += vectortype.struct_def->fixed
+ ? index
+ : GenBBAccess() + ".__indirect(" + index + ")";
+ code += ", " + GenBBAccess() + ")";
+ } else {
+ if (is_union) {
+ index = "obj, " + index;
+ } else if (IsString(vectortype)) {
+ index += ", optionalEncoding";
+ }
+ code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
+ }
+ code += " : ";
+ if (field.value.type.element == BASE_TYPE_BOOL) {
+ code += "false";
+ } else if (field.value.type.element == BASE_TYPE_LONG ||
+ field.value.type.element == BASE_TYPE_ULONG) {
+ code += "BigInt(0)";
+ } else if (IsScalar(field.value.type.element)) {
+ if (field.value.type.enum_def) {
+ code += field.value.constant;
+ } else {
+ code += "0";
+ }
+ } else {
+ code += "null";
+ }
+ code += ";\n";
+ break;
+ }
+
+ case BASE_TYPE_UNION: {
+ GenDocComment(field.doc_comment, code_ptr);
+ code += ConvertCase(field.name, Case::kLowerCamel);
+
+ const auto &union_enum = *(field.value.type.enum_def);
+ const auto union_type = GenUnionGenericTypeTS(union_enum);
+ code += "<T extends flatbuffers.Table>(obj:" + union_type +
+ "):" + union_type +
+ "|null "
+ "{\n";
+
+ code += offset_prefix +
+ GenGetter(field.value.type, "(obj, this.bb_pos + offset)") +
+ " : null;\n";
+ break;
+ }
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += "}\n\n";
+
+ // Adds the mutable scalar value to the output
+ if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer &&
+ !IsUnion(field.value.type)) {
+ std::string type =
+ GenTypeName(imports, struct_def, field.value.type, true);
+
+ code += "mutate_" + field.name + "(value:" + type + "):boolean {\n";
+
+ if (struct_def.fixed) {
+ code += " " + GenBBAccess() + ".write" +
+ ConvertCase(GenType(field.value.type), Case::kUpperCamel) +
+ "(this.bb_pos + " + NumToString(field.value.offset) + ", ";
+ } else {
+ code += " const offset = " + GenBBAccess() +
+ ".__offset(this.bb_pos, " + NumToString(field.value.offset) +
+ ");\n\n";
+ code += " if (offset === 0) {\n";
+ code += " return false;\n";
+ code += " }\n\n";
+
+ // special case for bools, which are treated as uint8
+ code += " " + GenBBAccess() + ".write" +
+ ConvertCase(GenType(field.value.type), Case::kUpperCamel) +
+ "(this.bb_pos + offset, ";
+ if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; }
+ }
+
+ code += "value);\n";
+ code += " return true;\n";
+ code += "}\n\n";
+ }
+
+ // Emit vector helpers
+ if (IsVector(field.value.type)) {
+ // Emit a length helper
+ GenDocComment(code_ptr);
+ code += ConvertCase(field.name, Case::kLowerCamel);
+ code += "Length():number {\n" + offset_prefix;
+
+ code +=
+ GenBBAccess() + ".__vector_len(this.bb_pos + offset) : 0;\n}\n\n";
+
+ // For scalar types, emit a typed array helper
+ auto vectorType = field.value.type.VectorType();
+ if (IsScalar(vectorType.base_type) && !IsLong(vectorType.base_type)) {
+ GenDocComment(code_ptr);
+
+ code += ConvertCase(field.name, Case::kLowerCamel);
+ code += "Array():" + GenType(vectorType) + "Array|null {\n" +
+ offset_prefix;
+
+ code += "new " + GenType(vectorType) + "Array(" + GenBBAccess() +
+ ".bytes().buffer, " + GenBBAccess() +
+ ".bytes().byteOffset + " + GenBBAccess() +
+ ".__vector(this.bb_pos + offset), " + GenBBAccess() +
+ ".__vector_len(this.bb_pos + offset)) : null;\n}\n\n";
+ }
+ }
+ }
+
+ // Emit the fully qualified name
+ if (parser_.opts.generate_name_strings) {
+ GenDocComment(code_ptr);
+ code += "static getFullyQualifiedName():string {\n";
+ code += " return '" + WrapInNameSpace(struct_def) + "';\n";
+ code += "}\n\n";
+ }
+
+ // Emit the size of the struct.
+ if (struct_def.fixed) {
+ GenDocComment(code_ptr);
+ code += "static sizeOf():number {\n";
+ code += " return " + NumToString(struct_def.bytesize) + ";\n";
+ code += "}\n\n";
+ }
+
+ // Emit a factory constructor
+ if (struct_def.fixed) {
+ std::string arguments;
+ GenStructArgs(imports, struct_def, &arguments, "");
+ GenDocComment(code_ptr);
+
+ code += "static create" + GetPrefixedName(struct_def) +
+ "(builder:flatbuffers.Builder";
+ code += arguments + "):flatbuffers.Offset {\n";
+
+ GenStructBody(struct_def, &code, "");
+ code += " return builder.offset();\n}\n\n";
+ } else {
+ // Generate a method to start building a new object
+ GenDocComment(code_ptr);
+
+ code += "static start" + GetPrefixedName(struct_def) +
+ "(builder:flatbuffers.Builder) {\n";
+
+ code += " builder.startObject(" +
+ NumToString(struct_def.fields.vec.size()) + ");\n";
+ code += "}\n\n";
+
+ // Generate a set of static methods that allow table construction
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ const auto argname = GetArgName(field);
+
+ // Generate the field insertion method
+ GenDocComment(code_ptr);
+ code += "static add" + ConvertCase(field.name, Case::kUpperCamel);
+ code += "(builder:flatbuffers.Builder, " + argname + ":" +
+ GetArgType(imports, struct_def, field, false) + ") {\n";
+ code += " builder.addField" + GenWriteMethod(field.value.type) + "(";
+ code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
+ if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; }
+ code += argname + ", ";
+ if (!IsScalar(field.value.type.base_type)) {
+ code += "0";
+ } else if (HasNullDefault(field)) {
+ if (IsLong(field.value.type.base_type)) {
+ code += "BigInt(0)";
+ } else {
+ code += "0";
+ }
+ } else {
+ if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; }
+ code += GenDefaultValue(field, imports);
+ }
+ code += ");\n}\n\n";
+
+ if (IsVector(field.value.type)) {
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+
+ // Generate a method to create a vector from a JavaScript array
+ if (!IsStruct(vector_type)) {
+ GenDocComment(code_ptr);
+
+ const std::string sig_begin =
+ "static create" + ConvertCase(field.name, Case::kUpperCamel) +
+ "Vector(builder:flatbuffers.Builder, data:";
+ const std::string sig_end = "):flatbuffers.Offset";
+ std::string type =
+ GenTypeName(imports, struct_def, vector_type, true) + "[]";
+ if (type == "number[]") {
+ const auto &array_type = GenType(vector_type);
+ // the old type should be deprecated in the future
+ std::string type_old = "number[]|Uint8Array";
+ std::string type_new = "number[]|" + array_type + "Array";
+ if (type_old == type_new) {
+ type = type_new;
+ } else {
+ // add function overloads
+ code += sig_begin + type_new + sig_end + ";\n";
+ code +=
+ "/**\n * @deprecated This Uint8Array overload will "
+ "be removed in the future.\n */\n";
+ code += sig_begin + type_old + sig_end + ";\n";
+ type = type_new + "|Uint8Array";
+ }
+ }
+ code += sig_begin + type + sig_end + " {\n";
+ code += " builder.startVector(" + NumToString(elem_size);
+ code += ", data.length, " + NumToString(alignment) + ");\n";
+ code += " for (let i = data.length - 1; i >= 0; i--) {\n";
+ code += " builder.add" + GenWriteMethod(vector_type) + "(";
+ if (vector_type.base_type == BASE_TYPE_BOOL) { code += "+"; }
+ code += "data[i]!);\n";
+ code += " }\n";
+ code += " return builder.endVector();\n";
+ code += "}\n\n";
+ }
+
+ // Generate a method to start a vector, data to be added manually
+ // after
+ GenDocComment(code_ptr);
+
+ code += "static start" + ConvertCase(field.name, Case::kUpperCamel);
+ code += "Vector(builder:flatbuffers.Builder, numElems:number) {\n";
+ code += " builder.startVector(" + NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment) + ");\n";
+ code += "}\n\n";
+ }
+ }
+
+ // Generate a method to stop building a new object
+ GenDocComment(code_ptr);
+
+ code += "static end" + GetPrefixedName(struct_def);
+ code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n";
+
+ code += " const offset = builder.endObject();\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated && field.IsRequired()) {
+ code += " builder.requiredField(offset, ";
+ code += NumToString(field.value.offset);
+ code += ") // " + field.name + "\n";
+ }
+ }
+ code += " return offset;\n";
+ code += "}\n\n";
+
+ // Generate the methods to complete buffer construction
+ GenerateFinisher(struct_def, code_ptr, code, false);
+ GenerateFinisher(struct_def, code_ptr, code, true);
+
+ // Generate a convenient CreateX function
+ if (CanCreateFactoryMethod(struct_def)) {
+ code += "static create" + GetPrefixedName(struct_def);
+ code += "(builder:flatbuffers.Builder";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) continue;
+ code += ", " + GetArgName(field) + ":" +
+ GetArgType(imports, struct_def, field, true);
+ }
+
+ code += "):flatbuffers.Offset {\n";
+ code += " " + object_name + ".start" +
+ GetPrefixedName(struct_def) + "(builder);\n";
+
+ std::string methodPrefix = object_name;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) continue;
+
+ const auto arg_name = GetArgName(field);
+
+ if (field.IsScalarOptional()) {
+ code += " if (" + arg_name + " !== null)\n ";
+ }
+
+ code += " " + methodPrefix + ".add" +
+ ConvertCase(field.name, Case::kUpperCamel) + "(";
+ code += "builder, " + arg_name + ");\n";
+ }
+
+ code += " return " + methodPrefix + ".end" +
+ GetPrefixedName(struct_def) + "(builder);\n";
+ code += "}\n";
+ }
+ }
+
+ if (!struct_def.fixed && parser_.services_.vec.size() != 0) {
+ auto name = GetPrefixedName(struct_def, "");
+ code += "\n";
+ code += "serialize():Uint8Array {\n";
+ code += " return this.bb!.bytes();\n";
+ code += "}\n";
+
+ code += "\n";
+ code += "static deserialize(buffer: Uint8Array):" + EscapeKeyword(name) +
+ " {\n";
+ code += " return " +
+ EscapeKeyword(AddImport(imports, struct_def, struct_def)) +
+ ".getRootAs" + name + "(new flatbuffers.ByteBuffer(buffer))\n";
+ code += "}\n";
+ }
+
+ if (parser_.opts.generate_object_based_api) {
+ std::string obj_api_class;
+ std::string obj_api_unpack_func;
+ GenObjApi(parser_, struct_def, obj_api_unpack_func, obj_api_class,
+ imports);
+
+ code += obj_api_unpack_func + "}\n" + obj_api_class;
+ } else {
+ code += "}\n";
+ }
+ }
+
+ static bool HasNullDefault(const FieldDef &field) {
+ return field.IsOptional() && field.value.constant == "null";
+ }
+
+ std::string GetArgType(import_set &imports, const Definition &owner,
+ const FieldDef &field, bool allowNull) {
+ return GenTypeName(imports, owner, field.value.type, true,
+ allowNull && field.IsOptional());
+ }
+
+ std::string GetArgName(const FieldDef &field) {
+ auto argname = ConvertCase(field.name, Case::kLowerCamel);
+ if (!IsScalar(field.value.type.base_type)) {
+ argname += "Offset";
+ } else {
+ argname = EscapeKeyword(argname);
+ }
+ return argname;
+ }
+
+ std::string GetPrefixedName(const StructDef &struct_def,
+ const char *prefix = "") {
+ return prefix + struct_def.name;
+ }
+}; // namespace ts
+} // namespace ts
+
+bool GenerateTS(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ ts::TsGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+std::string TSMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ ts::TsGenerator generator(parser, path, file_name);
+ std::string make_rule =
+ generator.GeneratedFileName(path, filebase, parser.opts) + ": ";
+
+ auto included_files = parser.GetIncludedFilesRecursive(file_name);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+} // namespace flatbuffers
diff --git a/third_party/flatbuffers/src/idl_parser.cpp b/third_party/flatbuffers/src/idl_parser.cpp
index 6d916e5..e9aa477 100644
--- a/third_party/flatbuffers/src/idl_parser.cpp
+++ b/third_party/flatbuffers/src/idl_parser.cpp
@@ -20,6 +20,7 @@
#include <string>
#include <utility>
+#include "flatbuffers/base.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
@@ -56,7 +57,7 @@
// The enums in the reflection schema should match the ones we use internally.
// Compare the last element to check if these go out of sync.
-static_assert(BASE_TYPE_UNION == static_cast<BaseType>(reflection::Union),
+static_assert(BASE_TYPE_UNION == static_cast<BaseType>(reflection::BaseType::Union),
"enums don't match");
// Any parsing calls have to be wrapped in this macro, which automates
@@ -92,33 +93,6 @@
return true;
}
-// Convert an underscore_based_indentifier in to camelCase.
-// Also uppercases the first character if first is true.
-std::string MakeCamel(const std::string &in, bool first) {
- std::string s;
- for (size_t i = 0; i < in.length(); i++) {
- if (!i && first)
- s += CharToUpper(in[0]);
- else if (in[i] == '_' && i + 1 < in.length())
- s += CharToUpper(in[++i]);
- else
- s += in[i];
- }
- return s;
-}
-
-// Convert an underscore_based_identifier in to screaming snake case.
-std::string MakeScreamingCamel(const std::string &in) {
- std::string s;
- for (size_t i = 0; i < in.length(); i++) {
- if (in[i] != '_')
- s += CharToUpper(in[i]);
- else
- s += in[i];
- }
- return s;
-}
-
void DeserializeDoc(std::vector<std::string> &doc,
const Vector<Offset<String>> *documentation) {
if (documentation == nullptr) return;
@@ -142,7 +116,12 @@
error_ += ": " + msg;
}
-void Parser::Warning(const std::string &msg) { Message("warning: " + msg); }
+void Parser::Warning(const std::string &msg) {
+ if (!opts.no_warnings) {
+ Message("warning: " + msg);
+ has_warning_ = true; // for opts.warnings_as_errors
+ }
+}
CheckedError Parser::Error(const std::string &msg) {
Message("error: " + msg);
@@ -152,19 +131,39 @@
inline CheckedError NoError() { return CheckedError(false); }
CheckedError Parser::RecurseError() {
- return Error("maximum parsing recursion of " +
- NumToString(FLATBUFFERS_MAX_PARSING_DEPTH) + " reached");
+ return Error("maximum parsing depth " + NumToString(parse_depth_counter_) +
+ " reached");
}
-template<typename F> CheckedError Parser::Recurse(F f) {
- if (recurse_protection_counter >= (FLATBUFFERS_MAX_PARSING_DEPTH))
- return RecurseError();
- recurse_protection_counter++;
- auto ce = f();
- recurse_protection_counter--;
- return ce;
+const std::string &Parser::GetPooledString(const std::string &s) const {
+ return *(string_cache_.insert(s).first);
}
+class Parser::ParseDepthGuard {
+ public:
+ explicit ParseDepthGuard(Parser *parser_not_null)
+ : parser_(*parser_not_null), caller_depth_(parser_.parse_depth_counter_) {
+ FLATBUFFERS_ASSERT(caller_depth_ <= (FLATBUFFERS_MAX_PARSING_DEPTH) &&
+ "Check() must be called to prevent stack overflow");
+ parser_.parse_depth_counter_ += 1;
+ }
+
+ ~ParseDepthGuard() { parser_.parse_depth_counter_ -= 1; }
+
+ CheckedError Check() {
+ return caller_depth_ >= (FLATBUFFERS_MAX_PARSING_DEPTH)
+ ? parser_.RecurseError()
+ : CheckedError(false);
+ }
+
+ FLATBUFFERS_DELETE_FUNC(ParseDepthGuard(const ParseDepthGuard &));
+ FLATBUFFERS_DELETE_FUNC(ParseDepthGuard &operator=(const ParseDepthGuard &));
+
+ private:
+ Parser &parser_;
+ const int caller_depth_;
+};
+
template<typename T> std::string TypeToIntervalString() {
return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
@@ -172,8 +171,20 @@
// atot: template version of atoi/atof: convert a string to an instance of T.
template<typename T>
-inline CheckedError atot(const char *s, Parser &parser, T *val) {
- auto done = StringToNumber(s, val);
+bool atot_scalar(const char *s, T *val, bool_constant<false>) {
+ return StringToNumber(s, val);
+}
+
+template<typename T>
+bool atot_scalar(const char *s, T *val, bool_constant<true>) {
+ // Normalize NaN parsed from fbs or json to unsigned NaN.
+ if (false == StringToNumber(s, val)) return false;
+ *val = (*val != *val) ? std::fabs(*val) : *val;
+ return true;
+}
+
+template<typename T> CheckedError atot(const char *s, Parser &parser, T *val) {
+ auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
if (done) return NoError();
if (0 == *val)
return parser.Error("invalid number: \"" + std::string(s) + "\"");
@@ -195,9 +206,10 @@
if (components.empty() || !max_components) { return name; }
std::string stream_str;
for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
- if (i) { stream_str += '.'; }
- stream_str += std::string(components[i]);
+ stream_str += components[i];
+ stream_str += '.';
}
+ if (!stream_str.empty()) stream_str.pop_back();
if (name.length()) {
stream_str += '.';
stream_str += name;
@@ -205,6 +217,29 @@
return stream_str;
}
+template<typename T>
+T *LookupTableByName(const SymbolTable<T> &table, const std::string &name,
+ const Namespace ¤t_namespace, size_t skip_top) {
+ const auto &components = current_namespace.components;
+ if (table.dict.empty()) return nullptr;
+ if (components.size() < skip_top) return nullptr;
+ const auto N = components.size() - skip_top;
+ std::string full_name;
+ for (size_t i = 0; i < N; i++) {
+ full_name += components[i];
+ full_name += '.';
+ }
+ for (size_t i = N; i > 0; i--) {
+ full_name += name;
+ auto obj = table.Lookup(full_name);
+ if (obj) return obj;
+ auto len = full_name.size() - components[i - 1].size() - 1 - name.size();
+ full_name.resize(len);
+ }
+ FLATBUFFERS_ASSERT(full_name.empty());
+ return table.Lookup(name); // lookup in global namespace
+}
+
// Declare tokens we'll use. Single character tokens are represented by their
// ascii character code (e.g. '{'), others above 256.
// clang-format off
@@ -444,15 +479,19 @@
}
FLATBUFFERS_FALLTHROUGH(); // else fall thru
default:
- const auto has_sign = (c == '+') || (c == '-');
- // '-'/'+' and following identifier - can be a predefined constant like:
- // NAN, INF, PI, etc or it can be a function name like cos/sin/deg.
- if (IsIdentifierStart(c) || (has_sign && IsIdentifierStart(*cursor_))) {
+ if (IsIdentifierStart(c)) {
// Collect all chars of an identifier:
const char *start = cursor_ - 1;
while (IsIdentifierStart(*cursor_) || is_digit(*cursor_)) cursor_++;
attribute_.append(start, cursor_);
- token_ = has_sign ? kTokenStringConstant : kTokenIdentifier;
+ token_ = kTokenIdentifier;
+ return NoError();
+ }
+
+ const auto has_sign = (c == '+') || (c == '-');
+ if (has_sign && IsIdentifierStart(*cursor_)) {
+ // '-'/'+' and following identifier - it could be a predefined
+ // constant. Return the sign in token_, see ParseSingleValue.
return NoError();
}
@@ -544,13 +583,7 @@
EnumDef *Parser::LookupEnum(const std::string &id) {
// Search thru parent namespaces.
- for (int components = static_cast<int>(current_namespace_->components.size());
- components >= 0; components--) {
- auto ed = enums_.Lookup(
- current_namespace_->GetFullyQualifiedName(id, components));
- if (ed) return ed;
- }
- return nullptr;
+ return LookupTableByName(enums_, id, *current_namespace_, 0);
}
StructDef *Parser::LookupStruct(const std::string &id) const {
@@ -559,6 +592,13 @@
return sd;
}
+StructDef *Parser::LookupStructThruParentNamespaces(
+ const std::string &id) const {
+ auto sd = LookupTableByName(structs_, id, *current_namespace_, 1);
+ if (sd) sd->refcount++;
+ return sd;
+}
+
CheckedError Parser::ParseTypeIdent(Type &type) {
std::string id = attribute_;
EXPECT(kTokenIdentifier);
@@ -617,9 +657,11 @@
ECHECK(ParseTypeIdent(type));
}
} else if (token_ == '[') {
+ ParseDepthGuard depth_guard(this);
+ ECHECK(depth_guard.Check());
NEXT();
Type subtype;
- ECHECK(Recurse([&]() { return ParseType(subtype); }));
+ ECHECK(ParseType(subtype));
if (IsSeries(subtype)) {
// We could support this, but it will complicate things, and it's
// easier to work around with a struct around the inner vector.
@@ -704,10 +746,13 @@
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_ |= static_cast<uint64_t>(reflection::AdvancedFeatures::AdvancedArrayFeatures);
+ if (!SupportsAdvancedArrayFeatures()) {
+ return Error(
+ "Arrays are not yet supported in all "
+ "the specified programming languages.");
+ }
}
FieldDef *typefield = nullptr;
@@ -717,6 +762,7 @@
ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
type.enum_def->underlying_type, &typefield));
} else if (IsVector(type) && type.element == BASE_TYPE_UNION) {
+ advanced_features_ |= static_cast<uint64_t>(reflection::AdvancedFeatures::AdvancedUnionFeatures);
// Only cpp, js and ts supports the union vector feature so far.
if (!SupportsAdvancedUnionFeatures()) {
return Error(
@@ -737,38 +783,23 @@
if (token_ == '=') {
NEXT();
ECHECK(ParseSingleValue(&field->name, field->value, true));
- if (!IsScalar(type.base_type) ||
- (struct_def.fixed && field->value.constant != "0"))
+ if (IsStruct(type) || (struct_def.fixed && field->value.constant != "0"))
return Error(
- "default values currently only supported for scalars in tables");
- }
-
- // Mark the optional scalars. Note that a side effect of ParseSingleValue is
- // fixing field->value.constant to null.
- if (IsScalar(type.base_type)) {
- field->optional = (field->value.constant == "null");
- if (field->optional) {
- if (type.enum_def && type.enum_def->Lookup("null")) {
- FLATBUFFERS_ASSERT(IsInteger(type.base_type));
+ "default values are not supported for struct fields, table fields, "
+ "or in structs.");
+ if (IsString(type) || IsVector(type)) {
+ advanced_features_ |= static_cast<uint64_t>(reflection::AdvancedFeatures::DefaultVectorsAndStrings);
+ if (field->value.constant != "0" && !SupportsDefaultVectorsAndStrings()) {
return Error(
- "the default 'null' is reserved for declaring optional scalar "
- "fields, it conflicts with declaration of enum '" +
- type.enum_def->name + "'.");
- }
- if (field->attributes.Lookup("key")) {
- return Error(
- "only a non-optional scalar field can be used as a 'key' field");
- }
- if (!SupportsOptionalScalars()) {
- return Error(
- "Optional scalars are not yet supported in at least one the of "
- "the specified programming languages.");
+ "Default values for strings and vectors are not supported in one "
+ "of the specified programming languages");
}
}
- } else {
- // For nonscalars, only required fields are non-optional.
- // At least until https://github.com/google/flatbuffers/issues/6053
- field->optional = !field->required;
+
+ if (IsVector(type) && field->value.constant != "0" &&
+ field->value.constant != "[]") {
+ return Error("The only supported default for vectors is `[]`.");
+ }
}
// Append .0 if the value has not it (skip hex and scientific floats).
@@ -786,27 +817,6 @@
field->value.constant += ".0";
}
}
- if (type.enum_def) {
- // The type.base_type can only be scalar, union, array or vector.
- // Table, struct or string can't have enum_def.
- // Default value of union and vector in NONE, NULL translated to "0".
- FLATBUFFERS_ASSERT(IsInteger(type.base_type) ||
- (type.base_type == BASE_TYPE_UNION) || IsVector(type) ||
- IsArray(type));
- if (IsVector(type)) {
- // Vector can't use initialization list.
- FLATBUFFERS_ASSERT(field->value.constant == "0");
- } else {
- // All unions should have the NONE ("0") enum value.
- auto in_enum = type.enum_def->attributes.Lookup("bit_flags") ||
- field->IsScalarOptional() ||
- type.enum_def->FindByValue(field->value.constant);
- if (false == in_enum)
- return Error("default value of " + field->value.constant +
- " for field " + name + " is not part of enum " +
- type.enum_def->name);
- }
- }
field->doc_comment = dc;
ECHECK(ParseMetaData(&field->attributes));
@@ -841,6 +851,87 @@
"hashing.");
}
}
+
+ // For historical convenience reasons, string keys are assumed required.
+ // Scalars are kDefault unless otherwise specified.
+ // Nonscalars are kOptional unless required;
+ field->key = field->attributes.Lookup("key") != nullptr;
+ const bool required = field->attributes.Lookup("required") != nullptr ||
+ (IsString(type) && field->key);
+ const bool default_str_or_vec =
+ ((IsString(type) || IsVector(type)) && field->value.constant != "0");
+ const bool optional = IsScalar(type.base_type)
+ ? (field->value.constant == "null")
+ : !(required || default_str_or_vec);
+ if (required && optional) {
+ return Error("Fields cannot be both optional and required.");
+ }
+ field->presence = FieldDef::MakeFieldPresence(optional, required);
+
+ if (required && (struct_def.fixed || IsScalar(type.base_type))) {
+ return Error("only non-scalar fields in tables may be 'required'");
+ }
+ if (field->key) {
+ if (struct_def.has_key) return Error("only one field may be set as 'key'");
+ struct_def.has_key = true;
+ if (!IsScalar(type.base_type) && !IsString(type)) {
+ return Error("'key' field must be string or scalar type");
+ }
+ }
+
+ if (field->IsScalarOptional()) {
+ advanced_features_ |= static_cast<uint64_t>(reflection::AdvancedFeatures::OptionalScalars);
+ if (type.enum_def && type.enum_def->Lookup("null")) {
+ FLATBUFFERS_ASSERT(IsInteger(type.base_type));
+ return Error(
+ "the default 'null' is reserved for declaring optional scalar "
+ "fields, it conflicts with declaration of enum '" +
+ type.enum_def->name + "'.");
+ }
+ if (field->attributes.Lookup("key")) {
+ return Error(
+ "only a non-optional scalar field can be used as a 'key' field");
+ }
+ if (!SupportsOptionalScalars()) {
+ return Error(
+ "Optional scalars are not yet supported in at least one of "
+ "the specified programming languages.");
+ }
+ }
+
+ if (type.enum_def) {
+ // Verify the enum's type and default value.
+ const std::string &constant = field->value.constant;
+ if (type.base_type == BASE_TYPE_UNION) {
+ if (constant != "0") { return Error("Union defaults must be NONE"); }
+ } else if (IsVector(type)) {
+ if (constant != "0" && constant != "[]") {
+ return Error("Vector defaults may only be `[]`.");
+ }
+ } else if (IsArray(type)) {
+ if (constant != "0") {
+ return Error("Array defaults are not supported yet.");
+ }
+ } else {
+ if (!IsInteger(type.base_type)) {
+ return Error("Enums must have integer base types");
+ }
+ // Optional and bitflags enums may have default constants that are not
+ // their specified variants.
+ if (!field->IsOptional() &&
+ type.enum_def->attributes.Lookup("bit_flags") == nullptr) {
+ if (type.enum_def->FindByValue(constant) == nullptr) {
+ return Error("default value of `" + constant + "` for " + "field `" +
+ name + "` is not part of enum `" + type.enum_def->name +
+ "`.");
+ }
+ }
+ }
+ }
+
+ if (field->deprecated && struct_def.fixed)
+ return Error("can't deprecate fields in a struct");
+
auto cpp_type = field->attributes.Lookup("cpp_type");
if (cpp_type) {
if (!hash_name)
@@ -854,28 +945,7 @@
field->attributes.Add("cpp_ptr_type", val);
}
}
- if (field->deprecated && struct_def.fixed)
- return Error("can't deprecate fields in a struct");
- field->required = field->attributes.Lookup("required") != nullptr;
- if (field->required && (struct_def.fixed || IsScalar(type.base_type)))
- return Error("only non-scalar fields in tables may be 'required'");
- if (!IsScalar(type.base_type)) {
- // For nonscalars, only required fields are non-optional.
- // At least until https://github.com/google/flatbuffers/issues/6053
- field->optional = !field->required;
- }
-
- field->key = field->attributes.Lookup("key") != nullptr;
- if (field->key) {
- if (struct_def.has_key) return Error("only one field may be set as 'key'");
- struct_def.has_key = true;
- if (!IsScalar(type.base_type)) {
- field->required = true;
- if (type.base_type != BASE_TYPE_STRING)
- return Error("'key' field must be string or scalar type");
- }
- }
field->shared = field->attributes.Lookup("shared") != nullptr;
if (field->shared && field->value.type.base_type != BASE_TYPE_STRING)
return Error("shared can only be defined on strings");
@@ -914,17 +984,28 @@
if (typefield) {
if (!IsScalar(typefield->value.type.base_type)) {
// this is a union vector field
- typefield->required = field->required;
+ typefield->presence = field->presence;
}
// If this field is a union, and it has a manually assigned id,
// the automatically added type field should have an id as well (of N - 1).
auto attr = field->attributes.Lookup("id");
if (attr) {
- auto id = atoi(attr->constant.c_str());
- auto val = new Value();
- val->type = attr->type;
- val->constant = NumToString(id - 1);
- typefield->attributes.Add("id", val);
+ const auto &id_str = attr->constant;
+ voffset_t id = 0;
+ const auto done = !atot(id_str.c_str(), *this, &id).Check();
+ if (done && id > 0) {
+ auto val = new Value();
+ val->type = attr->type;
+ val->constant = NumToString(id - 1);
+ typefield->attributes.Add("id", val);
+ } else {
+ return Error(
+ "a union type effectively adds two fields with non-negative ids, "
+ "its id must be that of the second field (the first field is "
+ "the type field and not explicitly declared in the schema);\n"
+ "field: " +
+ field->name + ", id: " + id_str);
+ }
}
// if this field is a union that is deprecated,
// the automatically added type field should be deprecated as well
@@ -1006,6 +1087,8 @@
}
if (next_name == type_name) {
EXPECT(':');
+ ParseDepthGuard depth_guard(this);
+ ECHECK(depth_guard.Check());
Value type_val = type_field->value;
ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr, 0));
constant = type_val.constant;
@@ -1018,6 +1101,9 @@
}
uint8_t enum_idx;
if (vector_of_union_types) {
+ if (vector_of_union_types->size() <= count)
+ return Error("union types vector smaller than union values vector"
+ " for: " + field->name);
enum_idx = vector_of_union_types->Get(count);
} else {
ECHECK(atot(constant.c_str(), *this, &enum_idx));
@@ -1132,6 +1218,9 @@
CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
uoffset_t *ovalue) {
+ ParseDepthGuard depth_guard(this);
+ ECHECK(depth_guard.Check());
+
size_t fieldn_outer = 0;
auto err = ParseTableDelimiters(
fieldn_outer, &struct_def,
@@ -1167,9 +1256,7 @@
ECHECK(
ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
} else {
- ECHECK(Recurse([&]() {
- return ParseAnyValue(val, field, fieldn, struct_def_inner, 0);
- }));
+ ECHECK(ParseAnyValue(val, field, fieldn, struct_def_inner, 0));
}
// Hardcoded insertion-sort with error-check.
// If fields are specified in order, then this loop exits
@@ -1195,7 +1282,7 @@
for (auto field_it = struct_def.fields.vec.begin();
field_it != struct_def.fields.vec.end(); ++field_it) {
auto required_field = *field_it;
- if (!required_field->required) { continue; }
+ if (!required_field->IsRequired()) { continue; }
bool found = false;
for (auto pf_it = field_stack_.end() - fieldn_outer;
pf_it != field_stack_.end(); ++pf_it) {
@@ -1227,7 +1314,7 @@
if (!struct_def.sortbysize ||
size == SizeOf(field_value.type.base_type)) {
switch (field_value.type.base_type) {
-// clang-format off
+ // clang-format off
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
case BASE_TYPE_ ## ENUM: \
builder_.Pad(field->padding); \
@@ -1303,22 +1390,71 @@
return NoError();
}
-static bool CompareType(const uint8_t *a, const uint8_t *b, BaseType ftype) {
- switch (ftype) {
-#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
- case BASE_TYPE_##ENUM: return ReadScalar<CTYPE>(a) < ReadScalar<CTYPE>(b);
+static bool CompareSerializedScalars(const uint8_t *a, const uint8_t *b,
+ const FieldDef &key) {
+ switch (key.value.type.base_type) {
+#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_##ENUM: { \
+ CTYPE def = static_cast<CTYPE>(0); \
+ if (!a || !b) { StringToNumber(key.value.constant.c_str(), &def); } \
+ const auto av = a ? ReadScalar<CTYPE>(a) : def; \
+ const auto bv = b ? ReadScalar<CTYPE>(b) : def; \
+ return av < bv; \
+ }
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
- case BASE_TYPE_STRING:
- // Indirect offset pointer to string pointer.
- a += ReadScalar<uoffset_t>(a);
- b += ReadScalar<uoffset_t>(b);
- return *reinterpret_cast<const String *>(a) <
- *reinterpret_cast<const String *>(b);
- default: return false;
+ default: {
+ FLATBUFFERS_ASSERT(false && "scalar type expected");
+ return false;
+ }
}
}
+static bool CompareTablesByScalarKey(const Offset<Table> *_a,
+ const Offset<Table> *_b,
+ const FieldDef &key) {
+ const voffset_t offset = key.value.offset;
+ // Indirect offset pointer to table pointer.
+ auto a = reinterpret_cast<const uint8_t *>(_a) + ReadScalar<uoffset_t>(_a);
+ auto b = reinterpret_cast<const uint8_t *>(_b) + ReadScalar<uoffset_t>(_b);
+ // Fetch field address from table.
+ a = reinterpret_cast<const Table *>(a)->GetAddressOf(offset);
+ b = reinterpret_cast<const Table *>(b)->GetAddressOf(offset);
+ return CompareSerializedScalars(a, b, key);
+}
+
+static bool CompareTablesByStringKey(const Offset<Table> *_a,
+ const Offset<Table> *_b,
+ const FieldDef &key) {
+ const voffset_t offset = key.value.offset;
+ // Indirect offset pointer to table pointer.
+ auto a = reinterpret_cast<const uint8_t *>(_a) + ReadScalar<uoffset_t>(_a);
+ auto b = reinterpret_cast<const uint8_t *>(_b) + ReadScalar<uoffset_t>(_b);
+ // Fetch field address from table.
+ a = reinterpret_cast<const Table *>(a)->GetAddressOf(offset);
+ b = reinterpret_cast<const Table *>(b)->GetAddressOf(offset);
+ if (a && b) {
+ // Indirect offset pointer to string pointer.
+ a += ReadScalar<uoffset_t>(a);
+ b += ReadScalar<uoffset_t>(b);
+ return *reinterpret_cast<const String *>(a) <
+ *reinterpret_cast<const String *>(b);
+ } else {
+ return a ? true : false;
+ }
+}
+
+static void SwapSerializedTables(Offset<Table> *a, Offset<Table> *b) {
+ // These are serialized offsets, so are relative where they are
+ // stored in memory, so compute the distance between these pointers:
+ ptrdiff_t diff = (b - a) * sizeof(Offset<Table>);
+ FLATBUFFERS_ASSERT(diff >= 0); // Guaranteed by SimpleQsort.
+ auto udiff = static_cast<uoffset_t>(diff);
+ a->o = EndianScalar(ReadScalar<uoffset_t>(a) - udiff);
+ b->o = EndianScalar(ReadScalar<uoffset_t>(b) + udiff);
+ std::swap(*a, *b);
+}
+
// See below for why we need our own sort :(
template<typename T, typename F, typename S>
void SimpleQsort(T *begin, T *end, size_t width, F comparator, S swapper) {
@@ -1339,34 +1475,50 @@
SimpleQsort(r, end, width, comparator, swapper);
}
+CheckedError Parser::ParseAlignAttribute(const std::string &align_constant,
+ size_t min_align, size_t *align) {
+ // Use uint8_t to avoid problems with size_t==`unsigned long` on LP64.
+ uint8_t align_value;
+ if (StringToNumber(align_constant.c_str(), &align_value) &&
+ VerifyAlignmentRequirements(static_cast<size_t>(align_value),
+ min_align)) {
+ *align = align_value;
+ return NoError();
+ }
+ return Error("unexpected force_align value '" + align_constant +
+ "', alignment must be a power of two integer ranging from the "
+ "type\'s natural alignment " +
+ NumToString(min_align) + " to " +
+ NumToString(FLATBUFFERS_MAX_ALIGNMENT));
+}
+
CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue,
FieldDef *field, size_t fieldn) {
uoffset_t count = 0;
auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
Value val;
val.type = type;
- ECHECK(Recurse([&]() {
- return ParseAnyValue(val, field, fieldn, nullptr, count, true);
- }));
+ ECHECK(ParseAnyValue(val, field, fieldn, nullptr, count, true));
field_stack_.push_back(std::make_pair(val, nullptr));
return NoError();
});
ECHECK(err);
- const auto *force_align = field->attributes.Lookup("force_align");
- const size_t align =
- force_align ? static_cast<size_t>(atoi(force_align->constant.c_str()))
- : 1;
const size_t len = count * InlineSize(type) / InlineAlignment(type);
const size_t elemsize = InlineAlignment(type);
- if (align > 1) { builder_.ForceVectorAlignment(len, elemsize, align); }
+ const auto force_align = field->attributes.Lookup("force_align");
+ if (force_align) {
+ size_t align;
+ ECHECK(ParseAlignAttribute(force_align->constant, 1, &align));
+ if (align > 1) { builder_.ForceVectorAlignment(len, elemsize, align); }
+ }
builder_.StartVector(len, elemsize);
for (uoffset_t i = 0; i < count; i++) {
// start at the back, since we're building the data backwards.
auto &val = field_stack_.back().first;
switch (val.type.base_type) {
-// clang-format off
+ // clang-format off
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE,...) \
case BASE_TYPE_ ## ENUM: \
if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
@@ -1405,23 +1557,21 @@
// globals, making parsing thread-unsafe.
// So for now, we use SimpleQsort above.
// TODO: replace with something better, preferably not recursive.
- voffset_t offset = key->value.offset;
- BaseType ftype = key->value.type.base_type;
if (type.struct_def->fixed) {
+ const voffset_t offset = key->value.offset;
+ const size_t struct_size = type.struct_def->bytesize;
auto v =
reinterpret_cast<VectorOfAny *>(builder_.GetCurrentBufferPointer());
SimpleQsort<uint8_t>(
v->Data(), v->Data() + v->size() * type.struct_def->bytesize,
type.struct_def->bytesize,
- [&](const uint8_t *a, const uint8_t *b) -> bool {
- return CompareType(a + offset, b + offset, ftype);
+ [offset, key](const uint8_t *a, const uint8_t *b) -> bool {
+ return CompareSerializedScalars(a + offset, b + offset, *key);
},
- [&](uint8_t *a, uint8_t *b) {
+ [struct_size](uint8_t *a, uint8_t *b) {
// FIXME: faster?
- for (size_t i = 0; i < type.struct_def->bytesize; i++) {
- std::swap(a[i], b[i]);
- }
+ for (size_t i = 0; i < struct_size; i++) { std::swap(a[i], b[i]); }
});
} else {
auto v = reinterpret_cast<Vector<Offset<Table>> *>(
@@ -1429,29 +1579,21 @@
// Here also can't use std::sort. We do have an iterator type for it,
// but it is non-standard as it will dereference the offsets, and thus
// can't be used to swap elements.
- SimpleQsort<Offset<Table>>(
- v->data(), v->data() + v->size(), 1,
- [&](const Offset<Table> *_a, const Offset<Table> *_b) -> bool {
- // Indirect offset pointer to table pointer.
- auto a = reinterpret_cast<const uint8_t *>(_a) +
- ReadScalar<uoffset_t>(_a);
- auto b = reinterpret_cast<const uint8_t *>(_b) +
- ReadScalar<uoffset_t>(_b);
- // Fetch field address from table.
- a = reinterpret_cast<const Table *>(a)->GetAddressOf(offset);
- b = reinterpret_cast<const Table *>(b)->GetAddressOf(offset);
- return CompareType(a, b, ftype);
- },
- [&](Offset<Table> *a, Offset<Table> *b) {
- // These are serialized offsets, so are relative where they are
- // stored in memory, so compute the distance between these pointers:
- ptrdiff_t diff = (b - a) * sizeof(Offset<Table>);
- FLATBUFFERS_ASSERT(diff >= 0); // Guaranteed by SimpleQsort.
- auto udiff = static_cast<uoffset_t>(diff);
- a->o = EndianScalar(ReadScalar<uoffset_t>(a) - udiff);
- b->o = EndianScalar(ReadScalar<uoffset_t>(b) + udiff);
- std::swap(*a, *b);
- });
+ if (key->value.type.base_type == BASE_TYPE_STRING) {
+ SimpleQsort<Offset<Table>>(
+ v->data(), v->data() + v->size(), 1,
+ [key](const Offset<Table> *_a, const Offset<Table> *_b) -> bool {
+ return CompareTablesByStringKey(_a, _b, *key);
+ },
+ SwapSerializedTables);
+ } else {
+ SimpleQsort<Offset<Table>>(
+ v->data(), v->data() + v->size(), 1,
+ [key](const Offset<Table> *_a, const Offset<Table> *_b) -> bool {
+ return CompareTablesByScalarKey(_a, _b, *key);
+ },
+ SwapSerializedTables);
+ }
}
}
return NoError();
@@ -1464,7 +1606,7 @@
auto length = array.type.fixed_length;
uoffset_t count = 0;
auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
- vector_emplace_back(&stack, Value());
+ stack.emplace_back(Value());
auto &val = stack.back();
val.type = type;
if (IsStruct(type)) {
@@ -1508,7 +1650,13 @@
size_t fieldn,
const StructDef *parent_struct_def) {
if (token_ == '[') { // backwards compat for 'legacy' ubyte buffers
- ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def, 0));
+ if (opts.json_nested_legacy_flatbuffers) {
+ ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def, 0));
+ } else {
+ return Error(
+ "cannot parse nested_flatbuffer as bytes unless"
+ " --json-nested-bytes is set");
+ }
} else {
auto cursor_at_value_begin = cursor_;
ECHECK(SkipAnyJsonValue());
@@ -1521,7 +1669,7 @@
nested_parser.enums_ = enums_;
nested_parser.opts = opts;
nested_parser.uses_flexbuffers_ = uses_flexbuffers_;
-
+ nested_parser.parse_depth_counter_ = parse_depth_counter_;
// Parse JSON substring into new flatbuffer builder using nested_parser
bool ok = nested_parser.Parse(substring.c_str(), nullptr, nullptr);
@@ -1670,6 +1818,9 @@
#endif
CheckedError Parser::ParseFunction(const std::string *name, Value &e) {
+ ParseDepthGuard depth_guard(this);
+ ECHECK(depth_guard.Check());
+
// Copy name, attribute will be changed on NEXT().
const auto functionname = attribute_;
if (!IsFloat(e.type.base_type)) {
@@ -1680,7 +1831,7 @@
}
NEXT();
EXPECT('(');
- ECHECK(Recurse([&]() { return ParseSingleValue(name, e, false); }));
+ ECHECK(ParseSingleValue(name, e, false));
EXPECT(')');
// calculate with double precision
double x, y = 0.0;
@@ -1712,56 +1863,61 @@
CheckedError Parser::TryTypedValue(const std::string *name, int dtoken,
bool check, Value &e, BaseType req,
bool *destmatch) {
- bool match = dtoken == token_;
- if (match) {
- FLATBUFFERS_ASSERT(*destmatch == false);
- *destmatch = true;
- e.constant = attribute_;
- // Check token match
- if (!check) {
- if (e.type.base_type == BASE_TYPE_NONE) {
- e.type.base_type = req;
- } else {
- return Error(
- std::string("type mismatch: expecting: ") +
- kTypeNames[e.type.base_type] + ", found: " + kTypeNames[req] +
- ", name: " + (name ? *name : "") + ", value: " + e.constant);
- }
+ FLATBUFFERS_ASSERT(*destmatch == false && dtoken == token_);
+ *destmatch = true;
+ e.constant = attribute_;
+ // Check token match
+ if (!check) {
+ if (e.type.base_type == BASE_TYPE_NONE) {
+ e.type.base_type = req;
+ } else {
+ return Error(std::string("type mismatch: expecting: ") +
+ kTypeNames[e.type.base_type] +
+ ", found: " + kTypeNames[req] +
+ ", name: " + (name ? *name : "") + ", value: " + e.constant);
}
- // The exponent suffix of hexadecimal float-point number is mandatory.
- // A hex-integer constant is forbidden as an initializer of float number.
- if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) {
- const auto &s = e.constant;
- const auto k = s.find_first_of("0123456789.");
- if ((std::string::npos != k) && (s.length() > (k + 1)) &&
- (s[k] == '0' && is_alpha_char(s[k + 1], 'X')) &&
- (std::string::npos == s.find_first_of("pP", k + 2))) {
- return Error(
- "invalid number, the exponent suffix of hexadecimal "
- "floating-point literals is mandatory: \"" +
- s + "\"");
- }
- }
- NEXT();
}
+ // The exponent suffix of hexadecimal float-point number is mandatory.
+ // A hex-integer constant is forbidden as an initializer of float number.
+ if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) {
+ const auto &s = e.constant;
+ const auto k = s.find_first_of("0123456789.");
+ if ((std::string::npos != k) && (s.length() > (k + 1)) &&
+ (s[k] == '0' && is_alpha_char(s[k + 1], 'X')) &&
+ (std::string::npos == s.find_first_of("pP", k + 2))) {
+ return Error(
+ "invalid number, the exponent suffix of hexadecimal "
+ "floating-point literals is mandatory: \"" +
+ s + "\"");
+ }
+ }
+ NEXT();
return NoError();
}
CheckedError Parser::ParseSingleValue(const std::string *name, Value &e,
bool check_now) {
+ if (token_ == '+' || token_ == '-') {
+ const char sign = static_cast<char>(token_);
+ // Get an indentifier: NAN, INF, or function name like cos/sin/deg.
+ NEXT();
+ if (token_ != kTokenIdentifier) return Error("constant name expected");
+ attribute_.insert(0, 1, sign);
+ }
+
const auto in_type = e.type.base_type;
const auto is_tok_ident = (token_ == kTokenIdentifier);
const auto is_tok_string = (token_ == kTokenStringConstant);
- // First see if this could be a conversion function:
+ // First see if this could be a conversion function.
if (is_tok_ident && *cursor_ == '(') { return ParseFunction(name, e); }
// clang-format off
auto match = false;
#define IF_ECHECK_(force, dtoken, check, req) \
- if (!match && ((check) || IsConstTrue(force))) \
- ECHECK(TryTypedValue(name, dtoken, check, e, req, &match))
+ if (!match && ((dtoken) == token_) && ((check) || IsConstTrue(force))) \
+ ECHECK(TryTypedValue(name, dtoken, check, e, req, &match))
#define TRY_ECHECK(dtoken, check, req) IF_ECHECK_(false, dtoken, check, req)
#define FORCE_ECHECK(dtoken, check, req) IF_ECHECK_(true, dtoken, check, req)
// clang-format on
@@ -1806,7 +1962,6 @@
match = true;
}
// Parse a float/integer number from the string.
- if (!match) check_now = true; // Re-pack if parsed from string literal.
// A "scalar-in-string" value needs extra checks.
if (!match && is_tok_string && IsScalar(in_type)) {
// Strip trailing whitespaces from attribute_.
@@ -1835,6 +1990,15 @@
// Integer token can init any scalar (integer of float).
FORCE_ECHECK(kTokenIntegerConstant, IsScalar(in_type), BASE_TYPE_INT);
}
+ // Match empty vectors for default-empty-vectors.
+ if (!match && IsVector(e.type) && token_ == '[') {
+ NEXT();
+ if (token_ != ']') { return Error("Expected `]` in vector default"); }
+ NEXT();
+ match = true;
+ e.constant = "[]";
+ }
+
#undef FORCE_ECHECK
#undef TRY_ECHECK
#undef IF_ECHECK_
@@ -1892,13 +2056,8 @@
}
return struct_def;
}
- if (!definition) {
- // Search thru parent namespaces.
- for (size_t components = current_namespace_->components.size();
- components && !struct_def; components--) {
- struct_def = LookupStruct(
- current_namespace_->GetFullyQualifiedName(name, components - 1));
- }
+ if (!definition && !struct_def) {
+ struct_def = LookupStructThruParentNamespaces(name);
}
if (!struct_def && create_if_new) {
struct_def = new StructDef();
@@ -1978,10 +2137,14 @@
auto &v = vals.vec;
if (IsUInt64())
std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) {
+ if (e1->GetAsUInt64() == e2->GetAsUInt64()) {
+ return e1->name < e2->name;
+ }
return e1->GetAsUInt64() < e2->GetAsUInt64();
});
else
std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) {
+ if (e1->GetAsInt64() == e2->GetAsInt64()) { return e1->name < e2->name; }
return e1->GetAsInt64() < e2->GetAsInt64();
});
}
@@ -2111,13 +2274,18 @@
bool user_value;
};
-CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest) {
+CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest,
+ const char *filename) {
std::vector<std::string> enum_comment = doc_comment_;
NEXT();
std::string enum_name = attribute_;
EXPECT(kTokenIdentifier);
EnumDef *enum_def;
ECHECK(StartEnum(enum_name, is_union, &enum_def));
+ if (filename != nullptr && !opts.project_root.empty()) {
+ enum_def->declaration_file =
+ &GetPooledString(RelativeToRootPath(opts.project_root, filename));
+ }
enum_def->doc_comment = enum_comment;
if (!is_union && !opts.proto_mode) {
// Give specialized error message, since this type spec used to
@@ -2237,14 +2405,18 @@
}
if (dest) *dest = enum_def;
- types_.Add(current_namespace_->GetFullyQualifiedName(enum_def->name),
- new Type(BASE_TYPE_UNION, nullptr, enum_def));
+ const auto qualified_name =
+ current_namespace_->GetFullyQualifiedName(enum_def->name);
+ if (types_.Add(qualified_name, new Type(BASE_TYPE_UNION, nullptr, enum_def)))
+ return Error("datatype already exists: " + qualified_name);
return NoError();
}
CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
auto &struct_def = *LookupCreateStruct(name, true, true);
- if (!struct_def.predecl) return Error("datatype already exists: " + name);
+ if (!struct_def.predecl)
+ return Error("datatype already exists: " +
+ current_namespace_->GetFullyQualifiedName(name));
struct_def.predecl = false;
struct_def.name = name;
struct_def.file = file_being_parsed_;
@@ -2280,31 +2452,34 @@
static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
IDLOptions::kKotlin | IDLOptions::kCpp | IDLOptions::kJava |
- IDLOptions::kCSharp | IDLOptions::kTs | IDLOptions::kJs |
- IDLOptions::kBinary;
+ IDLOptions::kCSharp | IDLOptions::kTs | IDLOptions::kBinary |
+ IDLOptions::kGo;
unsigned long langs = opts.lang_to_generate;
return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs);
}
-
bool Parser::SupportsOptionalScalars() const {
// Check in general if a language isn't specified.
return opts.lang_to_generate == 0 || SupportsOptionalScalars(opts);
}
+bool Parser::SupportsDefaultVectorsAndStrings() const {
+ static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
+ IDLOptions::kRust | IDLOptions::kSwift;
+ return !(opts.lang_to_generate & ~supported_langs);
+}
+
bool Parser::SupportsAdvancedUnionFeatures() const {
- return opts.lang_to_generate != 0 &&
- (opts.lang_to_generate &
- ~(IDLOptions::kCpp | IDLOptions::kJs | IDLOptions::kTs |
- IDLOptions::kPhp | IDLOptions::kJava | IDLOptions::kCSharp |
- IDLOptions::kKotlin | IDLOptions::kBinary | IDLOptions::kSwift)) ==
- 0;
+ return (opts.lang_to_generate &
+ ~(IDLOptions::kCpp | IDLOptions::kTs | IDLOptions::kPhp |
+ IDLOptions::kJava | IDLOptions::kCSharp | IDLOptions::kKotlin |
+ IDLOptions::kBinary | IDLOptions::kSwift)) == 0;
}
bool Parser::SupportsAdvancedArrayFeatures() const {
return (opts.lang_to_generate &
~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava |
IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson |
- IDLOptions::kBinary)) == 0;
+ IDLOptions::kBinary | IDLOptions::kRust)) == 0;
}
Namespace *Parser::UniqueNamespace(Namespace *ns) {
@@ -2339,7 +2514,7 @@
return a_id < b_id;
}
-CheckedError Parser::ParseDecl() {
+CheckedError Parser::ParseDecl(const char *filename) {
std::vector<std::string> dc = doc_comment_;
bool fixed = IsIdent("struct");
if (!fixed && !IsIdent("table")) return Error("declaration expected");
@@ -2350,22 +2525,21 @@
ECHECK(StartStruct(name, &struct_def));
struct_def->doc_comment = dc;
struct_def->fixed = fixed;
+ if (filename && !opts.project_root.empty()) {
+ struct_def->declaration_file =
+ &GetPooledString(RelativeToRootPath(opts.project_root, filename));
+ }
ECHECK(ParseMetaData(&struct_def->attributes));
struct_def->sortbysize =
struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
EXPECT('{');
while (token_ != '}') ECHECK(ParseField(*struct_def));
- auto force_align = struct_def->attributes.Lookup("force_align");
if (fixed) {
+ const auto force_align = struct_def->attributes.Lookup("force_align");
if (force_align) {
- auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
- if (force_align->type.base_type != BASE_TYPE_INT ||
- align < struct_def->minalign || align > FLATBUFFERS_MAX_ALIGNMENT ||
- align & (align - 1))
- return Error(
- "force_align must be a power of two integer ranging from the"
- "struct\'s natural alignment to " +
- NumToString(FLATBUFFERS_MAX_ALIGNMENT));
+ size_t align;
+ ECHECK(ParseAlignAttribute(force_align->constant, struct_def->minalign,
+ &align));
struct_def->minalign = align;
}
if (!struct_def->bytesize) return Error("size 0 structs not allowed");
@@ -2395,11 +2569,25 @@
// been specified.
std::sort(fields.begin(), fields.end(), compareFieldDefs);
// Verify we have a contiguous set, and reassign vtable offsets.
- for (int i = 0; i < static_cast<int>(fields.size()); i++) {
- if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
+ FLATBUFFERS_ASSERT(fields.size() <=
+ flatbuffers::numeric_limits<voffset_t>::max());
+ for (voffset_t i = 0; i < static_cast<voffset_t>(fields.size()); i++) {
+ auto &field = *fields[i];
+ const auto &id_str = field.attributes.Lookup("id")->constant;
+ // Metadata values have a dynamic type, they can be `float`, 'int', or
+ // 'string`.
+ // The FieldIndexToOffset(i) expects the voffset_t so `id` is limited by
+ // this type.
+ voffset_t id = 0;
+ const auto done = !atot(id_str.c_str(), *this, &id).Check();
+ if (!done)
+ return Error("field id\'s must be non-negative number, field: " +
+ field.name + ", id: " + id_str);
+ if (i != id)
return Error("field id\'s must be consecutive from 0, id " +
- NumToString(i) + " missing or set twice");
- fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i));
+ NumToString(i) + " missing or set twice, field: " +
+ field.name + ", id: " + id_str);
+ field.value.offset = FieldIndexToOffset(i);
}
}
}
@@ -2412,12 +2600,15 @@
ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
EXPECT('}');
- types_.Add(current_namespace_->GetFullyQualifiedName(struct_def->name),
- new Type(BASE_TYPE_STRUCT, struct_def, nullptr));
+ const auto qualified_name =
+ current_namespace_->GetFullyQualifiedName(struct_def->name);
+ if (types_.Add(qualified_name,
+ new Type(BASE_TYPE_STRUCT, struct_def, nullptr)))
+ return Error("datatype already exists: " + qualified_name);
return NoError();
}
-CheckedError Parser::ParseService() {
+CheckedError Parser::ParseService(const char *filename) {
std::vector<std::string> service_comment = doc_comment_;
NEXT();
auto service_name = attribute_;
@@ -2427,6 +2618,10 @@
service_def.file = file_being_parsed_;
service_def.doc_comment = service_comment;
service_def.defined_namespace = current_namespace_;
+ if (filename != nullptr && !opts.project_root.empty()) {
+ service_def.declaration_file =
+ &GetPooledString(RelativeToRootPath(opts.project_root, filename));
+ }
if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
&service_def))
return Error("service already exists: " + service_name);
@@ -2542,7 +2737,7 @@
} else if (IsIdent("enum")) {
// These are almost the same, just with different terminator:
EnumDef *enum_def;
- ECHECK(ParseEnum(false, &enum_def));
+ ECHECK(ParseEnum(false, &enum_def, nullptr));
if (Is(';')) NEXT();
// Temp: remove any duplicates, as .fbs files can't handle them.
enum_def->RemoveDuplicates();
@@ -2565,17 +2760,17 @@
return NoError();
}
-CheckedError Parser::StartEnum(const std::string &enum_name, bool is_union,
+CheckedError Parser::StartEnum(const std::string &name, bool is_union,
EnumDef **dest) {
auto &enum_def = *new EnumDef();
- enum_def.name = enum_name;
+ enum_def.name = name;
enum_def.file = file_being_parsed_;
enum_def.doc_comment = doc_comment_;
enum_def.is_union = is_union;
enum_def.defined_namespace = current_namespace_;
- if (enums_.Add(current_namespace_->GetFullyQualifiedName(enum_name),
- &enum_def))
- return Error("enum already exists: " + enum_name);
+ const auto qualified_name = current_namespace_->GetFullyQualifiedName(name);
+ if (enums_.Add(qualified_name, &enum_def))
+ return Error("enum already exists: " + qualified_name);
enum_def.underlying_type.base_type =
is_union ? BASE_TYPE_UTYPE : BASE_TYPE_INT;
enum_def.underlying_type.enum_def = &enum_def;
@@ -2634,11 +2829,11 @@
if (IsIdent("group") || oneof) {
if (!oneof) NEXT();
if (oneof && opts.proto_oneof_union) {
- auto name = MakeCamel(attribute_, true) + "Union";
+ auto name = ConvertCase(attribute_, Case::kUpperCamel) + "Union";
ECHECK(StartEnum(name, true, &oneof_union));
type = Type(BASE_TYPE_UNION, nullptr, oneof_union);
} else {
- auto name = "Anonymous" + NumToString(anonymous_counter++);
+ auto name = "Anonymous" + NumToString(anonymous_counter_++);
ECHECK(StartStruct(name, &anonymous_struct));
type = Type(BASE_TYPE_STRUCT, anonymous_struct);
}
@@ -2674,7 +2869,9 @@
}
if (!field) ECHECK(AddField(*struct_def, name, type, &field));
field->doc_comment = field_comment;
- if (!IsScalar(type.base_type)) field->required = required;
+ if (!IsScalar(type.base_type) && required) {
+ field->presence = FieldDef::kRequired;
+ }
// See if there's a default specified.
if (Is('[')) {
NEXT();
@@ -2811,22 +3008,24 @@
}
CheckedError Parser::SkipAnyJsonValue() {
+ ParseDepthGuard depth_guard(this);
+ ECHECK(depth_guard.Check());
+
switch (token_) {
case '{': {
size_t fieldn_outer = 0;
- return ParseTableDelimiters(
- fieldn_outer, nullptr,
- [&](const std::string &, size_t &fieldn,
- const StructDef *) -> CheckedError {
- ECHECK(Recurse([&]() { return SkipAnyJsonValue(); }));
- fieldn++;
- return NoError();
- });
+ return ParseTableDelimiters(fieldn_outer, nullptr,
+ [&](const std::string &, size_t &fieldn,
+ const StructDef *) -> CheckedError {
+ ECHECK(SkipAnyJsonValue());
+ fieldn++;
+ return NoError();
+ });
}
case '[': {
uoffset_t count = 0;
return ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
- return Recurse([&]() { return SkipAnyJsonValue(); });
+ return SkipAnyJsonValue();
});
}
case kTokenStringConstant:
@@ -2841,7 +3040,19 @@
return NoError();
}
+CheckedError Parser::ParseFlexBufferNumericConstant(
+ flexbuffers::Builder *builder) {
+ double d;
+ if (!StringToNumber(attribute_.c_str(), &d))
+ return Error("unexpected floating-point constant: " + attribute_);
+ builder->Double(d);
+ return NoError();
+}
+
CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
+ ParseDepthGuard depth_guard(this);
+ ECHECK(depth_guard.Check());
+
switch (token_) {
case '{': {
auto start = builder->StartMap();
@@ -2885,6 +3096,18 @@
EXPECT(kTokenFloatConstant);
break;
}
+ case '-':
+ case '+': {
+ // `[-+]?(nan|inf|infinity)`, see ParseSingleValue().
+ const auto sign = static_cast<char>(token_);
+ NEXT();
+ if (token_ != kTokenIdentifier)
+ return Error("floating-point constant expected");
+ attribute_.insert(0, 1, sign);
+ ECHECK(ParseFlexBufferNumericConstant(builder));
+ NEXT();
+ break;
+ }
default:
if (IsIdent("true")) {
builder->Bool(true);
@@ -2895,6 +3118,9 @@
} else if (IsIdent("null")) {
builder->Null();
NEXT();
+ } else if (IsIdent("inf") || IsIdent("infinity") || IsIdent("nan")) {
+ ECHECK(ParseFlexBufferNumericConstant(builder));
+ NEXT();
} else
return TokenError();
}
@@ -2903,15 +3129,19 @@
bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
flexbuffers::Builder *builder) {
+ const auto initial_depth = parse_depth_counter_;
+ (void)initial_depth;
auto ok = !StartParseFile(source, source_filename).Check() &&
!ParseFlexBufferValue(builder).Check();
if (ok) builder->Finish();
+ FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
return ok;
}
bool Parser::Parse(const char *source, const char **include_paths,
const char *source_filename) {
- FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
+ const auto initial_depth = parse_depth_counter_;
+ (void)initial_depth;
bool r;
if (opts.use_flexbuffers) {
@@ -2919,16 +3149,17 @@
} else {
r = !ParseRoot(source, include_paths, source_filename).Check();
}
- FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
+ FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
return r;
}
bool Parser::ParseJson(const char *json, const char *json_filename) {
- FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
+ const auto initial_depth = parse_depth_counter_;
+ (void)initial_depth;
builder_.Clear();
const auto done =
!StartParseFile(json, json_filename).Check() && !DoParseJson().Check();
- FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
+ FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
return done;
}
@@ -3014,7 +3245,7 @@
for (auto val_it = enum_def.Vals().begin();
val_it != enum_def.Vals().end(); ++val_it) {
auto &val = **val_it;
- if (!SupportsAdvancedUnionFeatures() &&
+ 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: " +
@@ -3022,16 +3253,38 @@
}
}
}
+ // Parse JSON object only if the scheme has been parsed.
+ if (token_ == '{') { ECHECK(DoParseJson()); }
+ EXPECT(kTokenEof);
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;
+
+ if (source_filename)
+ hash = HashFnv1a<uint64_t>(StripPath(source_filename).c_str());
+
+ if (source && *source) hash ^= HashFnv1a<uint64_t>(source);
+
+ return hash;
+}
+
CheckedError Parser::DoParse(const char *source, const char **include_paths,
const char *source_filename,
const char *include_filename) {
+ uint64_t source_hash = 0;
if (source_filename) {
- if (included_files_.find(source_filename) == included_files_.end()) {
- included_files_[source_filename] =
- include_filename ? include_filename : "";
+ // If the file is in-memory, don't include its contents in the hash as we
+ // won't be able to load them later.
+ if (FileExists(source_filename))
+ source_hash = HashFile(source_filename, source);
+ else
+ source_hash = HashFile(source_filename, nullptr);
+
+ if (included_files_.find(source_hash) == included_files_.end()) {
+ included_files_[source_hash] = include_filename ? include_filename : "";
files_included_per_file_[source_filename] = std::set<std::string>();
} else {
return NoError();
@@ -3056,7 +3309,7 @@
ECHECK(ParseProtoDecl());
} else if (IsIdent("native_include")) {
NEXT();
- vector_emplace_back(&native_included_files_, attribute_);
+ native_included_files_.emplace_back(attribute_);
EXPECT(kTokenStringConstant);
EXPECT(';');
} else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) {
@@ -3064,22 +3317,32 @@
if (opts.proto_mode && attribute_ == "public") NEXT();
auto name = flatbuffers::PosixPath(attribute_.c_str());
EXPECT(kTokenStringConstant);
- // Look for the file in include_paths.
+ // Look for the file relative to the directory of the current file.
std::string filepath;
- for (auto paths = include_paths; paths && *paths; paths++) {
- filepath = flatbuffers::ConCatPathFileName(*paths, name);
- if (FileExists(filepath.c_str())) break;
+ if (source_filename) {
+ auto source_file_directory =
+ flatbuffers::StripFileName(source_filename);
+ filepath = flatbuffers::ConCatPathFileName(source_file_directory, name);
+ }
+ if (filepath.empty() || !FileExists(filepath.c_str())) {
+ // Look for the file in include_paths.
+ for (auto paths = include_paths; paths && *paths; paths++) {
+ filepath = flatbuffers::ConCatPathFileName(*paths, name);
+ if (FileExists(filepath.c_str())) break;
+ }
}
if (filepath.empty())
return Error("unable to locate include file: " + name);
if (source_filename)
files_included_per_file_[source_filename].insert(filepath);
- if (included_files_.find(filepath) == included_files_.end()) {
+
+ std::string contents;
+ bool file_loaded = LoadFile(filepath.c_str(), true, &contents);
+ if (included_files_.find(HashFile(filepath.c_str(), contents.c_str())) ==
+ included_files_.end()) {
// We found an include file that we have not parsed yet.
- // Load it and parse it.
- std::string contents;
- if (!LoadFile(filepath.c_str(), true, &contents))
- return Error("unable to load include file: " + name);
+ // Parse it.
+ if (!file_loaded) return Error("unable to load include file: " + name);
ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
name.c_str()));
// We generally do not want to output code for any included files:
@@ -3096,7 +3359,7 @@
// entered into included_files_.
// This is recursive, but only go as deep as the number of include
// statements.
- if (source_filename) { included_files_.erase(source_filename); }
+ included_files_.erase(source_hash);
return DoParse(source, include_paths, source_filename,
include_filename);
}
@@ -3112,11 +3375,11 @@
} else if (IsIdent("namespace")) {
ECHECK(ParseNamespace());
} else if (token_ == '{') {
- ECHECK(DoParseJson());
+ return NoError();
} else if (IsIdent("enum")) {
- ECHECK(ParseEnum(false, nullptr));
+ ECHECK(ParseEnum(false, nullptr, source_filename));
} else if (IsIdent("union")) {
- ECHECK(ParseEnum(true, nullptr));
+ ECHECK(ParseEnum(true, nullptr, source_filename));
} else if (IsIdent("root_type")) {
NEXT();
auto root_type = attribute_;
@@ -3132,9 +3395,9 @@
NEXT();
file_identifier_ = attribute_;
EXPECT(kTokenStringConstant);
- if (file_identifier_.length() != FlatBufferBuilder::kFileIdentifierLength)
+ if (file_identifier_.length() != flatbuffers::kFileIdentifierLength)
return Error("file_identifier must be exactly " +
- NumToString(FlatBufferBuilder::kFileIdentifierLength) +
+ NumToString(flatbuffers::kFileIdentifierLength) +
" characters");
EXPECT(';');
} else if (IsIdent("file_extension")) {
@@ -3155,21 +3418,22 @@
EXPECT(';');
known_attributes_[name] = false;
} else if (IsIdent("rpc_service")) {
- ECHECK(ParseService());
+ ECHECK(ParseService(source_filename));
} else {
- ECHECK(ParseDecl());
+ ECHECK(ParseDecl(source_filename));
}
}
+ if (opts.warnings_as_errors && has_warning_) {
+ return Error("treating warnings as errors, failed due to above warnings");
+ }
return NoError();
}
-CheckedError Parser::DoParseJson()
-{
+CheckedError Parser::DoParseJson() {
if (token_ != '{') {
EXPECT('{');
} else {
- if (!root_struct_def_)
- return Error("no root type set to parse json with");
+ if (!root_struct_def_) return Error("no root type set to parse json with");
if (builder_.GetSize()) {
return Error("cannot have more than one json object in a file");
}
@@ -3181,8 +3445,8 @@
file_identifier_.length() ? file_identifier_.c_str() : nullptr);
} else {
builder_.Finish(Offset<Table>(toff), file_identifier_.length()
- ? file_identifier_.c_str()
- : nullptr);
+ ? file_identifier_.c_str()
+ : nullptr);
}
}
// Check that JSON file doesn't contain more objects or IDL directives.
@@ -3236,31 +3500,62 @@
AssignIndices(structs_.vec);
AssignIndices(enums_.vec);
std::vector<Offset<reflection::Object>> object_offsets;
+ std::set<std::string> files;
for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_, *this);
object_offsets.push_back(offset);
(*it)->serialized_location = offset.o;
+ const std::string *file = (*it)->declaration_file;
+ if (file) files.insert(*file);
}
std::vector<Offset<reflection::Enum>> enum_offsets;
for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_, *this);
enum_offsets.push_back(offset);
- (*it)->serialized_location = offset.o;
+ const std::string *file = (*it)->declaration_file;
+ if (file) files.insert(*file);
}
std::vector<Offset<reflection::Service>> service_offsets;
for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_, *this);
service_offsets.push_back(offset);
- (*it)->serialized_location = offset.o;
+ const std::string *file = (*it)->declaration_file;
+ if (file) files.insert(*file);
}
- auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
- auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
- auto fiid__ = builder_.CreateString(file_identifier_);
- auto fext__ = builder_.CreateString(file_extension_);
- auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
- auto schema_offset = reflection::CreateSchema(
+
+ // Create Schemafiles vector of tables.
+ flatbuffers::Offset<
+ flatbuffers::Vector<flatbuffers::Offset<reflection::SchemaFile>>>
+ schema_files__;
+ if (!opts.project_root.empty()) {
+ std::vector<Offset<reflection::SchemaFile>> schema_files;
+ std::vector<Offset<flatbuffers::String>> included_files;
+ for (auto f = files_included_per_file_.begin();
+ f != files_included_per_file_.end(); f++) {
+ // frc971 modification to make file paths in schemas deterministic.
+ const auto filename__ = builder_.CreateSharedString(f->first);
+ for (auto i = f->second.begin(); i != f->second.end(); i++) {
+ included_files.push_back(builder_.CreateSharedString(*i));
+ }
+ const auto included_files__ = builder_.CreateVector(included_files);
+ included_files.clear();
+
+ schema_files.push_back(
+ reflection::CreateSchemaFile(builder_, filename__, included_files__));
+ }
+ schema_files__ = builder_.CreateVectorOfSortedTables(&schema_files);
+ }
+
+ const auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
+ const auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
+ const auto fiid__ = builder_.CreateString(file_identifier_);
+ const auto fext__ = builder_.CreateString(file_extension_);
+ const auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
+ const 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_),
+ schema_files__);
if (opts.size_prefixed) {
builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
} else {
@@ -3294,6 +3589,14 @@
return ns;
}
+// frc971 modification to make declaration files in schemas deterministic.
+// TODO(james): Figure out a clean way to make this workspace root relative.
+namespace {
+std::string DeclarationFileStripped(const std::string *declaration_file) {
+ return declaration_file == nullptr ? "" : StripPath(*declaration_file);
+}
+}
+
Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
const Parser &parser) const {
std::vector<Offset<reflection::Field>> field_offsets;
@@ -3301,16 +3604,18 @@
field_offsets.push_back((*it)->Serialize(
builder, static_cast<uint16_t>(it - fields.vec.begin()), parser));
}
- auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
- auto name__ = builder->CreateString(qualified_name);
- auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
- auto attr__ = SerializeAttributes(builder, parser);
- auto docs__ = parser.opts.binary_schema_comments
- ? builder->CreateVectorOfStrings(doc_comment)
- : 0;
- return reflection::CreateObject(*builder, name__, flds__, fixed,
- static_cast<int>(minalign),
- static_cast<int>(bytesize), attr__, docs__);
+ const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
+ const auto name__ = builder->CreateString(qualified_name);
+ const auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
+ const auto attr__ = SerializeAttributes(builder, parser);
+ const auto docs__ = parser.opts.binary_schema_comments
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ const auto file__ =
+ builder->CreateSharedString(DeclarationFileStripped(declaration_file));
+ return reflection::CreateObject(
+ *builder, name__, flds__, fixed, static_cast<int>(minalign),
+ static_cast<int>(bytesize), attr__, docs__, file__);
}
bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) {
@@ -3363,8 +3668,8 @@
// Is uint64>max(int64) tested?
IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0,
// result may be platform-dependent if underlying is float (not double)
- IsFloat(value.type.base_type) ? d : 0.0, deprecated, required, key,
- attr__, docs__, optional);
+ IsFloat(value.type.base_type) ? d : 0.0, deprecated, IsRequired(), key,
+ attr__, docs__, IsOptional(), static_cast<uint16_t>(padding));
// TODO: value.constant is almost always "0", we could save quite a bit of
// space by sharing it. Same for common values of value.type.
}
@@ -3379,8 +3684,8 @@
} else if (IsFloat(value.type.base_type)) {
value.constant = FloatToString(field->default_real(), 16);
}
- deprecated = field->deprecated();
- required = field->required();
+ presence = FieldDef::MakeFieldPresence(field->optional(), field->required());
+ padding = field->padding();
key = field->key();
if (!DeserializeAttributes(parser, field->attributes())) return false;
// TODO: this should probably be handled by a separate attribute
@@ -3430,14 +3735,17 @@
for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) {
servicecall_offsets.push_back((*it)->Serialize(builder, parser));
}
- auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
- auto name__ = builder->CreateString(qualified_name);
- auto call__ = builder->CreateVector(servicecall_offsets);
- auto attr__ = SerializeAttributes(builder, parser);
- auto docs__ = parser.opts.binary_schema_comments
- ? builder->CreateVectorOfStrings(doc_comment)
- : 0;
- return reflection::CreateService(*builder, name__, call__, attr__, docs__);
+ const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
+ const auto name__ = builder->CreateString(qualified_name);
+ const auto call__ = builder->CreateVector(servicecall_offsets);
+ const auto attr__ = SerializeAttributes(builder, parser);
+ const auto docs__ = parser.opts.binary_schema_comments
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ const auto file__ =
+ builder->CreateSharedString(DeclarationFileStripped(declaration_file));
+ return reflection::CreateService(*builder, name__, call__, attr__, docs__,
+ file__);
}
bool ServiceDef::Deserialize(Parser &parser,
@@ -3464,16 +3772,18 @@
for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
enumval_offsets.push_back((*it)->Serialize(builder, parser));
}
- auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
- auto name__ = builder->CreateString(qualified_name);
- auto vals__ = builder->CreateVector(enumval_offsets);
- auto type__ = underlying_type.Serialize(builder);
- auto attr__ = SerializeAttributes(builder, parser);
- auto docs__ = parser.opts.binary_schema_comments
- ? builder->CreateVectorOfStrings(doc_comment)
- : 0;
+ const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
+ const auto name__ = builder->CreateString(qualified_name);
+ const auto vals__ = builder->CreateVector(enumval_offsets);
+ const auto type__ = underlying_type.Serialize(builder);
+ const auto attr__ = SerializeAttributes(builder, parser);
+ const auto docs__ = parser.opts.binary_schema_comments
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ const auto file__ =
+ builder->CreateSharedString(DeclarationFileStripped(declaration_file));
return reflection::CreateEnum(*builder, name__, vals__, is_union, type__,
- attr__, docs__);
+ attr__, docs__, file__);
}
bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) {
@@ -3502,10 +3812,7 @@
auto docs__ = parser.opts.binary_schema_comments
? builder->CreateVectorOfStrings(doc_comment)
: 0;
- return reflection::CreateEnumVal(
- *builder, name__, value,
- union_type.struct_def ? union_type.struct_def->serialized_location : 0,
- type__, docs__);
+ return reflection::CreateEnumVal(*builder, name__, value, type__, docs__);
}
bool EnumVal::Deserialize(const Parser &parser,
@@ -3522,7 +3829,8 @@
*builder, static_cast<reflection::BaseType>(base_type),
static_cast<reflection::BaseType>(element),
struct_def ? struct_def->index : (enum_def ? enum_def->index : -1),
- fixed_length);
+ fixed_length, static_cast<uint32_t>(SizeOf(base_type)),
+ static_cast<uint32_t>(SizeOf(element)));
}
bool Type::Deserialize(const Parser &parser, const reflection::Type *type) {
@@ -3531,10 +3839,10 @@
element = static_cast<BaseType>(type->element());
fixed_length = type->fixed_length();
if (type->index() >= 0) {
- bool is_series = type->base_type() == reflection::Vector ||
- type->base_type() == reflection::Array;
- if (type->base_type() == reflection::Obj ||
- (is_series && type->element() == reflection::Obj)) {
+ bool is_series = type->base_type() == reflection::BaseType::Vector ||
+ type->base_type() == reflection::BaseType::Array;
+ if (type->base_type() == reflection::BaseType::Obj ||
+ (is_series && type->element() == reflection::BaseType::Obj)) {
if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) {
struct_def = parser.structs_.vec[type->index()];
struct_def->refcount++;
@@ -3678,6 +3986,16 @@
}
}
}
+ advanced_features_ = static_cast<uint64_t>(schema->advanced_features());
+
+ if (schema->fbs_files())
+ for (auto s = schema->fbs_files()->begin(); s != schema->fbs_files()->end();
+ ++s) {
+ for (auto f = s->included_filenames()->begin();
+ f != s->included_filenames()->end(); ++f) {
+ files_included_per_file_[s->filename()->str()].insert(f->str());
+ }
+ }
return true;
}
diff --git a/third_party/flatbuffers/src/namer.h b/third_party/flatbuffers/src/namer.h
new file mode 100644
index 0000000..6c539cb
--- /dev/null
+++ b/third_party/flatbuffers/src/namer.h
@@ -0,0 +1,217 @@
+#ifndef FLATBUFFERS_NAMER
+#define FLATBUFFERS_NAMER
+
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+// Options for Namer::File.
+enum class SkipFile {
+ None = 0,
+ Suffix = 1,
+ Extension = 2,
+ SuffixAndExtension = 3,
+};
+inline SkipFile operator&(SkipFile a, SkipFile b) {
+ return static_cast<SkipFile>(static_cast<int>(a) & static_cast<int>(b));
+}
+// Options for Namer::Directories
+enum class SkipDir {
+ None = 0,
+ // Skip prefixing the -o $output_path.
+ OutputPath = 1,
+ // Skip trailing path seperator.
+ TrailingPathSeperator = 2,
+ OutputPathAndTrailingPathSeparator = 3,
+};
+inline SkipDir operator&(SkipDir a, SkipDir b) {
+ return static_cast<SkipDir>(static_cast<int>(a) & static_cast<int>(b));
+}
+
+// `Namer` applies style configuration to symbols in generated code. It manages
+// casing, escapes keywords, and object API naming.
+// TODO: Refactor all code generators to use this.
+class Namer {
+ public:
+ struct Config {
+ // Symbols in code.
+
+ // Case style for flatbuffers-defined types.
+ // e.g. `class TableA {}`
+ Case types;
+ // Case style for flatbuffers-defined constants.
+ // e.g. `uint64_t ENUM_A_MAX`;
+ Case constants;
+ // Case style for flatbuffers-defined methods.
+ // e.g. `class TableA { int field_a(); }`
+ Case methods;
+ // Case style for flatbuffers-defined functions.
+ // e.g. `TableA* get_table_a_root()`;
+ Case functions;
+ // Case style for flatbuffers-defined fields.
+ // e.g. `struct Struct { int my_field; }`
+ Case fields;
+ // Case style for flatbuffers-defined variables.
+ // e.g. `int my_variable = 2`
+ Case variables;
+ // Case style for flatbuffers-defined variants.
+ // e.g. `enum class Enum { MyVariant, }`
+ Case variants;
+ // Seperator for qualified enum names.
+ // e.g. `Enum::MyVariant` uses `::`.
+ std::string enum_variant_seperator;
+
+ // Namespaces
+
+ // e.g. `namespace my_namespace {}`
+ Case namespaces;
+ // The seperator between namespaces in a namespace path.
+ std::string namespace_seperator;
+
+ // Object API.
+ // Native versions flatbuffers types have this prefix.
+ // e.g. "" (it's usually empty string)
+ std::string object_prefix;
+ // Native versions flatbuffers types have this suffix.
+ // e.g. "T"
+ std::string object_suffix;
+
+ // Keywords.
+ // Prefix used to escape keywords. It is usually empty string.
+ std::string keyword_prefix;
+ // Suffix used to escape keywords. It is usually "_".
+ std::string keyword_suffix;
+
+ // Files.
+
+ // Case style for filenames. e.g. `foo_bar_generated.rs`
+ Case filenames;
+ // Case style for directories, e.g. `output_files/foo_bar/baz/`
+ Case directories;
+ // The directory within which we will generate files.
+ std::string output_path;
+ // Suffix for generated file names, e.g. "_generated".
+ std::string filename_suffix;
+ // Extension for generated files, e.g. ".cpp" or ".rs".
+ std::string filename_extension;
+
+ // This is a temporary helper function for code generators to call until all
+ // code generators are using `Namer`. After that point, we can centralize
+ // flag-overriding logic into flatc.cpp
+ Config WithFlagOptions(const IDLOptions &opts,
+ const std::string &path) const {
+ Config result = *this;
+ result.object_prefix = opts.object_prefix;
+ result.object_suffix = opts.object_suffix;
+ result.output_path = path;
+ result.filename_suffix = opts.filename_suffix;
+ return result;
+ }
+ };
+ Namer(Config config, std::set<std::string> keywords)
+ : config_(config), keywords_(std::move(keywords)) {}
+
+ std::string Type(const std::string &s) const {
+ return Format(s, config_.types);
+ }
+
+ std::string Method(const std::string &s) const {
+ return Format(s, config_.methods);
+ }
+
+ std::string Constant(const std::string &s) const {
+ return Format(s, config_.constants);
+ }
+
+ std::string Function(const std::string &s) const {
+ return Format(s, config_.functions);
+ }
+
+ std::string Field(const std::string &s) const {
+ return Format(s, config_.fields);
+ }
+
+ std::string Variable(const std::string &s) const {
+ return Format(s, config_.variables);
+ }
+
+ std::string Variant(const std::string &s) const {
+ return Format(s, config_.variants);
+ }
+
+ std::string EnumVariant(const std::string &e, const std::string v) const {
+ return Type(e) + config_.enum_variant_seperator + Variant(v);
+ }
+
+ std::string ObjectType(const std::string &s) const {
+ return config_.object_prefix + Type(s) + config_.object_suffix;
+ }
+
+ std::string Namespace(const std::string &s) const {
+ return Format(s, config_.namespaces);
+ }
+
+ std::string Namespace(const std::vector<std::string> &ns) const {
+ std::string result;
+ for (auto it = ns.begin(); it != ns.end(); it++) {
+ if (it != ns.begin()) result += config_.namespace_seperator;
+ result += Namespace(*it);
+ }
+ return result;
+ }
+
+ std::string NamespacedType(const std::vector<std::string> &ns,
+ const std::string &s) const {
+ return Namespace(ns) + config_.namespace_seperator + Type(s);
+ }
+
+ // Returns `filename` with the right casing, suffix, and extension.
+ std::string File(const std::string &filename,
+ SkipFile skips = SkipFile::None) const {
+ const bool skip_suffix = (skips & SkipFile::Suffix) != SkipFile::None;
+ const bool skip_ext = (skips & SkipFile::Extension) != SkipFile::None;
+ return ConvertCase(filename, config_.filenames, Case::kUpperCamel) +
+ (skip_suffix ? "" : config_.filename_suffix) +
+ (skip_ext ? "" : config_.filename_extension);
+ }
+ // Formats `directories` prefixed with the output_path and joined with the
+ // right seperator. Output path prefixing and the trailing separator may be
+ // skiped using `skips`.
+ // Callers may want to use `EnsureDirExists` with the result.
+ std::string Directories(const std::vector<std::string> &directories,
+ SkipDir skips = SkipDir::None) const {
+ const bool skip_output_path =
+ (skips & SkipDir::OutputPath) != SkipDir::None;
+ const bool skip_trailing_seperator =
+ (skips & SkipDir::TrailingPathSeperator) != SkipDir::None;
+ std::string result = skip_output_path ? "" : config_.output_path;
+ for (auto d = directories.begin(); d != directories.end(); d++) {
+ result += ConvertCase(*d, config_.directories, Case::kUpperCamel);
+ result.push_back(kPathSeparator);
+ }
+ if (skip_trailing_seperator) result.pop_back();
+ return result;
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ if (keywords_.find(name) == keywords_.end()) {
+ return name;
+ } else {
+ return config_.keyword_prefix + name + config_.keyword_suffix;
+ }
+ }
+
+ private:
+ std::string Format(const std::string &s, Case casing) const {
+ // NOTE: If you need to escape keywords after converting case, which would
+ // make more sense than this, make it a config option.
+ return ConvertCase(EscapeKeyword(s), casing, Case::kLowerCamel);
+ }
+ const Config config_;
+ const std::set<std::string> keywords_;
+};
+
+} // namespace flatbuffers
+
+#endif // FLATBUFFERS_NAMER
diff --git a/third_party/flatbuffers/src/reflection.cpp b/third_party/flatbuffers/src/reflection.cpp
index 2dedcb4..2d92229 100644
--- a/third_party/flatbuffers/src/reflection.cpp
+++ b/third_party/flatbuffers/src/reflection.cpp
@@ -23,22 +23,22 @@
namespace flatbuffers {
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
-// clang-format off
+ // clang-format off
#define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
switch (type) {
- case reflection::UType:
- case reflection::Bool:
- case reflection::UByte: return FLATBUFFERS_GET(uint8_t);
- case reflection::Byte: return FLATBUFFERS_GET(int8_t);
- case reflection::Short: return FLATBUFFERS_GET(int16_t);
- case reflection::UShort: return FLATBUFFERS_GET(uint16_t);
- case reflection::Int: return FLATBUFFERS_GET(int32_t);
- case reflection::UInt: return FLATBUFFERS_GET(uint32_t);
- case reflection::Long: return FLATBUFFERS_GET(int64_t);
- case reflection::ULong: return FLATBUFFERS_GET(uint64_t);
- case reflection::Float: return FLATBUFFERS_GET(float);
- case reflection::Double: return FLATBUFFERS_GET(double);
- case reflection::String: {
+ case reflection::BaseType::UType:
+ case reflection::BaseType::Bool:
+ case reflection::BaseType::UByte: return FLATBUFFERS_GET(uint8_t);
+ case reflection::BaseType::Byte: return FLATBUFFERS_GET(int8_t);
+ case reflection::BaseType::Short: return FLATBUFFERS_GET(int16_t);
+ case reflection::BaseType::UShort: return FLATBUFFERS_GET(uint16_t);
+ case reflection::BaseType::Int: return FLATBUFFERS_GET(int32_t);
+ case reflection::BaseType::UInt: return FLATBUFFERS_GET(uint32_t);
+ case reflection::BaseType::Long: return FLATBUFFERS_GET(int64_t);
+ case reflection::BaseType::ULong: return FLATBUFFERS_GET(uint64_t);
+ case reflection::BaseType::Float: return FLATBUFFERS_GET(float);
+ case reflection::BaseType::Double: return FLATBUFFERS_GET(double);
+ case reflection::BaseType::String: {
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
data);
return s ? StringToInt(s->c_str()) : 0;
@@ -51,9 +51,9 @@
double GetAnyValueF(reflection::BaseType type, const uint8_t *data) {
switch (type) {
- case reflection::Float: return static_cast<double>(ReadScalar<float>(data));
- case reflection::Double: return ReadScalar<double>(data);
- case reflection::String: {
+ case reflection::BaseType::Float: return static_cast<double>(ReadScalar<float>(data));
+ case reflection::BaseType::Double: return ReadScalar<double>(data);
+ case reflection::BaseType::String: {
auto s =
reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
if (s) {
@@ -71,14 +71,14 @@
std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
const reflection::Schema *schema, int type_index) {
switch (type) {
- case reflection::Float:
- case reflection::Double: return NumToString(GetAnyValueF(type, data));
- case reflection::String: {
+ case reflection::BaseType::Float:
+ case reflection::BaseType::Double: return NumToString(GetAnyValueF(type, data));
+ case reflection::BaseType::String: {
auto s =
reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
return s ? s->c_str() : "";
}
- case reflection::Obj:
+ case reflection::BaseType::Obj:
if (schema) {
// Convert the table to a string. This is mostly for debugging purposes,
// and does NOT promise to be JSON compliant.
@@ -96,7 +96,7 @@
auto &fielddef = **it;
if (!table_field->CheckField(fielddef.offset())) continue;
auto val = GetAnyFieldS(*table_field, fielddef, schema);
- if (fielddef.type()->base_type() == reflection::String) {
+ if (fielddef.type()->base_type() == reflection::BaseType::String) {
std::string esc;
flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true,
false);
@@ -113,29 +113,29 @@
} else {
return "(table)";
}
- case reflection::Vector:
+ case reflection::BaseType::Vector:
return "[(elements)]"; // TODO: implement this as well.
- case reflection::Union: return "(union)"; // TODO: implement this as well.
+ case reflection::BaseType::Union: return "(union)"; // TODO: implement this as well.
default: return NumToString(GetAnyValueI(type, data));
}
}
void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
-// clang-format off
+ // clang-format off
#define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
switch (type) {
- case reflection::UType:
- case reflection::Bool:
- case reflection::UByte: FLATBUFFERS_SET(uint8_t ); break;
- case reflection::Byte: FLATBUFFERS_SET(int8_t ); break;
- case reflection::Short: FLATBUFFERS_SET(int16_t ); break;
- case reflection::UShort: FLATBUFFERS_SET(uint16_t); break;
- case reflection::Int: FLATBUFFERS_SET(int32_t ); break;
- case reflection::UInt: FLATBUFFERS_SET(uint32_t); break;
- case reflection::Long: FLATBUFFERS_SET(int64_t ); break;
- case reflection::ULong: FLATBUFFERS_SET(uint64_t); break;
- case reflection::Float: FLATBUFFERS_SET(float ); break;
- case reflection::Double: FLATBUFFERS_SET(double ); break;
+ case reflection::BaseType::UType:
+ case reflection::BaseType::Bool:
+ case reflection::BaseType::UByte: FLATBUFFERS_SET(uint8_t ); break;
+ case reflection::BaseType::Byte: FLATBUFFERS_SET(int8_t ); break;
+ case reflection::BaseType::Short: FLATBUFFERS_SET(int16_t ); break;
+ case reflection::BaseType::UShort: FLATBUFFERS_SET(uint16_t); break;
+ case reflection::BaseType::Int: FLATBUFFERS_SET(int32_t ); break;
+ case reflection::BaseType::UInt: FLATBUFFERS_SET(uint32_t); break;
+ case reflection::BaseType::Long: FLATBUFFERS_SET(int64_t ); break;
+ case reflection::BaseType::ULong: FLATBUFFERS_SET(uint64_t); break;
+ case reflection::BaseType::Float: FLATBUFFERS_SET(float ); break;
+ case reflection::BaseType::Double: FLATBUFFERS_SET(double ); break;
// TODO: support strings
default: break;
}
@@ -145,8 +145,8 @@
void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) {
switch (type) {
- case reflection::Float: WriteScalar(data, static_cast<float>(val)); break;
- case reflection::Double: WriteScalar(data, val); break;
+ case reflection::BaseType::Float: WriteScalar(data, static_cast<float>(val)); break;
+ case reflection::BaseType::Double: WriteScalar(data, val); break;
// TODO: support strings.
default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break;
}
@@ -154,8 +154,8 @@
void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
switch (type) {
- case reflection::Float:
- case reflection::Double: {
+ case reflection::BaseType::Float:
+ case reflection::BaseType::Double: {
double d;
StringToNumber(val, &d);
SetAnyValueF(type, data, d);
@@ -180,7 +180,7 @@
std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr)
: schema_(schema),
- startptr_(vector_data(*flatbuf) + start),
+ startptr_(flatbuf->data() + start),
delta_(delta),
buf_(*flatbuf),
dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
@@ -188,8 +188,8 @@
delta_ = (delta_ + mask) & ~mask;
if (!delta_) return; // We can't shrink by less than largest_scalar_t.
// Now change all the offsets by delta_.
- auto root = GetAnyRoot(vector_data(buf_));
- Straddle<uoffset_t, 1>(vector_data(buf_), root, vector_data(buf_));
+ auto root = GetAnyRoot(buf_.data());
+ Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data());
ResizeTable(root_table ? *root_table : *schema.root_table(), root);
// We can now add or remove bytes at start.
if (delta_ > 0)
@@ -217,7 +217,7 @@
// will straddle and which won't.
uint8_t &DagCheck(const void *offsetloc) {
auto dag_idx = reinterpret_cast<const uoffset_t *>(offsetloc) -
- reinterpret_cast<const uoffset_t *>(vector_data(buf_));
+ reinterpret_cast<const uoffset_t *>(buf_.data());
return dag_check_[dag_idx];
}
@@ -239,13 +239,13 @@
auto &fielddef = **it;
auto base_type = fielddef.type()->base_type();
// Ignore scalars.
- if (base_type <= reflection::Double) continue;
+ if (base_type <= reflection::BaseType::Double) continue;
// Ignore fields that are not stored.
auto offset = table->GetOptionalFieldOffset(fielddef.offset());
if (!offset) continue;
// Ignore structs.
auto subobjectdef =
- base_type == reflection::Obj
+ base_type == reflection::BaseType::Obj
? schema_.objects()->Get(fielddef.type()->index())
: nullptr;
if (subobjectdef && subobjectdef->is_struct()) continue;
@@ -256,17 +256,17 @@
Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
// Recurse.
switch (base_type) {
- case reflection::Obj: {
+ case reflection::BaseType::Obj: {
ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
break;
}
- case reflection::Vector: {
+ case reflection::BaseType::Vector: {
auto elem_type = fielddef.type()->element();
- if (elem_type != reflection::Obj && elem_type != reflection::String)
+ if (elem_type != reflection::BaseType::Obj && elem_type != reflection::BaseType::String)
break;
auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
auto elemobjectdef =
- elem_type == reflection::Obj
+ elem_type == reflection::BaseType::Obj
? schema_.objects()->Get(fielddef.type()->index())
: nullptr;
if (elemobjectdef && elemobjectdef->is_struct()) break;
@@ -280,12 +280,12 @@
}
break;
}
- case reflection::Union: {
+ case reflection::BaseType::Union: {
ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
reinterpret_cast<Table *>(ref));
break;
}
- case reflection::String: break;
+ case reflection::BaseType::String: break;
default: FLATBUFFERS_ASSERT(false);
}
}
@@ -309,19 +309,19 @@
const reflection::Object *root_table) {
auto delta = static_cast<int>(val.size()) - static_cast<int>(str->size());
auto str_start = static_cast<uoffset_t>(
- reinterpret_cast<const uint8_t *>(str) - vector_data(*flatbuf));
+ reinterpret_cast<const uint8_t *>(str) - flatbuf->data());
auto start = str_start + static_cast<uoffset_t>(sizeof(uoffset_t));
if (delta) {
// Clear the old string, since we don't want parts of it remaining.
- memset(vector_data(*flatbuf) + start, 0, str->size());
+ memset(flatbuf->data() + start, 0, str->size());
// Different size, we must expand (or contract).
ResizeContext(schema, start, delta, flatbuf, root_table);
// Set the new length.
- WriteScalar(vector_data(*flatbuf) + str_start,
+ WriteScalar(flatbuf->data() + str_start,
static_cast<uoffset_t>(val.size()));
}
// Copy new data. Safe because we created the right amount of space.
- memcpy(vector_data(*flatbuf) + start, val.c_str(), val.size() + 1);
+ memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1);
}
uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
@@ -330,25 +330,26 @@
const reflection::Object *root_table) {
auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems);
auto delta_bytes = delta_elem * static_cast<int>(elem_size);
- auto vec_start =
- reinterpret_cast<const uint8_t *>(vec) - vector_data(*flatbuf);
- auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
- elem_size * num_elems);
+ auto vec_start = reinterpret_cast<const uint8_t *>(vec) - flatbuf->data();
+ auto start = static_cast<uoffset_t>(vec_start) +
+ static_cast<uoffset_t>(sizeof(uoffset_t)) +
+ elem_size * num_elems;
if (delta_bytes) {
if (delta_elem < 0) {
// Clear elements we're throwing away, since some might remain in the
// buffer.
auto size_clear = -delta_elem * elem_size;
- memset(vector_data(*flatbuf) + start - size_clear, 0, size_clear);
+ memset(flatbuf->data() + start - size_clear, 0, size_clear);
}
ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
- WriteScalar(vector_data(*flatbuf) + vec_start, newsize); // Length field.
+ WriteScalar(flatbuf->data() + vec_start, newsize); // Length field.
// Set new elements to 0.. this can be overwritten by the caller.
if (delta_elem > 0) {
- memset(vector_data(*flatbuf) + start, 0, delta_elem * elem_size);
+ memset(flatbuf->data() + start, 0,
+ static_cast<size_t>(delta_elem) * elem_size);
}
}
- return vector_data(*flatbuf) + start;
+ return flatbuf->data() + start;
}
const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
@@ -363,7 +364,7 @@
// Insert the entire FlatBuffer minus the root pointer.
flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen);
auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
- return vector_data(flatbuf) + insertion_point + root_offset;
+ return flatbuf.data() + insertion_point + root_offset;
}
void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
@@ -387,13 +388,13 @@
if (!table.CheckField(fielddef.offset())) continue;
uoffset_t offset = 0;
switch (fielddef.type()->base_type()) {
- case reflection::String: {
+ case reflection::BaseType::String: {
offset = use_string_pooling
? fbb.CreateSharedString(GetFieldS(table, fielddef)).o
: fbb.CreateString(GetFieldS(table, fielddef)).o;
break;
}
- case reflection::Obj: {
+ case reflection::BaseType::Obj: {
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
if (!subobjectdef.is_struct()) {
offset = CopyTable(fbb, schema, subobjectdef,
@@ -402,23 +403,23 @@
}
break;
}
- case reflection::Union: {
+ case reflection::BaseType::Union: {
auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
offset = CopyTable(fbb, schema, subobjectdef,
*GetFieldT(table, fielddef), use_string_pooling)
.o;
break;
}
- case reflection::Vector: {
+ case reflection::BaseType::Vector: {
auto vec =
table.GetPointer<const Vector<Offset<Table>> *>(fielddef.offset());
auto element_base_type = fielddef.type()->element();
auto elemobjectdef =
- element_base_type == reflection::Obj
+ element_base_type == reflection::BaseType::Obj
? schema.objects()->Get(fielddef.type()->index())
: nullptr;
switch (element_base_type) {
- case reflection::String: {
+ case reflection::BaseType::String: {
std::vector<Offset<const String *>> elements(vec->size());
auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
for (uoffset_t i = 0; i < vec_s->size(); i++) {
@@ -429,7 +430,7 @@
offset = fbb.CreateVector(elements).o;
break;
}
- case reflection::Obj: {
+ case reflection::BaseType::Obj: {
if (!elemobjectdef->is_struct()) {
std::vector<Offset<const Table *>> elements(vec->size());
for (uoffset_t i = 0; i < vec->size(); i++) {
@@ -467,7 +468,7 @@
if (!table.CheckField(fielddef.offset())) continue;
auto base_type = fielddef.type()->base_type();
switch (base_type) {
- case reflection::Obj: {
+ case reflection::BaseType::Obj: {
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
if (subobjectdef.is_struct()) {
CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
@@ -476,9 +477,9 @@
}
}
FLATBUFFERS_FALLTHROUGH(); // fall thru
- case reflection::Union:
- case reflection::String:
- case reflection::Vector:
+ case reflection::BaseType::Union:
+ case reflection::BaseType::String:
+ case reflection::BaseType::Vector:
fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
break;
default: { // Scalars.
@@ -504,8 +505,9 @@
auto offset = parent_table.GetOptionalFieldOffset(field_offset);
if (required && !offset) { return false; }
- return !offset || v.Verify(reinterpret_cast<const uint8_t *>(&parent_table),
- offset, obj.bytesize());
+ return !offset ||
+ v.VerifyFieldStruct(reinterpret_cast<const uint8_t *>(&parent_table),
+ offset, obj.bytesize(), obj.minalign());
}
bool VerifyVectorOfStructs(flatbuffers::Verifier &v,
@@ -531,7 +533,7 @@
if (utype >= fb_enum->values()->size()) return false;
auto elem_type = fb_enum->values()->Get(utype)->union_type();
switch (elem_type->base_type()) {
- case reflection::Obj: {
+ case reflection::BaseType::Obj: {
auto elem_obj = schema.objects()->Get(elem_type->index());
if (elem_obj->is_struct()) {
return v.VerifyFromPointer(elem, elem_obj->bytesize());
@@ -541,7 +543,7 @@
true);
}
}
- case reflection::String:
+ case reflection::BaseType::String:
return v.VerifyString(
reinterpret_cast<const flatbuffers::String *>(elem));
default: return false;
@@ -551,30 +553,31 @@
bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema,
const flatbuffers::Table &table,
const reflection::Field &vec_field) {
- FLATBUFFERS_ASSERT(vec_field.type()->base_type() == reflection::Vector);
- if (!table.VerifyField<uoffset_t>(v, vec_field.offset())) return false;
+ FLATBUFFERS_ASSERT(vec_field.type()->base_type() == reflection::BaseType::Vector);
+ if (!table.VerifyField<uoffset_t>(v, vec_field.offset(), sizeof(uoffset_t)))
+ return false;
switch (vec_field.type()->element()) {
- case reflection::UType:
+ case reflection::BaseType::UType:
return v.VerifyVector(flatbuffers::GetFieldV<uint8_t>(table, vec_field));
- case reflection::Bool:
- case reflection::Byte:
- case reflection::UByte:
+ case reflection::BaseType::Bool:
+ case reflection::BaseType::Byte:
+ case reflection::BaseType::UByte:
return v.VerifyVector(flatbuffers::GetFieldV<int8_t>(table, vec_field));
- case reflection::Short:
- case reflection::UShort:
+ case reflection::BaseType::Short:
+ case reflection::BaseType::UShort:
return v.VerifyVector(flatbuffers::GetFieldV<int16_t>(table, vec_field));
- case reflection::Int:
- case reflection::UInt:
+ case reflection::BaseType::Int:
+ case reflection::BaseType::UInt:
return v.VerifyVector(flatbuffers::GetFieldV<int32_t>(table, vec_field));
- case reflection::Long:
- case reflection::ULong:
+ case reflection::BaseType::Long:
+ case reflection::BaseType::ULong:
return v.VerifyVector(flatbuffers::GetFieldV<int64_t>(table, vec_field));
- case reflection::Float:
+ case reflection::BaseType::Float:
return v.VerifyVector(flatbuffers::GetFieldV<float>(table, vec_field));
- case reflection::Double:
+ case reflection::BaseType::Double:
return v.VerifyVector(flatbuffers::GetFieldV<double>(table, vec_field));
- case reflection::String: {
+ case reflection::BaseType::String: {
auto vec_string =
flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
table, vec_field);
@@ -584,7 +587,7 @@
return false;
}
}
- case reflection::Obj: {
+ case reflection::BaseType::Obj: {
auto obj = schema.objects()->Get(vec_field.type()->index());
if (obj->is_struct()) {
return VerifyVectorOfStructs(v, table, vec_field.offset(), *obj,
@@ -603,7 +606,7 @@
return true;
}
}
- case reflection::Union: {
+ case reflection::BaseType::Union: {
auto vec = flatbuffers::GetFieldV<flatbuffers::Offset<uint8_t>>(
table, vec_field);
if (!v.VerifyVector(vec)) return false;
@@ -619,8 +622,8 @@
}
return true;
}
- case reflection::Vector:
- case reflection::None:
+ case reflection::BaseType::Vector:
+ case reflection::BaseType::None:
default: FLATBUFFERS_ASSERT(false); return false;
}
}
@@ -633,43 +636,55 @@
for (uoffset_t i = 0; i < obj.fields()->size(); i++) {
auto field_def = obj.fields()->Get(i);
switch (field_def->type()->base_type()) {
- case reflection::None: FLATBUFFERS_ASSERT(false); break;
- case reflection::UType:
- if (!table->VerifyField<uint8_t>(v, field_def->offset())) return false;
+ case reflection::BaseType::None: FLATBUFFERS_ASSERT(false); break;
+ case reflection::BaseType::UType:
+ if (!table->VerifyField<uint8_t>(v, field_def->offset(),
+ sizeof(uint8_t)))
+ return false;
break;
- case reflection::Bool:
- case reflection::Byte:
- case reflection::UByte:
- if (!table->VerifyField<int8_t>(v, field_def->offset())) return false;
+ case reflection::BaseType::Bool:
+ case reflection::BaseType::Byte:
+ case reflection::BaseType::UByte:
+ if (!table->VerifyField<int8_t>(v, field_def->offset(), sizeof(int8_t)))
+ return false;
break;
- case reflection::Short:
- case reflection::UShort:
- if (!table->VerifyField<int16_t>(v, field_def->offset())) return false;
+ case reflection::BaseType::Short:
+ case reflection::BaseType::UShort:
+ if (!table->VerifyField<int16_t>(v, field_def->offset(),
+ sizeof(int16_t)))
+ return false;
break;
- case reflection::Int:
- case reflection::UInt:
- if (!table->VerifyField<int32_t>(v, field_def->offset())) return false;
+ case reflection::BaseType::Int:
+ case reflection::BaseType::UInt:
+ if (!table->VerifyField<int32_t>(v, field_def->offset(),
+ sizeof(int32_t)))
+ return false;
break;
- case reflection::Long:
- case reflection::ULong:
- if (!table->VerifyField<int64_t>(v, field_def->offset())) return false;
+ case reflection::BaseType::Long:
+ case reflection::BaseType::ULong:
+ if (!table->VerifyField<int64_t>(v, field_def->offset(),
+ sizeof(int64_t)))
+ return false;
break;
- case reflection::Float:
- if (!table->VerifyField<float>(v, field_def->offset())) return false;
+ case reflection::BaseType::Float:
+ if (!table->VerifyField<float>(v, field_def->offset(), sizeof(float)))
+ return false;
break;
- case reflection::Double:
- if (!table->VerifyField<double>(v, field_def->offset())) return false;
+ case reflection::BaseType::Double:
+ if (!table->VerifyField<double>(v, field_def->offset(), sizeof(double)))
+ return false;
break;
- case reflection::String:
- if (!table->VerifyField<uoffset_t>(v, field_def->offset()) ||
+ case reflection::BaseType::String:
+ if (!table->VerifyField<uoffset_t>(v, field_def->offset(),
+ sizeof(uoffset_t)) ||
!v.VerifyString(flatbuffers::GetFieldS(*table, *field_def))) {
return false;
}
break;
- case reflection::Vector:
+ case reflection::BaseType::Vector:
if (!VerifyVector(v, schema, *table, *field_def)) return false;
break;
- case reflection::Obj: {
+ case reflection::BaseType::Obj: {
auto child_obj = schema.objects()->Get(field_def->type()->index());
if (child_obj->is_struct()) {
if (!VerifyStruct(v, *table, field_def->offset(), *child_obj,
@@ -685,7 +700,7 @@
}
break;
}
- case reflection::Union: {
+ case reflection::BaseType::Union: {
// get union type from the prev field
voffset_t utype_offset = field_def->offset() - sizeof(voffset_t);
auto utype = table->GetField<uint8_t>(utype_offset, 0);
diff --git a/third_party/flatbuffers/src/util.cpp b/third_party/flatbuffers/src/util.cpp
index 3670a01..a1ed6c1 100644
--- a/third_party/flatbuffers/src/util.cpp
+++ b/third_party/flatbuffers/src/util.cpp
@@ -40,14 +40,17 @@
#endif
// clang-format on
-#include "flatbuffers/base.h"
#include "flatbuffers/util.h"
#include <sys/stat.h>
+
#include <clocale>
#include <cstdlib>
+#include <functional>
#include <fstream>
+#include "flatbuffers/base.h"
+
namespace flatbuffers {
bool FileExistsRaw(const char *name) {
@@ -156,7 +159,7 @@
const std::string &filename) {
std::string filepath = path;
if (filepath.length()) {
- char &filepath_last_character = string_back(filepath);
+ char &filepath_last_character = filepath.back();
if (filepath_last_character == kPathSeparatorWindows) {
filepath_last_character = kPathSeparator;
} else if (filepath_last_character != kPathSeparator) {
@@ -176,6 +179,9 @@
std::replace(p.begin(), p.end(), '\\', '/');
return p;
}
+std::string PosixPath(const std::string &path) {
+ return PosixPath(path.c_str());
+}
void EnsureDirExists(const std::string &filepath) {
auto parent = StripFileName(filepath);
@@ -215,6 +221,36 @@
// clang-format on
}
+std::string RelativeToRootPath(const std::string &project,
+ const std::string &filepath) {
+ std::string absolute_project = PosixPath(AbsolutePath(project));
+ if (absolute_project.back() != '/') absolute_project += "/";
+ std::string absolute_filepath = PosixPath(AbsolutePath(filepath));
+
+ // Find the first character where they disagree.
+ // The previous directory is the lowest common ancestor;
+ const char *a = absolute_project.c_str();
+ const char *b = absolute_filepath.c_str();
+ size_t common_prefix_len = 0;
+ while (*a != '\0' && *b != '\0' && *a == *b) {
+ if (*a == '/') common_prefix_len = a - absolute_project.c_str();
+ a++;
+ b++;
+ }
+ // the number of ../ to prepend to b depends on the number of remaining
+ // directories in A.
+ const char *suffix = absolute_project.c_str() + common_prefix_len;
+ size_t num_up = 0;
+ while (*suffix != '\0')
+ if (*suffix++ == '/') num_up++;
+ num_up--; // last one is known to be '/'.
+ std::string result = "//";
+ for (size_t i = 0; i < num_up; i++) result += "../";
+ result += absolute_filepath.substr(common_prefix_len + 1);
+
+ return result;
+}
+
// Locale-independent code.
#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && \
(FLATBUFFERS_LOCALE_INDEPENDENT > 0)
@@ -238,8 +274,7 @@
std::string RemoveStringQuotes(const std::string &s) {
auto ch = *s.c_str();
- return ((s.size() >= 2) && (ch == '\"' || ch == '\'') &&
- (ch == string_back(s)))
+ return ((s.size() >= 2) && (ch == '\"' || ch == '\'') && (ch == s.back()))
? s.substr(1, s.length() - 2)
: s;
}
@@ -284,4 +319,130 @@
// clang-format on
}
+namespace {
+
+static std::string ToCamelCase(const std::string &input, bool first) {
+ std::string s;
+ for (size_t i = 0; i < input.length(); i++) {
+ if (!i && first)
+ s += CharToUpper(input[i]);
+ else if (input[i] == '_' && i + 1 < input.length())
+ s += CharToUpper(input[++i]);
+ else
+ s += input[i];
+ }
+ return s;
+}
+
+static std::string ToSnakeCase(const std::string &input, bool screaming) {
+ std::string s;
+ for (size_t i = 0; i < input.length(); i++) {
+ if (i == 0) {
+ s += screaming ? CharToUpper(input[i]) : CharToLower(input[i]);
+ } else if (input[i] == '_') {
+ s += '_';
+ } else if (!islower(input[i])) {
+ // Prevent duplicate underscores for Upper_Snake_Case strings
+ // and UPPERCASE strings.
+ if (islower(input[i - 1])) { s += '_'; }
+ s += screaming ? CharToUpper(input[i]) : CharToLower(input[i]);
+ } else {
+ s += screaming ? CharToUpper(input[i]) : input[i];
+ }
+ }
+ return s;
+}
+
+static std::string ToAll(const std::string &input,
+ std::function<char(const char)> transform) {
+ std::string s;
+ for (size_t i = 0; i < input.length(); i++) { s += transform(input[i]); }
+ return s;
+}
+
+static std::string CamelToSnake(const std::string &input) {
+ std::string s;
+ for (size_t i = 0; i < input.length(); i++) {
+ if (i == 0) {
+ s += CharToLower(input[i]);
+ } else if (input[i] == '_') {
+ s += '_';
+ } else if (!islower(input[i])) {
+ // Prevent duplicate underscores for Upper_Snake_Case strings
+ // and UPPERCASE strings.
+ if (islower(input[i - 1])) { s += '_'; }
+ s += CharToLower(input[i]);
+ } else {
+ s += input[i];
+ }
+ }
+ return s;
+}
+
+static std::string DasherToSnake(const std::string &input) {
+ std::string s;
+ for (size_t i = 0; i < input.length(); i++) {
+ if (input[i] == '-') {
+ s += "_";
+ } else {
+ s += input[i];
+ }
+ }
+ return s;
+}
+
+static std::string ToDasher(const std::string &input) {
+ std::string s;
+ char p = 0;
+ for (size_t i = 0; i < input.length(); i++) {
+ char const &c = input[i];
+ if (c == '_') {
+ if (i > 0 && p != kPathSeparator &&
+ // The following is a special case to ignore digits after a _. This is
+ // because ThisExample3 would be converted to this_example_3 in the
+ // CamelToSnake conversion, and then dasher would do this-example-3,
+ // but it expects this-example3.
+ !(i + 1 < input.length() && isdigit(input[i + 1])))
+ s += "-";
+ } else {
+ s += c;
+ }
+ p = c;
+ }
+ return s;
+}
+
+} // namespace
+
+std::string ConvertCase(const std::string &input, Case output_case,
+ Case input_case) {
+ if (output_case == Case::kKeep) return input;
+ // The output cases expect snake_case inputs, so if we don't have that input
+ // format, try to convert to snake_case.
+ switch (input_case) {
+ case Case::kLowerCamel:
+ case Case::kUpperCamel:
+ return ConvertCase(CamelToSnake(input), output_case);
+ case Case::kDasher: return ConvertCase(DasherToSnake(input), output_case);
+ case Case::kKeep: printf("WARNING: Converting from kKeep case.\n"); break;
+ default:
+ case Case::kSnake:
+ case Case::kScreamingSnake:
+ case Case::kAllLower:
+ case Case::kAllUpper: break;
+ }
+
+ switch (output_case) {
+ case Case::kUpperCamel: return ToCamelCase(input, true);
+ case Case::kLowerCamel: return ToCamelCase(input, false);
+ case Case::kSnake: return input;
+ case Case::kScreamingSnake: return ToSnakeCase(input, true);
+ case Case::kAllUpper: return ToAll(input, CharToUpper);
+ case Case::kAllLower: return ToAll(input, CharToLower);
+ case Case::kDasher: return ToDasher(input);
+ default:
+ case Case::kUnknown: return input;
+ }
+}
+
} // namespace flatbuffers