aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/flatbuffers/src
diff options
context:
space:
mode:
authormax42 <max42@yandex-team.com>2023-06-30 03:37:03 +0300
committermax42 <max42@yandex-team.com>2023-06-30 03:37:03 +0300
commitfac2bd72b4b31ec3238292caf8fb2a8aaa6d6c4a (patch)
treeb8cbc1deb00309c7f1a7ab6df520a76cf0b5c6d7 /contrib/libs/flatbuffers/src
parent7bf166b1a7ed0af927f230022b245af618e998c1 (diff)
downloadydb-fac2bd72b4b31ec3238292caf8fb2a8aaa6d6c4a.tar.gz
YT-19324: move YT provider to ydb/library/yql
This commit is formed by the following script: https://paste.yandex-team.ru/6f92e4b8-efc5-4d34-948b-15ee2accd7e7/text. This commit has zero effect on all projects that depend on YQL. The summary of changes: - `yql/providers/yt -> ydb/library/yql/providers/yt `- the whole implementation of YT provider is moved into YDB code base for further export as a part of YT YQL plugin shared library; - `yql/providers/stat/{expr_nodes,uploader} -> ydb/library/yql/providers/stat/{expr_nodes,uploader}` - a small interface without implementation and the description of stat expr nodes; - `yql/core/extract_predicate/ut -> ydb/library/yql/core/extract_predicate/ut`; - `yql/core/{ut,ut_common} -> ydb/library/yql/core/{ut,ut_common}`; - `yql/core` is gone; - `yql/library/url_preprocessing -> ydb/library/yql/core/url_preprocessing`. **NB**: all new targets inside `ydb/` are under `IF (NOT CMAKE_EXPORT)` clause which disables them from open-source cmake generation and ya make build. They will be enabled in the subsequent commits.
Diffstat (limited to 'contrib/libs/flatbuffers/src')
-rw-r--r--contrib/libs/flatbuffers/src/code_generators.cpp395
-rw-r--r--contrib/libs/flatbuffers/src/flatc.cpp554
-rw-r--r--contrib/libs/flatbuffers/src/flatc_main.cpp121
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_cpp.cpp3514
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_cpp_yandex_maps_iter.cpp731
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_csharp.cpp2100
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_dart.cpp955
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_fbs.cpp154
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_go.cpp1374
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_grpc.cpp557
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_java.cpp1244
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_json_schema.cpp292
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_kotlin.cpp1527
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_lobster.cpp391
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_lua.cpp745
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_php.cpp939
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_python.cpp1782
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_rust.cpp2817
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_swift.cpp1575
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_text.cpp414
-rw-r--r--contrib/libs/flatbuffers/src/idl_gen_ts.cpp1583
-rw-r--r--contrib/libs/flatbuffers/src/idl_parser.cpp3986
-rw-r--r--contrib/libs/flatbuffers/src/reflection.cpp713
-rw-r--r--contrib/libs/flatbuffers/src/util.cpp287
24 files changed, 28750 insertions, 0 deletions
diff --git a/contrib/libs/flatbuffers/src/code_generators.cpp b/contrib/libs/flatbuffers/src/code_generators.cpp
new file mode 100644
index 0000000000..745406ba95
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/code_generators.cpp
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2016 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 "flatbuffers/code_generators.h"
+
+#include <assert.h>
+
+#include <cmath>
+
+#include "flatbuffers/base.h"
+#include "flatbuffers/util.h"
+
+#if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable : 4127) // C4127: conditional expression is constant
+#endif
+
+namespace flatbuffers {
+
+void CodeWriter::operator+=(std::string text) {
+ if (!ignore_ident_ && !text.empty()) AppendIdent(stream_);
+
+ while (true) {
+ auto begin = text.find("{{");
+ if (begin == std::string::npos) { break; }
+
+ auto end = text.find("}}");
+ if (end == std::string::npos || end < begin) { break; }
+
+ // Write all the text before the first {{ into the stream.
+ stream_.write(text.c_str(), begin);
+
+ // The key is between the {{ and }}.
+ const std::string key = text.substr(begin + 2, end - begin - 2);
+
+ // Find the value associated with the key. If it exists, write the
+ // value into the stream, otherwise write the key itself into the stream.
+ auto iter = value_map_.find(key);
+ if (iter != value_map_.end()) {
+ const std::string &value = iter->second;
+ stream_ << value;
+ } else {
+ FLATBUFFERS_ASSERT(false && "could not find key");
+ stream_ << key;
+ }
+
+ // Update the text to everything after the }}.
+ text = text.substr(end + 2);
+ }
+ if (!text.empty() && string_back(text) == '\\') {
+ text.pop_back();
+ ignore_ident_ = true;
+ stream_ << text;
+ } else {
+ ignore_ident_ = false;
+ stream_ << text << std::endl;
+ }
+}
+
+void CodeWriter::AppendIdent(std::stringstream &stream) {
+ int lvl = cur_ident_lvl_;
+ while (lvl--) {
+ stream.write(pad_.c_str(), static_cast<std::streamsize>(pad_.size()));
+ }
+}
+
+const char *BaseGenerator::FlatBuffersGeneratedWarning() {
+ return "automatically generated by the FlatBuffers compiler,"
+ " do not modify";
+}
+
+std::string BaseGenerator::NamespaceDir(const Parser &parser,
+ const std::string &path,
+ 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 += !dasherize ? *it : ToDasherizedCase(*it);
+ namespace_dir += kPathSeparator;
+ EnsureDirExists(namespace_dir);
+ }
+ return namespace_dir;
+}
+
+std::string BaseGenerator::NamespaceDir(const Namespace &ns,
+ const bool dasherize) const {
+ return BaseGenerator::NamespaceDir(parser_, path_, ns, dasherize);
+}
+
+std::string BaseGenerator::ToDasherizedCase(const std::string pascal_case) {
+ std::string dasherized_case;
+ char p = 0;
+ for (size_t i = 0; i < pascal_case.length(); i++) {
+ char const &c = pascal_case[i];
+ if (is_alpha_upper(c)) {
+ if (i > 0 && p != kPathSeparator) dasherized_case += "-";
+ dasherized_case += CharToLower(c);
+ } else {
+ dasherized_case += c;
+ }
+ p = c;
+ }
+ return dasherized_case;
+}
+
+std::string BaseGenerator::FullNamespace(const char *separator,
+ const Namespace &ns) {
+ std::string namespace_name;
+ auto &namespaces = ns.components;
+ for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+ if (namespace_name.length()) namespace_name += separator;
+ namespace_name += *it;
+ }
+ return namespace_name;
+}
+
+std::string BaseGenerator::LastNamespacePart(const Namespace &ns) {
+ if (!ns.components.empty())
+ return ns.components.back();
+ else
+ return std::string("");
+}
+
+// Ensure that a type is prefixed with its namespace.
+std::string BaseGenerator::WrapInNameSpace(const Namespace *ns,
+ const std::string &name) const {
+ std::string qualified_name = qualifying_start_;
+ for (auto it = ns->components.begin(); it != ns->components.end(); ++it)
+ qualified_name += *it + qualifying_separator_;
+ return qualified_name + name;
+}
+
+std::string BaseGenerator::WrapInNameSpace(const Definition &def) const {
+ return WrapInNameSpace(def.defined_namespace, def.name);
+}
+
+std::string BaseGenerator::GetNameSpace(const Definition &def) const {
+ const Namespace *ns = def.defined_namespace;
+ if (CurrentNameSpace() == ns) return "";
+ std::string qualified_name = qualifying_start_;
+ for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
+ qualified_name += *it;
+ if ((it + 1) != ns->components.end()) {
+ qualified_name += qualifying_separator_;
+ }
+ }
+
+ return qualified_name;
+}
+
+std::string BaseGenerator::GeneratedFileName(const std::string &path,
+ const std::string &file_name,
+ const IDLOptions &options) const {
+ return path + file_name + options.filename_suffix + "." +
+ (options.filename_extension.empty() ? default_extension_
+ : options.filename_extension);
+}
+
+// Generate a documentation comment, if available.
+void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
+ const CommentConfig *config, const char *prefix) {
+ if (dc.begin() == dc.end()) {
+ // Don't output empty comment blocks with 0 lines of comment content.
+ return;
+ }
+
+ std::string &code = *code_ptr;
+ if (config != nullptr && config->first_line != nullptr) {
+ code += std::string(prefix) + std::string(config->first_line) + "\n";
+ }
+ std::string line_prefix =
+ std::string(prefix) +
+ ((config != nullptr && config->content_line_prefix != nullptr)
+ ? config->content_line_prefix
+ : "///");
+ for (auto it = dc.begin(); it != dc.end(); ++it) {
+ code += line_prefix + *it + "\n";
+ }
+ if (config != nullptr && config->last_line != nullptr) {
+ code += std::string(prefix) + std::string(config->last_line) + "\n";
+ }
+}
+
+template<typename T>
+std::string FloatConstantGenerator::GenFloatConstantImpl(
+ const FieldDef &field) const {
+ const auto &constant = field.value.constant;
+ T v;
+ auto done = StringToNumber(constant.c_str(), &v);
+ FLATBUFFERS_ASSERT(done);
+ if (done) {
+#if (!defined(_MSC_VER) || (_MSC_VER >= 1800))
+ if (std::isnan(v)) return NaN(v);
+ if (std::isinf(v)) return Inf(v);
+#endif
+ return Value(v, constant);
+ }
+ return "#"; // compile time error
+}
+
+std::string FloatConstantGenerator::GenFloatConstant(
+ const FieldDef &field) const {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_FLOAT: return GenFloatConstantImpl<float>(field);
+ case BASE_TYPE_DOUBLE: return GenFloatConstantImpl<double>(field);
+ default: {
+ FLATBUFFERS_ASSERT(false);
+ return "INVALID_BASE_TYPE";
+ }
+ };
+}
+
+TypedFloatConstantGenerator::TypedFloatConstantGenerator(
+ const char *double_prefix, const char *single_prefix,
+ const char *nan_number, const char *pos_inf_number,
+ const char *neg_inf_number)
+ : double_prefix_(double_prefix),
+ single_prefix_(single_prefix),
+ nan_number_(nan_number),
+ pos_inf_number_(pos_inf_number),
+ neg_inf_number_(neg_inf_number) {}
+
+std::string TypedFloatConstantGenerator::MakeNaN(
+ const std::string &prefix) const {
+ return prefix + nan_number_;
+}
+std::string TypedFloatConstantGenerator::MakeInf(
+ bool neg, const std::string &prefix) const {
+ if (neg)
+ return !neg_inf_number_.empty() ? (prefix + neg_inf_number_)
+ : ("-" + prefix + pos_inf_number_);
+ else
+ return prefix + pos_inf_number_;
+}
+
+std::string TypedFloatConstantGenerator::Value(double v,
+ const std::string &src) const {
+ (void)v;
+ return src;
+}
+
+std::string TypedFloatConstantGenerator::Inf(double v) const {
+ return MakeInf(v < 0, double_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::NaN(double v) const {
+ (void)v;
+ return MakeNaN(double_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::Value(float v,
+ const std::string &src) const {
+ (void)v;
+ return src + "f";
+}
+
+std::string TypedFloatConstantGenerator::Inf(float v) const {
+ return MakeInf(v < 0, single_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::NaN(float v) const {
+ (void)v;
+ return MakeNaN(single_prefix_);
+}
+
+SimpleFloatConstantGenerator::SimpleFloatConstantGenerator(
+ const char *nan_number, const char *pos_inf_number,
+ const char *neg_inf_number)
+ : nan_number_(nan_number),
+ pos_inf_number_(pos_inf_number),
+ neg_inf_number_(neg_inf_number) {}
+
+std::string SimpleFloatConstantGenerator::Value(double v,
+ const std::string &src) const {
+ (void)v;
+ return src;
+}
+
+std::string SimpleFloatConstantGenerator::Inf(double v) const {
+ return (v < 0) ? neg_inf_number_ : pos_inf_number_;
+}
+
+std::string SimpleFloatConstantGenerator::NaN(double v) const {
+ (void)v;
+ return nan_number_;
+}
+
+std::string SimpleFloatConstantGenerator::Value(float v,
+ const std::string &src) const {
+ return this->Value(static_cast<double>(v), src);
+}
+
+std::string SimpleFloatConstantGenerator::Inf(float v) const {
+ return this->Inf(static_cast<double>(v));
+}
+
+std::string SimpleFloatConstantGenerator::NaN(float v) const {
+ return this->NaN(static_cast<double>(v));
+}
+
+std::string JavaCSharpMakeRule(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";
+
+ std::string make_rule;
+
+ for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ if (!make_rule.empty()) make_rule += " ";
+ std::string directory =
+ BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace);
+ make_rule += directory + enum_def.name + file_extension;
+ }
+
+ for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
+ ++it) {
+ auto &struct_def = **it;
+ if (!make_rule.empty()) make_rule += " ";
+ std::string directory = BaseGenerator::NamespaceDir(
+ parser, path, *struct_def.defined_namespace);
+ make_rule += directory + struct_def.name + file_extension;
+ }
+
+ make_rule += ": ";
+ auto included_files = parser.GetIncludedFilesRecursive(file_name);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+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";
+ return path + file_name + "." + ext;
+}
+
+bool GenerateBinary(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ if (parser.opts.use_flexbuffers) {
+ auto data_vec = parser.flex_builder_.GetBuffer();
+ auto data_ptr = reinterpret_cast<char *>(data(data_vec));
+ return !parser.flex_builder_.GetSize() ||
+ flatbuffers::SaveFile(
+ BinaryFileName(parser, path, file_name).c_str(), data_ptr,
+ parser.flex_builder_.GetSize(), true);
+ }
+ return !parser.builder_.GetSize() ||
+ flatbuffers::SaveFile(
+ BinaryFileName(parser, path, file_name).c_str(),
+ reinterpret_cast<char *>(parser.builder_.GetBufferPointer()),
+ parser.builder_.GetSize(), true);
+}
+
+std::string BinaryMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ if (!parser.builder_.GetSize()) return "";
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ std::string make_rule =
+ BinaryFileName(parser, path, filebase) + ": " + file_name;
+ auto included_files =
+ parser.GetIncludedFilesRecursive(parser.root_struct_def_->file);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+} // namespace flatbuffers
+
+#if defined(_MSC_VER)
+# pragma warning(pop)
+#endif
diff --git a/contrib/libs/flatbuffers/src/flatc.cpp b/contrib/libs/flatbuffers/src/flatc.cpp
new file mode 100644
index 0000000000..221b88676d
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/flatc.cpp
@@ -0,0 +1,554 @@
+/*
+ * 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.
+ */
+
+#include "flatbuffers/flatc.h"
+
+#include <list>
+
+namespace flatbuffers {
+
+const char *FLATC_VERSION() { return FLATBUFFERS_VERSION(); }
+
+void FlatCompiler::ParseFile(
+ flatbuffers::Parser &parser, const std::string &filename,
+ const std::string &contents,
+ std::vector<const char *> &include_directories) const {
+ auto local_include_directory = flatbuffers::StripFileName(filename);
+ include_directories.push_back(local_include_directory.c_str());
+ include_directories.push_back(nullptr);
+ if (!parser.Parse(contents.c_str(), &include_directories[0],
+ filename.c_str())) {
+ Error(parser.error_, false, false);
+ }
+ if (!parser.error_.empty()) { Warn(parser.error_, false); }
+ include_directories.pop_back();
+ include_directories.pop_back();
+}
+
+void FlatCompiler::LoadBinarySchema(flatbuffers::Parser &parser,
+ const std::string &filename,
+ const std::string &contents) {
+ if (!parser.Deserialize(reinterpret_cast<const uint8_t *>(contents.c_str()),
+ contents.size())) {
+ Error("failed to load binary schema: " + filename, false, false);
+ }
+}
+
+void FlatCompiler::Warn(const std::string &warn, bool show_exe_name) const {
+ params_.warn_fn(this, warn, show_exe_name);
+}
+
+void FlatCompiler::Error(const std::string &err, bool usage,
+ bool show_exe_name) const {
+ params_.error_fn(this, err, usage, show_exe_name);
+}
+
+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";
+ }
+ // 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"
+ " --cpp-static-reflection When using C++17, generate extra code to provide compile-time\n"
+ " (static) reflection of Flatbuffers types. Requires --cpp-std\n"
+ " to be \"c++17\" or higher.\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"
+ " --go-namespace Generate the overriding namespace in Golang.\n"
+ " --go-import Generate the overriding import for flatbuffers in Golang\n"
+ " (default is \"github.com/google/flatbuffers/go\").\n"
+ " --raw-binary Allow binaries without file_identifier 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"
+ " --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"
+ " --no-warnings Inhibit all warning messages.\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
+ return ss.str();
+}
+
+int FlatCompiler::Compile(int argc, const char **argv) {
+ if (params_.generators == nullptr || params_.num_generators == 0) {
+ return 0;
+ }
+
+ flatbuffers::IDLOptions opts;
+ std::string output_path;
+
+ bool any_generator = false;
+ bool print_make_rules = false;
+ bool raw_binary = false;
+ bool schema_binary = false;
+ bool grpc_enabled = false;
+ std::vector<std::string> filenames;
+ std::list<std::string> include_directories_storage;
+ std::vector<const char *> include_directories;
+ std::vector<const char *> conform_include_directories;
+ std::vector<bool> generator_enabled(params_.num_generators, false);
+ size_t binary_files_from = std::numeric_limits<size_t>::max();
+ std::string conform_to_schema;
+
+ for (int argi = 0; argi < argc; argi++) {
+ std::string arg = argv[argi];
+ if (arg[0] == '-') {
+ if (filenames.size() && arg[1] != '-')
+ Error("invalid option location: " + arg, true);
+ if (arg == "-o") {
+ if (++argi >= argc) Error("missing path following: " + arg, true);
+ output_path = flatbuffers::ConCatPathFileName(
+ flatbuffers::PosixPath(argv[argi]), "");
+ } else if (arg == "-I") {
+ if (++argi >= argc) Error("missing path following: " + arg, true);
+ include_directories_storage.push_back(
+ flatbuffers::PosixPath(argv[argi]));
+ include_directories.push_back(
+ include_directories_storage.back().c_str());
+ } else if (arg == "--conform") {
+ if (++argi >= argc) Error("missing path following: " + arg, true);
+ conform_to_schema = flatbuffers::PosixPath(argv[argi]);
+ } else if (arg == "--conform-includes") {
+ if (++argi >= argc) Error("missing path following: " + arg, true);
+ include_directories_storage.push_back(
+ flatbuffers::PosixPath(argv[argi]));
+ conform_include_directories.push_back(
+ include_directories_storage.back().c_str());
+ } else if (arg == "--include-prefix") {
+ if (++argi >= argc) Error("missing path following: " + arg, true);
+ opts.include_prefix = flatbuffers::ConCatPathFileName(
+ flatbuffers::PosixPath(argv[argi]), "");
+ } else if (arg == "--keep-prefix") {
+ opts.keep_include_path = true;
+ } else if (arg == "--strict-json") {
+ opts.strict_json = true;
+ } else if (arg == "--allow-non-utf8") {
+ opts.allow_non_utf8 = true;
+ } else if (arg == "--natural-utf8") {
+ opts.natural_utf8 = true;
+ } else if (arg == "--go-namespace") {
+ if (++argi >= argc) Error("missing golang namespace" + arg, true);
+ opts.go_namespace = argv[argi];
+ } else if (arg == "--go-import") {
+ if (++argi >= argc) Error("missing golang import" + arg, true);
+ opts.go_import = argv[argi];
+ } else if (arg == "--defaults-json") {
+ opts.output_default_scalars_in_json = true;
+ } else if (arg == "--unknown-json") {
+ opts.skip_unexpected_fields_in_json = true;
+ } else if (arg == "--no-prefix") {
+ opts.prefixed_enums = false;
+ } else if (arg == "--scoped-enums") {
+ opts.prefixed_enums = false;
+ opts.scoped_enums = true;
+ } else if (arg == "--no-union-value-namespacing") {
+ opts.union_value_namespacing = false;
+ } else if (arg == "--gen-mutable") {
+ opts.mutable_buffer = true;
+ } else if (arg == "--gen-name-strings") {
+ opts.generate_name_strings = true;
+ } else if (arg == "--gen-object-api") {
+ opts.generate_object_based_api = true;
+ } else if (arg == "--gen-compare") {
+ opts.gen_compare = true;
+ } else if (arg == "--cpp-include") {
+ if (++argi >= argc) Error("missing include following: " + arg, true);
+ opts.cpp_includes.push_back(argv[argi]);
+ } else if (arg == "--cpp-ptr-type") {
+ if (++argi >= argc) Error("missing type following: " + arg, true);
+ opts.cpp_object_api_pointer_type = argv[argi];
+ } else if (arg == "--cpp-str-type") {
+ if (++argi >= argc) Error("missing type following: " + arg, true);
+ opts.cpp_object_api_string_type = argv[argi];
+ } else if (arg == "--cpp-str-flex-ctor") {
+ opts.cpp_object_api_string_flexible_constructor = true;
+ } else if (arg == "--no-cpp-direct-copy") {
+ opts.cpp_direct_copy = false;
+ } 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 == "--object-prefix") {
+ if (++argi >= argc) Error("missing prefix following: " + arg, true);
+ opts.object_prefix = argv[argi];
+ } else if (arg == "--object-suffix") {
+ if (++argi >= argc) Error("missing suffix following: " + arg, true);
+ opts.object_suffix = argv[argi];
+ } else if (arg == "--gen-all") {
+ opts.generate_all = true;
+ opts.include_dependence_headers = 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");
+ } else if (arg == "--no-includes") {
+ opts.include_dependence_headers = false;
+ } else if (arg == "--gen-onefile") {
+ opts.one_file = true;
+ } else if (arg == "--raw-binary") {
+ raw_binary = true;
+ } else if (arg == "--size-prefixed") {
+ opts.size_prefixed = true;
+ } else if (arg == "--") { // Separator between text and binary inputs.
+ binary_files_from = filenames.size();
+ } else if (arg == "--proto") {
+ opts.proto_mode = true;
+ } else if (arg == "--proto-namespace-suffix") {
+ if (++argi >= argc) Error("missing namespace suffix" + arg, true);
+ opts.proto_namespace_suffix = argv[argi];
+ } else if (arg == "--oneof-union") {
+ opts.proto_oneof_union = true;
+ } else if (arg == "--schema") {
+ schema_binary = true;
+ } else if (arg == "-M") {
+ print_make_rules = true;
+ } else if (arg == "--version") {
+ printf("flatc version %s\n", FLATC_VERSION());
+ exit(0);
+ } else if (arg == "--grpc") {
+ grpc_enabled = true;
+ } else if (arg == "--bfbs-comments") {
+ opts.binary_schema_comments = true;
+ } else if (arg == "--bfbs-builtins") {
+ opts.binary_schema_builtins = true;
+ } else if (arg == "--bfbs-gen-embed") {
+ opts.binary_schema_gen_embed = true;
+ } else if (arg == "--reflect-types") {
+ opts.mini_reflect = IDLOptions::kTypes;
+ } else if (arg == "--reflect-names") {
+ opts.mini_reflect = IDLOptions::kTypesAndNames;
+ } else if (arg == "--require-explicit-ids") {
+ opts.require_explicit_ids = true;
+ } else if (arg == "--root-type") {
+ if (++argi >= argc) Error("missing type following: " + arg, true);
+ opts.root_type = argv[argi];
+ } else if (arg == "--filename-suffix") {
+ if (++argi >= argc) Error("missing filename suffix: " + arg, true);
+ opts.filename_suffix = argv[argi];
+ } else if (arg == "--filename-ext") {
+ if (++argi >= argc) Error("missing filename extension: " + arg, true);
+ opts.filename_extension = argv[argi];
+ } else if (arg == "--force-defaults") {
+ opts.force_defaults = true;
+ } else if (arg == "--force-empty") {
+ opts.set_empty_strings_to_null = false;
+ opts.set_empty_vectors_to_null = false;
+ } else if (arg == "--force-empty-vectors") {
+ opts.set_empty_vectors_to_null = false;
+ } else if (arg == "--java-primitive-has-method") {
+ opts.java_primitive_has_method = true;
+ } else if (arg == "--cs-gen-json-serializer") {
+ opts.cs_gen_json_serializer = true;
+ } else if (arg == "--flexbuffers") {
+ 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 == "--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 {
+ 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)) {
+ generator_enabled[i] = true;
+ any_generator = true;
+ opts.lang_to_generate |= params_.generators[i].lang;
+ goto found;
+ }
+ }
+ Error("unknown commandline argument: " + arg, true);
+ found:;
+ }
+ } else {
+ filenames.push_back(flatbuffers::PosixPath(argv[argi]));
+ }
+ }
+
+ if (!filenames.size()) Error("missing input files", false, true);
+
+ if (opts.proto_mode) {
+ if (any_generator)
+ Error("cannot generate code directly from .proto files", true);
+ } else if (!any_generator && conform_to_schema.empty()) {
+ Error("no options: specify at least one generator.", true);
+ }
+
+ flatbuffers::Parser conform_parser;
+ if (!conform_to_schema.empty()) {
+ std::string contents;
+ if (!flatbuffers::LoadFile(conform_to_schema.c_str(), true, &contents))
+ Error("unable to load schema: " + conform_to_schema);
+
+ if (flatbuffers::GetExtension(conform_to_schema) ==
+ reflection::SchemaExtension()) {
+ LoadBinarySchema(conform_parser, conform_to_schema, contents);
+ } else {
+ ParseFile(conform_parser, conform_to_schema, contents,
+ conform_include_directories);
+ }
+ }
+
+ std::unique_ptr<flatbuffers::Parser> parser(new flatbuffers::Parser(opts));
+
+ for (auto file_it = filenames.begin(); file_it != filenames.end();
+ ++file_it) {
+ auto &filename = *file_it;
+ std::string contents;
+ if (!flatbuffers::LoadFile(filename.c_str(), true, &contents))
+ Error("unable to load file: " + filename);
+
+ 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();
+ if (is_binary) {
+ parser->builder_.Clear();
+ parser->builder_.PushFlatBuffer(
+ reinterpret_cast<const uint8_t *>(contents.c_str()),
+ contents.length());
+ if (!raw_binary) {
+ // Generally reading binaries that do not correspond to the schema
+ // will crash, and sadly there's no way around that when the binary
+ // does not contain a file identifier.
+ // We'd expect that typically any binary used as a file would have
+ // such an identifier, so by default we require them to match.
+ if (!parser->file_identifier_.length()) {
+ Error("current schema has no file_identifier: cannot test if \"" +
+ filename +
+ "\" matches the schema, use --raw-binary to read this file"
+ " anyway.");
+ } else if (!flatbuffers::BufferHasIdentifier(
+ contents.c_str(), parser->file_identifier_.c_str(),
+ opts.size_prefixed)) {
+ Error("binary \"" + filename +
+ "\" does not have expected file_identifier \"" +
+ parser->file_identifier_ +
+ "\", use --raw-binary to read this file anyway.");
+ }
+ }
+ } else {
+ // Check if file contains 0 bytes.
+ if (!opts.use_flexbuffers && !is_binary_schema &&
+ contents.length() != strlen(contents.c_str())) {
+ Error("input file appears to be binary: " + filename, true);
+ }
+ if (is_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));
+ }
+ if (is_binary_schema) {
+ LoadBinarySchema(*parser.get(), filename, contents);
+ }
+ 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());
+ } else {
+ parser->flex_builder_.Clear();
+ ParseFile(*parser.get(), filename, contents, include_directories);
+ }
+ } else {
+ ParseFile(*parser.get(), filename, contents, include_directories);
+ if (!is_schema && !parser->builder_.GetSize()) {
+ // If a file doesn't end in .fbs, it must be json/binary. Ensure we
+ // didn't just parse a schema with a different extension.
+ Error("input file is neither json nor a .fbs (schema) file: " +
+ filename,
+ true);
+ }
+ }
+ 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 (schema_binary || opts.binary_schema_gen_embed) {
+ parser->Serialize();
+ }
+ if (schema_binary) {
+ parser->file_extension_ = reflection::SchemaExtension();
+ }
+ }
+
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(filename));
+
+ 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);
+ }
+ } else {
+ if (params_.generators[i].make_rule == nullptr) {
+ Error(std::string("Cannot generate make rule for ") +
+ params_.generators[i].lang_name);
+ } else {
+ std::string make_rule = params_.generators[i].make_rule(
+ *parser.get(), output_path, filename);
+ if (!make_rule.empty())
+ printf("%s\n",
+ flatbuffers::WordWrap(make_rule, 80, " ", " \\").c_str());
+ }
+ }
+ if (grpc_enabled) {
+ if (params_.generators[i].generateGRPC != nullptr) {
+ if (!params_.generators[i].generateGRPC(*parser.get(), output_path,
+ filebase)) {
+ Error(std::string("Unable to generate GRPC interface for") +
+ params_.generators[i].lang_name);
+ }
+ } else {
+ Warn(std::string("GRPC interface generator not implemented for ") +
+ params_.generators[i].lang_name);
+ }
+ }
+ }
+ }
+
+ if (!opts.root_type.empty()) {
+ if (!parser->SetRootType(opts.root_type.c_str()))
+ Error("unknown root type: " + opts.root_type);
+ else if (parser->root_struct_def_->fixed)
+ Error("root type must be a table");
+ }
+
+ if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase);
+
+ // We do not want to generate code for the definitions in this file
+ // in any files coming up next.
+ parser->MarkGenerated();
+ }
+ return 0;
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/flatc_main.cpp b/contrib/libs/flatbuffers/src/flatc_main.cpp
new file mode 100644
index 0000000000..31ccbc7185
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/flatc_main.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2017 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 "flatbuffers/flatc.h"
+#include "flatbuffers/util.h"
+
+static const char *g_program_name = nullptr;
+
+static void Warn(const flatbuffers::FlatCompiler *flatc,
+ 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());
+}
+
+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());
+ }
+ exit(1);
+}
+
+namespace flatbuffers {
+void LogCompilerWarn(const std::string &warn) {
+ Warn(static_cast<const flatbuffers::FlatCompiler *>(nullptr), warn, true);
+}
+void LogCompilerError(const std::string &err) {
+ Error(static_cast<const flatbuffers::FlatCompiler *>(nullptr), err, false,
+ true);
+}
+} // namespace flatbuffers
+
+int main(int argc, const char *argv[]) {
+ // Prevent Appveyor-CI hangs.
+ flatbuffers::SetupDefaultCRTReportMode();
+
+ g_program_name = argv[0];
+
+ const flatbuffers::FlatCompiler::Generator generators[] = {
+ { flatbuffers::GenerateBinary, "-b", "--binary", "binary", false, nullptr,
+ flatbuffers::IDLOptions::kBinary,
+ "Generate wire format binaries for any data definitions",
+ flatbuffers::BinaryMakeRule },
+ { flatbuffers::GenerateTextFile, "-t", "--json", "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::GenerateDart, "-d", "--dart", "Dart", true, nullptr,
+ flatbuffers::IDLOptions::kDart,
+ "Generate Dart classes for tables/structs", flatbuffers::DartMakeRule },
+ { flatbuffers::GenerateTS, "-T", "--ts", "TypeScript", true,
+ flatbuffers::GenerateTSGRPC, flatbuffers::IDLOptions::kTs,
+ "Generate TypeScript code for tables/structs", flatbuffers::TSMakeRule },
+ { flatbuffers::GenerateCSharp, "-n", "--csharp", "C#", true, nullptr,
+ flatbuffers::IDLOptions::kCSharp,
+ "Generate C# classes for tables/structs",
+ flatbuffers::JavaCSharpMakeRule },
+ { flatbuffers::GeneratePython, "-p", "--python", "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::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::GenerateCPPYandexMapsIter, nullptr, "--yandex-maps-iter", "C++Iter",
+ true, nullptr, flatbuffers::IDLOptions::kCppYandexMapsIter,
+ "Generate C++ template headers for tables/structs", nullptr },
+ };
+
+ flatbuffers::FlatCompiler::InitParams params;
+ params.generators = generators;
+ params.num_generators = sizeof(generators) / sizeof(generators[0]);
+ params.warn_fn = Warn;
+ params.error_fn = Error;
+
+ flatbuffers::FlatCompiler flatc(params);
+ return flatc.Compile(argc - 1, argv + 1);
+}
diff --git a/contrib/libs/flatbuffers/src/idl_gen_cpp.cpp b/contrib/libs/flatbuffers/src/idl_gen_cpp.cpp
new file mode 100644
index 0000000000..a33697eaed
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_cpp.cpp
@@ -0,0 +1,3514 @@
+/*
+ * 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 <unordered_set>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/flatc.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+// Make numerical literal with type-suffix.
+// This function is only needed for C++! Other languages do not need it.
+static inline std::string NumToStringCpp(std::string val, BaseType type) {
+ // Avoid issues with -2147483648, -9223372036854775808.
+ switch (type) {
+ case BASE_TYPE_INT:
+ return (val != "-2147483648") ? val : ("(-2147483647 - 1)");
+ case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL");
+ case BASE_TYPE_LONG:
+ if (val == "-9223372036854775808")
+ return "(-9223372036854775807LL - 1LL)";
+ else
+ return (val == "0") ? val : (val + "LL");
+ default: return val;
+ }
+}
+
+static std::string GenIncludeGuard(const std::string &file_name,
+ const Namespace &name_space,
+ const std::string &postfix = "") {
+ // Generate include guard.
+ std::string guard = file_name;
+ // Remove any non-alpha-numeric characters that may appear in a filename.
+ struct IsAlnum {
+ bool operator()(char c) const { return !is_alnum(c); }
+ };
+ guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
+ guard.end());
+ guard = "FLATBUFFERS_GENERATED_" + guard;
+ guard += "_";
+ // For further uniqueness, also add the namespace.
+ for (auto it = name_space.components.begin();
+ it != name_space.components.end(); ++it) {
+ guard += *it + "_";
+ }
+ // Anything extra to add to the guard?
+ if (!postfix.empty()) { guard += postfix + "_"; }
+ guard += "H_";
+ std::transform(guard.begin(), guard.end(), guard.begin(), CharToUpper);
+ return guard;
+}
+
+namespace cpp {
+
+enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
+
+// Define a style of 'struct' constructor if it has 'Array' fields.
+enum GenArrayArgMode {
+ kArrayArgModeNone, // don't generate initialization args
+ kArrayArgModeSpanStatic, // generate flatbuffers::span<T,N>
+};
+
+// Extension of IDLOptions for cpp-generator.
+struct IDLOptionsCpp : public IDLOptions {
+ // All fields start with 'g_' prefix to distinguish from the base IDLOptions.
+ CppStandard g_cpp_std; // Base version of C++ standard.
+ bool g_only_fixed_enums; // Generate underlaying type for all enums.
+
+ IDLOptionsCpp(const IDLOptions &opts)
+ : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {}
+};
+
+class CppGenerator : public BaseGenerator {
+ public:
+ CppGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name, IDLOptionsCpp opts)
+ : BaseGenerator(parser, path, file_name, "", "::", "h"),
+ cur_name_space_(nullptr),
+ opts_(opts),
+ float_const_gen_("std::numeric_limits<double>::",
+ "std::numeric_limits<float>::", "quiet_NaN()",
+ "infinity()") {
+ static const char *const keywords[] = {
+ "alignas",
+ "alignof",
+ "and",
+ "and_eq",
+ "asm",
+ "atomic_cancel",
+ "atomic_commit",
+ "atomic_noexcept",
+ "auto",
+ "bitand",
+ "bitor",
+ "bool",
+ "break",
+ "case",
+ "catch",
+ "char",
+ "char16_t",
+ "char32_t",
+ "class",
+ "compl",
+ "concept",
+ "const",
+ "constexpr",
+ "const_cast",
+ "continue",
+ "co_await",
+ "co_return",
+ "co_yield",
+ "decltype",
+ "default",
+ "delete",
+ "do",
+ "double",
+ "dynamic_cast",
+ "else",
+ "enum",
+ "explicit",
+ "export",
+ "extern",
+ "false",
+ "float",
+ "for",
+ "friend",
+ "goto",
+ "if",
+ "import",
+ "inline",
+ "int",
+ "long",
+ "module",
+ "mutable",
+ "namespace",
+ "new",
+ "noexcept",
+ "not",
+ "not_eq",
+ "nullptr",
+ "operator",
+ "or",
+ "or_eq",
+ "private",
+ "protected",
+ "public",
+ "register",
+ "reinterpret_cast",
+ "requires",
+ "return",
+ "short",
+ "signed",
+ "sizeof",
+ "static",
+ "static_assert",
+ "static_cast",
+ "struct",
+ "switch",
+ "synchronized",
+ "template",
+ "this",
+ "thread_local",
+ "throw",
+ "true",
+ "try",
+ "typedef",
+ "typeid",
+ "typename",
+ "union",
+ "unsigned",
+ "using",
+ "virtual",
+ "void",
+ "volatile",
+ "wchar_t",
+ "while",
+ "xor",
+ "xor_eq",
+ nullptr,
+ };
+ for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+ }
+
+ void GenIncludeDependencies() {
+ int num_includes = 0;
+ if (opts_.generate_object_based_api) {
+ for (auto it = parser_.native_included_files_.begin();
+ it != parser_.native_included_files_.end(); ++it) {
+ code_ += "#include \"" + *it + "\"";
+ num_includes++;
+ }
+ }
+ for (auto it = parser_.included_files_.begin();
+ it != parser_.included_files_.end(); ++it) {
+ if (it->second.empty()) continue;
+ auto noext = flatbuffers::StripExtension(it->second);
+ auto basename = flatbuffers::StripPath(noext);
+ auto includeName =
+ GeneratedFileName(opts_.include_prefix,
+ opts_.keep_include_path ? noext : basename, opts_);
+ code_ += "#include \"" + includeName + "\"";
+ num_includes++;
+ }
+ if (num_includes) code_ += "";
+ }
+
+ void GenExtraIncludes() {
+ for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) {
+ code_ += "#include \"" + opts_.cpp_includes[i] + "\"";
+ }
+ if (!opts_.cpp_includes.empty()) { code_ += ""; }
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : name + "_";
+ }
+
+ std::string Name(const Definition &def) const {
+ return EscapeKeyword(def.name);
+ }
+
+ std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
+
+ bool generate_bfbs_embed() {
+ code_.Clear();
+ code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ // If we don't have a root struct definition,
+ if (!parser_.root_struct_def_) {
+ // put a comment in the output why there is no code generated.
+ code_ += "// Binary schema not generated, no root struct found";
+ } else {
+ auto &struct_def = *parser_.root_struct_def_;
+ const auto include_guard =
+ GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs");
+
+ code_ += "#ifndef " + include_guard;
+ code_ += "#define " + include_guard;
+ code_ += "";
+ if (parser_.opts.gen_nullable) {
+ code_ += "#pragma clang system_header\n\n";
+ }
+
+ SetNameSpace(struct_def.defined_namespace);
+ auto name = Name(struct_def);
+ code_.SetValue("STRUCT_NAME", name);
+
+ // Create code to return the binary schema data.
+ auto binary_schema_hex_text =
+ BufferToHexText(parser_.builder_.GetBufferPointer(),
+ parser_.builder_.GetSize(), 105, " ", "");
+
+ code_ += "struct {{STRUCT_NAME}}BinarySchema {";
+ code_ += " static const uint8_t *data() {";
+ code_ += " // Buffer containing the binary schema.";
+ code_ += " static const uint8_t bfbsData[" +
+ NumToString(parser_.builder_.GetSize()) + "] = {";
+ code_ += binary_schema_hex_text;
+ code_ += " };";
+ code_ += " return bfbsData;";
+ code_ += " }";
+ code_ += " static size_t size() {";
+ code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";";
+ code_ += " }";
+ code_ += " const uint8_t *begin() {";
+ code_ += " return data();";
+ code_ += " }";
+ code_ += " const uint8_t *end() {";
+ code_ += " return data() + size();";
+ code_ += " }";
+ code_ += "};";
+ code_ += "";
+
+ if (cur_name_space_) SetNameSpace(nullptr);
+
+ // Close the include guard.
+ code_ += "#endif // " + include_guard;
+ }
+
+ // We are just adding "_bfbs" to the generated filename.
+ const auto file_path =
+ GeneratedFileName(path_, file_name_ + "_bfbs", opts_);
+ const auto final_code = code_.ToString();
+
+ return SaveFile(file_path.c_str(), final_code, false);
+ }
+
+ // Iterate through all definitions we haven't generate code for (enums,
+ // structs, and tables) and output them to a single file.
+ bool generate() {
+ code_.Clear();
+ code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ const auto include_guard =
+ GenIncludeGuard(file_name_, *parser_.current_namespace_);
+ code_ += "#ifndef " + include_guard;
+ code_ += "#define " + include_guard;
+ code_ += "";
+
+ if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; }
+
+ code_ += "#include <contrib/libs/flatbuffers/include/flatbuffers/flatbuffers.h>";
+ if (parser_.uses_flexbuffers_) {
+ code_ += "#include <contrib/libs/flatbuffers/include/flatbuffers/flexbuffers.h>";
+ }
+ code_ += "";
+
+ if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
+ GenExtraIncludes();
+
+ FLATBUFFERS_ASSERT(!cur_name_space_);
+
+ // Generate forward declarations for all structs/tables, since they may
+ // have circular references.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ code_ += "struct " + Name(struct_def) + ";";
+ if (!struct_def.fixed) {
+ code_ += "struct " + Name(struct_def) + "Builder;";
+ }
+ if (opts_.generate_object_based_api) {
+ auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
+ if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
+ }
+ code_ += "";
+ }
+ }
+
+ // Generate forward declarations for all equal operators
+ if (opts_.generate_object_based_api && opts_.gen_compare) {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
+ code_ += "bool operator==(const " + nativeName + " &lhs, const " +
+ nativeName + " &rhs);";
+ code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
+ nativeName + " &rhs);";
+ }
+ }
+ code_ += "";
+ }
+
+ // Generate preablmle code for mini reflection.
+ if (opts_.mini_reflect != IDLOptions::kNone) {
+ // To break cyclic dependencies, first pre-declare all tables/structs.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenMiniReflectPre(&struct_def);
+ }
+ }
+ }
+
+ // Generate code for all the enum declarations.
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ const auto &enum_def = **it;
+ if (!enum_def.generated) {
+ SetNameSpace(enum_def.defined_namespace);
+ GenEnum(enum_def);
+ }
+ }
+
+ // Generate code for all structs, then all tables.
+ 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) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenStruct(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) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenTable(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) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenTablePost(struct_def);
+ }
+ }
+
+ // Generate code for union verifiers.
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ const auto &enum_def = **it;
+ if (enum_def.is_union && !enum_def.generated) {
+ SetNameSpace(enum_def.defined_namespace);
+ GenUnionPost(enum_def);
+ }
+ }
+
+ // Generate code for mini reflection.
+ if (opts_.mini_reflect != IDLOptions::kNone) {
+ // Then the unions/enums that may refer to them.
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ const auto &enum_def = **it;
+ if (!enum_def.generated) {
+ SetNameSpace(enum_def.defined_namespace);
+ GenMiniReflect(nullptr, &enum_def);
+ }
+ }
+ // Then the full tables/structs.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenMiniReflect(&struct_def, nullptr);
+ }
+ }
+ }
+
+ // Generate convenient global helper functions:
+ if (parser_.root_struct_def_) {
+ auto &struct_def = *parser_.root_struct_def_;
+ SetNameSpace(struct_def.defined_namespace);
+ auto name = Name(struct_def);
+ auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
+ auto cpp_name = TranslateNameSpace(qualified_name);
+
+ code_.SetValue("STRUCT_NAME", name);
+ code_.SetValue("CPP_NAME", cpp_name);
+ code_.SetValue("NULLABLE_EXT", NullableExtension());
+
+ // The root datatype accessor:
+ code_ += "inline \\";
+ code_ +=
+ "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void "
+ "*buf) {";
+ code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline \\";
+ code_ +=
+ "const {{CPP_NAME}} "
+ "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void "
+ "*buf) {";
+ code_ += " return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);";
+ code_ += "}";
+ code_ += "";
+
+ if (opts_.mutable_buffer) {
+ code_ += "inline \\";
+ code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
+ code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
+ code_ += "}";
+ code_ += "";
+ }
+
+ if (parser_.file_identifier_.length()) {
+ // Return the identifier
+ code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
+ code_ += " return \"" + parser_.file_identifier_ + "\";";
+ code_ += "}";
+ code_ += "";
+
+ // Check if a buffer has the identifier.
+ code_ += "inline \\";
+ code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
+ code_ += " return flatbuffers::BufferHasIdentifier(";
+ code_ += " buf, {{STRUCT_NAME}}Identifier());";
+ code_ += "}";
+ code_ += "";
+ }
+
+ // The root verifier.
+ if (parser_.file_identifier_.length()) {
+ code_.SetValue("ID", name + "Identifier()");
+ } else {
+ code_.SetValue("ID", "nullptr");
+ }
+
+ code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
+ code_ += " flatbuffers::Verifier &verifier) {";
+ code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer(";
+ code_ += " flatbuffers::Verifier &verifier) {";
+ code_ +=
+ " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});";
+ code_ += "}";
+ code_ += "";
+
+ if (parser_.file_extension_.length()) {
+ // Return the extension
+ code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
+ code_ += " return \"" + parser_.file_extension_ + "\";";
+ code_ += "}";
+ code_ += "";
+ }
+
+ // Finish a buffer with a given root object:
+ code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
+ code_ += " flatbuffers::FlatBufferBuilder &fbb,";
+ code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
+ if (parser_.file_identifier_.length())
+ code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
+ else
+ code_ += " fbb.Finish(root);";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer(";
+ code_ += " flatbuffers::FlatBufferBuilder &fbb,";
+ code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
+ if (parser_.file_identifier_.length())
+ code_ += " fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());";
+ else
+ code_ += " fbb.FinishSizePrefixed(root);";
+ code_ += "}";
+ code_ += "";
+
+ if (opts_.generate_object_based_api) {
+ // A convenient root unpack function.
+ auto native_name = WrapNativeNameInNameSpace(struct_def, opts_);
+ code_.SetValue("UNPACK_RETURN",
+ GenTypeNativePtr(native_name, nullptr, false));
+ code_.SetValue("UNPACK_TYPE",
+ GenTypeNativePtr(native_name, nullptr, true));
+
+ code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
+ code_ += " const void *buf,";
+ code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
+ code_ += " return {{UNPACK_TYPE}}\\";
+ code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}(";
+ code_ += " const void *buf,";
+ code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
+ code_ += " return {{UNPACK_TYPE}}\\";
+ code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ if (cur_name_space_) SetNameSpace(nullptr);
+
+ // Close the include guard.
+ code_ += "#endif // " + include_guard;
+
+ const auto file_path = GeneratedFileName(path_, file_name_, opts_);
+ const auto final_code = code_.ToString();
+
+ // Save the file and optionally generate the binary schema code.
+ return SaveFile(file_path.c_str(), final_code, false) &&
+ (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed());
+ }
+
+ private:
+ CodeWriter code_;
+
+ std::unordered_set<std::string> keywords_;
+
+ // This tracks the current namespace so we can insert namespace declarations.
+ const Namespace *cur_name_space_;
+
+ const IDLOptionsCpp opts_;
+ const TypedFloatConstantGenerator float_const_gen_;
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ // Translates a qualified name in flatbuffer text format to the same name in
+ // the equivalent C++ namespace.
+ static std::string TranslateNameSpace(const std::string &qualified_name) {
+ std::string cpp_qualified_name = qualified_name;
+ size_t start_pos = 0;
+ while ((start_pos = cpp_qualified_name.find('.', start_pos)) !=
+ std::string::npos) {
+ cpp_qualified_name.replace(start_pos, 1, "::");
+ }
+ return cpp_qualified_name;
+ }
+
+ bool TypeHasKey(const Type &type) {
+ if (type.base_type != BASE_TYPE_STRUCT) { return false; }
+ for (auto it = type.struct_def->fields.vec.begin();
+ it != type.struct_def->fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.key) { return true; }
+ }
+ return false;
+ }
+
+ bool VectorElementUserFacing(const Type &type) const {
+ return 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 = "") {
+ std::string text;
+ ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
+ code_ += text + "\\";
+ }
+
+ // Return a C++ type from the table in idl.h
+ std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
+ // clang-format off
+ static const char *const ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ #CTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ if (user_facing_type) {
+ if (type.enum_def) return WrapInNameSpace(*type.enum_def);
+ if (type.base_type == BASE_TYPE_BOOL) return "bool";
+ }
+ return ctypename[type.base_type];
+ }
+
+ // Return a C++ pointer type, specialized to the actual struct/table types,
+ // and vector element types.
+ std::string GenTypePointer(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: {
+ return "flatbuffers::String";
+ }
+ case BASE_TYPE_VECTOR: {
+ const auto type_name = GenTypeWire(
+ type.VectorType(), "", VectorElementUserFacing(type.VectorType()));
+ return "flatbuffers::Vector<" + type_name + ">";
+ }
+ case BASE_TYPE_STRUCT: {
+ return WrapInNameSpace(*type.struct_def);
+ }
+ case BASE_TYPE_UNION:
+ // fall through
+ default: {
+ return "void";
+ }
+ }
+ }
+
+ // Return a C++ type for any type (scalar/pointer) specifically for
+ // building a flatbuffer.
+ std::string GenTypeWire(const Type &type, const char *postfix,
+ bool user_facing_type) const {
+ if (IsScalar(type.base_type)) {
+ return GenTypeBasic(type, user_facing_type) + postfix;
+ } else if (IsStruct(type)) {
+ return "const " + GenTypePointer(type) + " *";
+ } else {
+ return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
+ }
+ }
+
+ // Return a C++ type for any type (scalar/pointer) that reflects its
+ // serialized size.
+ std::string GenTypeSize(const Type &type) const {
+ if (IsScalar(type.base_type)) {
+ return GenTypeBasic(type, false);
+ } else if (IsStruct(type)) {
+ return GenTypePointer(type);
+ } else {
+ return "flatbuffers::uoffset_t";
+ }
+ }
+
+ std::string NullableExtension() {
+ return opts_.gen_nullable ? " _Nullable " : "";
+ }
+
+ static std::string NativeName(const std::string &name, const StructDef *sd,
+ const IDLOptions &opts) {
+ return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
+ : 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;
+ }
+
+ const std::string NativeString(const FieldDef *field) {
+ auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
+ auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type;
+ if (ret.empty()) { return "std::string"; }
+ return ret;
+ }
+
+ bool FlexibleStringConstructor(const FieldDef *field) {
+ auto attr = field
+ ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
+ : false;
+ auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor;
+ return ret && NativeString(field) !=
+ "std::string"; // Only for custom string types.
+ }
+
+ std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
+ bool is_constructor) {
+ auto &ptr_type = PtrType(field);
+ if (ptr_type != "naked") {
+ return (ptr_type != "default_ptr_type"
+ ? ptr_type
+ : opts_.cpp_object_api_pointer_type) +
+ "<" + type + ">";
+ } else if (is_constructor) {
+ return "";
+ } else {
+ return type + " *";
+ }
+ }
+
+ std::string GenPtrGet(const FieldDef &field) {
+ auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get");
+ if (cpp_ptr_type_get) return cpp_ptr_type_get->constant;
+ auto &ptr_type = PtrType(&field);
+ return ptr_type == "naked" ? "" : ".get()";
+ }
+
+ std::string GenOptionalNull() { return "flatbuffers::nullopt"; }
+
+ std::string GenOptionalDecl(const Type &type) {
+ return "flatbuffers::Optional<" + GenTypeBasic(type, true) + ">";
+ }
+
+ std::string GenTypeNative(const Type &type, bool invector,
+ const FieldDef &field) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: {
+ return NativeString(&field);
+ }
+ case BASE_TYPE_VECTOR: {
+ const auto type_name = GenTypeNative(type.VectorType(), true, field);
+ if (type.struct_def &&
+ type.struct_def->attributes.Lookup("native_custom_alloc")) {
+ auto native_custom_alloc =
+ type.struct_def->attributes.Lookup("native_custom_alloc");
+ return "std::vector<" + type_name + "," +
+ native_custom_alloc->constant + "<" + type_name + ">>";
+ } else
+ return "std::vector<" + type_name + ">";
+ }
+ case BASE_TYPE_STRUCT: {
+ auto type_name = WrapInNameSpace(*type.struct_def);
+ 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) {
+ return type_name;
+ } else {
+ return GenTypeNativePtr(type_name, &field, false);
+ }
+ } else {
+ return GenTypeNativePtr(
+ WrapNativeNameInNameSpace(*type.struct_def, opts_), &field,
+ false);
+ }
+ }
+ case BASE_TYPE_UNION: {
+ auto type_name = WrapInNameSpace(*type.enum_def);
+ return type_name + "Union";
+ }
+ default: {
+ return field.IsScalarOptional() ? GenOptionalDecl(type)
+ : GenTypeBasic(type, true);
+ }
+ }
+ }
+
+ // Return a C++ type for any type (scalar/pointer) specifically for
+ // using a flatbuffer.
+ std::string GenTypeGet(const Type &type, const char *afterbasic,
+ const char *beforeptr, const char *afterptr,
+ bool user_facing_type) {
+ if (IsScalar(type.base_type)) {
+ return GenTypeBasic(type, user_facing_type) + afterbasic;
+ } else if (IsArray(type)) {
+ auto element_type = type.VectorType();
+ // Check if enum arrays are used in C++ without specifying --scoped-enums
+ if (IsEnum(element_type) && !opts_.g_only_fixed_enums) {
+ LogCompilerError(
+ "--scoped-enums must be enabled to use enum arrays in C++");
+ FLATBUFFERS_ASSERT(true);
+ }
+ return beforeptr +
+ (IsScalar(element_type.base_type)
+ ? GenTypeBasic(element_type, user_facing_type)
+ : GenTypePointer(element_type)) +
+ afterptr;
+ } else {
+ return beforeptr + GenTypePointer(type) + afterptr;
+ }
+ }
+
+ std::string GenTypeSpan(const Type &type, bool immutable, size_t extent) {
+ // Generate "flatbuffers::span<const U, extent>".
+ FLATBUFFERS_ASSERT(IsSeries(type) && "unexpected type");
+ auto element_type = type.VectorType();
+ std::string text = "flatbuffers::span<";
+ text += immutable ? "const " : "";
+ if (IsScalar(element_type.base_type)) {
+ text += GenTypeBasic(element_type, IsEnum(element_type));
+ } else {
+ switch (element_type.base_type) {
+ case BASE_TYPE_STRING: {
+ text += "char";
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ FLATBUFFERS_ASSERT(type.struct_def);
+ text += WrapInNameSpace(*type.struct_def);
+ break;
+ }
+ default:
+ FLATBUFFERS_ASSERT(false && "unexpected element's type");
+ break;
+ }
+ }
+ if (extent != flatbuffers::dynamic_extent) {
+ text += ", ";
+ text += NumToString(extent);
+ }
+ text += "> ";
+ return text;
+ }
+
+ std::string GenEnumValDecl(const EnumDef &enum_def,
+ const std::string &enum_val) const {
+ return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
+ }
+
+ std::string GetEnumValUse(const EnumDef &enum_def,
+ const EnumVal &enum_val) const {
+ if (opts_.scoped_enums) {
+ return Name(enum_def) + "::" + Name(enum_val);
+ } else if (opts_.prefixed_enums) {
+ return Name(enum_def) + "_" + Name(enum_val);
+ } else {
+ return Name(enum_val);
+ }
+ }
+
+ std::string StripUnionType(const std::string &name) {
+ return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
+ }
+
+ std::string GetUnionElement(const EnumVal &ev, bool native_type,
+ const IDLOptions &opts) {
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ 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 native_type ? "std::string" : "flatbuffers::String";
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ return Name(ev);
+ }
+ }
+
+ std::string UnionVerifySignature(const EnumDef &enum_def) {
+ return "bool Verify" + Name(enum_def) +
+ "(flatbuffers::Verifier &verifier, const void *obj, " +
+ Name(enum_def) + " type)";
+ }
+
+ std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
+ return "bool Verify" + Name(enum_def) + "Vector" +
+ "(flatbuffers::Verifier &verifier, " +
+ "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
+ "const flatbuffers::Vector<uint8_t> *types)";
+ }
+
+ std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
+ return (inclass ? "static " : "") + std::string("void *") +
+ (inclass ? "" : Name(enum_def) + "Union::") +
+ "UnPack(const void *obj, " + Name(enum_def) +
+ " type, const flatbuffers::resolver_function_t *resolver)";
+ }
+
+ std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
+ return "flatbuffers::Offset<void> " +
+ (inclass ? "" : Name(enum_def) + "Union::") +
+ "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
+ "const flatbuffers::rehasher_function_t *_rehasher" +
+ (inclass ? " = nullptr" : "") + ") const";
+ }
+
+ std::string TableCreateSignature(const StructDef &struct_def, bool predecl,
+ const IDLOptions &opts) {
+ return "flatbuffers::Offset<" + Name(struct_def) + "> Create" +
+ Name(struct_def) + "(flatbuffers::FlatBufferBuilder &_fbb, const " +
+ NativeName(Name(struct_def), &struct_def, opts) +
+ " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
+ (predecl ? " = nullptr" : "") + ")";
+ }
+
+ std::string TablePackSignature(const StructDef &struct_def, bool inclass,
+ const IDLOptions &opts) {
+ return std::string(inclass ? "static " : "") + "flatbuffers::Offset<" +
+ Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") +
+ "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "const " +
+ NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
+ "const flatbuffers::rehasher_function_t *_rehasher" +
+ (inclass ? " = nullptr" : "") + ")";
+ }
+
+ std::string TableUnPackSignature(const StructDef &struct_def, bool inclass,
+ const IDLOptions &opts) {
+ return NativeName(Name(struct_def), &struct_def, opts) + " *" +
+ (inclass ? "" : Name(struct_def) + "::") +
+ "UnPack(const flatbuffers::resolver_function_t *_resolver" +
+ (inclass ? " = nullptr" : "") + ") const";
+ }
+
+ std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass,
+ const IDLOptions &opts) {
+ return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" +
+ NativeName(Name(struct_def), &struct_def, opts) + " *" +
+ "_o, const flatbuffers::resolver_function_t *_resolver" +
+ (inclass ? " = nullptr" : "") + ") const";
+ }
+
+ void GenMiniReflectPre(const StructDef *struct_def) {
+ code_.SetValue("NAME", struct_def->name);
+ code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable();";
+ code_ += "";
+ }
+
+ void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) {
+ code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
+ code_.SetValue("SEQ_TYPE",
+ struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
+ : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
+ auto num_fields =
+ struct_def ? struct_def->fields.vec.size() : enum_def->size();
+ code_.SetValue("NUM_FIELDS", NumToString(num_fields));
+ std::vector<std::string> names;
+ std::vector<Type> types;
+
+ if (struct_def) {
+ for (auto it = struct_def->fields.vec.begin();
+ it != struct_def->fields.vec.end(); ++it) {
+ const auto &field = **it;
+ names.push_back(Name(field));
+ types.push_back(field.value.type);
+ }
+ } else {
+ for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ names.push_back(Name(ev));
+ types.push_back(enum_def->is_union ? ev.union_type
+ : Type(enum_def->underlying_type));
+ }
+ }
+ std::string ts;
+ std::vector<std::string> type_refs;
+ std::vector<uint16_t> array_sizes;
+ for (auto it = types.begin(); it != types.end(); ++it) {
+ auto &type = *it;
+ if (!ts.empty()) ts += ",\n ";
+ auto is_vector = IsVector(type);
+ auto is_array = IsArray(type);
+ auto bt = is_vector || is_array ? type.element : type.base_type;
+ auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
+ ? 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) : "";
+ if (!ref_name.empty()) {
+ auto rit = type_refs.begin();
+ for (; rit != type_refs.end(); ++rit) {
+ if (*rit == ref_name) {
+ ref_idx = static_cast<int>(rit - type_refs.begin());
+ break;
+ }
+ }
+ if (rit == type_refs.end()) {
+ ref_idx = static_cast<int>(type_refs.size());
+ type_refs.push_back(ref_name);
+ }
+ }
+ if (is_array) { array_sizes.push_back(type.fixed_length); }
+ ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
+ NumToString(is_vector || is_array) + ", " + NumToString(ref_idx) +
+ " }";
+ }
+ std::string rs;
+ for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
+ if (!rs.empty()) rs += ",\n ";
+ rs += *it + "TypeTable";
+ }
+ std::string as;
+ for (auto it = array_sizes.begin(); it != array_sizes.end(); ++it) {
+ as += NumToString(*it);
+ as += ", ";
+ }
+ std::string ns;
+ for (auto it = names.begin(); it != names.end(); ++it) {
+ if (!ns.empty()) ns += ",\n ";
+ ns += "\"" + *it + "\"";
+ }
+ std::string vs;
+ const auto consecutive_enum_from_zero =
+ enum_def && enum_def->MinValue()->IsZero() &&
+ ((enum_def->size() - 1) == enum_def->Distance());
+ if (enum_def && !consecutive_enum_from_zero) {
+ for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (!vs.empty()) vs += ", ";
+ vs += NumToStringCpp(enum_def->ToString(ev),
+ enum_def->underlying_type.base_type);
+ }
+ } else if (struct_def && struct_def->fixed) {
+ for (auto it = struct_def->fields.vec.begin();
+ it != struct_def->fields.vec.end(); ++it) {
+ const auto &field = **it;
+ vs += NumToString(field.value.offset);
+ vs += ", ";
+ }
+ vs += NumToString(struct_def->bytesize);
+ }
+ code_.SetValue("TYPES", ts);
+ code_.SetValue("REFS", rs);
+ code_.SetValue("ARRAYSIZES", as);
+ code_.SetValue("NAMES", ns);
+ code_.SetValue("VALUES", vs);
+ code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {";
+ if (num_fields) {
+ code_ += " static const flatbuffers::TypeCode type_codes[] = {";
+ code_ += " {{TYPES}}";
+ code_ += " };";
+ }
+ if (!type_refs.empty()) {
+ code_ += " static const flatbuffers::TypeFunction type_refs[] = {";
+ code_ += " {{REFS}}";
+ code_ += " };";
+ }
+ if (!as.empty()) {
+ code_ += " static const int16_t array_sizes[] = { {{ARRAYSIZES}} };";
+ }
+ if (!vs.empty()) {
+ // Problem with uint64_t values greater than 9223372036854775807ULL.
+ code_ += " static const int64_t values[] = { {{VALUES}} };";
+ }
+ auto has_names =
+ num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames;
+ if (has_names) {
+ code_ += " static const char * const names[] = {";
+ code_ += " {{NAMES}}";
+ code_ += " };";
+ }
+ code_ += " static const flatbuffers::TypeTable tt = {";
+ code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
+ (num_fields ? "type_codes, " : "nullptr, ") +
+ (!type_refs.empty() ? "type_refs, " : "nullptr, ") +
+ (!as.empty() ? "array_sizes, " : "nullptr, ") +
+ (!vs.empty() ? "values, " : "nullptr, ") +
+ (has_names ? "names" : "nullptr");
+ code_ += " };";
+ code_ += " return &tt;";
+ code_ += "}";
+ code_ += "";
+ }
+
+ // Generate an enum declaration,
+ // an enum string lookup table,
+ // and an enum array of values
+
+ void GenEnum(const EnumDef &enum_def) {
+ code_.SetValue("ENUM_NAME", Name(enum_def));
+ code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
+
+ GenComment(enum_def.doc_comment);
+ code_ +=
+ (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\";
+ if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; }
+ code_ += " {";
+
+ code_.SetValue("SEP", ",");
+ auto add_sep = false;
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+ if (add_sep) code_ += "{{SEP}}";
+ GenComment(ev.doc_comment, " ");
+ code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev)));
+ code_.SetValue("VALUE",
+ NumToStringCpp(enum_def.ToString(ev),
+ enum_def.underlying_type.base_type));
+ code_ += " {{KEY}} = {{VALUE}}\\";
+ add_sep = true;
+ }
+ const EnumVal *minv = enum_def.MinValue();
+ const EnumVal *maxv = enum_def.MaxValue();
+
+ if (opts_.scoped_enums || opts_.prefixed_enums) {
+ FLATBUFFERS_ASSERT(minv && maxv);
+
+ code_.SetValue("SEP", ",\n");
+ if (enum_def.attributes.Lookup("bit_flags")) {
+ code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
+ code_.SetValue("VALUE", "0");
+ code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
+
+ code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
+ code_.SetValue("VALUE",
+ NumToStringCpp(enum_def.AllFlags(),
+ enum_def.underlying_type.base_type));
+ code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
+ } else { // MIN & MAX are useless for bit_flags
+ code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
+ code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv)));
+ code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
+
+ code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
+ code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv)));
+ code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
+ }
+ }
+ code_ += "";
+ code_ += "};";
+
+ if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
+ code_ +=
+ "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
+ }
+ code_ += "";
+
+ // Generate an array of all enumeration values
+ auto num_fields = NumToString(enum_def.size());
+ code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
+ num_fields + "] {";
+ code_ += " static const {{ENUM_NAME}} values[] = {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+ auto value = GetEnumValUse(enum_def, ev);
+ auto suffix = *it != enum_def.Vals().back() ? "," : "";
+ code_ += " " + value + suffix;
+ }
+ code_ += " };";
+ code_ += " return values;";
+ code_ += "}";
+ code_ += "";
+
+ // Generate a generate 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.
+ auto range = enum_def.Distance();
+ // 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) {
+ code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
+ code_ += " static const char * const names[" +
+ NumToString(range + 1 + 1) + "] = {";
+
+ auto val = enum_def.Vals().front();
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ auto ev = *it;
+ for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
+ code_ += " \"\",";
+ }
+ val = ev;
+ code_ += " \"" + Name(*ev) + "\",";
+ }
+ code_ += " nullptr";
+ code_ += " };";
+
+ code_ += " return names;";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
+
+ code_ += " if (flatbuffers::IsOutRange(e, " +
+ GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " +
+ GetEnumValUse(enum_def, *enum_def.MaxValue()) +
+ ")) return \"\";";
+
+ code_ += " const size_t index = static_cast<size_t>(e)\\";
+ if (enum_def.MinValue()->IsNonZero()) {
+ auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
+ code_ += " - static_cast<size_t>(" + vals + ")\\";
+ }
+ code_ += ";";
+
+ code_ += " return EnumNames{{ENUM_NAME}}()[index];";
+ code_ += "}";
+ code_ += "";
+ } else {
+ code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
+
+ code_ += " switch (e) {";
+
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ code_ += " case " + GetEnumValUse(enum_def, ev) + ": return \"" +
+ Name(ev) + "\";";
+ }
+
+ code_ += " default: return \"\";";
+ code_ += " }";
+
+ code_ += "}";
+ code_ += "";
+ }
+
+ // Generate type traits for unions to map from a type to union enum value.
+ if (enum_def.is_union && !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 {{ENUM_NAME}}Traits {";
+ } else {
+ auto name = GetUnionElement(ev, false, opts_);
+ code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
+ }
+
+ auto value = GetEnumValUse(enum_def, ev);
+ code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
+ code_ += "};";
+ code_ += "";
+ }
+ }
+
+ if (opts_.generate_object_based_api && enum_def.is_union) {
+ // Generate a union type
+ code_.SetValue("NAME", Name(enum_def));
+ FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
+ code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
+
+ code_ += "struct {{NAME}}Union {";
+ code_ += " {{NAME}} type;";
+ code_ += " void *value;";
+ code_ += "";
+ code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
+ code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
+ code_ += " type({{NONE}}), value(nullptr)";
+ code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
+ code_ += " {{NAME}}Union(const {{NAME}}Union &);";
+ code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)";
+ code_ +=
+ " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
+ "t.value); return *this; }";
+ code_ +=
+ " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
+ code_ +=
+ " { std::swap(type, u.type); std::swap(value, u.value); return "
+ "*this; }";
+ code_ += " ~{{NAME}}Union() { Reset(); }";
+ code_ += "";
+ 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_ += " Reset();";
+ code_ +=
+ " type = {{NAME}}Traits<typename RT::TableType>::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) + ";";
+ code_ += " " + UnionPackSignature(enum_def, true) + ";";
+ code_ += "";
+
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ 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));
+
+ code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
+ code_ += " return type == {{NATIVE_ID}} ?";
+ code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
+ code_ += " }";
+
+ code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
+ code_ += " return type == {{NATIVE_ID}} ?";
+ code_ +=
+ " reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
+ code_ += " }";
+ }
+ code_ += "};";
+ code_ += "";
+
+ if (opts_.gen_compare) {
+ code_ += "";
+ code_ +=
+ "inline bool operator==(const {{NAME}}Union &lhs, const "
+ "{{NAME}}Union &rhs) {";
+ code_ += " if (lhs.type != rhs.type) return false;";
+ code_ += " switch (lhs.type) {";
+
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
+ if (ev.IsNonZero()) {
+ const auto native_type = GetUnionElement(ev, true, opts_);
+ code_.SetValue("NATIVE_TYPE", native_type);
+ code_ += " case {{NATIVE_ID}}: {";
+ code_ +=
+ " return *(reinterpret_cast<const {{NATIVE_TYPE}} "
+ "*>(lhs.value)) ==";
+ code_ +=
+ " *(reinterpret_cast<const {{NATIVE_TYPE}} "
+ "*>(rhs.value));";
+ code_ += " }";
+ } else {
+ code_ += " case {{NATIVE_ID}}: {";
+ code_ += " return true;"; // "NONE" enum value.
+ code_ += " }";
+ }
+ }
+ code_ += " default: {";
+ code_ += " return false;";
+ code_ += " }";
+ code_ += " }";
+ code_ += "}";
+
+ code_ += "";
+ code_ +=
+ "inline bool operator!=(const {{NAME}}Union &lhs, const "
+ "{{NAME}}Union &rhs) {";
+ code_ += " return !(lhs == rhs);";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ if (enum_def.is_union) {
+ code_ += UnionVerifySignature(enum_def) + ";";
+ code_ += UnionVectorVerifySignature(enum_def) + ";";
+ code_ += "";
+ }
+ }
+
+ void GenUnionPost(const EnumDef &enum_def) {
+ // Generate a verifier function for this union that can be called by the
+ // table verifier functions. It uses a switch case to select a specific
+ // verifier function to call, this should be safe even if the union type
+ // has been corrupted, since the verifiers will simply fail when called
+ // on the wrong type.
+ code_.SetValue("ENUM_NAME", Name(enum_def));
+
+ code_ += "inline " + UnionVerifySignature(enum_def) + " {";
+ code_ += " switch (type) {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+ code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+
+ if (ev.IsNonZero()) {
+ 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_ +=
+ " return verifier.Verify<{{TYPE}}>(static_cast<const "
+ "uint8_t *>(obj), 0);";
+ } else {
+ code_ += getptr;
+ code_ += " return verifier.VerifyTable(ptr);";
+ }
+ } else if (IsString(ev.union_type)) {
+ code_ += getptr;
+ code_ += " return verifier.VerifyString(ptr);";
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ code_ += " }";
+ } else {
+ code_ += " case {{LABEL}}: {";
+ code_ += " return true;"; // "NONE" enum value.
+ code_ += " }";
+ }
+ }
+ code_ += " default: return true;"; // unknown values are OK.
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
+ code_ += " if (!values || !types) return !values && !types;";
+ code_ += " if (values->size() != types->size()) return false;";
+ code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
+ code_ += " if (!Verify" + Name(enum_def) + "(";
+ code_ += " verifier, values->Get(i), types->GetEnum<" +
+ Name(enum_def) + ">(i))) {";
+ code_ += " return false;";
+ code_ += " }";
+ code_ += " }";
+ code_ += " return true;";
+ code_ += "}";
+ code_ += "";
+
+ if (opts_.generate_object_based_api) {
+ // Generate union Unpack() and Pack() functions.
+ code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
+ code_ += " switch (type) {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+ 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) {
+ if (ev.union_type.struct_def->fixed) {
+ code_ += " return new " +
+ WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
+ } else {
+ code_ += " return ptr->UnPack(resolver);";
+ }
+ } else if (IsString(ev.union_type)) {
+ code_ += " return new std::string(ptr->c_str(), ptr->size());";
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ code_ += " }";
+ }
+ code_ += " default: return nullptr;";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
+ code_ += " switch (type) {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+ 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();";
+ }
+ } else if (IsString(ev.union_type)) {
+ code_ += " return _fbb.CreateString(*ptr).Union();";
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ code_ += " }";
+ }
+ code_ += " default: return 0;";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+
+ // Union copy constructor
+ code_ +=
+ "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
+ "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {";
+ code_ += " switch (type) {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+ code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+ code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
+ code_ += " case {{LABEL}}: {";
+ bool copyable = true;
+ if (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();
+ fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
+ const auto &field = **fit;
+ if (!field.deprecated && field.value.type.struct_def &&
+ !field.native_inline) {
+ copyable = false;
+ break;
+ }
+ }
+ }
+ if (copyable) {
+ code_ +=
+ " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
+ "(u.value));";
+ } else {
+ code_ +=
+ " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable.";
+ }
+ code_ += " break;";
+ code_ += " }";
+ }
+ code_ += " default:";
+ code_ += " break;";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+
+ // Union Reset() function.
+ FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
+ code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
+
+ code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
+ code_ += " switch (type) {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+ code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+ code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
+ code_ += " case {{LABEL}}: {";
+ code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
+ code_ += " delete ptr;";
+ code_ += " break;";
+ code_ += " }";
+ }
+ code_ += " default: break;";
+ code_ += " }";
+ code_ += " value = nullptr;";
+ code_ += " type = {{NONE}};";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ // Generates a value with optionally a cast applied if the field has a
+ // different underlying type from its interface type (currently only the
+ // case for enums. "from" specify the direction, true meaning from the
+ // underlying type to the interface type.
+ std::string GenUnderlyingCast(const FieldDef &field, bool from,
+ const std::string &val) {
+ if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
+ return val + " != 0";
+ } else if ((field.value.type.enum_def &&
+ IsScalar(field.value.type.base_type)) ||
+ field.value.type.base_type == BASE_TYPE_BOOL) {
+ return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
+ val + ")";
+ } else {
+ return val;
+ }
+ }
+
+ std::string GenFieldOffsetName(const FieldDef &field) {
+ std::string uname = Name(field);
+ std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper);
+ return "VT_" + uname;
+ }
+
+ void GenFullyQualifiedNameGetter(const StructDef &struct_def,
+ const std::string &name) {
+ if (!opts_.generate_name_strings) { return; }
+ auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
+ code_.SetValue("NAME", fullname);
+ code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
+ code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
+ code_ += " return \"{{NAME}}\";";
+ code_ += " }";
+ }
+
+ std::string GenDefaultConstant(const FieldDef &field) {
+ if (IsFloat(field.value.type.base_type))
+ return float_const_gen_.GenFloatConstant(field);
+ else
+ return NumToStringCpp(field.value.constant, field.value.type.base_type);
+ }
+
+ std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
+ const auto &type = field.value.type;
+ if (field.IsScalarOptional()) {
+ return GenOptionalNull();
+ } else if (type.enum_def && IsScalar(type.base_type)) {
+ auto ev = type.enum_def->FindByValue(field.value.constant);
+ if (ev) {
+ return WrapInNameSpace(type.enum_def->defined_namespace,
+ GetEnumValUse(*type.enum_def, *ev));
+ } else {
+ return GenUnderlyingCast(
+ field, true, NumToStringCpp(field.value.constant, type.base_type));
+ }
+ } else if (type.base_type == BASE_TYPE_BOOL) {
+ return field.value.constant == "0" ? "false" : "true";
+ } else if (field.attributes.Lookup("cpp_type")) {
+ if (is_ctor) {
+ if (PtrType(&field) == "naked") {
+ return "nullptr";
+ } else {
+ return "";
+ }
+ } else {
+ return "0";
+ }
+ } else {
+ return GenDefaultConstant(field);
+ }
+ }
+
+ void GenParam(const FieldDef &field, bool direct, const char *prefix) {
+ code_.SetValue("PRE", prefix);
+ code_.SetValue("PARAM_NAME", Name(field));
+ if (direct && IsString(field.value.type)) {
+ code_.SetValue("PARAM_TYPE", "const char *");
+ code_.SetValue("PARAM_VALUE", "nullptr");
+ } else if (direct && IsVector(field.value.type)) {
+ const auto vtype = field.value.type.VectorType();
+ std::string type;
+ if (IsStruct(vtype)) {
+ type = WrapInNameSpace(*vtype.struct_def);
+ } else {
+ type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
+ }
+ if (TypeHasKey(vtype)) {
+ code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
+ } else {
+ code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
+ }
+ code_.SetValue("PARAM_VALUE", "nullptr");
+ } else {
+ const auto &type = field.value.type;
+ code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
+ if (field.IsScalarOptional())
+ code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " ");
+ else
+ code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true));
+ }
+ code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
+ }
+
+ // Generate a member, including a default value for scalars and raw pointers.
+ void GenMember(const FieldDef &field) {
+ if (!field.deprecated && // Deprecated fields won't be accessible.
+ field.value.type.base_type != BASE_TYPE_UTYPE &&
+ (field.value.type.base_type != BASE_TYPE_VECTOR ||
+ field.value.type.element != BASE_TYPE_UTYPE)) {
+ auto type = GenTypeNative(field.value.type, false, field);
+ auto cpp_type = field.attributes.Lookup("cpp_type");
+ auto full_type =
+ (cpp_type
+ ? (IsVector(field.value.type)
+ ? "std::vector<" +
+ GenTypeNativePtr(cpp_type->constant, &field,
+ false) +
+ "> "
+ : GenTypeNativePtr(cpp_type->constant, &field, false))
+ : type + " ");
+ // Generate default member initializers for >= C++11.
+ std::string field_di = "";
+ if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
+ field_di = "{}";
+ auto native_default = field.attributes.Lookup("native_default");
+ // Scalar types get parsed defaults, raw pointers get nullptrs.
+ if (IsScalar(field.value.type.base_type)) {
+ field_di =
+ " = " + (native_default ? std::string(native_default->constant)
+ : GetDefaultScalarValue(field, true));
+ } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ if (IsStruct(field.value.type) && native_default) {
+ field_di = " = " + native_default->constant;
+ }
+ }
+ }
+ code_.SetValue("FIELD_TYPE", full_type);
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("FIELD_DI", field_di);
+ code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};";
+ }
+ }
+
+ // 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; }
+ std::string initializer_list;
+ 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.
+ field.value.type.base_type != BASE_TYPE_UTYPE) {
+ auto cpp_type = field.attributes.Lookup("cpp_type");
+ auto native_default = field.attributes.Lookup("native_default");
+ // Scalar types get parsed defaults, raw pointers get nullptrs.
+ if (IsScalar(field.value.type.base_type)) {
+ if (!initializer_list.empty()) { initializer_list += ",\n "; }
+ initializer_list += Name(field);
+ initializer_list +=
+ "(" +
+ (native_default ? std::string(native_default->constant)
+ : GetDefaultScalarValue(field, true)) +
+ ")";
+ } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ if (IsStruct(field.value.type)) {
+ if (native_default) {
+ if (!initializer_list.empty()) {
+ initializer_list += ",\n ";
+ }
+ initializer_list +=
+ Name(field) + "(" + native_default->constant + ")";
+ }
+ }
+ } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
+ if (!initializer_list.empty()) { initializer_list += ",\n "; }
+ initializer_list += Name(field) + "(0)";
+ }
+ }
+ }
+ if (!initializer_list.empty()) {
+ initializer_list = "\n : " + initializer_list;
+ }
+
+ code_.SetValue("INIT_LIST", initializer_list);
+
+ code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
+ code_ += " }";
+ }
+
+ void GenCompareOperator(const StructDef &struct_def,
+ std::string accessSuffix = "") {
+ std::string compare_op;
+ 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.
+ field.value.type.base_type != BASE_TYPE_UTYPE &&
+ (field.value.type.base_type != BASE_TYPE_VECTOR ||
+ 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 + ")";
+ }
+ }
+
+ std::string cmp_lhs;
+ std::string cmp_rhs;
+ if (compare_op.empty()) {
+ cmp_lhs = "";
+ cmp_rhs = "";
+ compare_op = " return true;";
+ } else {
+ cmp_lhs = "lhs";
+ cmp_rhs = "rhs";
+ compare_op = " return\n " + compare_op + ";";
+ }
+
+ code_.SetValue("CMP_OP", compare_op);
+ code_.SetValue("CMP_LHS", cmp_lhs);
+ code_.SetValue("CMP_RHS", cmp_rhs);
+ code_ += "";
+ code_ +=
+ "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
+ "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
+ code_ += "{{CMP_OP}}";
+ code_ += "}";
+
+ code_ += "";
+ code_ +=
+ "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
+ "{{NATIVE_NAME}} &rhs) {";
+ code_ += " return !(lhs == rhs);";
+ code_ += "}";
+ code_ += "";
+ }
+
+ void GenOperatorNewDelete(const StructDef &struct_def) {
+ if (auto native_custom_alloc =
+ struct_def.attributes.Lookup("native_custom_alloc")) {
+ code_ += " inline void *operator new (std::size_t count) {";
+ code_ += " return " + native_custom_alloc->constant +
+ "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
+ code_ += " }";
+ code_ += " inline void operator delete (void *ptr) {";
+ code_ += " return " + native_custom_alloc->constant +
+ "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
+ "ptr),1);";
+ code_ += " }";
+ }
+ }
+
+ void GenNativeTable(const StructDef &struct_def) {
+ const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+ code_.SetValue("NATIVE_NAME", native_name);
+
+ // Generate a C++ object that can hold an unpacked version of this table.
+ code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
+ code_ += " typedef {{STRUCT_NAME}} TableType;";
+ GenFullyQualifiedNameGetter(struct_def, native_name);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ GenMember(**it);
+ }
+ GenOperatorNewDelete(struct_def);
+ GenDefaultConstructor(struct_def);
+ code_ += "};";
+ if (opts_.gen_compare) 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.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_ +=
+ "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
+ } else {
+ code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
+ }
+
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_UNION: {
+ code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
+ code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
+ code_ +=
+ "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
+ "{{NAME}}{{SUFFIX}}())\\";
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (!field.value.type.struct_def->fixed) {
+ code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
+ }
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
+
+ switch (field.value.type.element) {
+ case BASE_TYPE_STRING: {
+ code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (!field.value.type.struct_def->fixed) {
+ code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
+ code_ +=
+ "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
+ "{{NAME}}_type())\\";
+ break;
+ }
+ default: break;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+
+ // Generate CompareWithValue method for a key field.
+ void GenKeyFieldMethods(const FieldDef &field) {
+ FLATBUFFERS_ASSERT(field.key);
+ const bool is_string = (IsString(field.value.type));
+
+ code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
+ if (is_string) {
+ // use operator< of flatbuffers::String
+ code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
+ } else {
+ code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
+ }
+ code_ += " }";
+
+ if (is_string) {
+ code_ += " int KeyCompareWithValue(const char *val) const {";
+ code_ += " return strcmp({{FIELD_NAME}}()->c_str(), val);";
+ code_ += " }";
+ } else {
+ FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
+ auto type = GenTypeBasic(field.value.type, false);
+ if (opts_.scoped_enums && field.value.type.enum_def &&
+ IsScalar(field.value.type.base_type)) {
+ type = GenTypeGet(field.value.type, " ", "const ", " *", true);
+ }
+ // 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);";
+ code_ += " }";
+ }
+ }
+
+ void GenTableUnionAsGetters(const FieldDef &field) {
+ const auto &type = field.value.type;
+ auto u = type.enum_def;
+
+ if (!type.enum_def->uses_multiple_type_instances)
+ code_ +=
+ " template<typename T> "
+ "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
+
+ 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, false, opts_);
+
+ // @TODO: Mby make this decisions more universal? How?
+ code_.SetValue("U_GET_TYPE",
+ EscapeKeyword(field.name + UnionTypeFieldSuffix()));
+ code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
+ GetEnumValUse(*u, ev)));
+ code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
+ code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
+ code_.SetValue("U_NULLABLE", NullableExtension());
+
+ // `const Type *union_name_asType() const` accessor.
+ code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
+ code_ +=
+ " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
+ "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
+ ": nullptr;";
+ code_ += " }";
+ }
+ }
+
+ void GenTableFieldGetter(const FieldDef &field) {
+ const auto &type = field.value.type;
+ const auto offset_str = GenFieldOffsetName(field);
+
+ GenComment(field.doc_comment, " ");
+ // Call a different accessor for pointers, that indirects.
+ if (false == field.IsScalarOptional()) {
+ const bool is_scalar = IsScalar(type.base_type);
+ std::string accessor;
+ if (is_scalar)
+ accessor = "GetField<";
+ else if (IsStruct(type))
+ accessor = "GetStruct<";
+ else
+ accessor = "GetPointer<";
+ auto offset_type = GenTypeGet(type, "", "const ", " *", false);
+ auto call = accessor + offset_type + ">(" + offset_str;
+ // Default value as second arg for non-pointer types.
+ if (is_scalar) { call += ", " + GenDefaultConstant(field); }
+ call += ")";
+
+ std::string afterptr = " *" + NullableExtension();
+ code_.SetValue("FIELD_TYPE",
+ GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
+ code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
+ code_.SetValue("NULLABLE_EXT", NullableExtension());
+ code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
+ code_ += " return {{FIELD_VALUE}};";
+ code_ += " }";
+ } else {
+ auto wire_type = GenTypeBasic(type, false);
+ auto face_type = GenTypeBasic(type, true);
+ auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
+ offset_str + ")";
+ code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
+ code_ += " {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
+ code_ += " return " + opt_value + ";";
+ code_ += " }";
+ }
+
+ 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) {
+ 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_ += " static constexpr std::array<\\";
+ code_.SetValue(
+ "FIELD_COUNT",
+ std::to_string(static_cast<long long>(non_deprecated_field_count)));
+ code_ += "const char *, {{FIELD_COUNT}}> 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) {
+ 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}}\";";
+ GenFieldNames(struct_def);
+ GenFieldTypeHelper(struct_def);
+ GenFieldsNumber(struct_def);
+ }
+ code_ += "};";
+ code_ += "";
+ }
+
+ void GenTableFieldSetter(const FieldDef &field) {
+ const auto &type = field.value.type;
+ const bool is_scalar = IsScalar(type.base_type);
+ if (is_scalar && IsUnion(type))
+ return; // changing of a union's type is forbidden
+
+ auto offset_str = GenFieldOffsetName(field);
+ if (is_scalar) {
+ const auto wire_type = GenTypeWire(type, "", false);
+ code_.SetValue("SET_FN", "SetField<" + wire_type + ">");
+ code_.SetValue("OFFSET_NAME", offset_str);
+ code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
+ code_.SetValue("FIELD_VALUE",
+ GenUnderlyingCast(field, false, "_" + Name(field)));
+
+ code_ +=
+ " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
+ "_{{FIELD_NAME}}) {";
+ if (false == field.IsScalarOptional()) {
+ code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
+ code_ +=
+ " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
+ "{{DEFAULT_VALUE}});";
+ } else {
+ code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
+ }
+ code_ += " }";
+ } else {
+ auto postptr = " *" + NullableExtension();
+ auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
+ std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<";
+ auto underlying = accessor + wire_type + ">(" + offset_str + ")";
+ code_.SetValue("FIELD_TYPE", wire_type);
+ code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
+
+ code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
+ code_ += " return {{FIELD_VALUE}};";
+ code_ += " }";
+ }
+ }
+
+ // 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); }
+
+ // Generate an accessor struct, with methods of the form:
+ // type name() const { return GetField<type>(offset, defaultval); }
+ GenComment(struct_def.doc_comment);
+
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+ code_ +=
+ "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
+ " : private flatbuffers::Table {";
+ if (opts_.generate_object_based_api) {
+ code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
+ }
+ code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
+ if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
+ if (opts_.mini_reflect != IDLOptions::kNone) {
+ code_ +=
+ " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
+ code_ += " return {{STRUCT_NAME}}TypeTable();";
+ code_ += " }";
+ }
+
+ GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
+
+ // Generate field id constants.
+ if (struct_def.fields.vec.size() > 0) {
+ // We need to add a trailing comma to all elements except the last one as
+ // older versions of gcc complain about this.
+ code_.SetValue("SEP", "");
+ code_ +=
+ " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
+ 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("OFFSET_NAME", GenFieldOffsetName(field));
+ code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
+ code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
+ code_.SetValue("SEP", ",\n");
+ }
+ code_ += "";
+ code_ += " };";
+ }
+
+ // Generate the accessors.
+ 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));
+ 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));
+
+ code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
+ code_ +=
+ " return "
+ "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
+ code_ += " }";
+ }
+
+ if (field.flexbuffer) {
+ code_ +=
+ " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
+ " const {";
+ // Both Data() and size() are const-methods, therefore call order
+ // doesn't matter.
+ code_ +=
+ " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
+ "{{FIELD_NAME}}()->size());";
+ code_ += " }";
+ }
+
+ // Generate a comparison function for this field if it is a key.
+ 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 {";
+ code_ += " return VerifyTableStart(verifier)\\";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) { continue; }
+ GenVerifyCall(field, " &&\n ");
+ }
+
+ code_ += " &&\n verifier.EndTable();";
+ code_ += " }";
+
+ if (opts_.generate_object_based_api) {
+ // Generate the UnPack() pre declaration.
+ code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
+ code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
+ code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
+ }
+
+ code_ += "};"; // End of table.
+ code_ += "";
+
+ // Explicit specializations for union accessors
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
+ continue;
+ }
+
+ auto u = field.value.type.enum_def;
+ if (u->uses_multiple_type_instances) continue;
+
+ code_.SetValue("FIELD_NAME", Name(field));
+
+ 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, false, opts_);
+
+ code_.SetValue(
+ "U_ELEMENT_TYPE",
+ WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
+ code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
+ code_.SetValue("U_ELEMENT_NAME", full_struct_name);
+ code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
+
+ // `template<> const T *union_name_as<T>() const` accessor.
+ code_ +=
+ "template<> "
+ "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
+ "<{{U_ELEMENT_NAME}}>() const {";
+ code_ += " return {{U_FIELD_NAME}}();";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ GenBuilders(struct_def);
+
+ if (opts_.generate_object_based_api) {
+ // Generate a pre-declaration for a CreateX method that works with an
+ // unpacked C++ object.
+ code_ += TableCreateSignature(struct_def, true, opts_) + ";";
+ code_ += "";
+ }
+ }
+
+ // Generate code to force vector alignment. Return empty string for vector
+ // that doesn't need alignment code.
+ std::string GenVectorForceAlign(const FieldDef &field,
+ const std::string &field_size) {
+ FLATBUFFERS_ASSERT(IsVector(field.value.type));
+ // Get the value of the force_align attribute.
+ const auto *force_align = field.attributes.Lookup("force_align");
+ const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
+ // Generate code to do force_align for the vector.
+ if (align > 1) {
+ const auto vtype = field.value.type.VectorType();
+ const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
+ : GenTypeWire(vtype, "", false);
+ return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type +
+ "), " + std::to_string(static_cast<long long>(align)) + ");";
+ }
+ return "";
+ }
+
+ void GenBuilders(const StructDef &struct_def) {
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+
+ // Generate a builder struct:
+ code_ += "struct {{STRUCT_NAME}}Builder {";
+ code_ += " typedef {{STRUCT_NAME}} Table;";
+ code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
+ code_ += " flatbuffers::uoffset_t start_;";
+
+ bool has_string_or_vector_fields = false;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) continue;
+ const bool is_scalar = IsScalar(field.value.type.base_type);
+ const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
+ const bool is_string = IsString(field.value.type);
+ const bool is_vector = IsVector(field.value.type);
+ if (is_string || is_vector) { has_string_or_vector_fields = true; }
+
+ std::string offset = GenFieldOffsetName(field);
+ std::string name = GenUnderlyingCast(field, false, Name(field));
+ std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
+
+ // Generate accessor functions of the form:
+ // void add_name(type name) {
+ // fbb_.AddElement<type>(offset, name, default);
+ // }
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
+ code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
+ code_.SetValue("ADD_NAME", name);
+ code_.SetValue("ADD_VALUE", value);
+ if (is_scalar) {
+ const auto type = GenTypeWire(field.value.type, "", false);
+ code_.SetValue("ADD_FN", "AddElement<" + type + ">");
+ } else if (IsStruct(field.value.type)) {
+ code_.SetValue("ADD_FN", "AddStruct");
+ } else {
+ code_.SetValue("ADD_FN", "AddOffset");
+ }
+
+ code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
+ code_ += " fbb_.{{ADD_FN}}(\\";
+ if (is_default_scalar) {
+ code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
+ } else {
+ code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
+ }
+ code_ += " }";
+ }
+
+ // Builder constructor
+ code_ +=
+ " explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
+ "&_fbb)";
+ code_ += " : fbb_(_fbb) {";
+ code_ += " start_ = fbb_.StartTable();";
+ code_ += " }";
+
+ // Finish() function.
+ code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
+ code_ += " const auto end = fbb_.EndTable(start_);";
+ code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ 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}});";
+ }
+ }
+ code_ += " return o;";
+ code_ += " }";
+ code_ += "};";
+ code_ += "";
+
+ // Generate a convenient CreateX function that uses the above builder
+ // to create a table in one go.
+ code_ +=
+ "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
+ "Create{{STRUCT_NAME}}(";
+ code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated) { GenParam(field, false, ",\n "); }
+ }
+ code_ += ") {";
+
+ code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
+ for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+ size; size /= 2) {
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated && (!struct_def.sortbysize ||
+ size == SizeOf(field.value.type.base_type))) {
+ code_.SetValue("FIELD_NAME", Name(field));
+ if (field.IsScalarOptional()) {
+ code_ +=
+ " if({{FIELD_NAME}}) { "
+ "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
+ } else {
+ code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
+ }
+ }
+ }
+ }
+ code_ += " return builder_.Finish();";
+ code_ += "}";
+ 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); }
+
+ // Generate a CreateXDirect function with vector types as parameters
+ if (opts_.cpp_direct_copy && has_string_or_vector_fields) {
+ code_ +=
+ "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
+ "Create{{STRUCT_NAME}}Direct(";
+ code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated) { GenParam(field, true, ",\n "); }
+ }
+ // Need to call "Create" with the struct namespace.
+ const auto qualified_create_name =
+ struct_def.defined_namespace->GetFullyQualifiedName("Create");
+ code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
+ code_ += ") {";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated) {
+ code_.SetValue("FIELD_NAME", Name(field));
+ if (IsString(field.value.type)) {
+ if (!field.shared) {
+ code_.SetValue("CREATE_STRING", "CreateString");
+ } else {
+ code_.SetValue("CREATE_STRING", "CreateSharedString");
+ }
+ code_ +=
+ " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
+ "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
+ } else if (IsVector(field.value.type)) {
+ const std::string force_align_code =
+ GenVectorForceAlign(field, Name(field) + "->size()");
+ if (!force_align_code.empty()) {
+ code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }";
+ }
+ code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
+ const auto vtype = field.value.type.VectorType();
+ const auto has_key = TypeHasKey(vtype);
+ if (IsStruct(vtype)) {
+ const auto type = WrapInNameSpace(*vtype.struct_def);
+ code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<"
+ : "_fbb.CreateVectorOfStructs<") +
+ type + ">\\";
+ } else if (has_key) {
+ const auto type = WrapInNameSpace(*vtype.struct_def);
+ code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
+ } else {
+ const auto type =
+ GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
+ code_ += "_fbb.CreateVector<" + type + ">\\";
+ }
+ code_ +=
+ has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
+ }
+ }
+ }
+ code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
+ code_ += " _fbb\\";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated) {
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_ += ",\n {{FIELD_NAME}}\\";
+ if (IsString(field.value.type) || IsVector(field.value.type)) {
+ code_ += "__\\";
+ }
+ }
+ }
+ code_ += ");";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ std::string GenUnionUnpackVal(const FieldDef &afield,
+ const char *vec_elem_access,
+ const char *vec_type_access) {
+ auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
+ return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
+ EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
+ vec_type_access + ", _resolver)";
+ }
+
+ std::string GenUnpackVal(const Type &type, const std::string &val,
+ bool invector, const FieldDef &afield) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: {
+ if (FlexibleStringConstructor(&afield)) {
+ return NativeString(&afield) + "(" + val + "->c_str(), " + val +
+ "->size())";
+ } else {
+ return val + "->str()";
+ }
+ }
+ case BASE_TYPE_STRUCT: {
+ if (IsStruct(type)) {
+ const auto &struct_attrs = type.struct_def->attributes;
+ const auto native_type = struct_attrs.Lookup("native_type");
+ if (native_type) {
+ 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(
+ WrapNativeNameInNameSpace(*type.struct_def, opts_), &afield,
+ true);
+ return ptype + "(" + val + "->UnPack(_resolver))";
+ }
+ }
+ case BASE_TYPE_UNION: {
+ return GenUnionUnpackVal(
+ afield, invector ? "->Get(_i)" : "",
+ invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
+ : "");
+ }
+ default: {
+ return val;
+ break;
+ }
+ }
+ }
+
+ std::string GenUnpackFieldStatement(const FieldDef &field,
+ const FieldDef *union_field) {
+ std::string code;
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_VECTOR: {
+ auto name = Name(field);
+ if (field.value.type.element == BASE_TYPE_UTYPE) {
+ name = StripUnionType(Name(field));
+ }
+ code += "{ _o->" + name + ".resize(_e->size()); ";
+ if (!field.value.type.enum_def && !IsBool(field.value.type.element) &&
+ IsOneByte(field.value.type.element)) {
+ // For vectors of bytes, std::copy is used to improve performance.
+ // This doesn't work for:
+ // - enum types because they have to be explicitly static_cast.
+ // - vectors of bool, since they are a template specialization.
+ // - multiple-byte types due to endianness.
+ code +=
+ "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }";
+ } else {
+ std::string indexing;
+ if (field.value.type.enum_def) {
+ indexing += "static_cast<" +
+ WrapInNameSpace(*field.value.type.enum_def) + ">(";
+ }
+ indexing += "_e->Get(_i)";
+ if (field.value.type.enum_def) { indexing += ")"; }
+ if (field.value.type.element == BASE_TYPE_BOOL) {
+ indexing += " != 0";
+ }
+ // Generate code that pushes data from _e to _o in the form:
+ // for (uoffset_t i = 0; i < _e->size(); ++i) {
+ // _o->field.push_back(_e->Get(_i));
+ // }
+ auto access =
+ field.value.type.element == BASE_TYPE_UTYPE
+ ? ".type"
+ : (field.value.type.element == BASE_TYPE_UNION ? ".value"
+ : "");
+
+ code += "for (flatbuffers::uoffset_t _i = 0;";
+ code += " _i < _e->size(); _i++) { ";
+ auto cpp_type = field.attributes.Lookup("cpp_type");
+ if (cpp_type) {
+ // Generate code that resolves the cpp pointer type, of the form:
+ // if (resolver)
+ // (*resolver)(&_o->field, (hash_value_t)(_e));
+ // else
+ // _o->field = nullptr;
+ code += "//vector resolver, " + PtrType(&field) + "\n";
+ code += "if (_resolver) ";
+ code += "(*_resolver)";
+ code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" +
+ access + "), ";
+ code +=
+ "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
+ if (PtrType(&field) == "naked") {
+ code += " else ";
+ code += "_o->" + name + "[_i]" + access + " = nullptr";
+ } else {
+ // code += " else ";
+ // code += "_o->" + name + "[_i]" + access + " = " +
+ // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
+ code += "/* else do nothing */";
+ }
+ } else {
+ code += "_o->" + name + "[_i]" + access + " = ";
+ code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
+ field);
+ }
+ code += "; } }";
+ }
+ break;
+ }
+ case BASE_TYPE_UTYPE: {
+ FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
+ BASE_TYPE_UNION);
+ // Generate code that sets the union type, of the form:
+ // _o->field.type = _e;
+ code += "_o->" + union_field->name + ".type = _e;";
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ // Generate code that sets the union value, of the form:
+ // _o->field.value = Union::Unpack(_e, field_type(), resolver);
+ code += "_o->" + Name(field) + ".value = ";
+ code += GenUnionUnpackVal(field, "", "");
+ code += ";";
+ break;
+ }
+ default: {
+ auto cpp_type = field.attributes.Lookup("cpp_type");
+ if (cpp_type) {
+ // Generate code that resolves the cpp pointer type, of the form:
+ // if (resolver)
+ // (*resolver)(&_o->field, (hash_value_t)(_e));
+ // else
+ // _o->field = nullptr;
+ code += "//scalar resolver, " + PtrType(&field) + " \n";
+ code += "if (_resolver) ";
+ code += "(*_resolver)";
+ code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
+ code += "static_cast<flatbuffers::hash_value_t>(_e));";
+ if (PtrType(&field) == "naked") {
+ code += " else ";
+ code += "_o->" + Name(field) + " = nullptr;";
+ } else {
+ // code += " else ";
+ // code += "_o->" + Name(field) + " = " +
+ // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
+ code += "/* else do nothing */;";
+ }
+ } else {
+ // Generate code for assigning the value, of the form:
+ // _o->field = value;
+ code += "_o->" + Name(field) + " = ";
+ code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
+ }
+ break;
+ }
+ }
+ return code;
+ }
+
+ std::string GenCreateParam(const FieldDef &field) {
+ std::string value = "_o->";
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) {
+ value += StripUnionType(Name(field));
+ value += ".type";
+ } else {
+ value += Name(field);
+ }
+ if (field.value.type.base_type != BASE_TYPE_VECTOR &&
+ field.attributes.Lookup("cpp_type")) {
+ auto type = GenTypeBasic(field.value.type, false);
+ value =
+ "_rehasher ? "
+ "static_cast<" +
+ type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
+ }
+
+ std::string code;
+ switch (field.value.type.base_type) {
+ // String fields are of the form:
+ // _fbb.CreateString(_o->field)
+ // or
+ // _fbb.CreateSharedString(_o->field)
+ case BASE_TYPE_STRING: {
+ if (!field.shared) {
+ code += "_fbb.CreateString(";
+ } else {
+ code += "_fbb.CreateSharedString(";
+ }
+ code += value;
+ code.push_back(')');
+
+ // For optional fields, check to see if there actually is any data
+ // 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.IsRequired()) {
+ auto empty_value = opts_.set_empty_strings_to_null
+ ? "0"
+ : "_fbb.CreateSharedString(\"\")";
+ code = value + ".empty() ? " + empty_value + " : " + code;
+ }
+ break;
+ }
+ // Vector fields come in several flavours, of the forms:
+ // _fbb.CreateVector(_o->field);
+ // _fbb.CreateVector((const utype*)_o->field.data(),
+ // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
+ // _fbb.CreateVectorOfStructs(_o->field)
+ // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
+ // return CreateT(_fbb, _o->Get(i), rehasher);
+ // });
+ case BASE_TYPE_VECTOR: {
+ auto vector_type = field.value.type.VectorType();
+ switch (vector_type.base_type) {
+ case BASE_TYPE_STRING: {
+ if (NativeString(&field) == "std::string") {
+ code += "_fbb.CreateVectorOfStrings(" + value + ")";
+ } else {
+ // Use by-function serialization to emulate
+ // CreateVectorOfStrings(); this works also with non-std strings.
+ code +=
+ "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
+ " ";
+ code += "(" + value + ".size(), ";
+ code += "[](size_t i, _VectorArgs *__va) { ";
+ code +=
+ "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
+ code += " }, &_va )";
+ }
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (IsStruct(vector_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) + ", " +
+ 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 + ")";
+ }
+ } else {
+ code += "_fbb.CreateVector<flatbuffers::Offset<";
+ code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
+ code += "(" + value + ".size(), ";
+ code += "[](size_t i, _VectorArgs *__va) { ";
+ code += "return Create" + vector_type.struct_def->name;
+ code += "(*__va->__fbb, __va->_" + value + "[i]" +
+ GenPtrGet(field) + ", ";
+ code += "__va->__rehasher); }, &_va )";
+ }
+ break;
+ }
+ case BASE_TYPE_BOOL: {
+ code += "_fbb.CreateVector(" + value + ")";
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ code +=
+ "_fbb.CreateVector<flatbuffers::"
+ "Offset<void>>(" +
+ value +
+ ".size(), [](size_t i, _VectorArgs *__va) { "
+ "return __va->_" +
+ value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
+ break;
+ }
+ 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)";
+ break;
+ }
+ default: {
+ if (field.value.type.enum_def &&
+ !VectorElementUserFacing(vector_type)) {
+ // For enumerations, we need to get access to the array data for
+ // the underlying storage type (eg. uint8_t).
+ const auto basetype = GenTypeBasic(
+ field.value.type.enum_def->underlying_type, false);
+ code += "_fbb.CreateVectorScalarCast<" + basetype +
+ ">(flatbuffers::data(" + value + "), " + value +
+ ".size())";
+ } else if (field.attributes.Lookup("cpp_type")) {
+ auto type = GenTypeBasic(vector_type, false);
+ code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
+ code += "[](size_t i, _VectorArgs *__va) { ";
+ code += "return __va->__rehasher ? ";
+ code += "static_cast<" + type + ">((*__va->__rehasher)";
+ code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
+ code += "; }, &_va )";
+ } else {
+ code += "_fbb.CreateVector(" + value + ")";
+ }
+ break;
+ }
+ }
+
+ // 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.IsRequired()) {
+ code = value + ".size() ? " + code + " : 0";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ // _o->field.Pack(_fbb);
+ code += value + ".Pack(_fbb)";
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (IsStruct(field.value.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";
+ 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 {
+ code += value + " ? " + value + GenPtrGet(field) + " : 0";
+ }
+ } else {
+ // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
+ const auto type = field.value.type.struct_def->name;
+ code += value + " ? Create" + type;
+ code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
+ code += " : 0";
+ }
+ break;
+ }
+ default: {
+ code += value;
+ break;
+ }
+ }
+ return code;
+ }
+
+ // Generate code for tables that needs to come after the regular definition.
+ void GenTablePost(const StructDef &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 X::UnPack() method.
+ code_ +=
+ "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
+
+ if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
+ auto native_name = WrapNativeNameInNameSpace(struct_def, parser_.opts);
+ code_.SetValue("POINTER_TYPE",
+ GenTypeNativePtr(native_name, nullptr, false));
+ code_ +=
+ " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
+ } else if (opts_.g_cpp_std == cpp::CPP_STD_11) {
+ code_ +=
+ " auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new "
+ "{{NATIVE_NAME}}());";
+ } else {
+ code_ += " auto _o = std::make_unique<{{NATIVE_NAME}}>();";
+ }
+ code_ += " UnPackTo(_o.get(), _resolver);";
+ code_ += " return _o.release();";
+ code_ += "}";
+ code_ += "";
+ code_ +=
+ "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
+ code_ += " (void)_o;";
+ code_ += " (void)_resolver;";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) { continue; }
+
+ // Assign a value from |this| to |_o|. Values from |this| are stored
+ // in a variable |_e| by calling this->field_type(). The value is then
+ // assigned to |_o| using the GenUnpackFieldStatement.
+ const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
+ const auto statement =
+ GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
+
+ code_.SetValue("FIELD_NAME", Name(field));
+ auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
+ auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
+ auto postfix = " }";
+ code_ += std::string(prefix) + check + statement + postfix;
+ }
+ code_ += "}";
+ code_ += "";
+
+ // Generate the X::Pack member function that simply calls the global
+ // CreateX function.
+ code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
+ code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
+ code_ += "}";
+ code_ += "";
+
+ // Generate a CreateX method that works with an unpacked C++ object.
+ code_ +=
+ "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
+ code_ += " (void)_rehasher;";
+ code_ += " (void)_o;";
+
+ code_ +=
+ " struct _VectorArgs "
+ "{ flatbuffers::FlatBufferBuilder *__fbb; "
+ "const " +
+ NativeName(Name(struct_def), &struct_def, opts_) +
+ "* __o; "
+ "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
+ "&_fbb, _o, _rehasher}; (void)_va;";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) { continue; }
+ if (IsVector(field.value.type)) {
+ const std::string force_align_code =
+ GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
+ if (!force_align_code.empty()) { code_ += " " + force_align_code; }
+ }
+ code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
+ }
+ // Need to call "Create" with the struct namespace.
+ const auto qualified_create_name =
+ struct_def.defined_namespace->GetFullyQualifiedName("Create");
+ code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
+
+ code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
+ code_ += " _fbb\\";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) { continue; }
+
+ bool pass_by_address = false;
+ if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ if (IsStruct(field.value.type)) {
+ auto native_type =
+ field.value.type.struct_def->attributes.Lookup("native_type");
+ if (native_type) { pass_by_address = true; }
+ }
+ }
+
+ // Call the CreateX function using values from |_o|.
+ if (pass_by_address) {
+ code_ += ",\n &_" + Name(field) + "\\";
+ } else {
+ code_ += ",\n _" + Name(field) + "\\";
+ }
+ }
+ code_ += ");";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ static void GenPadding(
+ const FieldDef &field, std::string *code_ptr, int *id,
+ const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
+ if (field.padding) {
+ for (int i = 0; i < 4; i++) {
+ if (static_cast<int>(field.padding) & (1 << i)) {
+ f((1 << i) * 8, code_ptr, id);
+ }
+ }
+ FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
+ }
+ }
+
+ static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
+ *code_ptr += " int" + NumToString(bits) + "_t padding" +
+ NumToString((*id)++) + "__;";
+ }
+
+ static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
+ (void)bits;
+ if (!code_ptr->empty()) *code_ptr += ",\n ";
+ *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
+ }
+
+ static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
+ (void)bits;
+ if (!code_ptr->empty()) *code_ptr += '\n';
+ *code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
+ }
+
+ void GenStructDefaultConstructor(const StructDef &struct_def) {
+ std::string init_list;
+ std::string body;
+ bool first_in_init_list = true;
+ int padding_initializer_id = 0;
+ int padding_body_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto field = *it;
+ const auto field_name = field->name + "_";
+
+ if (first_in_init_list) {
+ first_in_init_list = false;
+ } else {
+ init_list += ",";
+ init_list += "\n ";
+ }
+
+ init_list += field_name;
+ if (IsStruct(field->value.type) || IsArray(field->value.type)) {
+ // this is either default initialization of struct
+ // or
+ // implicit initialization of array
+ // for each object in array it:
+ // * sets it as zeros for POD types (integral, floating point, etc)
+ // * calls default constructor for classes/structs
+ init_list += "()";
+ } else {
+ init_list += "(0)";
+ }
+ if (field->padding) {
+ GenPadding(*field, &init_list, &padding_initializer_id,
+ PaddingInitializer);
+ GenPadding(*field, &body, &padding_body_id, PaddingNoop);
+ }
+ }
+
+ if (init_list.empty()) {
+ code_ += " {{STRUCT_NAME}}()";
+ code_ += " {}";
+ } else {
+ code_.SetValue("INIT_LIST", init_list);
+ code_ += " {{STRUCT_NAME}}()";
+ code_ += " : {{INIT_LIST}} {";
+ if (!body.empty()) { code_ += body; }
+ code_ += " }";
+ }
+ }
+
+ void GenStructConstructor(const StructDef &struct_def,
+ GenArrayArgMode array_mode) {
+ std::string arg_list;
+ std::string init_list;
+ int padding_id = 0;
+ auto first = struct_def.fields.vec.begin();
+ // skip arrays if generate ctor without array assignment
+ const auto init_arrays = (array_mode != kArrayArgModeNone);
+ 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;
+ const auto is_array = IsArray(type);
+ const auto arg_name = "_" + Name(field);
+ if (!is_array || init_arrays) {
+ if (it != first && !arg_list.empty()) { arg_list += ", "; }
+ arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
+ : GenTypeSpan(type, true, type.fixed_length);
+ arg_list += arg_name;
+ }
+ // skip an array with initialization from span
+ if (false == (is_array && init_arrays)) {
+ if (it != first && !init_list.empty()) { init_list += ",\n "; }
+ init_list += Name(field) + "_";
+ if (IsScalar(type.base_type)) {
+ auto scalar_type = GenUnderlyingCast(field, false, arg_name);
+ init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))";
+ } else {
+ FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type));
+ if (!is_array)
+ init_list += "(" + arg_name + ")";
+ else
+ init_list += "()";
+ }
+ }
+ if (field.padding)
+ GenPadding(field, &init_list, &padding_id, PaddingInitializer);
+ }
+
+ if (!arg_list.empty()) {
+ code_.SetValue("ARG_LIST", arg_list);
+ code_.SetValue("INIT_LIST", init_list);
+ if (!init_list.empty()) {
+ code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
+ code_ += " : {{INIT_LIST}} {";
+ } else {
+ code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
+ }
+ padding_id = 0;
+ 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 (IsArray(type) && init_arrays) {
+ const auto &element_type = type.VectorType();
+ const auto is_enum = IsEnum(element_type);
+ FLATBUFFERS_ASSERT(
+ (IsScalar(element_type.base_type) || IsStruct(element_type)) &&
+ "invalid declaration");
+ const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
+ std::string get_array =
+ is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
+ const auto field_name = Name(field) + "_";
+ const auto arg_name = "_" + Name(field);
+ code_ += " flatbuffers::" + get_array + "(" + field_name +
+ ").CopyFromSpan(" + arg_name + ");";
+ }
+ if (field.padding) {
+ std::string padding;
+ GenPadding(field, &padding, &padding_id, PaddingNoop);
+ code_ += padding;
+ }
+ }
+ code_ += " }";
+ }
+ }
+
+ void GenArrayAccessor(const Type &type, bool mutable_accessor) {
+ FLATBUFFERS_ASSERT(IsArray(type));
+ const auto is_enum = IsEnum(type.VectorType());
+ // The Array<bool,N> is a tricky case, like std::vector<bool>.
+ // It requires a specialization of Array class.
+ // Generate Array<uint8_t> for Array<bool>.
+ const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
+ std::string ret_type = "flatbuffers::Array<" + face_type + ", " +
+ NumToString(type.fixed_length) + ">";
+ if (mutable_accessor)
+ code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {";
+ else
+ code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {";
+
+ std::string get_array =
+ is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
+ code_ += " return &flatbuffers::" + get_array + "({{FIELD_VALUE}});";
+ code_ += " }";
+ }
+
+ // Generate an accessor struct with constructor for a flatbuffers struct.
+ void GenStruct(const StructDef &struct_def) {
+ // Generate an accessor struct, with private variables of the form:
+ // type name_;
+ // Generates manual padding and alignment.
+ // Variables are private because they contain little endian data on all
+ // platforms.
+ GenComment(struct_def.doc_comment);
+ code_.SetValue("ALIGN", NumToString(struct_def.minalign));
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+
+ code_ +=
+ "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
+ "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
+ code_ += " private:";
+
+ int padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ const auto &field_type = field.value.type;
+ code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("ARRAY",
+ IsArray(field_type)
+ ? "[" + NumToString(field_type.fixed_length) + "]"
+ : "");
+ code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
+
+ if (field.padding) {
+ std::string padding;
+ GenPadding(field, &padding, &padding_id, PaddingDefinition);
+ code_ += padding;
+ }
+ }
+
+ // Generate GetFullyQualifiedName
+ 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_ +=
+ " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
+ code_ += " return {{STRUCT_NAME}}TypeTable();";
+ code_ += " }";
+ }
+
+ GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
+
+ // Generate a default constructor.
+ GenStructDefaultConstructor(struct_def);
+
+ // Generate a constructor that takes all fields as arguments,
+ // excluding arrays.
+ GenStructConstructor(struct_def, kArrayArgModeNone);
+
+ auto arrays_num = std::count_if(struct_def.fields.vec.begin(),
+ struct_def.fields.vec.end(),
+ [](const flatbuffers::FieldDef *fd) {
+ return IsArray(fd->value.type);
+ });
+ if (arrays_num > 0) {
+ GenStructConstructor(struct_def, kArrayArgModeSpanStatic);
+ }
+
+ // Generate accessor methods of the form:
+ // type name() const { return flatbuffers::EndianScalar(name_); }
+ 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;
+ const auto is_scalar = IsScalar(type.base_type);
+ const auto is_array = IsArray(type);
+
+ const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
+ is_array ? "" : " &", true);
+ auto member = Name(field) + "_";
+ auto value =
+ is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
+
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("FIELD_TYPE", field_type);
+ code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
+
+ GenComment(field.doc_comment, " ");
+
+ // Generate a const accessor function.
+ if (is_array) {
+ GenArrayAccessor(type, false);
+ } else {
+ code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
+ code_ += " return {{FIELD_VALUE}};";
+ code_ += " }";
+ }
+
+ // Generate a mutable accessor function.
+ if (opts_.mutable_buffer) {
+ auto mut_field_type =
+ GenTypeGet(type, " ", "", is_array ? "" : " &", true);
+ code_.SetValue("FIELD_TYPE", mut_field_type);
+ if (is_scalar) {
+ code_.SetValue("ARG", GenTypeBasic(type, true));
+ code_.SetValue("FIELD_VALUE",
+ GenUnderlyingCast(field, false, "_" + Name(field)));
+
+ code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
+ code_ +=
+ " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
+ "{{FIELD_VALUE}});";
+ code_ += " }";
+ } else if (is_array) {
+ GenArrayAccessor(type, true);
+ } else {
+ code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
+ code_ += " return {{FIELD_VALUE}};";
+ code_ += " }";
+ }
+ }
+
+ // Generate a comparison function for this field if it is a key.
+ if (field.key) { GenKeyFieldMethods(field); }
+ }
+ 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
+ // different (closing/opening only what is necessary).
+ //
+ // The file must start and end with an empty (or null) namespace so that
+ // namespaces are properly opened and closed.
+ void SetNameSpace(const Namespace *ns) {
+ if (cur_name_space_ == ns) { return; }
+
+ // Compute the size of the longest common namespace prefix.
+ // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
+ // the common prefix is A::B:: and we have old_size = 4, new_size = 5
+ // and common_prefix_size = 2
+ size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
+ size_t new_size = ns ? ns->components.size() : 0;
+
+ size_t common_prefix_size = 0;
+ while (common_prefix_size < old_size && common_prefix_size < new_size &&
+ ns->components[common_prefix_size] ==
+ cur_name_space_->components[common_prefix_size]) {
+ common_prefix_size++;
+ }
+
+ // Close cur_name_space in reverse order to reach the common prefix.
+ // In the previous example, D then C are closed.
+ for (size_t j = old_size; j > common_prefix_size; --j) {
+ code_ += "} // namespace " + cur_name_space_->components[j - 1];
+ }
+ if (old_size != common_prefix_size) { code_ += ""; }
+
+ // open namespace parts to reach the ns namespace
+ // in the previous example, E, then F, then G are opened
+ for (auto j = common_prefix_size; j != new_size; ++j) {
+ code_ += "namespace " + ns->components[j] + " {";
+ }
+ if (new_size != common_prefix_size) { code_ += ""; }
+
+ cur_name_space_ = ns;
+ }
+};
+
+} // namespace cpp
+
+bool GenerateCPP(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ 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++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;
+ opts.g_only_fixed_enums = false;
+ } else if (cpp_std == "C++11") {
+ // Use the standard C++11 code generator.
+ opts.g_cpp_std = cpp::CPP_STD_11;
+ opts.g_only_fixed_enums = true;
+ } else if (cpp_std == "C++17") {
+ opts.g_cpp_std = cpp::CPP_STD_17;
+ // With c++17 generate strong enums only.
+ opts.scoped_enums = true;
+ // By default, prefixed_enums==true, reset it.
+ opts.prefixed_enums = false;
+ } else {
+ LogCompilerError("Unknown value of the '--cpp-std' switch: " +
+ opts.cpp_std);
+ return false;
+ }
+ // 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();
+}
+
+std::string CPPMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ const auto filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
+ const auto included_files = parser.GetIncludedFilesRecursive(file_name);
+ std::string make_rule =
+ geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_cpp_yandex_maps_iter.cpp b/contrib/libs/flatbuffers/src/idl_gen_cpp_yandex_maps_iter.cpp
new file mode 100644
index 0000000000..1ba2ef3e4a
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_cpp_yandex_maps_iter.cpp
@@ -0,0 +1,731 @@
+/*
+ * 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 <unordered_set>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/flatc.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+// Pedantic warning free version of toupper().
+inline char ToUpper(char c) {
+ return static_cast<char>(::toupper(static_cast<unsigned char>(c)));
+}
+
+static std::string GeneratedIterFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + ".iter.fbs.h";
+}
+
+namespace cpp_yandex_maps_iter {
+class CppIterGenerator : public BaseGenerator {
+ public:
+ CppIterGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "::", "h"),
+ cur_name_space_(nullptr) {
+ static const char *const keywords[] = {
+ "alignas",
+ "alignof",
+ "and",
+ "and_eq",
+ "asm",
+ "atomic_cancel",
+ "atomic_commit",
+ "atomic_noexcept",
+ "auto",
+ "bitand",
+ "bitor",
+ "bool",
+ "break",
+ "case",
+ "catch",
+ "char",
+ "char16_t",
+ "char32_t",
+ "class",
+ "compl",
+ "concept",
+ "const",
+ "constexpr",
+ "const_cast",
+ "continue",
+ "co_await",
+ "co_return",
+ "co_yield",
+ "decltype",
+ "default",
+ "delete",
+ "do",
+ "double",
+ "dynamic_cast",
+ "else",
+ "enum",
+ "explicit",
+ "export",
+ "extern",
+ "false",
+ "float",
+ "for",
+ "friend",
+ "goto",
+ "if",
+ "import",
+ "inline",
+ "int",
+ "long",
+ "module",
+ "mutable",
+ "namespace",
+ "new",
+ "noexcept",
+ "not",
+ "not_eq",
+ "nullptr",
+ "operator",
+ "or",
+ "or_eq",
+ "private",
+ "protected",
+ "public",
+ "register",
+ "reinterpret_cast",
+ "requires",
+ "return",
+ "short",
+ "signed",
+ "sizeof",
+ "static",
+ "static_assert",
+ "static_cast",
+ "struct",
+ "switch",
+ "synchronized",
+ "template",
+ "this",
+ "thread_local",
+ "throw",
+ "true",
+ "try",
+ "typedef",
+ "typeid",
+ "typename",
+ "union",
+ "unsigned",
+ "using",
+ "virtual",
+ "void",
+ "volatile",
+ "wchar_t",
+ "while",
+ "xor",
+ "xor_eq",
+ nullptr,
+ };
+ for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+ }
+
+ std::string GenIncludeGuard() const {
+ // Generate include guard.
+ std::string guard = file_name_;
+ // Remove any non-alpha-numeric characters that may appear in a filename.
+ struct IsAlnum {
+ bool operator()(char c) const { return !isalnum(c); }
+ };
+ guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
+ guard.end());
+ guard = "FLATBUFFERS_GENERATED_" + guard;
+ guard += "_";
+ // For further uniqueness, also add the namespace.
+ auto name_space = parser_.current_namespace_;
+ for (auto it = name_space->components.begin();
+ it != name_space->components.end(); ++it) {
+ guard += *it + "_";
+ }
+ guard += "ITER_";
+ guard += "H_";
+ std::transform(guard.begin(), guard.end(), guard.begin(), ToUpper);
+ return guard;
+ }
+
+ void GenIncludeDependencies() {
+ int num_includes = 0;
+ for (auto it = parser_.native_included_files_.begin();
+ it != parser_.native_included_files_.end(); ++it) {
+ code_ += "#include \"" + *it + "\"";
+ num_includes++;
+ }
+ for (auto it = parser_.included_files_.begin();
+ it != parser_.included_files_.end(); ++it) {
+ if (it->second.empty()) continue;
+ auto noext = flatbuffers::StripExtension(it->second);
+ auto basename = flatbuffers::StripPath(noext);
+
+ code_ += "#include \"" + parser_.opts.include_prefix +
+ (parser_.opts.keep_include_path ? noext : basename) +
+ ".iter.fbs.h\"";
+ num_includes++;
+ }
+ if (num_includes) code_ += "";
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : name + "_";
+ }
+
+ std::string Name(const Definition &def) const {
+ return EscapeKeyword(def.name);
+ }
+
+ std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
+
+ // Iterate through all definitions we haven't generate code for (enums,
+ // structs, and tables) and output them to a single file.
+ bool generate() {
+ code_.Clear();
+ code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ const auto include_guard = GenIncludeGuard();
+ code_ += "#ifndef " + include_guard;
+ code_ += "#define " + include_guard;
+ code_ += "";
+
+ if (parser_.opts.gen_nullable) {
+ code_ += "#pragma clang system_header\n\n";
+ }
+
+ code_ += "#include \"" + file_name_ + ".fbs.h\"";
+ code_ += "#include \"contrib/libs/flatbuffers/include/flatbuffers/flatbuffers_iter.h\"";
+ code_ += "";
+
+ if (parser_.opts.include_dependence_headers) { GenIncludeDependencies(); }
+
+ FLATBUFFERS_ASSERT(!cur_name_space_);
+
+ // Generate forward declarations for all structs/tables, since they may
+ // have circular references.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.generated && !struct_def.fixed) {
+ SetNameSpace(struct_def.defined_namespace);
+ code_ += "template <typename Iter>";
+ code_ += "struct " + Name(struct_def) + ";";
+ code_ += "";
+ }
+ }
+
+ 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) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenTable(struct_def);
+ }
+ }
+
+ // Generate convenient global helper functions:
+ if (parser_.root_struct_def_ && !parser_.root_struct_def_->fixed) {
+ auto &struct_def = *parser_.root_struct_def_;
+ SetNameSpace(struct_def.defined_namespace);
+ auto name = Name(struct_def);
+ auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
+ auto cpp_name = TranslateNameSpace(qualified_name, true);
+ const auto cpp_non_iter_name = TranslateNameSpace(qualified_name);
+ const auto cpp_non_iter_getter = TranslateNameSpace(
+ parser_.namespaces_.back()->GetFullyQualifiedName("Get"+name));
+
+ code_.SetValue("STRUCT_NAME", name);
+ code_.SetValue("CPP_NAME", cpp_name);
+ code_.SetValue("CPP_NON_ITER_NAME", cpp_non_iter_name);
+ code_.SetValue("CPP_NON_ITER_GETTER", cpp_non_iter_getter);
+
+ // The root datatype accessor:
+ code_ += "template <typename Iter>";
+ code_ += "inline \\";
+ code_ += "std::optional<{{CPP_NAME}}<Iter>> Get{{STRUCT_NAME}}(const Iter& buf) {";
+ code_ += " return yandex::maps::flatbuffers_iter::GetRoot<{{CPP_NAME}}<Iter>, Iter>(buf);";
+ code_ += "}";
+ code_ += "";
+
+ // The non_iter datatype accessor:
+ code_ += "inline \\";
+ code_ += "const {{CPP_NON_ITER_NAME}} *Get{{STRUCT_NAME}}(const char *buf) {";
+ code_ += " return {{CPP_NON_ITER_GETTER}}(buf);";
+ code_ += "}";
+ code_ += "";
+
+ if (parser_.file_identifier_.length()) {
+ // Return the identifier
+ code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
+ code_ += " return \"" + parser_.file_identifier_ + "\";";
+ code_ += "}";
+ code_ += "";
+
+ // Check if a buffer has the identifier.
+ code_ += "template <typename Iter>";
+ code_ += "inline \\";
+ code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const Iter& buf) {";
+ code_ += " return yandex::maps::flatbuffers_iter::BufferHasIdentifier(";
+ code_ += " buf, {{STRUCT_NAME}}Identifier());";
+ code_ += "}";
+ code_ += "";
+ }
+
+ // The root verifier.
+ if (parser_.file_identifier_.length()) {
+ code_.SetValue("ID", name + "Identifier()");
+ } else {
+ code_.SetValue("ID", "nullptr");
+ }
+
+ code_ += "template <typename Iter>";
+ code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
+ code_ += " yandex::maps::flatbuffers_iter::Verifier<Iter> &verifier) {";
+ code_ += " return verifier.template VerifyBuffer<{{CPP_NAME}}<Iter>>({{ID}});";
+ code_ += "}";
+ code_ += "";
+
+ if (parser_.file_extension_.length()) {
+ // Return the extension
+ code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
+ code_ += " return \"" + parser_.file_extension_ + "\";";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ if (cur_name_space_) SetNameSpace(nullptr);
+
+ // Close the include guard.
+ code_ += "#endif // " + include_guard;
+
+ const auto file_path = GeneratedIterFileName(path_, file_name_);
+ const auto final_code = code_.ToString();
+ return SaveFile(file_path.c_str(), final_code, false);
+ }
+
+ private:
+ CodeWriter code_;
+
+ std::unordered_set<std::string> keywords_;
+
+ // This tracks the current namespace so we can insert namespace declarations.
+ const Namespace *cur_name_space_;
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+// Ensure that a type is prefixed with its namespace whenever it is used
+// outside of its namespace.
+ std::string WrapInNameSpace(const Namespace *ns,
+ const std::string &name, bool needIter = false) const {
+ if (CurrentNameSpace() == ns) return name;
+ std::string qualified_name = qualifying_start_;
+ for (auto it = ns->components.begin(); it != ns->components.end(); ++it)
+ qualified_name += *it + qualifying_separator_;
+ if (needIter)
+ qualified_name += "iter" + qualifying_separator_;
+ return qualified_name + name;
+ }
+
+ std::string WrapInNameSpace(const Definition &def, bool needIter = false) const {
+ return WrapInNameSpace(def.defined_namespace, def.name, needIter);
+ }
+
+ // Translates a qualified name in flatbuffer text format to the same name in
+ // the equivalent C++ namespace.
+ static std::string TranslateNameSpace(const std::string &qualified_name, bool needIter = false) {
+ std::string cpp_qualified_name = qualified_name;
+ size_t start_pos = 0;
+ while ((start_pos = cpp_qualified_name.find(".", start_pos)) !=
+ std::string::npos) {
+ cpp_qualified_name.replace(start_pos, 1, "::");
+ }
+ if (needIter)
+ {
+ start_pos = cpp_qualified_name.rfind("::");
+ if (start_pos != std::string::npos)
+ cpp_qualified_name.replace(start_pos, 2, "::iter::");
+ }
+ return cpp_qualified_name;
+ }
+
+ void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
+ std::string text;
+ ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
+ code_ += text + "\\";
+ }
+
+ // Return a C++ type from the table in idl.h
+ std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
+ // clang-format off
+ static const char * const ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ #CTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ if (user_facing_type) {
+ if (type.enum_def) return WrapInNameSpace(*type.enum_def);
+ if (type.base_type == BASE_TYPE_BOOL) return "bool";
+ }
+ return ctypename[type.base_type];
+ }
+
+ // Return a C++ pointer type, specialized to the actual struct/table types,
+ // and vector element types.
+ std::string GenTypePointer(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: {
+ return "yandex::maps::flatbuffers_iter::String<Iter>";
+ }
+ case BASE_TYPE_VECTOR: {
+ const auto type_name = GenTypeWire(type.VectorType(), "", false);
+ return "yandex::maps::flatbuffers_iter::Vector<" + type_name + ", Iter>";
+ }
+ case BASE_TYPE_STRUCT: {
+ if (IsStruct(type))
+ return WrapInNameSpace(*type.struct_def, !type.struct_def->fixed);
+ return WrapInNameSpace(*type.struct_def, !type.struct_def->fixed) + "<Iter>";
+ }
+ case BASE_TYPE_UNION:
+ // fall through
+ default: { return "void"; }
+ }
+ }
+
+ // Return a C++ type for any type (scalar/pointer) specifically for
+ // building a flatbuffer.
+ std::string GenTypeWire(const Type &type, const char *postfix,
+ bool user_facing_type) const {
+ if (IsScalar(type.base_type)) {
+ return GenTypeBasic(type, user_facing_type) + postfix;
+ } else if (IsStruct(type)) {
+ return GenTypePointer(type);
+ } else {
+ return "yandex::maps::flatbuffers_iter::Offset<" + GenTypePointer(type) + ">" + postfix;
+ }
+ }
+
+ // Return a C++ type for any type (scalar/pointer) that reflects its
+ // serialized size.
+ std::string GenTypeSize(const Type &type) const {
+ if (IsScalar(type.base_type)) {
+ return GenTypeBasic(type, false);
+ } else if (IsStruct(type)) {
+ return GenTypePointer(type);
+ } else {
+ return "yandex::maps::flatbuffers_iter::uoffset_t";
+ }
+ }
+
+ // Return a C++ type for any type (scalar/pointer) specifically for
+ // using a flatbuffer.
+ std::string GenTypeGet(const Type &type, const char *afterbasic,
+ const char *beforeptr, const char *afterptr,
+ bool user_facing_type) {
+ if (IsScalar(type.base_type)) {
+ return GenTypeBasic(type, user_facing_type) + afterbasic;
+ } else {
+ return beforeptr + GenTypePointer(type) + afterptr;
+ }
+ }
+
+ // Generates a value with optionally a cast applied if the field has a
+ // different underlying type from its interface type (currently only the
+ // case for enums. "from" specify the direction, true meaning from the
+ // underlying type to the interface type.
+ std::string GenUnderlyingCast(const FieldDef &field, bool from,
+ const std::string &val) {
+ if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
+ return val + " != 0";
+ } else if ((field.value.type.enum_def &&
+ IsScalar(field.value.type.base_type)) ||
+ field.value.type.base_type == BASE_TYPE_BOOL) {
+ return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
+ val + ")";
+ } else {
+ return val;
+ }
+ }
+
+ std::string GenFieldOffsetName(const FieldDef &field) {
+ std::string uname = Name(field);
+ std::transform(uname.begin(), uname.end(), uname.begin(), ToUpper);
+ return "VT_" + uname;
+ }
+
+ std::string GenDefaultConstant(const FieldDef &field) {
+ return field.value.type.base_type == BASE_TYPE_FLOAT
+ ? field.value.constant + "f"
+ : field.value.constant;
+ }
+
+ // 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.IsRequired() ? "Required" : "");
+ code_.SetValue("SIZE", GenTypeSize(field.value.type));
+ code_.SetValue("OFFSET", GenFieldOffsetName(field));
+ code_ += "{{PRE}}this->template VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
+
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_UNION: {
+ code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
+ code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
+ code_ +=
+ "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
+ "{{NAME}}{{SUFFIX}}())\\";
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (!field.value.type.struct_def->fixed) {
+ code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
+ }
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ code_ += "{{PRE}}verifier.Verify({{NAME}}())\\";
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ code_ += "{{PRE}}verifier.Verify({{NAME}}())\\";
+
+ switch (field.value.type.element) {
+ case BASE_TYPE_STRING: {
+ code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (!field.value.type.struct_def->fixed) {
+ code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
+ code_ +=
+ "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
+ "{{NAME}}_type())\\";
+ break;
+ }
+ default: break;
+ }
+ break;
+ }
+ default: { break; }
+ }
+ }
+
+ // Generate CompareWithValue method for a key field.
+ void GenKeyFieldMethods(const FieldDef &field) {
+ FLATBUFFERS_ASSERT(field.key);
+ const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING);
+
+ code_ += " bool KeyCompareLessThan(const std::optional<{{STRUCT_NAME}}<Iter>>& o) const {";
+ if (is_string) {
+ // use operator< of flatbuffers::String
+ code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
+ } else {
+ code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
+ }
+ code_ += " }";
+
+ if (is_string) {
+ code_ += " int KeyCompareWithValue(const char *val) const {";
+ code_ += " return strcmp({{FIELD_NAME}}()->str().c_str(), val);";
+ code_ += " }";
+ } else {
+ FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
+ auto type = GenTypeBasic(field.value.type, false);
+ if (parser_.opts.scoped_enums && field.value.type.enum_def &&
+ IsScalar(field.value.type.base_type)) {
+ type = GenTypeGet(field.value.type, " ", "const ", " *", true);
+ }
+ // 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);";
+ code_ += " }";
+ }
+ }
+
+
+ // Generate an accessor struct, builder structs & function for a table.
+ void GenTable(const StructDef &struct_def) {
+ // Generate an accessor struct, with methods of the form:
+ // type name() const { return GetField<type>(offset, defaultval); }
+ GenComment(struct_def.doc_comment);
+
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+ code_ += "template <typename Iter>";
+ code_ +=
+ "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
+ " : private yandex::maps::flatbuffers_iter::Table<Iter> {";
+
+ // Generate field id constants.
+ if (struct_def.fields.vec.size() > 0) {
+ // We need to add a trailing comma to all elements except the last one as
+ // older versions of gcc complain about this.
+ code_.SetValue("SEP", "");
+ code_ += " enum {";
+ 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("OFFSET_NAME", GenFieldOffsetName(field));
+ code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
+ code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
+ code_.SetValue("SEP", ",\n");
+ }
+ code_ += "";
+ code_ += " };";
+ }
+
+ code_ += "";
+ code_ += " using yandex::maps::flatbuffers_iter::Table<Iter>::Table;";
+
+ // Generate the accessors.
+ 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;
+ }
+
+ const bool is_struct = IsStruct(field.value.type);
+ const bool is_scalar = IsScalar(field.value.type.base_type);
+ code_.SetValue("FIELD_NAME", Name(field));
+
+ // Call a different accessor for pointers, that indirects.
+ std::string accessor = "";
+ if (is_scalar) {
+ accessor = "this->template GetField<";
+ } else if (is_struct) {
+ accessor = "this->template GetStruct<";
+ } else {
+ accessor = "this->template GetPointer<";
+ }
+ auto offset_str = GenFieldOffsetName(field);
+ auto offset_type =
+ GenTypeGet(field.value.type, "", "", "", false);
+
+ auto call = accessor + offset_type + ">(" + offset_str;
+ // Default value as second arg for non-pointer types.
+ if (is_scalar) { call += ", " + GenDefaultConstant(field); }
+ call += ")";
+
+ GenComment(field.doc_comment, " ");
+ code_.SetValue("FIELD_TYPE",
+ GenTypeGet(field.value.type, " ", "std::optional<", "> ", true));
+ code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
+
+ code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
+ code_ += " return {{FIELD_VALUE}};";
+ code_ += " }";
+
+ // Generate a comparison function for this field if it is a key.
+ if (field.key) {
+ GenKeyFieldMethods(field);
+ }
+ }
+
+ // Generate a verifier function that can check a buffer from an untrusted
+ // source will never cause reads outside the buffer.
+ code_ += " bool Verify(yandex::maps::flatbuffers_iter::Verifier<Iter> &verifier) const {";
+ code_ += " return this->VerifyTableStart(verifier)\\";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) { continue; }
+ GenVerifyCall(field, " &&\n ");
+ }
+
+ code_ += " &&\n verifier.EndTable();";
+ code_ += " }";
+
+ code_ += "};"; // End of table.
+ code_ += "";
+ }
+
+ // Set up the correct namespace. Only open a namespace if the existing one is
+ // different (closing/opening only what is necessary).
+ //
+ // The file must start and end with an empty (or null) namespace so that
+ // namespaces are properly opened and closed.
+ void SetNameSpace(const Namespace *ns) {
+ if (cur_name_space_ == ns) { return; }
+
+ // Compute the size of the longest common namespace prefix.
+ // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
+ // the common prefix is A::B:: and we have old_size = 4, new_size = 5
+ // and common_prefix_size = 2
+ size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
+ size_t new_size = ns ? ns->components.size() : 0;
+
+ size_t common_prefix_size = 0;
+ while (common_prefix_size < old_size && common_prefix_size < new_size &&
+ ns->components[common_prefix_size] ==
+ cur_name_space_->components[common_prefix_size]) {
+ common_prefix_size++;
+ }
+
+ // Close cur_name_space in reverse order to reach the common prefix.
+ // In the previous example, D then C are closed.
+ if (old_size > 0)
+ code_ += "} // namespace iter";
+ for (size_t j = old_size; j > common_prefix_size; --j) {
+ code_ += "} // namespace " + cur_name_space_->components[j - 1];
+ }
+ if (old_size != common_prefix_size) { code_ += ""; }
+
+ // open namespace parts to reach the ns namespace
+ // in the previous example, E, then F, then G are opened
+ for (auto j = common_prefix_size; j != new_size; ++j) {
+ code_ += "namespace " + ns->components[j] + " {";
+ }
+ if (new_size > 0)
+ code_ += "namespace iter {";
+ if (new_size != common_prefix_size) { code_ += ""; }
+
+ cur_name_space_ = ns;
+ }
+};
+
+} // namespace cpp_yandex_maps_iter
+
+bool GenerateCPPYandexMapsIter(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ cpp_yandex_maps_iter::CppIterGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_csharp.cpp b/contrib/libs/flatbuffers/src/idl_gen_csharp.cpp
new file mode 100644
index 0000000000..681ab6d642
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_csharp.cpp
@@ -0,0 +1,2100 @@
+/*
+ * 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 "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",
+ "PositiveInfinity",
+ "NegativeInfinity");
+static CommentConfig comment_config = {
+ nullptr,
+ "///",
+ nullptr,
+};
+
+namespace csharp {
+class CSharpGenerator : public BaseGenerator {
+ struct FieldArrayLength {
+ std::string name;
+ int length;
+ };
+
+ public:
+ CSharpGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", ".", "cs"),
+ cur_name_space_(nullptr) {}
+
+ CSharpGenerator &operator=(const CSharpGenerator &);
+
+ bool generate() {
+ std::string one_file_code;
+ cur_name_space_ = parser_.current_namespace_;
+
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ std::string enumcode;
+ auto &enum_def = **it;
+ if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
+ GenEnum(enum_def, &enumcode, parser_.opts);
+ if (parser_.opts.one_file) {
+ one_file_code += enumcode;
+ } else {
+ if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
+ false))
+ return false;
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ std::string declcode;
+ auto &struct_def = **it;
+ if (!parser_.opts.one_file)
+ cur_name_space_ = struct_def.defined_namespace;
+ GenStruct(struct_def, &declcode, parser_.opts);
+ if (parser_.opts.one_file) {
+ one_file_code += declcode;
+ } else {
+ if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
+ true))
+ return false;
+ }
+ }
+
+ if (parser_.opts.one_file) {
+ return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
+ true);
+ }
+ return true;
+ }
+
+ // 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 {
+ if (!classcode.length()) return true;
+
+ std::string code =
+ "// <auto-generated>\n"
+ "// " +
+ std::string(FlatBuffersGeneratedWarning()) +
+ "\n"
+ "// </auto-generated>\n\n";
+
+ std::string namespace_name = FullNamespace(".", ns);
+ if (!namespace_name.empty()) {
+ code += "namespace " + namespace_name + "\n{\n\n";
+ }
+ if (needs_includes) {
+ code += "using global::System;\n";
+ code += "using global::System.Collections.Generic;\n";
+ code += "using global::FlatBuffers;\n\n";
+ }
+ code += classcode;
+ if (!namespace_name.empty()) { code += "\n}\n"; }
+ auto filename = NamespaceDir(ns) + defname + ".cs";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ std::string GenTypeBasic(const Type &type, bool enableLangOverrides) const {
+ // clang-format off
+ static const char * const csharp_typename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, ...) \
+ #NTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+
+ if (enableLangOverrides) {
+ if (IsEnum(type)) return WrapInNameSpace(*type.enum_def);
+ if (type.base_type == BASE_TYPE_STRUCT) {
+ return "Offset<" + WrapInNameSpace(*type.struct_def) + ">";
+ }
+ }
+
+ return csharp_typename[type.base_type];
+ }
+
+ inline std::string GenTypeBasic(const Type &type) const {
+ return GenTypeBasic(type, true);
+ }
+
+ 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());
+ case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
+ case BASE_TYPE_UNION: return "TTable";
+ default: return "Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) const {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type)
+ : (IsArray(type) ? GenTypeGet(type.VectorType())
+ : GenTypePointer(type));
+ }
+
+ std::string GenOffsetType(const StructDef &struct_def) const {
+ return "Offset<" + WrapInNameSpace(struct_def) + ">";
+ }
+
+ std::string GenOffsetConstruct(const StructDef &struct_def,
+ const std::string &variable_name) const {
+ return "new Offset<" + WrapInNameSpace(struct_def) + ">(" + variable_name +
+ ")";
+ }
+
+ // Casts necessary to correctly read serialized data
+ std::string DestinationCast(const Type &type) const {
+ if (IsSeries(type)) {
+ return DestinationCast(type.VectorType());
+ } else {
+ if (IsEnum(type)) return "(" + WrapInNameSpace(*type.enum_def) + ")";
+ }
+ return "";
+ }
+
+ // Cast statements for mutator method parameters.
+ // In Java, parameters representing unsigned numbers need to be cast down to
+ // their respective type. For example, a long holding an unsigned int value
+ // 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 {
+ if (IsSeries(type)) {
+ return SourceCast(type.VectorType());
+ } else {
+ if (IsEnum(type)) return "(" + GenTypeBasic(type, false) + ")";
+ }
+ return "";
+ }
+
+ std::string SourceCastBasic(const Type &type) const {
+ return IsScalar(type.base_type) ? SourceCast(type) : "";
+ }
+
+ std::string GenEnumDefaultValue(const FieldDef &field) const {
+ 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);
+ return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+ : value.constant;
+ }
+
+ std::string GenDefaultValue(const FieldDef &field,
+ bool enableLangOverrides) const {
+ // If it is an optional scalar field, the default is null
+ if (field.IsScalarOptional()) { return "null"; }
+
+ auto &value = field.value;
+ if (enableLangOverrides) {
+ // handles both enum case and vector of enum case
+ if (value.type.enum_def != nullptr &&
+ value.type.base_type != BASE_TYPE_UNION) {
+ return GenEnumDefaultValue(field);
+ }
+ }
+
+ auto longSuffix = "";
+ switch (value.type.base_type) {
+ case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
+ case BASE_TYPE_ULONG: return value.constant;
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_LONG: return value.constant + longSuffix;
+ default:
+ if (IsFloat(value.type.base_type))
+ return CSharpFloatGen.GenFloatConstant(field);
+ else
+ return value.constant;
+ }
+ }
+
+ std::string GenDefaultValue(const FieldDef &field) const {
+ return GenDefaultValue(field, true);
+ }
+
+ std::string GenDefaultValueBasic(const FieldDef &field,
+ bool enableLangOverrides) const {
+ auto &value = field.value;
+ if (!IsScalar(value.type.base_type)) {
+ if (enableLangOverrides) {
+ switch (value.type.base_type) {
+ case BASE_TYPE_STRING: return "default(StringOffset)";
+ case BASE_TYPE_STRUCT:
+ return "default(Offset<" + WrapInNameSpace(*value.type.struct_def) +
+ ">)";
+ case BASE_TYPE_VECTOR: return "default(VectorOffset)";
+ default: break;
+ }
+ }
+ return "0";
+ }
+ return GenDefaultValue(field, enableLangOverrides);
+ }
+
+ std::string GenDefaultValueBasic(const FieldDef &field) const {
+ return GenDefaultValueBasic(field, true);
+ }
+
+ void GenEnum(EnumDef &enum_def, std::string *code_ptr,
+ const IDLOptions &opts) const {
+ std::string &code = *code_ptr;
+ if (enum_def.generated) return;
+
+ // Generate enum definitions of the form:
+ // public static (final) int name = value;
+ // In Java, we use ints rather than the Enum feature, because we want them
+ // to map directly to how they're used in C/C++ and file formats.
+ // That, and Java Enums are expensive, and not universally liked.
+ GenComment(enum_def.doc_comment, code_ptr, &comment_config);
+
+ if (opts.cs_gen_json_serializer && opts.generate_object_based_api) {
+ code +=
+ "[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters."
+ "StringEnumConverter))]\n";
+ }
+ // In C# this indicates enumeration values can be treated as bit flags.
+ if (enum_def.attributes.Lookup("bit_flags")) {
+ code += "[System.FlagsAttribute]\n";
+ }
+ if (enum_def.attributes.Lookup("private")) {
+ code += "internal ";
+ } else {
+ code += "public ";
+ }
+ code += "enum " + enum_def.name;
+ 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 += enum_def.ToString(ev);
+ code += ",\n";
+ }
+ // Close the class
+ code += "};\n\n";
+
+ if (opts.generate_object_based_api) {
+ GenEnum_ObjectAPI(enum_def, code_ptr, opts);
+ }
+ }
+
+ bool HasUnionStringValue(const EnumDef &enum_def) const {
+ if (!enum_def.is_union) return false;
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &val = **it;
+ if (IsString(val.union_type)) { return true; }
+ }
+ return false;
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetter(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "__p.__string";
+ case BASE_TYPE_STRUCT: return "__p.__struct";
+ case BASE_TYPE_UNION: return "__p.__union";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
+ default: {
+ std::string getter = "__p.bb.Get";
+ if (type.base_type == BASE_TYPE_BOOL) {
+ getter = "0!=" + getter;
+ } else if (GenTypeBasic(type, false) != "byte") {
+ getter += MakeCamel(GenTypeBasic(type, false));
+ }
+ return getter;
+ }
+ }
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
+ const std::string &data_buffer,
+ const char *num = nullptr) const {
+ auto type = key_field->value.type;
+ auto dest_mask = "";
+ auto dest_cast = DestinationCast(type);
+ auto getter = data_buffer + ".Get";
+ if (GenTypeBasic(type, false) != "byte") {
+ getter += MakeCamel(GenTypeBasic(type, false));
+ }
+ getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
+ dest_mask;
+ return getter;
+ }
+
+ // Direct mutation is only allowed for scalar fields.
+ // Hence a setter method will only be generated for such fields.
+ std::string GenSetter(const Type &type) const {
+ if (IsScalar(type.base_type)) {
+ std::string setter = "__p.bb.Put";
+ if (GenTypeBasic(type, false) != "byte" &&
+ type.base_type != BASE_TYPE_BOOL) {
+ setter += MakeCamel(GenTypeBasic(type, false));
+ }
+ return setter;
+ } else {
+ return "";
+ }
+ }
+
+ // 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");
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix, size_t array_count = 0) const {
+ std::string &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;
+ const auto array_field = IsArray(field_type);
+ const auto &type = array_field ? field_type.VectorType() : field_type;
+ const auto array_cnt = array_field ? (array_count + 1) : array_count;
+ if (IsStruct(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_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), array_cnt);
+ } else {
+ code += ", ";
+ code += GenTypeBasic(type);
+ if (field.IsScalarOptional()) { code += "?"; }
+ if (array_cnt > 0) {
+ code += "[";
+ for (size_t i = 1; i < array_cnt; i++) code += ",";
+ code += "]";
+ }
+ code += " ";
+ code += nameprefix;
+ code += MakeCamel(field.name, true);
+ }
+ }
+ }
+
+ // Recusively generate struct construction statements of the form:
+ // builder.putType(name);
+ // and insert manual padding.
+ void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix, size_t index = 0,
+ bool in_array = false) const {
+ std::string &code = *code_ptr;
+ std::string indent((index + 1) * 2, ' ');
+ code += indent + " builder.Prep(";
+ code += NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ");\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ if (field.padding) {
+ code += indent + " builder.Pad(";
+ code += NumToString(field.padding) + ");\n";
+ }
+ if (IsStruct(field_type)) {
+ GenStructBody(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), index,
+ in_array);
+ } else {
+ const auto &type =
+ IsArray(field_type) ? field_type.VectorType() : field_type;
+ const auto index_var = "_idx" + NumToString(index);
+ if (IsArray(field_type)) {
+ code += indent + " for (int " + index_var + " = ";
+ code += NumToString(field_type.fixed_length);
+ code += "; " + index_var + " > 0; " + index_var + "--) {\n";
+ in_array = true;
+ }
+ if (IsStruct(type)) {
+ GenStructBody(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), index + 1,
+ in_array);
+ } else {
+ code += IsArray(field_type) ? " " : "";
+ code += indent + " builder.Put";
+ code += GenMethod(type) + "(";
+ code += SourceCast(type);
+ auto argname = nameprefix + MakeCamel(field.name, true);
+ code += argname;
+ size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
+ if (array_cnt > 0) {
+ code += "[";
+ for (size_t i = 0; in_array && i < array_cnt; i++) {
+ code += "_idx" + NumToString(i) + "-1";
+ if (i != (array_cnt - 1)) code += ",";
+ }
+ code += "]";
+ }
+ code += ");\n";
+ }
+ if (IsArray(field_type)) { code += indent + " }\n"; }
+ }
+ }
+ }
+ std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+ const char *num = nullptr) const {
+ std::string key_offset =
+ "Table.__offset(" + NumToString(key_field->value.offset) + ", ";
+ if (num) {
+ key_offset += num;
+ key_offset += ".Value, builder.DataBuffer)";
+ } else {
+ key_offset += "bb.Length";
+ key_offset += " - tableOffset, bb)";
+ }
+ return key_offset;
+ }
+
+ std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
+ std::string key_getter = " ";
+ key_getter += "int tableOffset = Table.";
+ key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
+ key_getter += ", bb);\n ";
+ if (IsString(key_field->value.type)) {
+ key_getter += "int comp = Table.";
+ key_getter += "CompareStrings(";
+ key_getter += GenOffsetGetter(key_field);
+ key_getter += ", byteKey, bb);\n";
+ } else {
+ auto get_val = GenGetterForLookupByKey(key_field, "bb");
+ key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
+ }
+ return key_getter;
+ }
+
+ std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
+ std::string key_getter = "";
+ auto data_buffer = "builder.DataBuffer";
+ if (IsString(key_field->value.type)) {
+ key_getter += "Table.CompareStrings(";
+ key_getter += GenOffsetGetter(key_field, "o1") + ", ";
+ key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
+ } else {
+ auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
+ key_getter += field_getter;
+ field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
+ key_getter += ".CompareTo(" + field_getter + ")";
+ }
+ return key_getter;
+ }
+
+ void GenStruct(StructDef &struct_def, std::string *code_ptr,
+ const IDLOptions &opts) const {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+
+ // Generate a struct accessor class, with methods of the form:
+ // public type name() { return bb.getType(i + offset); }
+ // or for tables of the form:
+ // public type name() {
+ // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
+ // }
+ GenComment(struct_def.doc_comment, code_ptr, &comment_config);
+ if (struct_def.attributes.Lookup("private")) {
+ code += "internal ";
+ } else {
+ code += "public ";
+ }
+ if (struct_def.attributes.Lookup("csharp_partial")) {
+ // generate a partial class for this C# struct/table
+ code += "partial ";
+ }
+ code += "struct " + struct_def.name;
+ code += " : IFlatbufferObject";
+ code += "\n{\n";
+ code += " private ";
+ code += struct_def.fixed ? "Struct" : "Table";
+ code += " __p;\n";
+
+ code += " public ByteBuffer ByteBuffer { get { return __p.bb; } }\n";
+
+ if (!struct_def.fixed) {
+ // Generate verson check method.
+ // Force compile time error if not using the same version runtime.
+ code += " public static void ValidateVersion() {";
+ code += " FlatBufferConstants.";
+ code += "FLATBUFFERS_2_0_0(); ";
+ code += "}\n";
+
+ // Generate a special accessor for the table that when used as the root
+ // of a FlatBuffer
+ std::string method_name = "GetRootAs" + struct_def.name;
+ std::string method_signature =
+ " public static " + struct_def.name + " " + method_name;
+
+ // create convenience method that doesn't require an existing object
+ code += method_signature + "(ByteBuffer _bb) ";
+ code += "{ return " + method_name + "(_bb, new " + struct_def.name +
+ "()); }\n";
+
+ // create method that allows object reuse
+ code +=
+ method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
+ code += "return (obj.__assign(_bb.GetInt(_bb.Position";
+ code += ") + _bb.Position";
+ code += ", _bb)); }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
+ if (parser_.file_identifier_.length()) {
+ // Check if a buffer has the identifier.
+ code += " public static ";
+ code += "bool " + struct_def.name;
+ code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
+ code += "Table.__has_identifier(_bb, \"";
+ code += parser_.file_identifier_;
+ code += "\"); }\n";
+ }
+ }
+ }
+ // Generate the __init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ code += " public void __init(int _i, ByteBuffer _bb) ";
+ code += "{ ";
+ code += "__p = new ";
+ code += struct_def.fixed ? "Struct" : "Table";
+ code += "(_i, _bb); ";
+ code += "}\n";
+ code +=
+ " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
+ code += "{ __init(_i, _bb); return this; }\n\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ GenComment(field.doc_comment, code_ptr, &comment_config, " ");
+ std::string type_name = GenTypeGet(field.value.type);
+ std::string type_name_dest = GenTypeGet(field.value.type);
+ std::string conditional_cast = "";
+ std::string optional = "";
+ if (!struct_def.fixed &&
+ (field.value.type.base_type == BASE_TYPE_STRUCT ||
+ field.value.type.base_type == BASE_TYPE_UNION ||
+ (IsVector(field.value.type) &&
+ (field.value.type.element == BASE_TYPE_STRUCT ||
+ field.value.type.element == BASE_TYPE_UNION)))) {
+ optional = "?";
+ conditional_cast = "(" + type_name_dest + optional + ")";
+ }
+ if (field.IsScalarOptional()) { optional = "?"; }
+ 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 method_start =
+ " public " + type_name_dest + optional + " " + field_name_camel;
+ std::string obj = "(new " + type_name + "())";
+
+ // Most field accessors need to retrieve and test the field offset first,
+ // this is the prefix code for that:
+ auto offset_prefix =
+ IsArray(field.value.type)
+ ? " { return "
+ : (" { int o = __p.__offset(" + NumToString(field.value.offset) +
+ "); return o != 0 ? ");
+ // Generate the accessors that don't do object reuse.
+ if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ } else if (IsVector(field.value.type) &&
+ field.value.type.element == BASE_TYPE_STRUCT) {
+ } else if (field.value.type.base_type == BASE_TYPE_UNION ||
+ (IsVector(field.value.type) &&
+ field.value.type.VectorType().base_type == BASE_TYPE_UNION)) {
+ method_start += "<TTable>";
+ type_name = type_name_dest;
+ }
+ std::string getter = dest_cast + GenGetter(field.value.type);
+ code += method_start;
+ std::string default_cast = "";
+ // only create default casts for c# scalars or vectors of scalars
+ if ((IsScalar(field.value.type.base_type) ||
+ (IsVector(field.value.type) &&
+ IsScalar(field.value.type.element)))) {
+ // For scalars, default value will be returned by GetDefaultValue().
+ // If the scalar is an enum, GetDefaultValue() returns an actual c# enum
+ // that doesn't need to be casted. However, default values for enum
+ // elements of vectors are integer literals ("0") and are still casted
+ // for clarity.
+ // If the scalar is optional and enum, we still need the cast.
+ if ((field.value.type.enum_def == nullptr ||
+ IsVector(field.value.type)) ||
+ (IsEnum(field.value.type) && field.IsScalarOptional())) {
+ default_cast = "(" + type_name_dest + optional + ")";
+ }
+ }
+ std::string member_suffix = "; ";
+ if (IsScalar(field.value.type.base_type)) {
+ code += " { get";
+ member_suffix += "} ";
+ if (struct_def.fixed) {
+ code += " { return " + getter;
+ code += "(__p.bb_pos + ";
+ code += NumToString(field.value.offset) + ")";
+ code += dest_mask;
+ } else {
+ code += offset_prefix + getter;
+ code += "(o + __p.bb_pos)" + dest_mask;
+ code += " : " + default_cast;
+ code += GenDefaultValue(field);
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ code += " { get";
+ member_suffix += "} ";
+ if (struct_def.fixed) {
+ code += " { return " + obj + ".__assign(" + "__p.";
+ code += "bb_pos + " + NumToString(field.value.offset) + ", ";
+ code += "__p.bb)";
+ } else {
+ code += offset_prefix + conditional_cast;
+ code += obj + ".__assign(";
+ code += field.value.type.struct_def->fixed
+ ? "o + __p.bb_pos"
+ : "__p.__indirect(o + __p.bb_pos)";
+ code += ", __p.bb) : null";
+ }
+ break;
+ case BASE_TYPE_STRING:
+ code += " { get";
+ member_suffix += "} ";
+ code += offset_prefix + getter + "(o + " + "__p.";
+ code += "bb_pos) : null";
+ break;
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ conditional_cast = "(TTable?)";
+ getter += "<TTable>";
+ }
+ code += "(";
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ getter = obj + ".__assign";
+ } else if (vectortype.base_type == BASE_TYPE_UNION) {
+ }
+ code += "int j)";
+ const auto body = offset_prefix + conditional_cast + getter + "(";
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ code += " where TTable : struct, IFlatbufferObject" + body;
+ } else {
+ code += body;
+ }
+ std::string index = "__p.";
+ if (IsArray(field.value.type)) {
+ index += "bb_pos + " + NumToString(field.value.offset) + " + ";
+ } else {
+ index += "__vector(o) + ";
+ }
+ index += "j * " + NumToString(InlineSize(vectortype));
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += vectortype.struct_def->fixed
+ ? index
+ : "__p.__indirect(" + index + ")";
+ code += ", __p.bb";
+ } else {
+ code += index;
+ }
+ code += ")" + dest_mask;
+ if (!IsArray(field.value.type)) {
+ code += " : ";
+ code +=
+ field.value.type.element == BASE_TYPE_BOOL
+ ? "false"
+ : (IsScalar(field.value.type.element) ? default_cast + "0"
+ : "null");
+ }
+ if (vectortype.base_type == BASE_TYPE_UNION &&
+ HasUnionStringValue(*vectortype.enum_def)) {
+ code += member_suffix;
+ code += "}\n";
+ code += " public string " + MakeCamel(field.name, true) +
+ "AsString(int j)";
+ code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
+ code += "(" + index + ") : null";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION:
+ code += "() where TTable : struct, IFlatbufferObject";
+ code += offset_prefix + "(TTable?)" + getter;
+ code += "<TTable>(o + __p.bb_pos) : null";
+ if (HasUnionStringValue(*field.value.type.enum_def)) {
+ code += member_suffix;
+ code += "}\n";
+ code += " public string " + MakeCamel(field.name, true) +
+ "AsString()";
+ code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
+ code += "(o + __p.bb_pos) : null";
+ }
+ // As<> accesors for Unions
+ // Loop through all the possible union types and generate an As
+ // accessor that casts to the correct type.
+ for (auto uit = field.value.type.enum_def->Vals().begin();
+ uit != field.value.type.enum_def->Vals().end(); ++uit) {
+ auto val = *uit;
+ if (val->union_type.base_type == BASE_TYPE_NONE) { continue; }
+ auto union_field_type_name = GenTypeGet(val->union_type);
+ code += member_suffix + "}\n";
+ if (val->union_type.base_type == BASE_TYPE_STRUCT &&
+ val->union_type.struct_def->attributes.Lookup("private")) {
+ code += " internal ";
+ } else {
+ code += " public ";
+ }
+ code += union_field_type_name + " ";
+ code += field_name_camel + "As" + val->name + "() { return ";
+ code += field_name_camel;
+ if (IsString(val->union_type)) {
+ code += "AsString()";
+ } else {
+ code += "<" + union_field_type_name + ">().Value";
+ }
+ }
+ break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += member_suffix;
+ code += "}\n";
+ if (IsVector(field.value.type)) {
+ code += " public int " + MakeCamel(field.name, true);
+ code += "Length";
+ code += " { get";
+ code += offset_prefix;
+ code += "__p.__vector_len(o) : 0; ";
+ code += "} ";
+ code += "}\n";
+ // See if we should generate a by-key accessor.
+ if (field.value.type.element == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ auto &sd = *field.value.type.struct_def;
+ auto &fields = sd.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ auto qualified_name = WrapInNameSpace(sd);
+ code += " public " + qualified_name + "? ";
+ code += MakeCamel(field.name, true) + "ByKey(";
+ code += GenTypeGet(key_field.value.type) + " key)";
+ code += offset_prefix;
+ code += qualified_name + ".__lookup_by_key(";
+ code += "__p.__vector(o), key, ";
+ code += "__p.bb) : null; ";
+ code += "}\n";
+ break;
+ }
+ }
+ }
+ }
+ // Generate a ByteBuffer accessor for strings & vectors of scalars.
+ if ((IsVector(field.value.type) &&
+ IsScalar(field.value.type.VectorType().base_type)) ||
+ IsString(field.value.type)) {
+ code += "#if ENABLE_SPAN_T\n";
+ code += " public Span<" + GenTypeBasic(field.value.type.VectorType()) +
+ "> Get";
+ code += MakeCamel(field.name, true);
+ code += "Bytes() { return ";
+ code += "__p.__vector_as_span<" +
+ GenTypeBasic(field.value.type.VectorType()) + ">(";
+ code += NumToString(field.value.offset);
+ code +=
+ ", " + NumToString(SizeOf(field.value.type.VectorType().base_type));
+ code += "); }\n";
+ code += "#else\n";
+ code += " public ArraySegment<byte>? Get";
+ code += MakeCamel(field.name, true);
+ code += "Bytes() { return ";
+ code += "__p.__vector_as_arraysegment(";
+ code += NumToString(field.value.offset);
+ code += "); }\n";
+ code += "#endif\n";
+
+ // For direct blockcopying the data into a typed array
+ code += " public ";
+ code += GenTypeBasic(field.value.type.VectorType());
+ code += "[] Get";
+ code += MakeCamel(field.name, true);
+ code += "Array() { ";
+ if (IsEnum(field.value.type.VectorType())) {
+ // Since __vector_as_array does not work for enum types,
+ // fill array using an explicit loop.
+ code += "int o = __p.__offset(";
+ code += NumToString(field.value.offset);
+ code += "); if (o == 0) return null; int p = ";
+ code += "__p.__vector(o); int l = ";
+ code += "__p.__vector_len(o); ";
+ code += GenTypeBasic(field.value.type.VectorType());
+ code += "[] a = new ";
+ code += GenTypeBasic(field.value.type.VectorType());
+ code += "[l]; for (int i = 0; i < l; i++) { a[i] = " + getter;
+ code += "(p + i * ";
+ code += NumToString(InlineSize(field.value.type.VectorType()));
+ code += "); } return a;";
+ } else {
+ code += "return ";
+ code += "__p.__vector_as_array<";
+ code += GenTypeBasic(field.value.type.VectorType());
+ code += ">(";
+ code += NumToString(field.value.offset);
+ code += ");";
+ }
+ code += " }\n";
+ }
+ // 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, true) + "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 + "?)";
+ obj = "(new " + nested_type_name + "())";
+ code += " public " + nested_type_name + "? ";
+ code += get_nested_method_name + "(";
+ code += ") { int o = __p.__offset(";
+ code += NumToString(field.value.offset) + "); ";
+ code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
+ code += "__p.";
+ code += "__indirect(__p.__vector(o)), ";
+ code += "__p.bb) : null; }\n";
+ }
+ // Generate mutators for scalar fields or vectors of scalars.
+ if (parser_.opts.mutable_buffer) {
+ auto is_series = (IsSeries(field.value.type));
+ const auto &underlying_type =
+ 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);
+ // 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 +
+ ") { ";
+ auto setter_index =
+ is_series
+ ? "__p." +
+ (IsArray(field.value.type)
+ ? "bb_pos + " + NumToString(field.value.offset)
+ : "__vector(o)") +
+ +" + j * " + NumToString(InlineSize(underlying_type))
+ : (struct_def.fixed
+ ? "__p.bb_pos + " + NumToString(field.value.offset)
+ : "o + __p.bb_pos");
+ 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_params;
+ if (struct_def.fixed) {
+ code += GenSetter(underlying_type) + "(" + setter_index + ", ";
+ code += src_cast + setter_parameter + "); }\n";
+ } else {
+ code += "int o = __p.__offset(";
+ code += NumToString(field.value.offset) + ");";
+ code += " if (o != 0) { " + GenSetter(underlying_type);
+ code += "(" + setter_index + ", " + src_cast + setter_parameter +
+ "); return true; } else { return false; } }\n";
+ }
+ }
+ }
+ 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) + ";";
+
+ 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(struct_def) + " ";
+ code += "Create";
+ code += struct_def.name + "(FlatBufferBuilder builder";
+ GenStructArgs(struct_def, code_ptr, "");
+ code += ") {\n";
+ GenStructBody(struct_def, code_ptr, "");
+ code += " return ";
+ code += GenOffsetConstruct(struct_def, "builder.Offset");
+ code += ";\n }\n";
+ } else {
+ // Generate a method that creates a table in one go. This is only possible
+ // when the table has no struct fields, since those have to be created
+ // inline, and there's no way to do so in Java.
+ bool has_no_struct_fields = true;
+ int num_fields = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (IsStruct(field.value.type)) {
+ has_no_struct_fields = false;
+ } else {
+ num_fields++;
+ }
+ }
+ // 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 || opts.generate_object_based_api) &&
+ 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(struct_def) + " ";
+ code += "Create" + struct_def.name;
+ code += "(FlatBufferBuilder builder";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code += ",\n ";
+ if (IsStruct(field.value.type) && opts.generate_object_based_api) {
+ code += WrapInNameSpace(
+ field.value.type.struct_def->defined_namespace,
+ GenTypeName_ObjectAPI(field.value.type.struct_def->name, opts));
+ code += " ";
+ code += field.name;
+ code += " = null";
+ } else {
+ code += GenTypeBasic(field.value.type);
+ if (field.IsScalarOptional()) { code += "?"; }
+ code += " ";
+ code += field.name;
+ if (!IsScalar(field.value.type.base_type)) code += "Offset";
+
+ code += " = ";
+ code += GenDefaultValueBasic(field);
+ }
+ }
+ code += ") {\n builder.";
+ code += "StartTable(";
+ code += NumToString(struct_def.fields.vec.size()) + ");\n";
+ for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+ size; size /= 2) {
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated &&
+ (!struct_def.sortbysize ||
+ size == SizeOf(field.value.type.base_type))) {
+ code += " " + struct_def.name + ".";
+ code += "Add";
+ code += MakeCamel(field.name) + "(builder, ";
+ if (IsStruct(field.value.type) &&
+ opts.generate_object_based_api) {
+ code += GenTypePointer(field.value.type) + ".Pack(builder, " +
+ field.name + ")";
+ } else {
+ code += field.name;
+ if (!IsScalar(field.value.type.base_type)) code += "Offset";
+ }
+
+ code += ");\n";
+ }
+ }
+ }
+ code += " return " + struct_def.name + ".";
+ code += "End" + struct_def.name;
+ code += "(builder);\n }\n\n";
+ }
+ // Generate a set of static methods that allow table construction,
+ // of the form:
+ // public static void addName(FlatBufferBuilder builder, short name)
+ // { builder.addShort(id, name, default); }
+ // Unlike the Create function, these always work.
+ code += " public static void Start";
+ code += struct_def.name;
+ code += "(FlatBufferBuilder builder) { builder.";
+ code += "StartTable(";
+ code += NumToString(struct_def.fields.vec.size()) + "); }\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.key) key_field = &field;
+ code += " public static void Add";
+ code += MakeCamel(field.name);
+ code += "(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(field.value.type);
+ auto argname = MakeCamel(field.name, false);
+ if (!IsScalar(field.value.type.base_type)) argname += "Offset";
+ if (field.IsScalarOptional()) { code += "?"; }
+ code += " " + argname + ") { builder.Add";
+ code += GenMethod(field.value.type) + "(";
+ code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
+ code += SourceCastBasic(field.value.type);
+ code += argname;
+ if (!IsScalar(field.value.type.base_type) &&
+ field.value.type.base_type != BASE_TYPE_UNION) {
+ code += ".Value";
+ }
+ if (!field.IsScalarOptional()) {
+ // When the scalar is optional, use the builder method that doesn't
+ // supply a default value. Otherwise, we to continue to use the
+ // default value method.
+ code += ", ";
+ code += GenDefaultValue(field, false);
+ }
+ code += "); }\n";
+ if (IsVector(field.value.type)) {
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ if (!IsStruct(vector_type)) {
+ field_has_create_set.insert(&field);
+ code += " public static VectorOffset ";
+ code += "Create";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(vector_type) + "[] data) ";
+ code += "{ builder.StartVector(";
+ code += NumToString(elem_size);
+ code += ", data.Length, ";
+ code += NumToString(alignment);
+ code += "); for (int i = data.";
+ code += "Length - 1; i >= 0; i--) builder.";
+ code += "Add";
+ code += GenMethod(vector_type);
+ code += "(";
+ code += SourceCastBasic(vector_type);
+ code += "data[i]";
+ if (vector_type.base_type == BASE_TYPE_STRUCT ||
+ IsString(vector_type))
+ code += ".Value";
+ code += "); return ";
+ code += "builder.EndVector(); }\n";
+
+ code += " public static VectorOffset ";
+ code += "Create";
+ code += MakeCamel(field.name);
+ code += "VectorBlock(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(vector_type) + "[] data) ";
+ code += "{ builder.StartVector(";
+ code += NumToString(elem_size);
+ code += ", data.Length, ";
+ code += NumToString(alignment);
+ code += "); builder.Add(data); return builder.EndVector(); }\n";
+ }
+ // Generate a method to start a vector, data to be added manually
+ // after.
+ code += " public static void Start";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, int numElems) ";
+ code += "{ builder.StartVector(";
+ code += NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment);
+ code += "); }\n";
+ }
+ }
+ code += " public static " + GenOffsetType(struct_def) + " ";
+ code += "End" + struct_def.name;
+ code += "(FlatBufferBuilder builder) {\n int o = builder.";
+ code += "EndTable();\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.Required(o, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
+ std::string size_prefix[] = { "", "SizePrefixed" };
+ for (int i = 0; i < 2; ++i) {
+ code += " public static void ";
+ code += "Finish" + size_prefix[i] + struct_def.name;
+ code +=
+ "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def);
+ code += " offset) {";
+ code += " builder.Finish" + size_prefix[i] + "(offset";
+ code += ".Value";
+
+ if (parser_.file_identifier_.length())
+ code += ", \"" + parser_.file_identifier_ + "\"";
+ code += "); }\n";
+ }
+ }
+ }
+ // Only generate key compare function for table,
+ // because `key_field` is not set for struct
+ if (struct_def.has_key && !struct_def.fixed) {
+ FLATBUFFERS_ASSERT(key_field);
+ code += "\n public static VectorOffset ";
+ code += "CreateSortedVectorOf" + struct_def.name;
+ code += "(FlatBufferBuilder builder, ";
+ code += "Offset<" + struct_def.name + ">";
+ code += "[] offsets) {\n";
+ code += " Array.Sort(offsets, (Offset<" + struct_def.name +
+ "> o1, Offset<" + struct_def.name + "> o2) => " +
+ GenKeyGetter(key_field);
+ code += ");\n";
+ code += " return builder.CreateVectorOfTables(offsets);\n }\n";
+
+ code += "\n public static " + struct_def.name + "?";
+ code += " __lookup_by_key(";
+ code += "int vectorLocation, ";
+ code += GenTypeGet(key_field->value.type);
+ code += " key, ByteBuffer bb) {\n";
+ if (IsString(key_field->value.type)) {
+ code += " byte[] byteKey = ";
+ code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
+ }
+ code += " int span = ";
+ code += "bb.GetInt(vectorLocation - 4);\n";
+ code += " int start = 0;\n";
+ code += " while (span != 0) {\n";
+ code += " int middle = span / 2;\n";
+ code += GenLookupKeyGetter(key_field);
+ code += " if (comp > 0) {\n";
+ code += " span = middle;\n";
+ code += " } else if (comp < 0) {\n";
+ code += " middle++;\n";
+ code += " start += middle;\n";
+ code += " span -= middle;\n";
+ code += " } else {\n";
+ code += " return ";
+ code += "new " + struct_def.name + "()";
+ code += ".__assign(tableOffset, bb);\n";
+ code += " }\n }\n";
+ code += " return null;\n";
+ code += " }\n";
+ }
+
+ if (opts.generate_object_based_api) {
+ GenPackUnPack_ObjectAPI(struct_def, code_ptr, opts, struct_has_create,
+ field_has_create_set);
+ }
+ code += "};\n\n";
+
+ if (opts.generate_object_based_api) {
+ GenStruct_ObjectAPI(struct_def, code_ptr, opts);
+ }
+ }
+
+ void GenVectorAccessObject(StructDef &struct_def,
+ std::string *code_ptr) const {
+ auto &code = *code_ptr;
+ // Generate a vector of structs accessor class.
+ code += "\n";
+ code += " ";
+ if (!struct_def.attributes.Lookup("private")) code += "public ";
+ code += "static struct Vector : BaseVector\n{\n";
+
+ // Generate the __assign method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ std::string method_indent = " ";
+ code += method_indent + "public Vector ";
+ code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { ";
+ code += "__reset(_vector, _element_size, _bb); return this; }\n\n";
+
+ auto type_name = struct_def.name;
+ auto method_start = method_indent + "public " + type_name + " Get";
+ // Generate the accessors that don't do object reuse.
+ code += method_start + "(int j) { return Get";
+ code += "(new " + type_name + "(), j); }\n";
+ code += method_start + "(" + type_name + " obj, int j) { ";
+ code += " return obj.__assign(";
+ code += struct_def.fixed ? "__p.__element(j)"
+ : "__p.__indirect(__p.__element(j), bb)";
+ code += ", __p.bb); }\n";
+ // See if we should generate a by-key accessor.
+ if (!struct_def.fixed) {
+ auto &fields = struct_def.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ auto nullable_annotation =
+ parser_.opts.gen_nullable ? "@Nullable " : "";
+ code += method_indent + nullable_annotation;
+ code += "public " + type_name + "? ";
+ code += "GetByKey(";
+ code += GenTypeGet(key_field.value.type) + " key) { ";
+ code += " return __lookup_by_key(null, ";
+ code += "__p.__vector(), key, ";
+ code += "__p.bb); ";
+ code += "}\n";
+ code += method_indent + nullable_annotation;
+ code += "public " + type_name + "?" + " ";
+ code += "GetByKey(";
+ code += type_name + "? obj, ";
+ code += GenTypeGet(key_field.value.type) + " key) { ";
+ code += " return __lookup_by_key(obj, ";
+ code += "__p.__vector(), key, ";
+ code += "__p.bb); ";
+ code += "}\n";
+ break;
+ }
+ }
+ }
+ code += " }\n";
+ }
+
+ void GenEnum_ObjectAPI(EnumDef &enum_def, std::string *code_ptr,
+ const IDLOptions &opts) const {
+ auto &code = *code_ptr;
+ if (enum_def.generated) return;
+ if (!enum_def.is_union) return;
+ if (enum_def.attributes.Lookup("private")) {
+ code += "internal ";
+ } else {
+ code += "public ";
+ }
+ auto union_name = enum_def.name + "Union";
+ code += "class " + union_name + " {\n";
+ // Type
+ code += " public " + enum_def.name + " Type { get; set; }\n";
+ // Value
+ code += " public object Value { get; set; }\n";
+ code += "\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<T>
+ code += " public T As<T>() where T : class { return this.Value as T; }\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);
+ 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";
+ }
+ code += "\n";
+ // Pack()
+ code += " public static int Pack(FlatBuffers.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) {
+ code += " default: return 0;\n";
+ } else {
+ code += " case " + enum_def.name + "." + ev.name + ": return ";
+ if (IsString(ev.union_type)) {
+ code += "builder.CreateString(_o.As" + ev.name + "()).Value;\n";
+ } else {
+ code += GenTypeGet(ev.union_type) + ".Pack(builder, _o.As" + ev.name +
+ "()).Value;\n";
+ }
+ }
+ }
+ code += " }\n";
+ code += " }\n";
+ code += "}\n\n";
+ // JsonConverter
+ if (opts.cs_gen_json_serializer) {
+ if (enum_def.attributes.Lookup("private")) {
+ code += "internal ";
+ } else {
+ code += "public ";
+ }
+ code += "class " + union_name +
+ "_JsonConverter : Newtonsoft.Json.JsonConverter {\n";
+ code += " public override bool CanConvert(System.Type objectType) {\n";
+ code += " return objectType == typeof(" + union_name +
+ ") || objectType == typeof(System.Collections.Generic.List<" +
+ union_name + ">);\n";
+ code += " }\n";
+ code +=
+ " public override void WriteJson(Newtonsoft.Json.JsonWriter writer, "
+ "object value, "
+ "Newtonsoft.Json.JsonSerializer serializer) {\n";
+ code += " var _olist = value as System.Collections.Generic.List<" +
+ union_name + ">;\n";
+ code += " if (_olist != null) {\n";
+ code += " writer.WriteStartArray();\n";
+ code +=
+ " foreach (var _o in _olist) { this.WriteJson(writer, _o, "
+ "serializer); }\n";
+ code += " writer.WriteEndArray();\n";
+ code += " } else {\n";
+ code += " this.WriteJson(writer, value as " + union_name +
+ ", serializer);\n";
+ code += " }\n";
+ code += " }\n";
+ code += " public void WriteJson(Newtonsoft.Json.JsonWriter writer, " +
+ union_name +
+ " _o, "
+ "Newtonsoft.Json.JsonSerializer serializer) {\n";
+ code += " if (_o == null) return;\n";
+ code += " serializer.Serialize(writer, _o.Value);\n";
+ code += " }\n";
+ code +=
+ " public override object ReadJson(Newtonsoft.Json.JsonReader "
+ "reader, "
+ "System.Type objectType, "
+ "object existingValue, Newtonsoft.Json.JsonSerializer serializer) "
+ "{\n";
+ code +=
+ " var _olist = existingValue as System.Collections.Generic.List<" +
+ union_name + ">;\n";
+ code += " if (_olist != null) {\n";
+ code += " for (var _j = 0; _j < _olist.Count; ++_j) {\n";
+ code += " reader.Read();\n";
+ code +=
+ " _olist[_j] = this.ReadJson(reader, _olist[_j], "
+ "serializer);\n";
+ code += " }\n";
+ code += " reader.Read();\n";
+ code += " return _olist;\n";
+ code += " } else {\n";
+ code += " return this.ReadJson(reader, existingValue as " +
+ union_name + ", serializer);\n";
+ code += " }\n";
+ code += " }\n";
+ code += " public " + union_name +
+ " ReadJson(Newtonsoft.Json.JsonReader reader, " + union_name +
+ " _o, Newtonsoft.Json.JsonSerializer serializer) {\n";
+ code += " if (_o == null) return null;\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) {
+ code += " default: break;\n";
+ } else {
+ auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts);
+ code += " case " + enum_def.name + "." + ev.name +
+ ": _o.Value = serializer.Deserialize<" + type_name +
+ ">(reader); break;\n";
+ }
+ }
+ code += " }\n";
+ code += " return _o;\n";
+ code += " }\n";
+ code += "}\n\n";
+ }
+ }
+
+ 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 &camel_name,
+ bool is_vector) const {
+ auto &code = *code_ptr;
+ std::string varialbe_name = "_o." + camel_name;
+ std::string type_suffix = "";
+ std::string func_suffix = "()";
+ std::string indent = " ";
+ if (is_vector) {
+ varialbe_name = "_o_" + camel_name;
+ type_suffix = "(_j)";
+ func_suffix = "(_j)";
+ indent = " ";
+ }
+ if (is_vector) {
+ code += indent + "var " + varialbe_name + " = new ";
+ } else {
+ code += indent + varialbe_name + " = new ";
+ }
+ code += WrapInNameSpace(enum_def) + "Union();\n";
+ code += indent + varialbe_name + ".Type = this." + camel_name + "Type" +
+ type_suffix + ";\n";
+ code +=
+ indent + "switch (this." + camel_name + "Type" + type_suffix + ") {\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) {
+ code += indent + " default: break;\n";
+ } else {
+ code += indent + " case " + WrapInNameSpace(enum_def) + "." + ev.name +
+ ":\n";
+ code += indent + " " + varialbe_name + ".Value = this." + camel_name;
+ if (IsString(ev.union_type)) {
+ code += "AsString" + func_suffix + ";\n";
+ } else {
+ code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix;
+ code += ".HasValue ? this." + camel_name;
+ code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix +
+ ".Value.UnPack() : null;\n";
+ }
+ code += indent + " break;\n";
+ }
+ }
+ code += indent + "}\n";
+ if (is_vector) {
+ code += indent + "_o." + camel_name + ".Add(" + varialbe_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 += " var _o = new " + struct_name + "();\n";
+ code += " this.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;
+ auto camel_name = MakeCamel(field.name);
+ auto start = " _o." + camel_name + " = ";
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ auto fixed = struct_def.fixed && field.value.type.struct_def->fixed;
+ if (fixed) {
+ code += start + "this." + camel_name + ".UnPack();\n";
+ } else {
+ code += start + "this." + camel_name + ".HasValue ? this." +
+ camel_name + ".Value.UnPack() : null;\n";
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
+ auto length_str = NumToString(field.value.type.fixed_length);
+ auto unpack_method = field.value.type.struct_def == nullptr
+ ? ""
+ : field.value.type.struct_def->fixed
+ ? ".UnPack()"
+ : "?.UnPack()";
+ code += start + "new " + type_name.substr(0, type_name.length() - 1) +
+ length_str + "];\n";
+ code += " for (var _j = 0; _j < " + length_str + "; ++_j) { _o." +
+ camel_name + "[_j] = this." + camel_name + "(_j)" +
+ unpack_method + "; }\n";
+ break;
+ }
+ case BASE_TYPE_VECTOR:
+ if (field.value.type.element == BASE_TYPE_UNION) {
+ code += start + "new " +
+ GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n";
+ code += " for (var _j = 0; _j < this." + camel_name +
+ "Length; ++_j) {\n";
+ GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
+ 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 " +
+ GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n";
+ code += " for (var _j = 0; _j < this." + camel_name +
+ "Length; ++_j) {";
+ code += "_o." + camel_name + ".Add(";
+ if (fixed) {
+ code += "this." + camel_name + "(_j)";
+ } else {
+ code += "this." + camel_name + "(_j).HasValue ? this." +
+ camel_name + "(_j).Value.UnPack() : null";
+ }
+ code += ");}\n";
+ }
+ break;
+ case BASE_TYPE_UTYPE: break;
+ case BASE_TYPE_UNION: {
+ GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
+ camel_name, false);
+ break;
+ }
+ default: {
+ code += start + "this." + camel_name + ";\n";
+ break;
+ }
+ }
+ }
+ code += " }\n";
+ // Pack()
+ code += " public static " + GenOffsetType(struct_def) +
+ " Pack(FlatBufferBuilder builder, " + struct_name + " _o) {\n";
+ code += " if (_o == null) return default(" + GenOffsetType(struct_def) +
+ ");\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 = MakeCamel(field.name);
+ // pre
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ if (!field.value.type.struct_def->fixed) {
+ code += " var _" + field.name + " = _o." + camel_name +
+ " == null ? default(" +
+ GenOffsetType(*field.value.type.struct_def) +
+ ") : " + GenTypeGet(field.value.type) +
+ ".Pack(builder, _o." + camel_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 =
+ field.shared ? "CreateSharedString" : "CreateString";
+ code += " var _" + field.name + " = _o." + camel_name +
+ " == null ? default(StringOffset) : "
+ "builder." +
+ create_string + "(_o." + camel_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 = "__" + field.name;
+ std::string array_type = "";
+ std::string to_array = "";
+ switch (field.value.type.element) {
+ case BASE_TYPE_STRING: {
+ std::string create_string =
+ field.shared ? "CreateSharedString" : "CreateString";
+ array_type = "StringOffset";
+ to_array += "builder." + create_string + "(_o." +
+ property_name + "[_j])";
+ break;
+ }
+ case BASE_TYPE_STRUCT:
+ array_type = "Offset<" + GenTypeGet(field.value.type) + ">";
+ to_array = GenTypeGet(field.value.type) + ".Pack(builder, _o." +
+ property_name + "[_j])";
+ break;
+ case BASE_TYPE_UTYPE:
+ property_name = camel_name.substr(0, camel_name.size() - 4);
+ array_type = WrapInNameSpace(*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) +
+ "Union.Pack(builder, _o." + property_name + "[_j])";
+ break;
+ default: gen_for_loop = false; break;
+ }
+ code += " var _" + field.name + " = default(VectorOffset);\n";
+ code += " if (_o." + property_name + " != null) {\n";
+ if (gen_for_loop) {
+ code += " var " + array_name + " = new " + array_type +
+ "[_o." + property_name + ".Count];\n";
+ code += " for (var _j = 0; _j < " + array_name +
+ ".Length; ++_j) { ";
+ code += array_name + "[_j] = " + to_array + "; }\n";
+ } else {
+ code += " var " + array_name + " = _o." + property_name +
+ ".ToArray();\n";
+ }
+ code += " _" + field.name + " = Create" + camel_name +
+ "Vector(builder, " + array_name + ");\n";
+ code += " }\n";
+ } else {
+ auto pack_method =
+ field.value.type.struct_def == nullptr
+ ? "builder.Add" + GenMethod(field.value.type.VectorType()) +
+ "(_o." + camel_name + "[_j]);"
+ : GenTypeGet(field.value.type) + ".Pack(builder, _o." +
+ camel_name + "[_j]);";
+ code += " var _" + field.name + " = default(VectorOffset);\n";
+ code += " if (_o." + camel_name + " != null) {\n";
+ code += " Start" + camel_name + "Vector(builder, _o." +
+ camel_name + ".Count);\n";
+ code += " for (var _j = _o." + camel_name +
+ ".Count - 1; _j >= 0; --_j) { " + pack_method + " }\n";
+ code += " _" + field.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 += " var _" + field.name + " = _o." + camel_name + ";\n";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ code += " var _" + field.name + "_type = _o." + camel_name +
+ " == null ? " + WrapInNameSpace(*field.value.type.enum_def) +
+ ".NONE : " + "_o." + camel_name + ".Type;\n";
+ code +=
+ " var _" + field.name + " = _o." + camel_name +
+ " == null ? 0 : " + GenTypeGet_ObjectAPI(field.value.type, opts) +
+ ".Pack(builder, _o." + camel_name + ");\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 = MakeCamel(field.name);
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ if (struct_def.fixed) {
+ GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
+ code_ptr,
+ " _" + field.name + "_");
+ } else {
+ code += ",\n";
+ if (field.value.type.struct_def->fixed) {
+ if (opts.generate_object_based_api)
+ code += " _o." + camel_name;
+ else
+ 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,
+ " _" + field.name + "_");
+ } else {
+ code += ",\n";
+ code += " _" + field.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 += " _" + field.name;
+ break;
+ }
+ default: // scalar
+ code += ",\n";
+ code += " _o." + camel_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 = MakeCamel(field.name);
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ if (field.value.type.struct_def->fixed) {
+ code += " Add" + camel_name + "(builder, " +
+ GenTypeGet(field.value.type) + ".Pack(builder, _o." +
+ camel_name + "));\n";
+ } else {
+ code +=
+ " Add" + camel_name + "(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 + "(builder, _" + field.name + ");\n";
+ break;
+ }
+ case BASE_TYPE_UTYPE: break;
+ case BASE_TYPE_UNION: {
+ code += " Add" + camel_name + "Type(builder, _" + field.name +
+ "_type);\n";
+ code +=
+ " Add" + camel_name + "(builder, _" + field.name + ");\n";
+ break;
+ }
+ // scalar
+ default: {
+ code +=
+ " Add" + camel_name + "(builder, _o." + camel_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 += "_" + array_lengths[i].name;
+ }
+ code += " var " + name + " = ";
+ if (array_only_lengths.size() > 0) {
+ 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 (var " + 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 += "." + MakeCamel(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 += "_o";
+ for (size_t i = 0; i < array_lengths.size(); ++i) {
+ code += "." + MakeCamel(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 + field.name + "_");
+ } else {
+ code += ",\n";
+ code += prefix + field.name;
+ }
+ }
+ }
+
+ std::string GenTypeGet_ObjectAPI(flatbuffers::Type type,
+ const IDLOptions &opts) const {
+ auto type_name = GenTypeGet(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: {
+ type_name = type_name + "[]";
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ type_name = "List<" + type_name + ">";
+ break;
+ }
+ default: break;
+ }
+ return type_name;
+ }
+
+ void GenStruct_ObjectAPI(StructDef &struct_def, std::string *code_ptr,
+ const IDLOptions &opts) const {
+ auto &code = *code_ptr;
+ if (struct_def.attributes.Lookup("private")) {
+ code += "internal ";
+ } else {
+ code += "public ";
+ }
+ if (struct_def.attributes.Lookup("csharp_partial")) {
+ // generate a partial class for this C# struct/table
+ code += "partial ";
+ }
+ auto class_name = GenTypeName_ObjectAPI(struct_def.name, opts);
+ code += "class " + class_name;
+ code += "\n{\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);
+ if (field.IsScalarOptional()) type_name += "?";
+ auto camel_name = MakeCamel(field.name, true);
+ if (opts.cs_gen_json_serializer) {
+ if (IsUnion(field.value.type)) {
+ auto utype_name = WrapInNameSpace(*field.value.type.enum_def);
+ code +=
+ " [Newtonsoft.Json.JsonProperty(\"" + field.name + "_type\")]\n";
+ if (IsVector(field.value.type)) {
+ code += " private " + utype_name + "[] " + camel_name + "Type {\n";
+ code += " get {\n";
+ code += " if (this." + camel_name + " == null) return null;\n";
+ code += " var _o = new " + utype_name + "[this." + camel_name +
+ ".Count];\n";
+ code +=
+ " for (var _j = 0; _j < _o.Length; ++_j) { _o[_j] = "
+ "this." +
+ camel_name + "[_j].Type; }\n";
+ code += " return _o;\n";
+ code += " }\n";
+ code += " set {\n";
+ code += " this." + camel_name + " = new List<" + utype_name +
+ "Union>();\n";
+ code += " for (var _j = 0; _j < value.Length; ++_j) {\n";
+ code += " var _o = new " + utype_name + "Union();\n";
+ code += " _o.Type = value[_j];\n";
+ code += " this." + camel_name + ".Add(_o);\n";
+ code += " }\n";
+ code += " }\n";
+ code += " }\n";
+ } else {
+ code += " private " + utype_name + " " + camel_name + "Type {\n";
+ code += " get {\n";
+ code += " return this." + camel_name + " != null ? this." +
+ camel_name + ".Type : " + utype_name + ".NONE;\n";
+ code += " }\n";
+ code += " set {\n";
+ code += " this." + camel_name + " = new " + utype_name +
+ "Union();\n";
+ code += " this." + camel_name + ".Type = value;\n";
+ code += " }\n";
+ code += " }\n";
+ }
+ }
+ code += " [Newtonsoft.Json.JsonProperty(\"" + field.name + "\")]\n";
+ if (IsUnion(field.value.type)) {
+ auto union_name =
+ (IsVector(field.value.type))
+ ? GenTypeGet_ObjectAPI(field.value.type.VectorType(), opts)
+ : type_name;
+ code += " [Newtonsoft.Json.JsonConverter(typeof(" + union_name +
+ "_JsonConverter))]\n";
+ }
+ if (field.attributes.Lookup("hash")) {
+ code += " [Newtonsoft.Json.JsonIgnore()]\n";
+ }
+ }
+ code += " public " + type_name + " " + camel_name + " { get; set; }\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." + MakeCamel(field.name) + " = ";
+ auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
+ if (IsScalar(field.value.type.base_type)) {
+ 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";
+ // Generate Serialization
+ if (opts.cs_gen_json_serializer &&
+ parser_.root_struct_def_ == &struct_def) {
+ code += "\n";
+ code += " public static " + class_name +
+ " DeserializeFromJson(string jsonText) {\n";
+ code += " return Newtonsoft.Json.JsonConvert.DeserializeObject<" +
+ class_name + ">(jsonText);\n";
+ code += " }\n";
+ code += " public string SerializeToJson() {\n";
+ code +=
+ " return Newtonsoft.Json.JsonConvert.SerializeObject(this, "
+ "Newtonsoft.Json.Formatting.Indented);\n";
+ 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 +
+ "(new ByteBuffer(fbBuffer)).UnPack();\n";
+ code += " }\n";
+ code += " public byte[] SerializeToBinary() {\n";
+ code += " var fbb = new FlatBufferBuilder(0x10000);\n";
+ code += " " + struct_def.name + ".Finish" + struct_def.name +
+ "Buffer(fbb, " + struct_def.name + ".Pack(fbb, this));\n";
+ code += " return fbb.DataBuffer.ToSizedArray();\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_;
+};
+} // namespace csharp
+
+bool GenerateCSharp(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ csharp::CSharpGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_dart.cpp b/contrib/libs/flatbuffers/src/idl_gen_dart.cpp
new file mode 100644
index 0000000000..56c4a82555
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_dart.cpp
@@ -0,0 +1,955 @@
+/*
+ * Copyright 2018 Dan Field
+ *
+ * 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 <cassert>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+namespace dart {
+
+const std::string _kFb = "fb";
+// see https://www.dartlang.org/guides/language/language-tour#keywords
+// yeild*, async*, and sync* shouldn't be problems anyway but keeping them in
+static const char *keywords[] = {
+ "abstract", "deferred", "if", "super", "as", "do",
+ "implements", "switch", "assert", "dynamic", "import", "sync*",
+ "async", "else", "in", "this", "async*", "enum",
+ "is", "throw", "await", "export", "library", "true",
+ "break", "external", "new", "try", "case", "extends",
+ "null", "typedef", "catch", "factory", "operator", "var",
+ "class", "false", "part", "void", "const", "final",
+ "rethrow", "while", "continue", "finally", "return", "with",
+ "covariant", "for", "set", "yield", "default", "get",
+ "static", "yield*"
+};
+
+// Iterate through all definitions we haven't generate code for (enums, structs,
+// and tables) and output them to a single file.
+class DartGenerator : public BaseGenerator {
+ public:
+ typedef std::map<std::string, std::string> namespace_code_map;
+
+ DartGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", ".", "dart") {}
+ // Iterate through all definitions we haven't generate code for (enums,
+ // structs, and tables) and output them to a single file.
+ bool generate() {
+ std::string code;
+ namespace_code_map namespace_code;
+ GenerateEnums(&namespace_code);
+ GenerateStructs(&namespace_code);
+
+ for (auto kv = namespace_code.begin(); kv != namespace_code.end(); ++kv) {
+ code.clear();
+ code = code + "// " + FlatBuffersGeneratedWarning() + "\n";
+ code = code +
+ "// ignore_for_file: unused_import, unused_field, "
+ "unused_local_variable\n\n";
+
+ if (!kv->first.empty()) { code += "library " + kv->first + ";\n\n"; }
+
+ code += "import 'dart:typed_data' show Uint8List;\n";
+ code += "import 'package:flat_buffers/flat_buffers.dart' as " + _kFb +
+ ";\n\n";
+
+ for (auto kv2 = namespace_code.begin(); kv2 != namespace_code.end();
+ ++kv2) {
+ if (kv2->first != kv->first) {
+ code +=
+ "import '" +
+ GeneratedFileName(
+ "./",
+ file_name_ + (!kv2->first.empty() ? "_" + kv2->first : ""),
+ parser_.opts) +
+ "' as " + ImportAliasName(kv2->first) + ";\n";
+ }
+ }
+ code += "\n";
+ code += kv->second;
+
+ if (!SaveFile(
+ GeneratedFileName(
+ path_,
+ file_name_ + (!kv->first.empty() ? "_" + kv->first : ""),
+ parser_.opts)
+ .c_str(),
+ code, false)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ static std::string ImportAliasName(const std::string &ns) {
+ std::string ret;
+ ret.assign(ns);
+ size_t pos = ret.find('.');
+ while (pos != std::string::npos) {
+ ret.replace(pos, 1, "_");
+ pos = ret.find('.', pos + 1);
+ }
+
+ return ret;
+ }
+
+ static std::string BuildNamespaceName(const Namespace &ns) {
+ if (ns.components.empty()) { return ""; }
+ std::stringstream sstream;
+ std::copy(ns.components.begin(), ns.components.end() - 1,
+ std::ostream_iterator<std::string>(sstream, "."));
+
+ auto ret = sstream.str() + ns.components.back();
+ for (size_t i = 0; i < ret.size(); i++) {
+ auto lower = CharToLower(ret[i]);
+ if (lower != ret[i]) {
+ ret[i] = lower;
+ if (i != 0 && ret[i - 1] != '.') {
+ ret.insert(i, "_");
+ i++;
+ }
+ }
+ }
+ // std::transform(ret.begin(), ret.end(), ret.begin(), CharToLower);
+ return ret;
+ }
+
+ void GenIncludeDependencies(std::string *code,
+ const std::string &the_namespace) {
+ for (auto it = parser_.included_files_.begin();
+ it != parser_.included_files_.end(); ++it) {
+ if (it->second.empty()) continue;
+
+ auto noext = flatbuffers::StripExtension(it->second);
+ auto basename = flatbuffers::StripPath(noext);
+
+ *code +=
+ "import '" +
+ GeneratedFileName(
+ "", basename + (the_namespace == "" ? "" : "_" + the_namespace),
+ parser_.opts) +
+ "';\n";
+ }
+ }
+
+ 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); }
+ }
+
+ return MakeCamel(name, false);
+ }
+
+ void GenerateEnums(namespace_code_map *namespace_code) {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ GenEnum(enum_def, namespace_code); // enum_code_ptr);
+ }
+ }
+
+ void GenerateStructs(namespace_code_map *namespace_code) {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ GenStruct(struct_def, namespace_code);
+ }
+ }
+
+ // 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;
+ }
+
+ auto &code = *code_ptr;
+
+ 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;
+ }
+ }
+ }
+ }
+
+ static void GenDocComment(std::string *code_ptr,
+ const std::string &extra_lines) {
+ GenDocComment(std::vector<std::string>(), code_ptr, extra_lines);
+ }
+
+ // Generate an enum declaration and an enum string lookup table.
+ void GenEnum(EnumDef &enum_def, namespace_code_map *namespace_code) {
+ if (enum_def.generated) return;
+ auto ns = BuildNamespaceName(*enum_def.defined_namespace);
+ std::string code;
+ 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");
+
+ 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 += name + "');\n";
+ code += " }\n";
+
+ code += " return values[value];\n";
+ code += " }\n\n";
+
+ // this is meaningless for bit_flags
+ // however, note that unlike "regular" dart enums this enum can still have
+ // holes.
+ if (!is_bit_flags) {
+ code += " static const int minValue = " +
+ enum_def.ToString(*enum_def.MinValue()) + ";\n";
+ code += " static const int maxValue = " +
+ enum_def.ToString(*enum_def.MaxValue()) + ";\n";
+ }
+
+ code +=
+ " static bool containsValue(int value) =>"
+ " values.containsKey(value);\n\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, "", " ");
+ }
+ code += " static const " + name + " " + ev.name + " = ";
+ code += "const " + name + "._(" + enum_def.ToString(ev) + ");\n";
+ }
+
+ code += " static const Map<int," + name + "> values = {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ code += enum_def.ToString(ev) + ": " + ev.name + ",";
+ }
+ code += "};\n\n";
+
+ code += " static const " + _kFb + ".Reader<" + name +
+ "> reader = const _" + name + "Reader();\n\n";
+ code += " @override\n";
+ code += " String toString() {\n";
+ code += " return '" + name + "{value: $value}';\n";
+ code += " }\n";
+ code += "}\n\n";
+
+ GenEnumReader(enum_def, name, &code);
+ (*namespace_code)[ns] += code;
+ }
+
+ void GenEnumReader(EnumDef &enum_def, const std::string &name,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ code += "class _" + name + "Reader extends " + _kFb + ".Reader<" + name +
+ "> {\n";
+ code += " const _" + name + "Reader();\n\n";
+ code += " @override\n";
+ code += " int get size => 1;\n\n";
+ code += " @override\n";
+ code +=
+ " " + name + " read(" + _kFb + ".BufferContext bc, int offset) =>\n";
+ code += " new " + name + ".fromValue(const " + _kFb + "." +
+ GenType(enum_def.underlying_type) + "Reader().read(bc, offset));\n";
+ code += "}\n\n";
+ }
+
+ static std::string GenType(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_BOOL: return "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;
+ case BASE_TYPE_UNION: return type.enum_def->name + "TypeId";
+ default: return "Table";
+ }
+ }
+
+ std::string GenReaderTypeName(const Type &type, Namespace *current_namespace,
+ const FieldDef &def,
+ bool parent_is_vector = false) {
+ if (type.base_type == BASE_TYPE_BOOL) {
+ return "const " + _kFb + ".BoolReader()";
+ } else if (IsVector(type)) {
+ return "const " + _kFb + ".ListReader<" +
+ GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
+ GenReaderTypeName(type.VectorType(), current_namespace, def,
+ true) +
+ ")";
+ } else if (IsString(type)) {
+ return "const " + _kFb + ".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()";
+ } else {
+ return GenDartTypeName(type, current_namespace, def) + ".reader";
+ }
+ }
+
+ std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
+ const FieldDef &def, bool addBuilder = false) {
+ if (type.enum_def) {
+ if (type.enum_def->is_union && type.base_type != BASE_TYPE_UNION) {
+ return type.enum_def->name + "TypeId";
+ } else if (type.enum_def->is_union) {
+ return "dynamic";
+ } else if (type.base_type != BASE_TYPE_VECTOR) {
+ return type.enum_def->name;
+ }
+ }
+
+ switch (type.base_type) {
+ case BASE_TYPE_BOOL: return "bool";
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG:
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT:
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_UCHAR: return "int";
+ case BASE_TYPE_FLOAT:
+ 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);
+ case BASE_TYPE_VECTOR:
+ return "List<" +
+ GenDartTypeName(type.VectorType(), current_namespace, def,
+ addBuilder) +
+ ">";
+ default: assert(0); return "dynamic";
+ }
+ }
+
+ static const std::string MaybeWrapNamespace(const std::string &type_name,
+ Namespace *current_ns,
+ const FieldDef &field) {
+ auto curr_ns_str = BuildNamespaceName(*current_ns);
+ std::string field_ns_str = "";
+ if (field.value.type.struct_def) {
+ field_ns_str +=
+ BuildNamespaceName(*field.value.type.struct_def->defined_namespace);
+ } else if (field.value.type.enum_def) {
+ field_ns_str +=
+ BuildNamespaceName(*field.value.type.enum_def->defined_namespace);
+ }
+
+ if (field_ns_str != "" && field_ns_str != curr_ns_str) {
+ return ImportAliasName(field_ns_str) + "." + type_name;
+ } else {
+ return type_name;
+ }
+ }
+
+ // Generate an accessor struct with constructor for a flatbuffers struct.
+ void GenStruct(const StructDef &struct_def,
+ namespace_code_map *namespace_code) {
+ if (struct_def.generated) return;
+
+ auto object_namespace = BuildNamespaceName(*struct_def.defined_namespace);
+ std::string code;
+
+ const auto &object_name = struct_def.name;
+
+ // Emit constructor
+
+ GenDocComment(struct_def.doc_comment, &code, "");
+
+ auto reader_name = "_" + object_name + "Reader";
+ auto builder_name = object_name + "Builder";
+ auto object_builder_name = object_name + "ObjectBuilder";
+
+ std::string reader_code, builder_code;
+
+ code += "class " + object_name + " {\n";
+
+ 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 += " return reader.read(rootRef, 0);\n";
+ code += " }\n";
+ }
+
+ code += "\n";
+ code += " static const " + _kFb + ".Reader<" + object_name +
+ "> reader = const " + reader_name + "();\n\n";
+
+ code += " final " + _kFb + ".BufferContext _bc;\n";
+ code += " final int _bcOffset;\n\n";
+
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto offset = static_cast<int>(it - struct_def.fields.vec.begin());
+ non_deprecated_fields.push_back(std::make_pair(offset, &field));
+ }
+
+ GenImplementationGetters(struct_def, non_deprecated_fields, &code);
+
+ code += "}\n\n";
+
+ 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,
+ &builder_code);
+
+ code += reader_code;
+ code += builder_code;
+
+ (*namespace_code)[object_namespace] += code;
+ }
+
+ std::string NamespaceAliasFromUnionType(Namespace *root_namespace,
+ const Type &type) {
+ const std::vector<std::string> qualified_name_parts =
+ type.struct_def->defined_namespace->components;
+ if (std::equal(root_namespace->components.begin(),
+ root_namespace->components.end(),
+ qualified_name_parts.begin())) {
+ return type.struct_def->name;
+ }
+
+ std::string ns;
+
+ for (auto it = qualified_name_parts.begin();
+ it != qualified_name_parts.end(); ++it) {
+ auto &part = *it;
+
+ for (size_t i = 0; i < part.length(); i++) {
+ if (i && !isdigit(part[i]) && part[i] == CharToUpper(part[i])) {
+ ns += "_";
+ ns += CharToLower(part[i]);
+ } else {
+ ns += CharToLower(part[i]);
+ }
+ }
+ if (it != qualified_name_parts.end() - 1) { ns += "_"; }
+ }
+
+ return ns + "." + type.struct_def->name;
+ }
+
+ void GenImplementationGetters(
+ const StructDef &struct_def,
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ 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);
+
+ GenDocComment(field.doc_comment, &code, "", " ");
+
+ code += " " + type_name + " get " + field_name;
+ if (field.value.type.base_type == BASE_TYPE_UNION) {
+ code += " {\n";
+ code += " switch (" + field_name + "Type?.value) {\n";
+ auto &enum_def = *field.value.type.enum_def;
+ for (auto en_it = enum_def.Vals().begin() + 1;
+ en_it != enum_def.Vals().end(); ++en_it) {
+ auto &ev = **en_it;
+
+ 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";
+ }
+ code += " default: return null;\n";
+ code += " }\n";
+ code += " }\n";
+ } else {
+ code += " => ";
+ if (field.value.type.enum_def &&
+ field.value.type.base_type != BASE_TYPE_VECTOR) {
+ code += "new " +
+ GenDartTypeName(field.value.type,
+ struct_def.defined_namespace, field) +
+ ".fromValue(";
+ }
+
+ code += GenReaderTypeName(field.value.type,
+ struct_def.defined_namespace, field);
+ if (struct_def.fixed) {
+ 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;
+ }
+ } else {
+ if (IsBool(field.value.type.base_type)) {
+ code += "false";
+ } else if (IsScalar(field.value.type.base_type)) {
+ code += "0";
+ } else {
+ code += "null";
+ }
+ }
+ code += ")";
+ }
+ if (field.value.type.enum_def &&
+ field.value.type.base_type != BASE_TYPE_VECTOR) {
+ code += ")";
+ }
+ code += ";\n";
+ }
+ }
+
+ code += "\n";
+
+ code += " @override\n";
+ code += " String toString() {\n";
+ code += " return '" + struct_def.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);
+ if (it != non_deprecated_fields.end() - 1) { code += ", "; }
+ }
+ code += "}';\n";
+ code += " }\n";
+ }
+
+ void GenReader(const StructDef &struct_def, std::string *reader_name_ptr,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto &reader_name = *reader_name_ptr;
+ auto &impl_name = struct_def.name;
+
+ code += "class " + reader_name + " extends " + _kFb;
+ if (struct_def.fixed) {
+ code += ".StructReader<";
+ } else {
+ code += ".TableReader<";
+ }
+ code += impl_name + "> {\n";
+ code += " const " + reader_name + "();\n\n";
+
+ if (struct_def.fixed) {
+ code += " @override\n";
+ code += " int get size => " + NumToString(struct_def.bytesize) + ";\n\n";
+ }
+ code += " @override\n";
+ code += " " + impl_name +
+ " createObject(fb.BufferContext bc, int offset) => \n new " +
+ impl_name + "._(bc, offset);\n";
+ code += "}\n\n";
+ }
+
+ void GenBuilder(const StructDef &struct_def,
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *builder_name_ptr, std::string *code_ptr) {
+ if (non_deprecated_fields.size() == 0) { return; }
+ auto &code = *code_ptr;
+ 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 += " final " + _kFb + ".Builder fbBuilder;\n\n";
+
+ if (struct_def.fixed) {
+ StructBuilderBody(struct_def, non_deprecated_fields, code_ptr);
+ } else {
+ TableBuilderBody(struct_def, non_deprecated_fields, code_ptr);
+ }
+
+ code += "}\n\n";
+ }
+
+ void StructBuilderBody(
+ const StructDef &struct_def,
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ code += " int finish(";
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+
+ if (IsStruct(field.value.type)) {
+ code += "fb.StructBuilder";
+ } else {
+ code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field);
+ }
+ code += " " + field.name;
+ if (it != non_deprecated_fields.end() - 1) { code += ", "; }
+ }
+ code += ") {\n";
+
+ for (auto it = non_deprecated_fields.rbegin();
+ it != non_deprecated_fields.rend(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+
+ if (field.padding) {
+ code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
+ }
+
+ if (IsStruct(field.value.type)) {
+ code += " " + field.name + "();\n";
+ } else {
+ code += " fbBuilder.put" + GenType(field.value.type) + "(";
+ code += field.name;
+ if (field.value.type.enum_def) { code += "?.value"; }
+ code += ");\n";
+ }
+ }
+ code += " return fbBuilder.offset;\n";
+ code += " }\n\n";
+ }
+
+ void TableBuilderBody(
+ const StructDef &struct_def,
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ code += " void begin() {\n";
+ code += " fbBuilder.startTable();\n";
+ code += " }\n\n";
+
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+ auto offset = pair.first;
+
+ if (IsScalar(field.value.type.base_type)) {
+ code += " int add" + MakeCamel(field.name) + "(";
+ code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field);
+ code += " " + MakeCamel(field.name, false) + ") {\n";
+ code += " fbBuilder.add" + GenType(field.value.type) + "(" +
+ NumToString(offset) + ", ";
+ code += MakeCamel(field.name, false);
+ 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 +=
+ " fbBuilder.addStruct(" + NumToString(offset) + ", offset);\n";
+ } else {
+ code += " int add" + MakeCamel(field.name) + "Offset(int offset) {\n";
+ code +=
+ " fbBuilder.addOffset(" + NumToString(offset) + ", offset);\n";
+ }
+ code += " return fbBuilder.offset;\n";
+ code += " }\n";
+ }
+
+ code += "\n";
+ code += " int finish() {\n";
+ code += " return fbBuilder.endTable();\n";
+ code += " }\n";
+ }
+
+ void GenObjectBuilder(
+ const StructDef &struct_def,
+ std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
+ std::string *builder_name_ptr, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto &builder_name = *builder_name_ptr;
+
+ code += "class " + builder_name + " extends " + _kFb + ".ObjectBuilder {\n";
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+
+ code += " final " +
+ GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field, true) +
+ " _" + MakeCamel(field.name, false) + ";\n";
+ }
+ code += "\n";
+ code += " " + builder_name + "(";
+
+ if (non_deprecated_fields.size() != 0) {
+ code += "{\n";
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+
+ code += " " +
+ GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field, true) +
+ " " + MakeCamel(field.name, false) + ",\n";
+ }
+ code += " })\n";
+ code += " : ";
+ 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);
+ if (it == non_deprecated_fields.end() - 1) {
+ code += ";\n\n";
+ } else {
+ code += ",\n ";
+ }
+ }
+ } else {
+ code += ");\n\n";
+ }
+
+ 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 += " }\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 += " }\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;
+
+ for (auto it = non_deprecated_fields.rbegin();
+ it != non_deprecated_fields.rend(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+
+ if (field.padding) {
+ code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
+ }
+
+ if (IsStruct(field.value.type)) {
+ code += " ";
+ if (prependUnderscore) { code += "_"; }
+ code += field.name + ".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"; }
+ code += ");\n";
+ }
+ }
+
+ code += " return fbBuilder.offset;\n";
+ }
+
+ 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";
+
+ for (auto it = non_deprecated_fields.begin();
+ it != non_deprecated_fields.end(); ++it) {
+ auto pair = *it;
+ auto &field = *pair.second;
+ auto offset = pair.first;
+
+ 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"; }
+ 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 += " }\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 += " return fbBuilder.endTable();\n";
+ }
+};
+} // namespace dart
+
+bool GenerateDart(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ dart::DartGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+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);
+ auto make_rule =
+ generator.GeneratedFileName(path, file_name, 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/contrib/libs/flatbuffers/src/idl_gen_fbs.cpp b/contrib/libs/flatbuffers/src/idl_gen_fbs.cpp
new file mode 100644
index 0000000000..35c1a7d4f5
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_fbs.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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 "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static std::string GenType(const Type &type, bool underlying = false) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRUCT:
+ return type.struct_def->defined_namespace->GetFullyQualifiedName(
+ type.struct_def->name);
+ case BASE_TYPE_VECTOR: return "[" + GenType(type.VectorType()) + "]";
+ default:
+ if (type.enum_def && !underlying) {
+ return type.enum_def->defined_namespace->GetFullyQualifiedName(
+ type.enum_def->name);
+ } else {
+ return kTypeNames[type.base_type];
+ }
+ }
+}
+
+static void GenNameSpace(const Namespace &name_space, std::string *_schema,
+ const Namespace **last_namespace) {
+ if (*last_namespace == &name_space) return;
+ *last_namespace = &name_space;
+ auto &schema = *_schema;
+ schema += "namespace ";
+ for (auto it = name_space.components.begin();
+ it != name_space.components.end(); ++it) {
+ if (it != name_space.components.begin()) schema += ".";
+ schema += *it;
+ }
+ schema += ";\n\n";
+}
+
+// Generate a flatbuffer schema from the Parser's internal representation.
+std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
+ // Proto namespaces may clash with table names, escape the ones that were
+ // generated from a table:
+ for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
+ ++it) {
+ auto &ns = **it;
+ for (size_t i = 0; i < ns.from_table; i++) {
+ ns.components[ns.components.size() - 1 - i] += "_";
+ }
+
+ if (parser.opts.proto_mode && !parser.opts.proto_namespace_suffix.empty()) {
+ // Since we know that all these namespaces come from a .proto, and all are
+ // being converted, we can simply apply this suffix to all of them.
+ ns.components.insert(ns.components.end() - ns.from_table,
+ parser.opts.proto_namespace_suffix);
+ }
+ }
+
+ std::string schema;
+ schema += "// Generated from " + file_name + ".proto\n\n";
+ if (parser.opts.include_dependence_headers) {
+ // clang-format off
+ int num_includes = 0;
+ for (auto it = parser.included_files_.begin();
+ it != parser.included_files_.end(); ++it) {
+ if (it->second.empty())
+ continue;
+ std::string basename;
+ if(parser.opts.keep_include_path) {
+ basename = flatbuffers::StripExtension(it->second);
+ } else {
+ basename = flatbuffers::StripPath(
+ flatbuffers::StripExtension(it->second));
+ }
+ schema += "include \"" + basename + ".fbs\";\n";
+ num_includes++;
+ }
+ if (num_includes) schema += "\n";
+ // clang-format on
+ }
+ // Generate code for all the enum declarations.
+ const Namespace *last_namespace = nullptr;
+ for (auto enum_def_it = parser.enums_.vec.begin();
+ enum_def_it != parser.enums_.vec.end(); ++enum_def_it) {
+ EnumDef &enum_def = **enum_def_it;
+ if (parser.opts.include_dependence_headers && enum_def.generated) {
+ continue;
+ }
+ GenNameSpace(*enum_def.defined_namespace, &schema, &last_namespace);
+ GenComment(enum_def.doc_comment, &schema, nullptr);
+ if (enum_def.is_union)
+ schema += "union " + enum_def.name;
+ else
+ schema += "enum " + enum_def.name + " : ";
+ schema += GenType(enum_def.underlying_type, true) + " {\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, &schema, nullptr, " ");
+ if (enum_def.is_union)
+ schema += " " + GenType(ev.union_type) + ",\n";
+ else
+ schema += " " + ev.name + " = " + enum_def.ToString(ev) + ",\n";
+ }
+ schema += "}\n\n";
+ }
+ // Generate code for all structs/tables.
+ for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
+ ++it) {
+ StructDef &struct_def = **it;
+ if (parser.opts.include_dependence_headers && struct_def.generated) {
+ continue;
+ }
+ GenNameSpace(*struct_def.defined_namespace, &schema, &last_namespace);
+ GenComment(struct_def.doc_comment, &schema, nullptr);
+ schema += "table " + struct_def.name + " {\n";
+ for (auto field_it = struct_def.fields.vec.begin();
+ field_it != struct_def.fields.vec.end(); ++field_it) {
+ auto &field = **field_it;
+ if (field.value.type.base_type != BASE_TYPE_UTYPE) {
+ GenComment(field.doc_comment, &schema, nullptr, " ");
+ schema += " " + field.name + ":" + GenType(field.value.type);
+ if (field.value.constant != "0") schema += " = " + field.value.constant;
+ if (field.IsRequired()) schema += " (required)";
+ schema += ";\n";
+ }
+ }
+ schema += "}\n\n";
+ }
+ return schema;
+}
+
+bool GenerateFBS(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ return SaveFile((path + file_name + ".fbs").c_str(),
+ GenerateFBS(parser, file_name), false);
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_go.cpp b/contrib/libs/flatbuffers/src/idl_gen_go.cpp
new file mode 100644
index 0000000000..867f402322
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_go.cpp
@@ -0,0 +1,1374 @@
+/*
+ * 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 <sstream>
+#include <string>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#ifdef _WIN32
+# include <direct.h>
+# define PATH_SEPARATOR "\\"
+# define mkdir(n, m) _mkdir(n)
+#else
+# include <sys/stat.h>
+# define PATH_SEPARATOR "/"
+#endif
+
+namespace flatbuffers {
+
+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",
+};
+
+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);
+}
+
+class GoGenerator : public BaseGenerator {
+ public:
+ GoGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name, const std::string &go_namespace)
+ : BaseGenerator(parser, path, file_name, "" /* not used*/,
+ "" /* not used */, "go"),
+ cur_name_space_(nullptr) {
+ std::istringstream iss(go_namespace);
+ std::string component;
+ while (std::getline(iss, component, '.')) {
+ go_namespace_.components.push_back(component);
+ }
+ }
+
+ bool generate() {
+ std::string one_file_code;
+ bool needs_imports = false;
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ tracked_imported_namespaces_.clear();
+ needs_imports = false;
+ std::string enumcode;
+ GenEnum(**it, &enumcode);
+ if ((*it)->is_union && parser_.opts.generate_object_based_api) {
+ GenNativeUnion(**it, &enumcode);
+ GenNativeUnionPack(**it, &enumcode);
+ GenNativeUnionUnPack(**it, &enumcode);
+ needs_imports = true;
+ }
+ if (parser_.opts.one_file) {
+ one_file_code += enumcode;
+ } else {
+ if (!SaveType(**it, enumcode, needs_imports, true)) return false;
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ tracked_imported_namespaces_.clear();
+ std::string declcode;
+ GenStruct(**it, &declcode);
+ if (parser_.opts.one_file) {
+ one_file_code += declcode;
+ } else {
+ if (!SaveType(**it, declcode, true, false)) return false;
+ }
+ }
+
+ if (parser_.opts.one_file) {
+ std::string code = "";
+ const bool is_enum = !parser_.enums_.vec.empty();
+ BeginFile(LastNamespacePart(go_namespace_), true, is_enum, &code);
+ code += one_file_code;
+ const std::string filename =
+ GeneratedFileName(path_, file_name_, parser_.opts);
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ return true;
+ }
+
+ private:
+ Namespace go_namespace_;
+ Namespace *cur_name_space_;
+
+ struct NamespacePtrLess {
+ bool operator()(const Namespace *a, const Namespace *b) const {
+ return *a < *b;
+ }
+ };
+ std::set<const Namespace *, NamespacePtrLess> tracked_imported_namespaces_;
+
+ // 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) {
+ return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" +
+ NumToString(field.value.offset) + "))\n\tif o != 0 {\n";
+ }
+
+ // Begin a class declaration.
+ void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "type " + struct_def.name + " struct {\n\t";
+
+ // _ is reserved in flatbuffers field names, so no chance of name conflict:
+ code += "_tab ";
+ code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table";
+ code += "\n}\n\n";
+ }
+
+ // 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));
+ }
+
+ // Create a type for the enum values.
+ void GenEnumType(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "type " + GetEnumTypeName(enum_def) + " ";
+ code += GenTypeBasic(enum_def.underlying_type) + "\n\n";
+ }
+
+ // Begin enum code with a class declaration.
+ void BeginEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "const (\n";
+ }
+
+ // A single enum member.
+ void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
+ size_t max_name_length, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\t";
+ code += enum_def.name;
+ code += ev.name;
+ code += " ";
+ code += std::string(max_name_length - ev.name.length(), ' ');
+ code += GetEnumTypeName(enum_def);
+ code += " = ";
+ code += enum_def.ToString(ev) + "\n";
+ }
+
+ // End enum code.
+ void EndEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += ")\n\n";
+ }
+
+ // Begin enum name map.
+ void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "var EnumNames";
+ code += enum_def.name;
+ code += " = map[" + GetEnumTypeName(enum_def) + "]string{\n";
+ }
+
+ // A single enum name member.
+ void EnumNameMember(const EnumDef &enum_def, const EnumVal &ev,
+ size_t max_name_length, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\t";
+ code += enum_def.name;
+ code += ev.name;
+ code += ": ";
+ code += std::string(max_name_length - ev.name.length(), ' ');
+ code += "\"";
+ code += ev.name;
+ code += "\",\n";
+ }
+
+ // End enum name map.
+ void EndEnumNames(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n\n";
+ }
+
+ // 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";
+ code += "\t\treturn s\n";
+ code += "\t}\n";
+ code += "\treturn \"" + enum_def.name;
+ code += "(\" + strconv.FormatInt(int64(v), 10) + \")\"\n";
+ code += "}\n\n";
+ }
+
+ // Begin enum value map.
+ void BeginEnumValues(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "var EnumValues";
+ code += enum_def.name;
+ code += " = map[string]" + GetEnumTypeName(enum_def) + "{\n";
+ }
+
+ // A single enum value member.
+ void EnumValueMember(const EnumDef &enum_def, const EnumVal &ev,
+ size_t max_name_length, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\t\"";
+ code += ev.name;
+ code += "\": ";
+ code += std::string(max_name_length - ev.name.length(), ' ');
+ code += enum_def.name;
+ code += ev.name;
+ code += ",\n";
+ }
+
+ // End enum value map.
+ void EndEnumValues(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n\n";
+ }
+
+ // Initialize a new struct or table from existing data.
+ void NewRootTypeFromBuffer(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string size_prefix[] = { "", "SizePrefixed" };
+
+ for (int i = 0; i < 2; i++) {
+ code += "func Get" + size_prefix[i] + "RootAs";
+ code += struct_def.name;
+ code += "(buf []byte, offset flatbuffers.UOffsetT) ";
+ code += "*" + struct_def.name + "";
+ code += " {\n";
+ if (i == 0) {
+ code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n";
+ } else {
+ code +=
+ "\tn := "
+ "flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])\n";
+ }
+ code += "\tx := &" + struct_def.name + "{}\n";
+ if (i == 0) {
+ code += "\tx.Init(buf, n+offset)\n";
+ } else {
+ code += "\tx.Init(buf, n+offset+flatbuffers.SizeUint32)\n";
+ }
+ code += "\treturn x\n";
+ code += "}\n\n";
+ }
+ }
+
+ // Initialize an existing object with other data, to avoid an allocation.
+ void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += " Init(buf []byte, i flatbuffers.UOffsetT) ";
+ code += "{\n";
+ code += "\trcv._tab.Bytes = buf\n";
+ code += "\trcv._tab.Pos = i\n";
+ code += "}\n\n";
+ }
+
+ // Implement the table accessor
+ void GenTableAccessor(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += " Table() flatbuffers.Table ";
+ code += "{\n";
+
+ if (struct_def.fixed) {
+ code += "\treturn rcv._tab.Table\n";
+ } else {
+ code += "\treturn rcv._tab\n";
+ }
+ code += "}\n\n";
+ }
+
+ // Get the length of a vector.
+ void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name) + "Length(";
+ code += ") int " + OffsetPrefix(field);
+ code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n";
+ code += "\treturn 0\n}\n\n";
+ }
+
+ // Get a [ubyte] vector as a byte slice.
+ void GetUByteSlice(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(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";
+ }
+
+ // Get the value of a struct's scalar.
+ void GetScalarFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "() " + TypeName(field) + " {\n";
+ code += "\treturn " +
+ CastToEnum(field.value.type,
+ getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" +
+ NumToString(field.value.offset) + "))");
+ code += "\n}\n";
+ }
+
+ // Get the value of a table's scalar.
+ void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "() " + TypeName(field) + " ";
+ code += OffsetPrefix(field) + "\t\treturn ";
+ code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)");
+ code += "\n\t}\n";
+ code += "\treturn " + GenConstant(field) + "\n";
+ code += "}\n\n";
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Struct.
+ void GetStructFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "(obj *" + TypeName(field);
+ code += ") *" + TypeName(field);
+ code += " {\n";
+ code += "\tif obj == nil {\n";
+ code += "\t\tobj = new(" + TypeName(field) + ")\n";
+ code += "\t}\n";
+ code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+";
+ code += NumToString(field.value.offset) + ")";
+ code += "\n\treturn obj\n";
+ code += "}\n";
+ }
+
+ // 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 = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "(obj *";
+ code += TypeName(field);
+ code += ") *" + TypeName(field) + " " + OffsetPrefix(field);
+ if (field.value.type.struct_def->fixed) {
+ code += "\t\tx := o + rcv._tab.Pos\n";
+ } else {
+ code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n";
+ }
+ code += "\t\tif obj == nil {\n";
+ code += "\t\t\tobj = new(" + TypeName(field) + ")\n";
+ code += "\t\t}\n";
+ code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
+ code += "\t\treturn obj\n\t}\n\treturn nil\n";
+ code += "}\n\n";
+ }
+
+ // Get the value of a string.
+ void GetStringField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(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";
+ code += "}\n\n";
+ }
+
+ // 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 = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name) + "(";
+ code += "obj " + GenTypePointer(field.value.type) + ") bool ";
+ code += OffsetPrefix(field);
+ code += "\t\t" + GenGetter(field.value.type);
+ code += "(obj, o)\n\t\treturn true\n\t}\n";
+ code += "\treturn false\n";
+ code += "}\n\n";
+ }
+
+ // Get the value of a vector's struct member.
+ void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "(obj *" + TypeName(field);
+ code += ", j int) bool " + OffsetPrefix(field);
+ code += "\t\tx := rcv._tab.Vector(o)\n";
+ code += "\t\tx += flatbuffers.UOffsetT(j) * ";
+ code += NumToString(InlineSize(vectortype)) + "\n";
+ if (!(vectortype.struct_def->fixed)) {
+ code += "\t\tx = rcv._tab.Indirect(x)\n";
+ }
+ code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
+ code += "\t\treturn true\n\t}\n";
+ code += "\treturn false\n";
+ code += "}\n\n";
+ }
+
+ // Get the value of a vector's non-struct member.
+ void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "(j int) " + TypeName(field) + " ";
+ code += OffsetPrefix(field);
+ code += "\t\ta := rcv._tab.Vector(o)\n";
+ code += "\t\treturn " +
+ CastToEnum(field.value.type,
+ GenGetter(field.value.type) +
+ "(a + flatbuffers.UOffsetT(j*" +
+ NumToString(InlineSize(vectortype)) + "))");
+ code += "\n\t}\n";
+ if (IsString(vectortype)) {
+ code += "\treturn nil\n";
+ } else if (vectortype.base_type == BASE_TYPE_BOOL) {
+ code += "\treturn false\n";
+ } else {
+ code += "\treturn 0\n";
+ }
+ code += "}\n\n";
+ }
+
+ // Begin the creator function signature.
+ void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ if (code.substr(code.length() - 2) != "\n\n") {
+ // a previous mutate has not put an extra new line
+ code += "\n";
+ }
+ code += "func Create" + struct_def.name;
+ code += "(builder *flatbuffers.Builder";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ 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.
+ StructBuilderArgs(*field.value.type.struct_def,
+ (nameprefix + (field.name + "_")).c_str(), code_ptr);
+ } else {
+ std::string &code = *code_ptr;
+ code += std::string(", ") + nameprefix;
+ code += GoIdentity(field.name);
+ code += " " + TypeName(field);
+ }
+ }
+ }
+
+ // End the creator function signature.
+ void EndBuilderArgs(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += ") flatbuffers.UOffsetT {\n";
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", ";
+ code += 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)
+ code += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n";
+ if (IsStruct(field.value.type)) {
+ StructBuilderBody(*field.value.type.struct_def,
+ (nameprefix + (field.name + "_")).c_str(), code_ptr);
+ } else {
+ code += "\tbuilder.Prepend" + GenMethod(field) + "(";
+ code += CastToBaseType(field.value.type,
+ nameprefix + GoIdentity(field.name)) +
+ ")\n";
+ }
+ }
+ }
+
+ void EndBuilderBody(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\treturn builder.Offset()\n";
+ code += "}\n";
+ }
+
+ // 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 += "(builder *flatbuffers.Builder) {\n";
+ code += "\tbuilder.StartObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ")\n}\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) {
+ std::string &code = *code_ptr;
+ code += "func " + struct_def.name + "Add" + MakeCamel(field.name);
+ code += "(builder *flatbuffers.Builder, ";
+ code += GoIdentity(field.name) + " ";
+ if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+ code += "flatbuffers.UOffsetT";
+ } else {
+ code += TypeName(field);
+ }
+ 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 += "(";
+ code += GoIdentity(field.name) + ")";
+ } else {
+ code += CastToBaseType(field.value.type, GoIdentity(field.name));
+ }
+ code += ", " + GenConstant(field);
+ code += ")\n}\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 += "Vector(builder *flatbuffers.Builder, numElems int) ";
+ code += "flatbuffers.UOffsetT {\n\treturn 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 += ", numElems, " + NumToString(alignment);
+ code += ")\n}\n";
+ }
+
+ // 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 += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT ";
+ code += "{\n\treturn builder.EndObject()\n}\n";
+ }
+
+ // 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 + ")";
+ }
+
+ // Generate a struct field getter, conditioned on its child type(s).
+ void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, nullptr, "");
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ GetScalarFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetScalarFieldOfTable(struct_def, field, code_ptr);
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ GetStructFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetStructFieldOfTable(struct_def, field, code_ptr);
+ }
+ break;
+ case BASE_TYPE_STRING:
+ GetStringField(struct_def, field, code_ptr);
+ break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ if (IsVector(field.value.type)) {
+ GetVectorLen(struct_def, field, code_ptr);
+ if (field.value.type.element == BASE_TYPE_UCHAR) {
+ GetUByteSlice(struct_def, field, code_ptr);
+ }
+ }
+ }
+
+ // Mutate the value of a struct's scalar.
+ 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;
+ GenReceiver(struct_def, code_ptr);
+ code += " Mutate" + MakeCamel(field.name);
+ code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter;
+ code += "(rcv._tab.Pos+flatbuffers.UOffsetT(";
+ code += NumToString(field.value.offset) + "), ";
+ code += CastToBaseType(field.value.type, "n") + ")\n}\n\n";
+ }
+
+ // Mutate the value of a table's scalar.
+ 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";
+ GenReceiver(struct_def, code_ptr);
+ code += " Mutate" + MakeCamel(field.name);
+ code += "(n " + TypeName(field) + ") bool {\n\treturn ";
+ code += setter + "(" + NumToString(field.value.offset) + ", ";
+ code += CastToBaseType(field.value.type, "n") + ")\n";
+ code += "}\n\n";
+ }
+
+ // Mutate an element of a vector of scalars.
+ void MutateElementOfVectorOfNonStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ 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;
+ GenReceiver(struct_def, code_ptr);
+ code += " Mutate" + MakeCamel(field.name);
+ code += "(j int, n " + TypeName(field) + ") bool ";
+ code += OffsetPrefix(field);
+ code += "\t\ta := rcv._tab.Vector(o)\n";
+ code += "\t\treturn " + setter + "(";
+ code += "a+flatbuffers.UOffsetT(j*";
+ code += NumToString(InlineSize(vectortype)) + "), ";
+ code += CastToBaseType(vectortype, "n") + ")\n";
+ code += "\t}\n";
+ code += "\treturn false\n";
+ code += "}\n\n";
+ }
+
+ // Generate a struct field setter, conditioned on its child type(s).
+ void GenStructMutator(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, nullptr, "");
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ MutateScalarFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ MutateScalarFieldOfTable(struct_def, field, code_ptr);
+ }
+ } else if (IsVector(field.value.type)) {
+ if (IsScalar(field.value.type.element)) {
+ MutateElementOfVectorOfNonStruct(struct_def, field, code_ptr);
+ }
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
+ GetStartOfTable(struct_def, code_ptr);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ BuildFieldOfTable(struct_def, field, offset, code_ptr);
+ if (IsVector(field.value.type)) {
+ BuildVectorOfTable(struct_def, field, code_ptr);
+ }
+ }
+
+ GetEndOffsetOnTable(struct_def, code_ptr);
+ }
+
+ // Generate struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ cur_name_space_ = struct_def.defined_namespace;
+
+ GenComment(struct_def.doc_comment, code_ptr, nullptr);
+ if (parser_.opts.generate_object_based_api) {
+ GenNativeStruct(struct_def, code_ptr);
+ }
+ BeginClass(struct_def, code_ptr);
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ NewRootTypeFromBuffer(struct_def, code_ptr);
+ }
+ // Generate the Init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ InitializeExisting(struct_def, code_ptr);
+ // Generate _tab accessor
+ GenTableAccessor(struct_def, code_ptr);
+
+ // Generate struct fields accessors
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ GenStructAccessor(struct_def, field, code_ptr);
+ GenStructMutator(struct_def, field, code_ptr);
+ }
+
+ // Generate builders
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ } else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
+ }
+ }
+
+ void GenNativeStruct(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "type " + NativeName(struct_def) + " struct {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.deprecated) continue;
+ if (IsScalar(field.value.type.base_type) &&
+ 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 += "}\n\n";
+
+ if (!struct_def.fixed) {
+ GenNativeTablePack(struct_def, code_ptr);
+ GenNativeTableUnPack(struct_def, code_ptr);
+ } else {
+ GenNativeStructPack(struct_def, code_ptr);
+ GenNativeStructUnPack(struct_def, code_ptr);
+ }
+ }
+
+ 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 += "\tValue interface{}\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeUnionPack(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "func (t *" + NativeName(enum_def) +
+ ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
+ code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
+
+ code += "\tswitch t.Type {\n";
+ for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
+ ++it2) {
+ const EnumVal &ev = **it2;
+ if (ev.IsZero()) continue;
+ code += "\tcase " + enum_def.name + ev.name + ":\n";
+ code += "\t\treturn t.Value.(" + NativeType(ev.union_type) +
+ ").Pack(builder)\n";
+ }
+ code += "\t}\n";
+ code += "\treturn 0\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeUnionUnPack(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (rcv " + enum_def.name +
+ ") UnPack(table flatbuffers.Table) *" + NativeName(enum_def) +
+ " {\n";
+ code += "\tswitch rcv {\n";
+
+ for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
+ ++it2) {
+ const EnumVal &ev = **it2;
+ if (ev.IsZero()) continue;
+ code += "\tcase " + 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";
+ }
+ code += "\t}\n";
+ code += "\treturn nil\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeTablePack(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (t *" + NativeName(struct_def) +
+ ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
+ code += "\tif t == nil { return 0 }\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const FieldDef &field = **it;
+ if (field.deprecated) continue;
+ if (IsScalar(field.value.type.base_type)) continue;
+
+ std::string offset = MakeCamel(field.name, false) + "Offset";
+
+ if (IsString(field.value.type)) {
+ code += "\t" + offset + " := builder.CreateString(t." +
+ MakeCamel(field.name) + ")\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 += "\t\t" + offset + " = builder.CreateByteString(t." +
+ MakeCamel(field.name) + ")\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";
+ 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";
+ 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) +
+ "[j].Pack(builder)\n";
+ code += "\t\t}\n";
+ }
+ code += "\t\t" + struct_def.name + "Start" + MakeCamel(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())) + "(" +
+ CastToBaseType(field.value.type.VectorType(),
+ "t." + MakeCamel(field.name) + "[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";
+ } else {
+ code += "\t\t\tbuilder.PrependUOffsetT(" + offsets + "[j])\n";
+ }
+ code += "\t\t}\n";
+ code += "\t\t" + offset + " = builder.EndVector(" + length + ")\n";
+ 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";
+ } else if (field.value.type.base_type == BASE_TYPE_UNION) {
+ code += "\t" + offset + " := t." + MakeCamel(field.name) +
+ ".Pack(builder)\n";
+ code += "\t\n";
+ } else {
+ FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += "\t" + struct_def.name + "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;
+
+ std::string offset = MakeCamel(field.name, false) + "Offset";
+ if (IsScalar(field.value.type.base_type)) {
+ 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";
+ }
+ } 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";
+ } 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 += "\t}\n";
+ }
+ code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) +
+ "(builder, " + offset + ")\n";
+ }
+ }
+ code += "\treturn " + struct_def.name + "End(builder)\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeTableUnPack(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (rcv *" + 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.deprecated) continue;
+ std::string field_name_camel = MakeCamel(field.name);
+ std::string length = MakeCamel(field.name, false) + "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";
+ } else if (IsString(field.value.type)) {
+ code += "\tt." + field_name_camel + " = string(rcv." +
+ field_name_camel + "())\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";
+ } else if (IsVector(field.value.type)) {
+ code += "\t" + length + " := rcv." + field_name_camel + "Length()\n";
+ code += "\tt." + field_name_camel + " = 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 := " +
+ WrapInNameSpaceAndTrack(*field.value.type.struct_def) +
+ "{}\n";
+ code += "\t\trcv." + field_name_camel + "(&x, j)\n";
+ }
+ code += "\t\tt." + field_name_camel + "[j] = ";
+ if (IsScalar(field.value.type.element)) {
+ code += "rcv." + field_name_camel + "(j)";
+ } else if (field.value.type.element == BASE_TYPE_STRING) {
+ code += "string(rcv." + field_name_camel + "(j))";
+ } else if (field.value.type.element == BASE_TYPE_STRUCT) {
+ code += "x.UnPack()";
+ } else {
+ // TODO(iceboy): Support vector of unions.
+ FLATBUFFERS_ASSERT(0);
+ }
+ 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";
+ code += "\t}\n";
+ } else {
+ FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += "}\n\n";
+
+ code += "func (rcv *" + struct_def.name + ") UnPack() *" +
+ NativeName(struct_def) + " {\n";
+ code += "\tif rcv == nil { return nil }\n";
+ code += "\tt := &" + NativeName(struct_def) + "{}\n";
+ code += "\trcv.UnPackTo(t)\n";
+ code += "\treturn t\n";
+ code += "}\n\n";
+ }
+
+ void GenNativeStructPack(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ 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";
+ StructPackArgs(struct_def, "", code_ptr);
+ code += ")\n";
+ code += "}\n";
+ }
+
+ void StructPackArgs(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ 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) {
+ StructPackArgs(*field.value.type.struct_def,
+ (nameprefix + MakeCamel(field.name) + ".").c_str(),
+ code_ptr);
+ } else {
+ code += std::string(", t.") + nameprefix + MakeCamel(field.name);
+ }
+ }
+ }
+
+ void GenNativeStructUnPack(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func (rcv *" + 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";
+ } else {
+ code += "\tt." + MakeCamel(field.name) + " = rcv." +
+ MakeCamel(field.name) + "()\n";
+ }
+ }
+ code += "}\n\n";
+
+ code += "func (rcv *" + struct_def.name + ") UnPack() *" +
+ NativeName(struct_def) + " {\n";
+ code += "\tif rcv == nil { return nil }\n";
+ code += "\tt := &" + NativeName(struct_def) + "{}\n";
+ code += "\trcv.UnPackTo(t)\n";
+ code += "\treturn t\n";
+ code += "}\n\n";
+ }
+
+ // Generate enum declarations.
+ void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+
+ auto max_name_length = MaxNameLength(enum_def);
+ cur_name_space_ = enum_def.defined_namespace;
+
+ GenComment(enum_def.doc_comment, code_ptr, nullptr);
+ GenEnumType(enum_def, code_ptr);
+ BeginEnum(code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const EnumVal &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
+ EnumMember(enum_def, ev, max_name_length, code_ptr);
+ }
+ EndEnum(code_ptr);
+
+ BeginEnumNames(enum_def, code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const EnumVal &ev = **it;
+ EnumNameMember(enum_def, ev, max_name_length, code_ptr);
+ }
+ EndEnumNames(code_ptr);
+
+ BeginEnumValues(enum_def, code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ EnumValueMember(enum_def, ev, max_name_length, code_ptr);
+ }
+ EndEnumValues(code_ptr);
+
+ EnumStringer(enum_def, code_ptr);
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetter(const Type &type) {
+ switch (type.base_type) {
+ 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));
+ }
+ }
+
+ // 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))
+ : (IsStruct(field.value.type) ? "Struct" : "UOffsetT");
+ }
+
+ std::string GenTypeBasic(const Type &type) {
+ // clang-format off
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, ...) \
+ #GTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ return ctypename[type.base_type];
+ }
+
+ std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "[]byte";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return WrapInNameSpaceAndTrack(*type.struct_def);
+ case BASE_TYPE_UNION:
+ // fall through
+ default: return "*flatbuffers.Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) {
+ if (type.enum_def != nullptr) { return GetEnumTypeName(*type.enum_def); }
+ return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+ }
+
+ std::string TypeName(const FieldDef &field) {
+ return GenTypeGet(field.value.type);
+ }
+
+ // If type is an enum, returns value with a cast to the enum type, otherwise
+ // returns value as-is.
+ std::string CastToEnum(const Type &type, std::string value) {
+ if (type.enum_def == nullptr) {
+ return value;
+ } else {
+ return GenTypeGet(type) + "(" + value + ")";
+ }
+ }
+
+ // If type is an enum, returns value with a cast to the enum base type,
+ // otherwise returns value as-is.
+ std::string CastToBaseType(const Type &type, std::string value) {
+ if (type.enum_def == nullptr) {
+ return value;
+ } else {
+ return GenTypeBasic(type) + "(" + value + ")";
+ }
+ }
+
+ std::string GenConstant(const FieldDef &field) {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_BOOL:
+ return field.value.constant == "0" ? "false" : "true";
+ default: return field.value.constant;
+ }
+ }
+
+ std::string NativeName(const StructDef &struct_def) {
+ return parser_.opts.object_prefix + struct_def.name +
+ parser_.opts.object_suffix;
+ }
+
+ std::string NativeName(const EnumDef &enum_def) {
+ return parser_.opts.object_prefix + enum_def.name +
+ parser_.opts.object_suffix;
+ }
+
+ std::string NativeType(const Type &type) {
+ if (IsScalar(type.base_type)) {
+ if (type.enum_def == nullptr) {
+ return GenTypeBasic(type);
+ } else {
+ return GetEnumTypeName(*type.enum_def);
+ }
+ } else if (IsString(type)) {
+ return "string";
+ } else if (IsVector(type)) {
+ return "[]" + NativeType(type.VectorType());
+ } else if (type.base_type == BASE_TYPE_STRUCT) {
+ return "*" + WrapInNameSpaceAndTrack(type.struct_def->defined_namespace,
+ NativeName(*type.struct_def));
+ } else if (type.base_type == BASE_TYPE_UNION) {
+ return "*" + WrapInNameSpaceAndTrack(type.enum_def->defined_namespace,
+ NativeName(*type.enum_def));
+ }
+ FLATBUFFERS_ASSERT(0);
+ return std::string();
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
+ BeginBuilderArgs(struct_def, code_ptr);
+ StructBuilderArgs(struct_def, "", code_ptr);
+ EndBuilderArgs(code_ptr);
+
+ StructBuilderBody(struct_def, "", code_ptr);
+ EndBuilderBody(code_ptr);
+ }
+ // Begin by declaring namespace and imports.
+ void BeginFile(const std::string &name_space_name, const bool needs_imports,
+ const bool is_enum, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code = code +
+ "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
+ code += "package " + name_space_name + "\n\n";
+ if (needs_imports) {
+ code += "import (\n";
+ if (is_enum) { code += "\t\"strconv\"\n\n"; }
+ if (!parser_.opts.go_import.empty()) {
+ code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
+ } else {
+ code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
+ }
+ if (tracked_imported_namespaces_.size() > 0) {
+ code += "\n";
+ for (auto it = tracked_imported_namespaces_.begin();
+ it != tracked_imported_namespaces_.end(); ++it) {
+ code += "\t" + NamespaceImportName(*it) + " \"" +
+ NamespaceImportPath(*it) + "\"\n";
+ }
+ }
+ code += ")\n\n";
+ } else {
+ if (is_enum) { code += "import \"strconv\"\n\n"; }
+ }
+ }
+
+ // Save out the generated code for a Go Table type.
+ bool SaveType(const Definition &def, const std::string &classcode,
+ const bool needs_imports, const bool is_enum) {
+ if (!classcode.length()) return true;
+
+ Namespace &ns = go_namespace_.components.empty() ? *def.defined_namespace
+ : go_namespace_;
+ std::string code = "";
+ BeginFile(LastNamespacePart(ns), needs_imports, is_enum, &code);
+ code += classcode;
+ // Strip extra newlines at end of file to make it gofmt-clean.
+ while (code.length() > 2 && code.substr(code.length() - 2) == "\n\n") {
+ code.pop_back();
+ }
+ std::string filename = NamespaceDir(ns) + def.name + ".go";
+ 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;
+ }
+
+ // 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;
+ }
+
+ // Ensure that a type is prefixed with its go package import name if it is
+ // used outside of its namespace.
+ std::string WrapInNameSpaceAndTrack(const Namespace *ns,
+ const std::string &name) {
+ if (CurrentNameSpace() == ns) return name;
+
+ tracked_imported_namespaces_.insert(ns);
+
+ std::string import_name = NamespaceImportName(ns);
+ return import_name + "." + name;
+ }
+
+ std::string WrapInNameSpaceAndTrack(const Definition &def) {
+ return WrapInNameSpaceAndTrack(def.defined_namespace, def.name);
+ }
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ static size_t MaxNameLength(const EnumDef &enum_def) {
+ size_t max = 0;
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ max = std::max((*it)->name.length(), max);
+ }
+ return max;
+ }
+};
+} // namespace go
+
+bool GenerateGo(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_grpc.cpp b/contrib/libs/flatbuffers/src/idl_gen_grpc.cpp
new file mode 100644
index 0000000000..9aea745d4e
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_grpc.cpp
@@ -0,0 +1,557 @@
+/*
+ * 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 "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+#include "src/compiler/cpp_generator.h"
+#include "src/compiler/go_generator.h"
+#include "src/compiler/java_generator.h"
+#include "src/compiler/python_generator.h"
+#include "src/compiler/swift_generator.h"
+#include "src/compiler/ts_generator.h"
+
+#if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable : 4512) // C4512: 'class' : assignment operator could
+// not be generated
+#endif
+
+namespace flatbuffers {
+
+class FlatBufMethod : public grpc_generator::Method {
+ public:
+ enum Streaming { kNone, kClient, kServer, kBiDi };
+
+ FlatBufMethod(const RPCCall *method) : method_(method) {
+ streaming_ = kNone;
+ auto val = method_->attributes.Lookup("streaming");
+ if (val) {
+ if (val->constant == "client") streaming_ = kClient;
+ if (val->constant == "server") streaming_ = kServer;
+ if (val->constant == "bidi") streaming_ = kBiDi;
+ }
+ }
+
+ grpc::string GetLeadingComments(const grpc::string) const { return ""; }
+
+ grpc::string GetTrailingComments(const grpc::string) const { return ""; }
+
+ std::vector<grpc::string> GetAllComments() const {
+ return method_->doc_comment;
+ }
+
+ std::string name() const { return method_->name; }
+
+ // TODO: This method need to incorporate namespace for C++ side. Other
+ // language bindings simply don't use this method.
+ std::string GRPCType(const StructDef &sd) const {
+ return "flatbuffers::grpc::Message<" + sd.name + ">";
+ }
+
+ std::vector<std::string> get_input_namespace_parts() const {
+ return (*method_->request).defined_namespace->components;
+ }
+
+ std::string get_input_type_name() const { return (*method_->request).name; }
+
+ std::vector<std::string> get_output_namespace_parts() const {
+ return (*method_->response).defined_namespace->components;
+ }
+
+ std::string get_output_type_name() const { return (*method_->response).name; }
+
+ bool get_module_and_message_path_input(grpc::string * /*str*/,
+ grpc::string /*generator_file_name*/,
+ bool /*generate_in_pb2_grpc*/,
+ grpc::string /*import_prefix*/) const {
+ return true;
+ }
+
+ bool get_module_and_message_path_output(
+ grpc::string * /*str*/, grpc::string /*generator_file_name*/,
+ bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
+ return true;
+ }
+
+ std::string get_fb_builder() const { return "builder"; }
+
+ std::string input_type_name() const { return GRPCType(*method_->request); }
+
+ std::string output_type_name() const { return GRPCType(*method_->response); }
+
+ bool NoStreaming() const { return streaming_ == kNone; }
+
+ bool ClientStreaming() const { return streaming_ == kClient; }
+
+ bool ServerStreaming() const { return streaming_ == kServer; }
+
+ bool BidiStreaming() const { return streaming_ == kBiDi; }
+
+ private:
+ const RPCCall *method_;
+ Streaming streaming_;
+};
+
+class FlatBufService : public grpc_generator::Service {
+ public:
+ FlatBufService(const ServiceDef *service) : service_(service) {}
+
+ grpc::string GetLeadingComments(const grpc::string) const { return ""; }
+
+ grpc::string GetTrailingComments(const grpc::string) const { return ""; }
+
+ std::vector<grpc::string> GetAllComments() const {
+ return service_->doc_comment;
+ }
+
+ std::vector<grpc::string> namespace_parts() const {
+ return service_->defined_namespace->components;
+ }
+
+ std::string name() const { return service_->name; }
+ bool is_internal() const {
+ return service_->Definition::attributes.Lookup("private") ? true : false;
+ }
+
+ int method_count() const {
+ return static_cast<int>(service_->calls.vec.size());
+ }
+
+ std::unique_ptr<const grpc_generator::Method> method(int i) const {
+ return std::unique_ptr<const grpc_generator::Method>(
+ new FlatBufMethod(service_->calls.vec[i]));
+ }
+
+ private:
+ const ServiceDef *service_;
+};
+
+class FlatBufPrinter : public grpc_generator::Printer {
+ public:
+ 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) {
+ std::string s = string_template;
+ // Replace any occurrences of strings in "vars" that are surrounded
+ // by the escape character by what they're mapped to.
+ size_t pos;
+ while ((pos = s.find(escape_char_)) != std::string::npos) {
+ // Found an escape char, must also find the closing one.
+ size_t pos2 = s.find(escape_char_, pos + 1);
+ // If placeholder not closed, ignore.
+ if (pos2 == std::string::npos) break;
+ auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1));
+ // If unknown placeholder, ignore.
+ if (it == vars.end()) break;
+ // Subtitute placeholder.
+ s.replace(pos, pos2 - pos + 1, it->second);
+ }
+ Print(s.c_str());
+ }
+
+ void Print(const char *s) {
+ if (s == nullptr || *s == '\0') { return; }
+ // Add this string, but for each part separated by \n, add indentation.
+ for (;;) {
+ // Current indentation.
+ 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) {
+ (*str_) += std::string(s, lf + 1);
+ s = lf + 1;
+ if (!*s) break; // Only continue if there's more lines.
+ } else {
+ (*str_) += s;
+ break;
+ }
+ }
+ }
+
+ void SetIndentationSize(const int size) {
+ FLATBUFFERS_ASSERT(str_->empty());
+ indentation_size_ = size;
+ }
+
+ void Indent() { indent_++; }
+
+ void Outdent() {
+ indent_--;
+ FLATBUFFERS_ASSERT(indent_ >= 0);
+ }
+
+ private:
+ std::string *str_;
+ char escape_char_;
+ int indent_;
+ int indentation_size_;
+ char indentation_type_;
+};
+
+class FlatBufFile : public grpc_generator::File {
+ public:
+ enum Language {
+ kLanguageGo,
+ kLanguageCpp,
+ kLanguageJava,
+ kLanguagePython,
+ kLanguageSwift,
+ kLanguageTS
+ };
+
+ FlatBufFile(const Parser &parser, const std::string &file_name,
+ Language language)
+ : parser_(parser), file_name_(file_name), language_(language) {}
+
+ FlatBufFile &operator=(const FlatBufFile &);
+
+ grpc::string GetLeadingComments(const grpc::string) const { return ""; }
+
+ grpc::string GetTrailingComments(const grpc::string) const { return ""; }
+
+ std::vector<grpc::string> GetAllComments() const {
+ return std::vector<grpc::string>();
+ }
+
+ std::string filename() const { return file_name_; }
+
+ std::string filename_without_ext() const {
+ return StripExtension(file_name_);
+ }
+
+ std::string message_header_ext() const { return "_generated.h"; }
+
+ std::string service_header_ext() const { return ".grpc.fb.h"; }
+
+ std::string package() const {
+ return parser_.current_namespace_->GetFullyQualifiedName("");
+ }
+
+ std::vector<std::string> package_parts() const {
+ return parser_.current_namespace_->components;
+ }
+
+ std::string additional_headers() const {
+ switch (language_) {
+ case kLanguageCpp: {
+ return "#include \"flatbuffers/grpc.h\"\n";
+ }
+ case kLanguageGo: {
+ return "import \"github.com/google/flatbuffers/go\"";
+ }
+ case kLanguageJava: {
+ return "import com.google.flatbuffers.grpc.FlatbuffersUtils;";
+ }
+ case kLanguagePython: {
+ return "";
+ }
+ case kLanguageSwift: {
+ return "";
+ }
+ case kLanguageTS: {
+ return "";
+ }
+ }
+ return "";
+ }
+
+ int service_count() const {
+ return static_cast<int>(parser_.services_.vec.size());
+ }
+
+ std::unique_ptr<const grpc_generator::Service> service(int i) const {
+ return std::unique_ptr<const grpc_generator::Service>(
+ new FlatBufService(parser_.services_.vec[i]));
+ }
+
+ std::unique_ptr<grpc_generator::Printer> CreatePrinter(
+ std::string *str, const char indentation_type = ' ') const {
+ return std::unique_ptr<grpc_generator::Printer>(
+ new FlatBufPrinter(str, indentation_type));
+ }
+
+ private:
+ const Parser &parser_;
+ const std::string &file_name_;
+ const Language language_;
+};
+
+class GoGRPCGenerator : public flatbuffers::BaseGenerator {
+ public:
+ GoGRPCGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "" /*Unused*/, "go"),
+ parser_(parser),
+ path_(path),
+ file_name_(file_name) {}
+
+ bool generate() {
+ FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageGo);
+ grpc_go_generator::Parameters p;
+ p.custom_method_io_type = "flatbuffers.Builder";
+ for (int i = 0; i < file.service_count(); i++) {
+ auto service = file.service(i);
+ const Definition *def = parser_.services_.vec[i];
+ p.package_name = LastNamespacePart(*(def->defined_namespace));
+ p.service_prefix =
+ def->defined_namespace->GetFullyQualifiedName(""); // file.package();
+ std::string output =
+ grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
+ std::string filename =
+ NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go";
+ if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
+ }
+ return true;
+ }
+
+ protected:
+ const Parser &parser_;
+ const std::string &path_, &file_name_;
+};
+
+bool GenerateGoGRPC(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+ return GoGRPCGenerator(parser, path, file_name).generate();
+}
+
+bool GenerateCppGRPC(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+
+ grpc_cpp_generator::Parameters generator_parameters;
+ // TODO(wvo): make the other parameters in this struct configurable.
+ generator_parameters.use_system_headers = true;
+
+ FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
+
+ std::string header_code =
+ grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
+
+ std::string source_code =
+ grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
+
+ return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
+ header_code, false) &&
+ flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
+ source_code, false);
+}
+
+class JavaGRPCGenerator : public flatbuffers::BaseGenerator {
+ public:
+ JavaGRPCGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "." /*separator*/, "java") {}
+
+ bool generate() {
+ FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageJava);
+ grpc_java_generator::Parameters p;
+ for (int i = 0; i < file.service_count(); i++) {
+ auto service = file.service(i);
+ const Definition *def = parser_.services_.vec[i];
+ p.package_name =
+ def->defined_namespace->GetFullyQualifiedName(""); // file.package();
+ std::string output =
+ grpc_java_generator::GenerateServiceSource(&file, service.get(), &p);
+ std::string filename =
+ NamespaceDir(*def->defined_namespace) + def->name + "Grpc.java";
+ if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
+ }
+ return true;
+ }
+};
+
+bool GenerateJavaGRPC(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+ 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;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+
+ return PythonGRPCGenerator(parser, file_name).generate();
+}
+
+class SwiftGRPCGenerator : public flatbuffers::BaseGenerator {
+ private:
+ CodeWriter code_;
+
+ public:
+ SwiftGRPCGenerator(const Parser &parser, const std::string &path,
+ const std::string &filename)
+ : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "swift") {}
+
+ bool generate() {
+ code_.Clear();
+ code_ += "// Generated GRPC code for FlatBuffers swift!";
+ code_ += grpc_swift_generator::GenerateHeader();
+ FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageSwift);
+ for (int i = 0; i < file.service_count(); i++) {
+ auto service = file.service(i);
+ code_ += grpc_swift_generator::Generate(&file, service.get());
+ }
+ const auto final_code = code_.ToString();
+ const auto filename = GeneratedFileName(path_, file_name_);
+ return SaveFile(filename.c_str(), final_code, false);
+ }
+
+ static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + ".grpc.swift";
+ }
+};
+
+bool GenerateSwiftGRPC(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+ return SwiftGRPCGenerator(parser, path, file_name).generate();
+}
+
+class TSGRPCGenerator : public flatbuffers::BaseGenerator {
+ private:
+ CodeWriter code_;
+
+ public:
+ TSGRPCGenerator(const Parser &parser, const std::string &path,
+ const std::string &filename)
+ : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "ts") {}
+
+ bool generate() {
+ code_.Clear();
+ FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageTS);
+
+ for (int i = 0; i < file.service_count(); i++) {
+ auto service = file.service(i);
+ code_ += grpc_ts_generator::Generate(&file, service.get(), file_name_);
+ const auto ts_name = GeneratedFileName(path_, file_name_);
+ if (!SaveFile(ts_name.c_str(), code_.ToString(), false)) return false;
+
+ code_.Clear();
+ code_ += grpc_ts_generator::GenerateInterface(&file, service.get(),
+ file_name_);
+ const auto ts_interface_name = GeneratedFileName(path_, file_name_, true);
+ if (!SaveFile(ts_interface_name.c_str(), code_.ToString(), false))
+ return false;
+ }
+ return true;
+ }
+
+ static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name,
+ const bool is_interface = false) {
+ if (is_interface) return path + file_name + "_grpc.d.ts";
+ return path + file_name + "_grpc.js";
+ }
+};
+
+bool GenerateTSGRPC(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+ return TSGRPCGenerator(parser, path, file_name).generate();
+}
+
+} // namespace flatbuffers
+
+#if defined(_MSC_VER)
+# pragma warning(pop)
+#endif
diff --git a/contrib/libs/flatbuffers/src/idl_gen_java.cpp b/contrib/libs/flatbuffers/src/idl_gen_java.cpp
new file mode 100644
index 0000000000..cfd3a55cdb
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_java.cpp
@@ -0,0 +1,1244 @@
+/*
+ * 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 "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 {
+namespace java {
+
+static TypedFloatConstantGenerator JavaFloatGen("Double.", "Float.", "NaN",
+ "POSITIVE_INFINITY",
+ "NEGATIVE_INFINITY");
+
+static CommentConfig comment_config = {
+ "/**",
+ " *",
+ " */",
+};
+
+class JavaGenerator : public BaseGenerator {
+ public:
+ JavaGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", ".", "java"),
+ cur_name_space_(nullptr) {}
+
+ JavaGenerator &operator=(const JavaGenerator &);
+ bool generate() {
+ std::string one_file_code;
+ cur_name_space_ = parser_.current_namespace_;
+
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ std::string enumcode;
+ auto &enum_def = **it;
+ if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
+ GenEnum(enum_def, &enumcode);
+ if (parser_.opts.one_file) {
+ one_file_code += enumcode;
+ } else {
+ if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
+ /* needs_includes= */ false))
+ return false;
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ std::string declcode;
+ auto &struct_def = **it;
+ if (!parser_.opts.one_file)
+ cur_name_space_ = struct_def.defined_namespace;
+ GenStruct(struct_def, &declcode);
+ if (parser_.opts.one_file) {
+ one_file_code += declcode;
+ } else {
+ if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
+ /* needs_includes= */ true))
+ return false;
+ }
+ }
+
+ if (parser_.opts.one_file) {
+ return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
+ /* needs_includes= */ true);
+ }
+ return true;
+ }
+
+ // 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 {
+ if (!classcode.length()) return true;
+
+ std::string code;
+ code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ std::string namespace_name = FullNamespace(".", ns);
+ if (!namespace_name.empty()) {
+ code += "package " + namespace_name + ";";
+ code += "\n\n";
+ }
+ if (needs_includes) {
+ code +=
+ "import java.nio.*;\nimport java.lang.*;\nimport "
+ "java.util.*;\nimport com.google.flatbuffers.*;\n";
+ if (parser_.opts.gen_nullable) {
+ code += "\nimport javax.annotation.Nullable;\n";
+ }
+ if (parser_.opts.java_checkerframework) {
+ code += "\nimport org.checkerframework.dataflow.qual.Pure;\n";
+ }
+ code += "\n";
+ }
+
+ code += classcode;
+ if (!namespace_name.empty()) code += "";
+ auto filename = NamespaceDir(ns) + defname + ".java";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ std::string GenNullableAnnotation(const Type &t) const {
+ return parser_.opts.gen_nullable &&
+ !IsScalar(DestinationType(t, true).base_type) &&
+ t.base_type != BASE_TYPE_VECTOR
+ ? " @Nullable "
+ : "";
+ }
+
+ std::string GenPureAnnotation(const Type &t) const {
+ return parser_.opts.java_checkerframework &&
+ !IsScalar(DestinationType(t, true).base_type)
+ ? " @Pure "
+ : "";
+ }
+
+ std::string GenTypeBasic(const Type &type) const {
+ // clang-format off
+ static const char * const java_typename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, ...) \
+ #JTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ return java_typename[type.base_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());
+ case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
+ case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ default: return "Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) const {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type)
+ : (IsArray(type) ? GenTypeGet(type.VectorType())
+ : GenTypePointer(type));
+ }
+
+ // Find the destination type the user wants to receive the value in (e.g.
+ // one size higher signed types for unsigned serialized values in Java).
+ Type DestinationType(const Type &type, bool vectorelem) const {
+ switch (type.base_type) {
+ // We use int for both uchar/ushort, since that generally means less
+ // casting than using short for uchar.
+ case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT);
+ case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT);
+ case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
+ case BASE_TYPE_ARRAY:
+ case BASE_TYPE_VECTOR:
+ if (vectorelem) return DestinationType(type.VectorType(), vectorelem);
+ FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ default: return type;
+ }
+ }
+
+ std::string GenOffsetType() const { return "int"; }
+
+ std::string GenOffsetConstruct(const std::string &variable_name) const {
+ return variable_name;
+ }
+
+ std::string GenVectorOffsetType() const { return "int"; }
+
+ // Generate destination type name
+ std::string GenTypeNameDest(const Type &type) const {
+ return GenTypeGet(DestinationType(type, true));
+ }
+
+ // Mask to turn serialized value into destination type value.
+ std::string DestinationMask(const Type &type, bool vectorelem) const {
+ switch (type.base_type) {
+ case BASE_TYPE_UCHAR: return " & 0xFF";
+ case BASE_TYPE_USHORT: return " & 0xFFFF";
+ case BASE_TYPE_UINT: return " & 0xFFFFFFFFL";
+ case BASE_TYPE_VECTOR:
+ if (vectorelem) return DestinationMask(type.VectorType(), vectorelem);
+ FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ default: return "";
+ }
+ }
+
+ // Casts necessary to correctly read serialized data
+ std::string DestinationCast(const Type &type) const {
+ if (IsSeries(type)) {
+ return DestinationCast(type.VectorType());
+ } else {
+ // Cast necessary to correctly read serialized unsigned values.
+ if (type.base_type == BASE_TYPE_UINT) return "(long)";
+ }
+ return "";
+ }
+
+ // Cast statements for mutator method parameters.
+ // In Java, parameters representing unsigned numbers need to be cast down to
+ // their respective type. For example, a long holding an unsigned int value
+ // would be cast down to int before being put onto the buffer.
+ std::string SourceCast(const Type &type, bool castFromDest) const {
+ if (IsSeries(type)) {
+ return SourceCast(type.VectorType(), castFromDest);
+ } else {
+ if (castFromDest) {
+ if (type.base_type == BASE_TYPE_UINT)
+ return "(int)";
+ else if (type.base_type == BASE_TYPE_USHORT)
+ return "(short)";
+ else if (type.base_type == BASE_TYPE_UCHAR)
+ return "(byte)";
+ }
+ }
+ return "";
+ }
+
+ std::string SourceCast(const Type &type) const {
+ return SourceCast(type, true);
+ }
+
+ std::string SourceCastBasic(const Type &type, bool castFromDest) const {
+ return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : "";
+ }
+
+ std::string SourceCastBasic(const Type &type) const {
+ return SourceCastBasic(type, true);
+ }
+
+ std::string GenEnumDefaultValue(const FieldDef &field) const {
+ 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);
+ return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+ : value.constant;
+ }
+
+ std::string GenDefaultValue(const FieldDef &field) const {
+ auto &value = field.value;
+ auto constant = field.IsScalarOptional() ? "0" : value.constant;
+ auto longSuffix = "L";
+ switch (value.type.base_type) {
+ case BASE_TYPE_BOOL: return constant == "0" ? "false" : "true";
+ case BASE_TYPE_ULONG: {
+ // Converts the ulong into its bits signed equivalent
+ uint64_t defaultValue = StringToUInt(constant.c_str());
+ return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix;
+ }
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_LONG: return constant + longSuffix;
+ default:
+ if (IsFloat(value.type.base_type)) {
+ if (field.IsScalarOptional()) {
+ return value.type.base_type == BASE_TYPE_DOUBLE ? "0.0" : "0f";
+ }
+ return JavaFloatGen.GenFloatConstant(field);
+ } else {
+ return constant;
+ }
+ }
+ }
+
+ std::string GenDefaultValueBasic(const FieldDef &field) const {
+ auto &value = field.value;
+ if (!IsScalar(value.type.base_type)) { return "0"; }
+ return GenDefaultValue(field);
+ }
+
+ void GenEnum(EnumDef &enum_def, std::string *code_ptr) const {
+ std::string &code = *code_ptr;
+ if (enum_def.generated) return;
+
+ // Generate enum definitions of the form:
+ // public static (final) int name = value;
+ // In Java, we use ints rather than the Enum feature, because we want them
+ // to map directly to how they're used in C/C++ and file formats.
+ // That, and Java Enums are expensive, and not universally liked.
+ GenComment(enum_def.doc_comment, code_ptr, &comment_config);
+
+ if (enum_def.attributes.Lookup("private")) {
+ // For Java, we leave the enum unmarked to indicate package-private
+ } else {
+ code += "public ";
+ }
+ code += "final class " + enum_def.name;
+ code += " {\n";
+ code += " private " + enum_def.name + "() { }\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 += " public static final ";
+ 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.
+ // 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.
+ auto range = enum_def.Distance();
+ // 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) {
+ code += "\n public static final String";
+ code += "[] names = { ";
+ auto val = enum_def.Vals().front();
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ auto ev = *it;
+ for (auto k = enum_def.Distance(val, ev); k > 1; --k) code += "\"\", ";
+ val = ev;
+ code += "\"" + (*it)->name + "\", ";
+ }
+ code += "};\n\n";
+ code += " public static ";
+ code += "String";
+ code += " " + MakeCamel("name", false);
+ code += "(int e) { return names[e";
+ if (enum_def.MinValue()->IsNonZero())
+ code += " - " + enum_def.MinValue()->name;
+ code += "]; }\n";
+ }
+
+ // Close the class
+ code += "}\n\n";
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetter(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "__string";
+ case BASE_TYPE_STRUCT: return "__struct";
+ case BASE_TYPE_UNION: return "__union";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
+ default: {
+ std::string getter = "bb.get";
+ if (type.base_type == BASE_TYPE_BOOL) {
+ getter = "0!=" + getter;
+ } else if (GenTypeBasic(type) != "byte") {
+ getter += MakeCamel(GenTypeBasic(type));
+ }
+ return getter;
+ }
+ }
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
+ const std::string &data_buffer,
+ const char *num = nullptr) const {
+ auto type = key_field->value.type;
+ auto dest_mask = DestinationMask(type, true);
+ auto dest_cast = DestinationCast(type);
+ auto getter = data_buffer + ".get";
+ if (GenTypeBasic(type) != "byte") {
+ getter += MakeCamel(GenTypeBasic(type));
+ }
+ getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
+ dest_mask;
+ return getter;
+ }
+
+ // Direct mutation is only allowed for scalar fields.
+ // Hence a setter method will only be generated for such fields.
+ std::string GenSetter(const Type &type) const {
+ if (IsScalar(type.base_type)) {
+ std::string setter = "bb.put";
+ if (GenTypeBasic(type) != "byte" && type.base_type != BASE_TYPE_BOOL) {
+ setter += MakeCamel(GenTypeBasic(type));
+ }
+ return setter;
+ } else {
+ return "";
+ }
+ }
+
+ // 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");
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix, size_t array_count = 0) const {
+ std::string &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;
+ const auto array_field = IsArray(field_type);
+ const auto &type = array_field ? field_type.VectorType()
+ : DestinationType(field_type, false);
+ const auto array_cnt = array_field ? (array_count + 1) : array_count;
+ if (IsStruct(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_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), array_cnt);
+ } else {
+ code += ", ";
+ code += GenTypeBasic(type);
+ for (size_t i = 0; i < array_cnt; i++) code += "[]";
+ code += " ";
+ code += nameprefix;
+ code += MakeCamel(field.name, false);
+ }
+ }
+ }
+
+ // Recusively generate struct construction statements of the form:
+ // builder.putType(name);
+ // and insert manual padding.
+ void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix, size_t index = 0,
+ bool in_array = false) const {
+ std::string &code = *code_ptr;
+ std::string indent((index + 1) * 2, ' ');
+ code += indent + " builder.prep(";
+ code += NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ");\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ if (field.padding) {
+ code += indent + " builder.pad(";
+ code += NumToString(field.padding) + ");\n";
+ }
+ if (IsStruct(field_type)) {
+ GenStructBody(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), index,
+ in_array);
+ } else {
+ const auto &type =
+ IsArray(field_type) ? field_type.VectorType() : field_type;
+ const auto index_var = "_idx" + NumToString(index);
+ if (IsArray(field_type)) {
+ code += indent + " for (int " + index_var + " = ";
+ code += NumToString(field_type.fixed_length);
+ code += "; " + index_var + " > 0; " + index_var + "--) {\n";
+ in_array = true;
+ }
+ if (IsStruct(type)) {
+ GenStructBody(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), index + 1,
+ in_array);
+ } else {
+ code += IsArray(field_type) ? " " : "";
+ code += indent + " builder.put";
+ code += GenMethod(type) + "(";
+ code += SourceCast(type);
+ auto argname = nameprefix + MakeCamel(field.name, false);
+ code += argname;
+ 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]";
+ }
+ code += ");\n";
+ }
+ if (IsArray(field_type)) { code += indent + " }\n"; }
+ }
+ }
+ }
+
+ std::string GenByteBufferLength(const char *bb_name) const {
+ std::string bb_len = bb_name;
+ bb_len += ".capacity()";
+ return bb_len;
+ }
+
+ std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+ const char *num = nullptr) const {
+ std::string key_offset = "";
+ key_offset += "__offset(" + NumToString(key_field->value.offset) + ", ";
+ if (num) {
+ key_offset += num;
+ key_offset += ", _bb)";
+ } else {
+ key_offset += GenByteBufferLength("bb");
+ key_offset += " - tableOffset, bb)";
+ }
+ return key_offset;
+ }
+
+ std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
+ std::string key_getter = " ";
+ key_getter += "int tableOffset = ";
+ key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
+ key_getter += ", bb);\n ";
+ if (IsString(key_field->value.type)) {
+ key_getter += "int comp = ";
+ key_getter += "compareStrings(";
+ key_getter += GenOffsetGetter(key_field);
+ key_getter += ", byteKey, bb);\n";
+ } else {
+ auto get_val = GenGetterForLookupByKey(key_field, "bb");
+ key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
+ key_getter += get_val + ";\n";
+ key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n";
+ }
+ return key_getter;
+ }
+
+ std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
+ std::string key_getter = "";
+ auto data_buffer = "_bb";
+ if (IsString(key_field->value.type)) {
+ key_getter += " return ";
+ key_getter += "";
+ key_getter += "compareStrings(";
+ key_getter += GenOffsetGetter(key_field, "o1") + ", ";
+ key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
+ key_getter += ";";
+ } else {
+ auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
+ key_getter +=
+ "\n " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
+ key_getter +=
+ field_getter + ";\n " + GenTypeNameDest(key_field->value.type);
+ key_getter += " val_2 = ";
+ field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
+ key_getter += field_getter + ";\n";
+ key_getter += " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
+ }
+ return key_getter;
+ }
+
+ void GenStruct(StructDef &struct_def, std::string *code_ptr) const {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+
+ // Generate a struct accessor class, with methods of the form:
+ // public type name() { return bb.getType(i + offset); }
+ // or for tables of the form:
+ // public type name() {
+ // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
+ // }
+ GenComment(struct_def.doc_comment, code_ptr, &comment_config);
+
+ if (parser_.opts.gen_generated) {
+ code += "@javax.annotation.Generated(value=\"flatc\")\n";
+ }
+ code += "@SuppressWarnings(\"unused\")\n";
+ if (struct_def.attributes.Lookup("private")) {
+ // For Java, we leave the struct unmarked to indicate package-private
+ } else {
+ code += "public ";
+ }
+ code += "final class " + struct_def.name;
+ code += " extends ";
+ code += struct_def.fixed ? "Struct" : "Table";
+ code += " {\n";
+
+ if (!struct_def.fixed) {
+ // Generate verson check method.
+ // Force compile time error if not using the same version runtime.
+ code += " public static void ValidateVersion() {";
+ code += " Constants.";
+ code += "FLATBUFFERS_2_0_0(); ";
+ code += "}\n";
+
+ // Generate a special accessor for the table that when used as the root
+ // of a FlatBuffer
+ std::string method_name = "getRootAs" + struct_def.name;
+ std::string method_signature =
+ " public static " + struct_def.name + " " + method_name;
+
+ // create convenience method that doesn't require an existing object
+ code += method_signature + "(ByteBuffer _bb) ";
+ code += "{ return " + method_name + "(_bb, new " + struct_def.name +
+ "()); }\n";
+
+ // create method that allows object reuse
+ code +=
+ method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
+ code += "_bb.order(ByteOrder.LITTLE_ENDIAN); ";
+ code += "return (obj.__assign(_bb.getInt(_bb.";
+ code += "position()";
+ code += ") + _bb.";
+ code += "position()";
+ code += ", _bb)); }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
+ if (parser_.file_identifier_.length()) {
+ // Check if a buffer has the identifier.
+ code += " public static ";
+ code += "boolean " + struct_def.name;
+ code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
+ code += "__has_identifier(_bb, \"";
+ code += parser_.file_identifier_;
+ code += "\"); }\n";
+ }
+ }
+ }
+ // Generate the __init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ code += " public void __init(int _i, ByteBuffer _bb) ";
+ code += "{ ";
+ code += "__reset(_i, _bb); ";
+ code += "}\n";
+ code +=
+ " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
+ code += "{ __init(_i, _bb); return this; }\n\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ GenComment(field.doc_comment, code_ptr, &comment_config, " ");
+ std::string type_name = GenTypeGet(field.value.type);
+ std::string type_name_dest = GenTypeNameDest(field.value.type);
+ std::string conditional_cast = "";
+ std::string optional = "";
+ std::string dest_mask = DestinationMask(field.value.type, true);
+ std::string dest_cast = DestinationCast(field.value.type);
+ std::string src_cast = SourceCast(field.value.type);
+ std::string method_start =
+ " public " +
+ (field.IsRequired() ? "" : GenNullableAnnotation(field.value.type)) +
+ GenPureAnnotation(field.value.type) + type_name_dest + optional +
+ " " + MakeCamel(field.name, false);
+ std::string obj = "obj";
+
+ // Most field accessors need to retrieve and test the field offset first,
+ // this is the prefix code for that:
+ auto offset_prefix =
+ IsArray(field.value.type)
+ ? " { return "
+ : (" { int o = __offset(" + NumToString(field.value.offset) +
+ "); return o != 0 ? ");
+ // Generate the accessors that don't do object reuse.
+ 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 += "(new ";
+ code += type_name + "()); }\n";
+ } else if (IsVector(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 += "(new " + type_name + "(), j); }\n";
+ }
+
+ if (field.IsScalarOptional()) { code += GenOptionalScalarCheck(field); }
+ std::string getter = dest_cast + GenGetter(field.value.type);
+ code += method_start;
+ std::string default_cast = "";
+ std::string member_suffix = "; ";
+ if (IsScalar(field.value.type.base_type)) {
+ code += "()";
+ member_suffix += "";
+ if (struct_def.fixed) {
+ code += " { return " + getter;
+ code += "(bb_pos + ";
+ code += NumToString(field.value.offset) + ")";
+ code += dest_mask;
+ } else {
+ code += offset_prefix + getter;
+ code += "(o + bb_pos)" + dest_mask;
+ code += " : " + default_cast;
+ code += GenDefaultValue(field);
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ code += "(" + type_name + " obj)";
+ if (struct_def.fixed) {
+ code += " { return " + obj + ".__assign(";
+ code += "bb_pos + " + NumToString(field.value.offset) + ", ";
+ code += "bb)";
+ } else {
+ code += offset_prefix + conditional_cast;
+ code += obj + ".__assign(";
+ code += field.value.type.struct_def->fixed
+ ? "o + bb_pos"
+ : "__indirect(o + bb_pos)";
+ code += ", bb) : null";
+ }
+ break;
+ case BASE_TYPE_STRING:
+ code += "()";
+ member_suffix += "";
+ code += offset_prefix + getter + "(o + ";
+ code += "bb_pos) : null";
+ break;
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ code += "(";
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += type_name + " obj, ";
+ getter = obj + ".__assign";
+ } else if (vectortype.base_type == BASE_TYPE_UNION) {
+ code += type_name + " obj, ";
+ }
+ code += "int j)";
+ const auto body = offset_prefix + conditional_cast + getter + "(";
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ code += body + "obj, ";
+ } else {
+ code += body;
+ }
+ std::string index;
+ if (IsArray(field.value.type)) {
+ index += "bb_pos + " + NumToString(field.value.offset) + " + ";
+ } else {
+ index += "__vector(o) + ";
+ }
+ index += "j * " + NumToString(InlineSize(vectortype));
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += vectortype.struct_def->fixed
+ ? index
+ : "__indirect(" + index + ")";
+ code += ", bb";
+ } else {
+ code += index;
+ }
+ code += ")" + dest_mask;
+ if (!IsArray(field.value.type)) {
+ code += " : ";
+ code +=
+ field.value.type.element == BASE_TYPE_BOOL
+ ? "false"
+ : (IsScalar(field.value.type.element) ? default_cast + "0"
+ : "null");
+ }
+
+ break;
+ }
+ case BASE_TYPE_UNION:
+ code += "(" + type_name + " obj)" + offset_prefix + getter;
+ code += "(obj, o + bb_pos) : null";
+ break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += member_suffix;
+ code += "}\n";
+ if (IsVector(field.value.type)) {
+ code += " public int " + MakeCamel(field.name, false);
+ code += "Length";
+ code += "()";
+ code += offset_prefix;
+ code += "__vector_len(o) : 0; ";
+ code += "";
+ code += "}\n";
+ // See if we should generate a by-key accessor.
+ if (field.value.type.element == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ auto &sd = *field.value.type.struct_def;
+ auto &fields = sd.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ auto qualified_name = WrapInNameSpace(sd);
+ code += " public " + qualified_name + " ";
+ code += MakeCamel(field.name, false) + "ByKey(";
+ code += GenTypeNameDest(key_field.value.type) + " key)";
+ code += offset_prefix;
+ code += qualified_name + ".__lookup_by_key(";
+ code += "null, ";
+ code += "__vector(o), key, ";
+ code += "bb) : null; ";
+ code += "}\n";
+ code += " public " + qualified_name + " ";
+ code += MakeCamel(field.name, false) + "ByKey(";
+ code += qualified_name + " obj, ";
+ code += GenTypeNameDest(key_field.value.type) + " key)";
+ code += offset_prefix;
+ code += qualified_name + ".__lookup_by_key(obj, ";
+ code += "__vector(o), key, ";
+ code += "bb) : null; ";
+ code += "}\n";
+ break;
+ }
+ }
+ }
+ }
+ // Generate the accessors for vector of structs with vector access object
+ if (IsVector(field.value.type)) {
+ 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";
+ } else if (element_base_type == BASE_TYPE_STRING) {
+ vector_type_name = "StringVector";
+ } else if (element_base_type == BASE_TYPE_UNION) {
+ vector_type_name = "UnionVector";
+ } 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";
+ code += vector_method_start + "() { return ";
+ code += MakeCamel(field.name, false) + "Vector";
+ code += "(new " + vector_type_name + "()); }\n";
+ code += vector_method_start + "(" + vector_type_name + " obj)";
+ code += offset_prefix + conditional_cast + obj + ".__assign(";
+ code += "__vector(o), ";
+ if (!IsScalar(element_base_type)) {
+ auto vectortype = field.value.type.VectorType();
+ code += NumToString(InlineSize(vectortype)) + ", ";
+ }
+ code += "bb) : null" + member_suffix + "}\n";
+ }
+ // Generate a ByteBuffer accessor for strings & vectors of scalars.
+ if ((IsVector(field.value.type) &&
+ IsScalar(field.value.type.VectorType().base_type)) ||
+ IsString(field.value.type)) {
+ code += " public ByteBuffer ";
+ code += MakeCamel(field.name, false);
+ code += "AsByteBuffer() { return ";
+ code += "__vector_as_bytebuffer(";
+ code += NumToString(field.value.offset) + ", ";
+ code += NumToString(IsString(field.value.type)
+ ? 1
+ : InlineSize(field.value.type.VectorType()));
+ code += "); }\n";
+ code += " public ByteBuffer ";
+ code += MakeCamel(field.name, false);
+ code += "InByteBuffer(ByteBuffer _bb) { return ";
+ code += "__vector_in_bytebuffer(_bb, ";
+ code += NumToString(field.value.offset) + ", ";
+ code += NumToString(IsString(field.value.type)
+ ? 1
+ : InlineSize(field.value.type.VectorType()));
+ code += "); }\n";
+ }
+ // 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 get_nested_method_name = nested_method_name;
+ code += " public " + nested_type_name + " ";
+ code += nested_method_name + "() { return ";
+ code +=
+ get_nested_method_name + "(new " + nested_type_name + "()); }\n";
+ code += " public " + nested_type_name + " ";
+ code += get_nested_method_name + "(";
+ code += nested_type_name + " obj";
+ code += ") { int o = __offset(";
+ code += NumToString(field.value.offset) + "); ";
+ code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
+ code += "";
+ code += "__indirect(__vector(o)), ";
+ code += "bb) : null; }\n";
+ }
+ // Generate mutators for scalar fields or vectors of scalars.
+ if (parser_.opts.mutable_buffer) {
+ auto is_series = (IsSeries(field.value.type));
+ const auto &underlying_type =
+ 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", false);
+ // A vector mutator also needs the index of the vector element it should
+ // mutate.
+ auto mutator_params = (is_series ? "(int j, " : "(") +
+ GenTypeNameDest(underlying_type) + " " +
+ field.name + ") { ";
+ auto setter_index =
+ is_series
+ ? (IsArray(field.value.type)
+ ? "bb_pos + " + NumToString(field.value.offset)
+ : "__vector(o)") +
+ +" + j * " + NumToString(InlineSize(underlying_type))
+ : (struct_def.fixed
+ ? "bb_pos + " + NumToString(field.value.offset)
+ : "o + bb_pos");
+ 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_params;
+ if (struct_def.fixed) {
+ code += GenSetter(underlying_type) + "(" + setter_index + ", ";
+ code += src_cast + setter_parameter + "); }\n";
+ } else {
+ code += "int o = __offset(";
+ code += NumToString(field.value.offset) + ");";
+ code += " if (o != 0) { " + GenSetter(underlying_type);
+ code += "(" + setter_index + ", " + src_cast + setter_parameter +
+ "); return true; } else { return false; } }\n";
+ }
+ }
+ }
+ 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) + ";";
+
+ code += vt_offset_constant;
+ code += "\n";
+ }
+ }
+ code += "\n";
+ flatbuffers::FieldDef *key_field = nullptr;
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ code += " public static " + GenOffsetType() + " ";
+ code += "create";
+ code += struct_def.name + "(FlatBufferBuilder builder";
+ GenStructArgs(struct_def, code_ptr, "");
+ code += ") {\n";
+ GenStructBody(struct_def, code_ptr, "");
+ code += " return ";
+ code += GenOffsetConstruct("builder." + std::string("offset()"));
+ code += ";\n }\n";
+ } else {
+ // Generate a method that creates a table in one go. This is only possible
+ // when the table has no struct fields, since those have to be created
+ // inline, and there's no way to do so in Java.
+ bool has_no_struct_fields = true;
+ int num_fields = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (IsStruct(field.value.type)) {
+ has_no_struct_fields = false;
+ } else {
+ num_fields++;
+ }
+ }
+ // 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) {
+ // Generate a table constructor of the form:
+ // public static int createName(FlatBufferBuilder builder, args...)
+ code += " public static " + GenOffsetType() + " ";
+ code += "create" + struct_def.name;
+ code += "(FlatBufferBuilder builder";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code += ",\n ";
+ code += GenTypeBasic(DestinationType(field.value.type, false));
+ code += " ";
+ code += field.name;
+ if (!IsScalar(field.value.type.base_type)) code += "Offset";
+ }
+ code += ") {\n builder.";
+ code += "startTable(";
+ code += NumToString(struct_def.fields.vec.size()) + ");\n";
+ for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+ size; size /= 2) {
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ 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;
+ if (!IsScalar(field.value.type.base_type)) code += "Offset";
+ code += ");\n";
+ }
+ }
+ }
+ code += " return " + struct_def.name + ".";
+ code += "end" + struct_def.name;
+ code += "(builder);\n }\n\n";
+ }
+ // Generate a set of static methods that allow table construction,
+ // of the form:
+ // public static void addName(FlatBufferBuilder builder, short name)
+ // { builder.addShort(id, name, default); }
+ // Unlike the Create function, these always work.
+ code += " public static void start";
+ code += struct_def.name;
+ code += "(FlatBufferBuilder builder) { builder.";
+ code += "startTable(";
+ code += NumToString(struct_def.fields.vec.size()) + "); }\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.key) key_field = &field;
+ code += " public static void add";
+ code += MakeCamel(field.name);
+ code += "(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(DestinationType(field.value.type, false));
+ auto argname = MakeCamel(field.name, false);
+ if (!IsScalar(field.value.type.base_type)) argname += "Offset";
+ code += " " + argname + ") { builder.add";
+ code += GenMethod(field.value.type) + "(";
+ code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
+ code += SourceCastBasic(field.value.type);
+ code += argname;
+ code += ", ";
+ code += SourceCastBasic(field.value.type);
+ code += GenDefaultValue(field);
+ code += "); }\n";
+ if (IsVector(field.value.type)) {
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ if (!IsStruct(vector_type)) {
+ // 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 += "Vector(FlatBufferBuilder builder, byte[] data) ";
+ code += "{ return builder.createByteVector(data); }\n";
+
+ code += " public static " + GenVectorOffsetType() + " ";
+ code += "create";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, ByteBuffer data) ";
+ code += "{ return builder.createByteVector(data); }\n";
+ } else {
+ code += " public static " + GenVectorOffsetType() + " ";
+ code += "create";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(vector_type) + "[] data) ";
+ code += "{ builder.startVector(";
+ code += NumToString(elem_size);
+ code += ", data.length, ";
+ code += NumToString(alignment);
+ code += "); for (int i = data.";
+ code += "length - 1; i >= 0; i--) builder.";
+ code += "add";
+ code += GenMethod(vector_type);
+ code += "(";
+ code += SourceCastBasic(vector_type, false);
+ code += "data[i]";
+ code += "); return ";
+ code += "builder.endVector(); }\n";
+ }
+ }
+ // Generate a method to start a vector, data to be added manually
+ // after.
+ code += " public static void start";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, int numElems) ";
+ code += "{ builder.startVector(";
+ code += NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment);
+ code += "); }\n";
+ }
+ }
+ code += " public static " + GenOffsetType() + " ";
+ code += "end" + struct_def.name;
+ code += "(FlatBufferBuilder builder) {\n int o = builder.";
+ code += "endTable();\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.required(o, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += " return " + GenOffsetConstruct("o") + ";\n }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
+ std::string size_prefix[] = { "", "SizePrefixed" };
+ for (int i = 0; i < 2; ++i) {
+ code += " public static void ";
+ code += "finish" + size_prefix[i] + struct_def.name;
+ code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType();
+ code += " offset) {";
+ code += " builder.finish" + size_prefix[i] + "(offset";
+
+ if (parser_.file_identifier_.length())
+ code += ", \"" + parser_.file_identifier_ + "\"";
+ code += "); }\n";
+ }
+ }
+ }
+ // Only generate key compare function for table,
+ // because `key_field` is not set for struct
+ if (struct_def.has_key && !struct_def.fixed) {
+ FLATBUFFERS_ASSERT(key_field);
+ code += "\n @Override\n protected int keysCompare(";
+ code += "Integer o1, Integer o2, ByteBuffer _bb) {";
+ code += GenKeyGetter(key_field);
+ code += " }\n";
+
+ code += "\n public static " + struct_def.name;
+ code += " __lookup_by_key(";
+ code += struct_def.name + " obj, ";
+ code += "int vectorLocation, ";
+ code += GenTypeNameDest(key_field->value.type);
+ code += " key, ByteBuffer bb) {\n";
+ if (IsString(key_field->value.type)) {
+ code += " byte[] byteKey = ";
+ code += "key.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n";
+ }
+ code += " int span = ";
+ code += "bb.getInt(vectorLocation - 4);\n";
+ code += " int start = 0;\n";
+ code += " while (span != 0) {\n";
+ code += " int middle = span / 2;\n";
+ code += GenLookupKeyGetter(key_field);
+ code += " if (comp > 0) {\n";
+ code += " span = middle;\n";
+ code += " } else if (comp < 0) {\n";
+ code += " middle++;\n";
+ code += " start += middle;\n";
+ code += " span -= middle;\n";
+ code += " } else {\n";
+ code += " return ";
+ code += "(obj == null ? new " + struct_def.name + "() : obj)";
+ code += ".__assign(tableOffset, bb);\n";
+ code += " }\n }\n";
+ code += " return null;\n";
+ code += " }\n";
+ }
+ GenVectorAccessObject(struct_def, code_ptr);
+ code += "}";
+ code += "\n\n";
+ }
+
+ std::string GenOptionalScalarCheck(FieldDef &field) const {
+ if (!field.IsScalarOptional()) return "";
+ return " public boolean has" + MakeCamel(field.name, true) +
+ "() { return 0 != __offset(" + NumToString(field.value.offset) +
+ "); }\n";
+ }
+
+ void GenVectorAccessObject(StructDef &struct_def,
+ std::string *code_ptr) const {
+ auto &code = *code_ptr;
+ // Generate a vector of structs accessor class.
+ code += "\n";
+ code += " ";
+ if (!struct_def.attributes.Lookup("private")) code += "public ";
+ code += "static ";
+ code += "final ";
+ code += "class Vector extends ";
+ code += "BaseVector {\n";
+
+ // Generate the __assign method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ std::string method_indent = " ";
+ code += method_indent + "public Vector ";
+ code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { ";
+ code += "__reset(_vector, _element_size, _bb); return this; }\n\n";
+
+ auto type_name = struct_def.name;
+ auto method_start = method_indent + "public " + type_name + " get";
+ // Generate the accessors that don't do object reuse.
+ code += method_start + "(int j) { return get";
+ code += "(new " + type_name + "(), j); }\n";
+ code += method_start + "(" + type_name + " obj, int j) { ";
+ code += " return obj.__assign(";
+ std::string index = "__element(j)";
+ code += struct_def.fixed ? index : "__indirect(" + index + ", bb)";
+ code += ", bb); }\n";
+ // See if we should generate a by-key accessor.
+ if (!struct_def.fixed) {
+ auto &fields = struct_def.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ auto nullable_annotation =
+ parser_.opts.gen_nullable ? "@Nullable " : "";
+ code += method_indent + nullable_annotation;
+ code += "public " + type_name + " ";
+ code += "getByKey(";
+ code += GenTypeNameDest(key_field.value.type) + " key) { ";
+ code += " return __lookup_by_key(null, ";
+ code += "__vector(), key, ";
+ code += "bb); ";
+ code += "}\n";
+ code += method_indent + nullable_annotation;
+ code += "public " + type_name + " ";
+ code += "getByKey(";
+ code += type_name + " obj, ";
+ code += GenTypeNameDest(key_field.value.type) + " key) { ";
+ code += " return __lookup_by_key(obj, ";
+ code += "__vector(), key, ";
+ code += "bb); ";
+ code += "}\n";
+ break;
+ }
+ }
+ }
+ code += " }\n";
+ }
+
+ // This tracks the current namespace used to determine if a type need to be
+ // prefixed by its namespace
+ const Namespace *cur_name_space_;
+};
+} // namespace java
+
+bool GenerateJava(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ java::JavaGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_json_schema.cpp b/contrib/libs/flatbuffers/src/idl_gen_json_schema.cpp
new file mode 100644
index 0000000000..d58bb84976
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_json_schema.cpp
@@ -0,0 +1,292 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+namespace jsons {
+
+template<class T> std::string GenFullName(const T *enum_def) {
+ std::string full_name;
+ const auto &name_spaces = enum_def->defined_namespace->components;
+ for (auto ns = name_spaces.cbegin(); ns != name_spaces.cend(); ++ns) {
+ full_name.append(*ns + "_");
+ }
+ full_name.append(enum_def->name);
+ return full_name;
+}
+
+template<class T> std::string GenTypeRef(const T *enum_def) {
+ return "\"$ref\" : \"#/definitions/" + GenFullName(enum_def) + "\"";
+}
+
+std::string GenType(const std::string &name) {
+ return "\"type\" : \"" + name + "\"";
+}
+
+std::string GenType(BaseType type) {
+ switch (type) {
+ case BASE_TYPE_BOOL: return "\"type\" : \"boolean\"";
+ case BASE_TYPE_CHAR:
+ return "\"type\" : \"integer\", \"minimum\" : " +
+ NumToString(std::numeric_limits<int8_t>::min()) +
+ ", \"maximum\" : " +
+ NumToString(std::numeric_limits<int8_t>::max());
+ case BASE_TYPE_UCHAR:
+ return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" :" +
+ NumToString(std::numeric_limits<uint8_t>::max());
+ case BASE_TYPE_SHORT:
+ return "\"type\" : \"integer\", \"minimum\" : " +
+ NumToString(std::numeric_limits<int16_t>::min()) +
+ ", \"maximum\" : " +
+ NumToString(std::numeric_limits<int16_t>::max());
+ case BASE_TYPE_USHORT:
+ return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" : " +
+ NumToString(std::numeric_limits<uint16_t>::max());
+ case BASE_TYPE_INT:
+ return "\"type\" : \"integer\", \"minimum\" : " +
+ NumToString(std::numeric_limits<int32_t>::min()) +
+ ", \"maximum\" : " +
+ NumToString(std::numeric_limits<int32_t>::max());
+ case BASE_TYPE_UINT:
+ return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" : " +
+ NumToString(std::numeric_limits<uint32_t>::max());
+ case BASE_TYPE_LONG:
+ return "\"type\" : \"integer\", \"minimum\" : " +
+ NumToString(std::numeric_limits<int64_t>::min()) +
+ ", \"maximum\" : " +
+ NumToString(std::numeric_limits<int64_t>::max());
+ case BASE_TYPE_ULONG:
+ return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" : " +
+ NumToString(std::numeric_limits<uint64_t>::max());
+ case BASE_TYPE_FLOAT:
+ case BASE_TYPE_DOUBLE: return "\"type\" : \"number\"";
+ case BASE_TYPE_STRING: return "\"type\" : \"string\"";
+ default: return "";
+ }
+}
+
+std::string GenBaseType(const Type &type) {
+ if (type.struct_def != nullptr) { return GenTypeRef(type.struct_def); }
+ if (type.enum_def != nullptr) { return GenTypeRef(type.enum_def); }
+ return GenType(type.base_type);
+}
+
+std::string GenArrayType(const Type &type) {
+ std::string element_type;
+ if (type.struct_def != nullptr) {
+ element_type = GenTypeRef(type.struct_def);
+ } else if (type.enum_def != nullptr) {
+ element_type = GenTypeRef(type.enum_def);
+ } else {
+ element_type = GenType(type.element);
+ }
+
+ return "\"type\" : \"array\", \"items\" : {" + element_type + "}";
+}
+
+std::string GenType(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ return GenArrayType(type);
+ }
+ case BASE_TYPE_STRUCT: {
+ return GenTypeRef(type.struct_def);
+ }
+ case BASE_TYPE_UNION: {
+ std::string union_type_string("\"anyOf\": [");
+ const auto &union_types = type.enum_def->Vals();
+ for (auto ut = union_types.cbegin(); ut < union_types.cend(); ++ut) {
+ const auto &union_type = *ut;
+ if (union_type->union_type.base_type == BASE_TYPE_NONE) { continue; }
+ if (union_type->union_type.base_type == BASE_TYPE_STRUCT) {
+ union_type_string.append(
+ "{ " + GenTypeRef(union_type->union_type.struct_def) + " }");
+ }
+ if (union_type != *type.enum_def->Vals().rbegin()) {
+ union_type_string.append(",");
+ }
+ }
+ union_type_string.append("]");
+ return union_type_string;
+ }
+ case BASE_TYPE_UTYPE: return GenTypeRef(type.enum_def);
+ default: {
+ return GenBaseType(type);
+ }
+ }
+}
+
+class JsonSchemaGenerator : public BaseGenerator {
+ private:
+ std::string code_;
+
+ public:
+ JsonSchemaGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "", "json") {}
+
+ explicit JsonSchemaGenerator(const BaseGenerator &base_generator)
+ : BaseGenerator(base_generator) {}
+
+ std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name,
+ const IDLOptions &options /* unused */) const {
+ (void)options;
+ return path + file_name + ".schema.json";
+ }
+
+ // If indentation is less than 0, that indicates we don't want any newlines
+ // either.
+ std::string NewLine() const {
+ return parser_.opts.indent_step >= 0 ? "\n" : "";
+ }
+
+ std::string Indent(int indent) const {
+ const auto num_spaces = indent * std::max(parser_.opts.indent_step, 0);
+ return std::string(num_spaces, ' ');
+ }
+
+ bool generate() {
+ code_ = "";
+ if (parser_.root_struct_def_ == nullptr) { return false; }
+ code_ += "{" + NewLine();
+ code_ += Indent(1) +
+ "\"$schema\": \"https://json-schema.org/draft/2019-09/schema\"," +
+ NewLine();
+ code_ += Indent(1) + "\"definitions\": {" + NewLine();
+ for (auto e = parser_.enums_.vec.cbegin(); e != parser_.enums_.vec.cend();
+ ++e) {
+ code_ += Indent(2) + "\"" + GenFullName(*e) + "\" : {" + NewLine();
+ code_ += Indent(3) + GenType("string") + "," + NewLine();
+ auto enumdef(Indent(3) + "\"enum\": [");
+ for (auto enum_value = (*e)->Vals().begin();
+ enum_value != (*e)->Vals().end(); ++enum_value) {
+ enumdef.append("\"" + (*enum_value)->name + "\"");
+ if (*enum_value != (*e)->Vals().back()) { enumdef.append(", "); }
+ }
+ enumdef.append("]");
+ code_ += enumdef + NewLine();
+ code_ += Indent(2) + "}," + NewLine(); // close type
+ }
+ for (auto s = parser_.structs_.vec.cbegin();
+ s != parser_.structs_.vec.cend(); ++s) {
+ 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);
+ }
+ 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;
+ for (auto prop = properties.cbegin(); prop != properties.cend(); ++prop) {
+ const auto &property = *prop;
+ std::string arrayInfo = "";
+ if (IsArray(property->value.type)) {
+ arrayInfo = "," + NewLine() + Indent(8) + "\"minItems\": " +
+ NumToString(property->value.type.fixed_length) + "," +
+ NewLine() + Indent(8) + "\"maxItems\": " +
+ NumToString(property->value.type.fixed_length);
+ }
+ std::string deprecated_info = "";
+ if (property->deprecated) {
+ deprecated_info =
+ "," + 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;
+ typeLine += NewLine() + Indent(7) + "}";
+ if (property != properties.back()) { typeLine.append(","); }
+ code_ += typeLine + NewLine();
+ }
+ code_ += Indent(3) + "}," + NewLine(); // close properties
+
+ std::vector<FieldDef *> requiredProperties;
+ std::copy_if(properties.begin(), properties.end(),
+ back_inserter(requiredProperties),
+ [](FieldDef const *prop) { return prop->IsRequired(); });
+ if (!requiredProperties.empty()) {
+ auto required_string(Indent(3) + "\"required\" : [");
+ for (auto req_prop = requiredProperties.cbegin();
+ req_prop != requiredProperties.cend(); ++req_prop) {
+ required_string.append("\"" + (*req_prop)->name + "\"");
+ if (*req_prop != requiredProperties.back()) {
+ required_string.append(", ");
+ }
+ }
+ required_string.append("],");
+ code_ += required_string + NewLine();
+ }
+ code_ += Indent(3) + "\"additionalProperties\" : false" + NewLine();
+ auto closeType(Indent(2) + "}");
+ if (*s != parser_.structs_.vec.back()) { closeType.append(","); }
+ code_ += closeType + NewLine(); // close type
+ }
+ code_ += Indent(1) + "}," + NewLine(); // close definitions
+
+ // mark root type
+ code_ += Indent(1) + "\"$ref\" : \"#/definitions/" +
+ GenFullName(parser_.root_struct_def_) + "\"" + NewLine();
+
+ code_ += "}" + NewLine(); // close schema root
+ return true;
+ }
+
+ bool save() const {
+ const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts);
+ return SaveFile(file_path.c_str(), code_, false);
+ }
+
+ const std::string getJson() { return code_; }
+};
+} // namespace jsons
+
+bool GenerateJsonSchema(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ jsons::JsonSchemaGenerator generator(parser, path, file_name);
+ if (!generator.generate()) { return false; }
+ return generator.save();
+}
+
+bool GenerateJsonSchema(const Parser &parser, std::string *json) {
+ jsons::JsonSchemaGenerator generator(parser, "", "");
+ if (!generator.generate()) { return false; }
+ *json = generator.getJson();
+ return true;
+}
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_kotlin.cpp b/contrib/libs/flatbuffers/src/idl_gen_kotlin.cpp
new file mode 100644
index 0000000000..fb4ce87a67
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_kotlin.cpp
@@ -0,0 +1,1527 @@
+/*
+ * 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 <functional>
+#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 {
+
+namespace kotlin {
+
+typedef std::map<std::string, std::pair<std::string, std::string> > FbbParamMap;
+static TypedFloatConstantGenerator KotlinFloatGen("Double.", "Float.", "NaN",
+ "POSITIVE_INFINITY",
+ "NEGATIVE_INFINITY");
+
+static const CommentConfig comment_config = { "/**", " *", " */" };
+static const std::string ident_pad = " ";
+static const char *keywords[] = {
+ "package", "as", "typealias", "class", "this", "super",
+ "val", "var", "fun", "for", "null", "true",
+ "false", "is", "in", "throw", "return", "break",
+ "continue", "object", "if", "try", "else", "while",
+ "do", "when", "interface", "typeof", "Any", "Character"
+};
+
+// 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); }
+ }
+
+ return MakeCamel(name, false);
+}
+
+class KotlinGenerator : public BaseGenerator {
+ public:
+ KotlinGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", ".", "kt"),
+ cur_name_space_(nullptr) {}
+
+ KotlinGenerator &operator=(const KotlinGenerator &);
+ bool generate() FLATBUFFERS_OVERRIDE {
+ std::string one_file_code;
+
+ cur_name_space_ = parser_.current_namespace_;
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ CodeWriter enumWriter(ident_pad);
+ auto &enum_def = **it;
+ if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
+ GenEnum(enum_def, enumWriter);
+ if (parser_.opts.one_file) {
+ one_file_code += enumWriter.ToString();
+ } else {
+ if (!SaveType(enum_def.name, *enum_def.defined_namespace,
+ enumWriter.ToString(), false))
+ return false;
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ CodeWriter structWriter(ident_pad);
+ auto &struct_def = **it;
+ if (!parser_.opts.one_file)
+ cur_name_space_ = struct_def.defined_namespace;
+ GenStruct(struct_def, structWriter, parser_.opts);
+ if (parser_.opts.one_file) {
+ one_file_code += structWriter.ToString();
+ } else {
+ if (!SaveType(struct_def.name, *struct_def.defined_namespace,
+ structWriter.ToString(), true))
+ return false;
+ }
+ }
+
+ if (parser_.opts.one_file) {
+ return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
+ true);
+ }
+ return true;
+ }
+
+ // 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 {
+ if (!classcode.length()) return true;
+
+ std::string code =
+ "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ std::string namespace_name = FullNamespace(".", ns);
+ if (!namespace_name.empty()) {
+ code += "package " + namespace_name;
+ code += "\n\n";
+ }
+ if (needs_includes) {
+ code += "import java.nio.*\n";
+ code += "import kotlin.math.sign\n";
+ code += "import com.google.flatbuffers.*\n\n";
+ }
+ code += classcode;
+ auto filename = NamespaceDir(ns) + defname + ".kt";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ const Namespace *CurrentNameSpace() const FLATBUFFERS_OVERRIDE {
+ return cur_name_space_;
+ }
+
+ static bool IsEnum(const Type &type) {
+ return type.enum_def != nullptr && IsInteger(type.base_type);
+ }
+
+ static std::string GenTypeBasic(const BaseType &type) {
+ // clang-format off
+ static const char * const kotlin_typename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, ...) \
+ #KTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ return kotlin_typename[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());
+ case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
+ default: return "Table";
+ }
+ }
+
+ // with the addition of optional scalar types,
+ // we are adding the nullable '?' operator to return type of a field.
+ std::string GetterReturnType(const FieldDef &field) const {
+ auto base_type = field.value.type.base_type;
+
+ auto r_type = GenTypeGet(field.value.type);
+ if (field.IsScalarOptional() ||
+ // string, structs and unions
+ (base_type == BASE_TYPE_STRING || base_type == BASE_TYPE_STRUCT ||
+ base_type == BASE_TYPE_UNION) ||
+ // vector of anything not scalar
+ (base_type == BASE_TYPE_VECTOR &&
+ !IsScalar(field.value.type.VectorType().base_type))) {
+ r_type += "?";
+ }
+ return r_type;
+ }
+
+ std::string GenTypeGet(const Type &type) const {
+ return IsScalar(type.base_type) ? GenTypeBasic(type.base_type)
+ : GenTypePointer(type);
+ }
+
+ std::string GenEnumDefaultValue(const FieldDef &field) const {
+ 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);
+ return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+ : value.constant;
+ }
+
+ // Generate default values to compare against a default value when
+ // `force_defaults` is `false`.
+ // Main differences are:
+ // - Floats are upcasted to doubles
+ // - Unsigned are casted to signed
+ std::string GenFBBDefaultValue(const FieldDef &field) const {
+ if (field.IsScalarOptional()) {
+ // although default value is null, java API forces us to present a real
+ // default value for scalars, while adding a field to the buffer. This is
+ // not a problem because the default can be representing just by not
+ // calling builder.addMyField()
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_DOUBLE:
+ case BASE_TYPE_FLOAT: return "0.0";
+ case BASE_TYPE_BOOL: return "false";
+ default: return "0";
+ }
+ }
+ auto out = GenDefaultValue(field, true);
+ // All FlatBufferBuilder default floating point values are doubles
+ if (field.value.type.base_type == BASE_TYPE_FLOAT) {
+ if (out.find("Float") != std::string::npos) {
+ out.replace(0, 5, "Double");
+ }
+ }
+ // Guarantee all values are doubles
+ if (out.back() == 'f') out.pop_back();
+ return out;
+ }
+
+ // FlatBufferBuilder only store signed types, so this function
+ // returns a cast for unsigned values
+ std::string GenFBBValueCast(const FieldDef &field) const {
+ if (IsUnsigned(field.value.type.base_type)) {
+ return CastToSigned(field.value.type);
+ }
+ return "";
+ }
+
+ std::string GenDefaultValue(const FieldDef &field,
+ bool force_signed = false) const {
+ auto &value = field.value;
+ auto base_type = field.value.type.base_type;
+
+ if (field.IsScalarOptional()) { return "null"; }
+ if (IsFloat(base_type)) {
+ auto val = KotlinFloatGen.GenFloatConstant(field);
+ if (base_type == BASE_TYPE_DOUBLE && val.back() == 'f') {
+ val.pop_back();
+ }
+ return val;
+ }
+
+ if (base_type == BASE_TYPE_BOOL) {
+ return value.constant == "0" ? "false" : "true";
+ }
+
+ std::string suffix = "";
+
+ if (base_type == BASE_TYPE_LONG || !force_signed) {
+ suffix = LiteralSuffix(base_type);
+ }
+ return value.constant + suffix;
+ }
+
+ void GenEnum(EnumDef &enum_def, CodeWriter &writer) const {
+ if (enum_def.generated) return;
+
+ GenerateComment(enum_def.doc_comment, writer, &comment_config);
+
+ writer += "@Suppress(\"unused\")";
+ writer += "@ExperimentalUnsignedTypes";
+ writer += "class " + Esc(enum_def.name) + " private constructor() {";
+ writer.IncrementIdentLevel();
+
+ GenerateCompanionObject(writer, [&]() {
+ // Write all properties
+ auto vals = enum_def.Vals();
+ for (auto it = vals.begin(); it != vals.end(); ++it) {
+ auto &ev = **it;
+ auto field_type = GenTypeBasic(enum_def.underlying_type.base_type);
+ auto val = enum_def.ToString(ev);
+ auto suffix = LiteralSuffix(enum_def.underlying_type.base_type);
+ writer.SetValue("name", Esc(ev.name));
+ writer.SetValue("type", field_type);
+ writer.SetValue("val", val + suffix);
+ GenerateComment(ev.doc_comment, writer, &comment_config);
+ writer += "const val {{name}}: {{type}} = {{val}}";
+ }
+
+ // Generate a generate 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.
+ auto range = enum_def.Distance();
+ // 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) {
+ GeneratePropertyOneLine(writer, "names", "Array<String>", [&]() {
+ writer += "arrayOf(\\";
+ auto val = enum_def.Vals().front();
+ for (auto it = vals.begin(); it != vals.end(); ++it) {
+ auto ev = *it;
+ for (auto k = enum_def.Distance(val, ev); k > 1; --k)
+ writer += "\"\", \\";
+ val = ev;
+ writer += "\"" + (*it)->name + "\"\\";
+ if (it + 1 != vals.end()) { writer += ", \\"; }
+ }
+ writer += ")";
+ });
+ GenerateFunOneLine(
+ writer, "name", "e: Int", "String",
+ [&]() {
+ writer += "names[e\\";
+ if (enum_def.MinValue()->IsNonZero())
+ writer += " - " + enum_def.MinValue()->name + ".toInt()\\";
+ writer += "]";
+ },
+ parser_.opts.gen_jvmstatic);
+ }
+ });
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string ByteBufferGetter(const Type &type,
+ std::string bb_var_name) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "__string";
+ case BASE_TYPE_STRUCT: return "__struct";
+ case BASE_TYPE_UNION: return "__union";
+ case BASE_TYPE_VECTOR:
+ return ByteBufferGetter(type.VectorType(), bb_var_name);
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT: return bb_var_name + ".getInt";
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT: return bb_var_name + ".getShort";
+ case BASE_TYPE_ULONG:
+ case BASE_TYPE_LONG: return bb_var_name + ".getLong";
+ case BASE_TYPE_FLOAT: return bb_var_name + ".getFloat";
+ case BASE_TYPE_DOUBLE: return bb_var_name + ".getDouble";
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_NONE:
+ 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));
+ }
+ }
+
+ std::string ByteBufferSetter(const Type &type) const {
+ if (IsScalar(type.base_type)) {
+ switch (type.base_type) {
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT: return "bb.putInt";
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT: return "bb.putShort";
+ case BASE_TYPE_ULONG:
+ case BASE_TYPE_LONG: return "bb.putLong";
+ case BASE_TYPE_FLOAT: return "bb.putFloat";
+ case BASE_TYPE_DOUBLE: return "bb.putDouble";
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_BOOL:
+ case BASE_TYPE_NONE:
+ case BASE_TYPE_UTYPE: return "bb.put";
+ default: return "bb.put" + MakeCamel(GenTypeBasic(type.base_type));
+ }
+ }
+ return "";
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenLookupByKey(flatbuffers::FieldDef *key_field,
+ const std::string &bb_var_name,
+ const char *num = nullptr) const {
+ auto type = key_field->value.type;
+ return ByteBufferGetter(type, bb_var_name) + "(" +
+ GenOffsetGetter(key_field, num) + ")";
+ }
+
+ // Returns the method name for use with add/put calls.
+ static std::string GenMethod(const Type &type) {
+ return IsScalar(type.base_type) ? ToSignedType(type)
+ : (IsStruct(type) ? "Struct" : "Offset");
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ static void GenStructArgs(const StructDef &struct_def, CodeWriter &writer,
+ const char *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, writer,
+ (nameprefix + (field.name + "_")).c_str());
+ } else {
+ writer += std::string(", ") + nameprefix + "\\";
+ writer += MakeCamel(field.name) + ": \\";
+ writer += GenTypeBasic(field.value.type.base_type) + "\\";
+ }
+ }
+ }
+
+ // Recusively generate struct construction statements of the form:
+ // builder.putType(name);
+ // and insert manual padding.
+ static void GenStructBody(const StructDef &struct_def, CodeWriter &writer,
+ const char *nameprefix) {
+ writer.SetValue("align", NumToString(struct_def.minalign));
+ writer.SetValue("size", NumToString(struct_def.bytesize));
+ writer += "builder.prep({{align}}, {{size}})";
+ auto fields_vec = struct_def.fields.vec;
+ for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); ++it) {
+ auto &field = **it;
+
+ if (field.padding) {
+ writer.SetValue("pad", NumToString(field.padding));
+ writer += "builder.pad({{pad}})";
+ }
+ if (IsStruct(field.value.type)) {
+ GenStructBody(*field.value.type.struct_def, writer,
+ (nameprefix + (field.name + "_")).c_str());
+ } else {
+ writer.SetValue("type", GenMethod(field.value.type));
+ writer.SetValue("argname", nameprefix + MakeCamel(field.name, false));
+ writer.SetValue("cast", CastToSigned(field.value.type));
+ writer += "builder.put{{type}}({{argname}}{{cast}})";
+ }
+ }
+ }
+
+ std::string GenByteBufferLength(const char *bb_name) const {
+ std::string bb_len = bb_name;
+ bb_len += ".capacity()";
+ return bb_len;
+ }
+
+ std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+ const char *num = nullptr) const {
+ std::string key_offset =
+ "__offset(" + NumToString(key_field->value.offset) + ", ";
+ if (num) {
+ key_offset += num;
+ key_offset += ", _bb)";
+ } else {
+ key_offset += GenByteBufferLength("bb");
+ key_offset += " - tableOffset, bb)";
+ }
+ return key_offset;
+ }
+
+ void GenStruct(StructDef &struct_def, CodeWriter &writer,
+ IDLOptions options) const {
+ if (struct_def.generated) return;
+
+ GenerateComment(struct_def.doc_comment, writer, &comment_config);
+ auto fixed = struct_def.fixed;
+
+ writer.SetValue("struct_name", Esc(struct_def.name));
+ writer.SetValue("superclass", fixed ? "Struct" : "Table");
+
+ writer += "@Suppress(\"unused\")";
+ writer += "@ExperimentalUnsignedTypes";
+ writer += "class {{struct_name}} : {{superclass}}() {\n";
+
+ writer.IncrementIdentLevel();
+
+ {
+ // Generate the __init() method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ GenerateFun(writer, "__init", "_i: Int, _bb: ByteBuffer", "",
+ [&]() { writer += "__reset(_i, _bb)"; });
+
+ // Generate assign method
+ GenerateFun(writer, "__assign", "_i: Int, _bb: ByteBuffer",
+ Esc(struct_def.name), [&]() {
+ writer += "__init(_i, _bb)";
+ writer += "return this";
+ });
+
+ // Generate all getters
+ GenerateStructGetters(struct_def, writer);
+
+ // Generate Static Fields
+ GenerateCompanionObject(writer, [&]() {
+ if (!struct_def.fixed) {
+ FieldDef *key_field = nullptr;
+
+ // Generate verson check method.
+ // Force compile time error if not using the same version
+ // runtime.
+ GenerateFunOneLine(
+ writer, "validateVersion", "", "",
+ [&]() { writer += "Constants.FLATBUFFERS_2_0_0()"; },
+ options.gen_jvmstatic);
+
+ GenerateGetRootAsAccessors(Esc(struct_def.name), writer, options);
+ GenerateBufferHasIdentifier(struct_def, writer, options);
+ GenerateTableCreator(struct_def, writer, options);
+
+ GenerateStartStructMethod(struct_def, writer, options);
+
+ // Static Add for fields
+ auto fields = struct_def.fields.vec;
+ int field_pos = -1;
+ for (auto it = fields.begin(); it != fields.end(); ++it) {
+ auto &field = **it;
+ field_pos++;
+ if (field.deprecated) continue;
+ if (field.key) key_field = &field;
+ GenerateAddField(NumToString(field_pos), field, writer, options);
+
+ if (IsVector(field.value.type)) {
+ auto vector_type = field.value.type.VectorType();
+ if (!IsStruct(vector_type)) {
+ GenerateCreateVectorField(field, writer, options);
+ }
+ GenerateStartVectorField(field, writer, options);
+ }
+ }
+
+ GenerateEndStructMethod(struct_def, writer, options);
+ auto file_identifier = parser_.file_identifier_;
+ if (parser_.root_struct_def_ == &struct_def) {
+ GenerateFinishStructBuffer(struct_def, file_identifier, writer,
+ options);
+ GenerateFinishSizePrefixed(struct_def, file_identifier, writer,
+ options);
+ }
+
+ if (struct_def.has_key) {
+ GenerateLookupByKey(key_field, struct_def, writer, options);
+ }
+ } else {
+ GenerateStaticConstructor(struct_def, writer, options);
+ }
+ });
+ }
+
+ // class closing
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ // TODO: move key_field to reference instead of pointer
+ void GenerateLookupByKey(FieldDef *key_field, StructDef &struct_def,
+ CodeWriter &writer, const IDLOptions options) const {
+ std::stringstream params;
+ params << "obj: " << Esc(struct_def.name) << "?"
+ << ", ";
+ params << "vectorLocation: Int, ";
+ params << "key: " << GenTypeGet(key_field->value.type) << ", ";
+ params << "bb: ByteBuffer";
+
+ auto statements = [&]() {
+ auto base_type = key_field->value.type.base_type;
+ writer.SetValue("struct_name", Esc(struct_def.name));
+ if (base_type == BASE_TYPE_STRING) {
+ writer +=
+ "val byteKey = key."
+ "toByteArray(java.nio.charset.StandardCharsets.UTF_8)";
+ }
+ writer += "var span = bb.getInt(vectorLocation - 4)";
+ writer += "var start = 0";
+ writer += "while (span != 0) {";
+ writer.IncrementIdentLevel();
+ writer += "var middle = span / 2";
+ writer +=
+ "val tableOffset = __indirect(vector"
+ "Location + 4 * (start + middle), bb)";
+ if (IsString(key_field->value.type)) {
+ writer += "val comp = compareStrings(\\";
+ writer += GenOffsetGetter(key_field) + "\\";
+ writer += ", byteKey, bb)";
+ } else {
+ auto cast = CastToUsigned(key_field->value.type);
+ auto get_val = GenLookupByKey(key_field, "bb");
+ writer += "val value = " + get_val + cast;
+ writer += "val comp = value.compareTo(key)";
+ }
+ writer += "when {";
+ writer.IncrementIdentLevel();
+ writer += "comp > 0 -> span = middle";
+ writer += "comp < 0 -> {";
+ writer.IncrementIdentLevel();
+ writer += "middle++";
+ writer += "start += middle";
+ writer += "span -= middle";
+ writer.DecrementIdentLevel();
+ writer += "}"; // end comp < 0
+ writer += "else -> {";
+ writer.IncrementIdentLevel();
+ writer += "return (obj ?: {{struct_name}}()).__assign(tableOffset, bb)";
+ writer.DecrementIdentLevel();
+ writer += "}"; // end else
+ writer.DecrementIdentLevel();
+ writer += "}"; // end when
+ writer.DecrementIdentLevel();
+ writer += "}"; // end while
+ writer += "return null";
+ };
+ GenerateFun(writer, "__lookup_by_key", params.str(),
+ Esc(struct_def.name) + "?", statements, options.gen_jvmstatic);
+ }
+
+ void GenerateFinishSizePrefixed(StructDef &struct_def,
+ const std::string &identifier,
+ CodeWriter &writer,
+ const IDLOptions options) const {
+ auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
+ auto params = "builder: FlatBufferBuilder, offset: Int";
+ auto method_name = "finishSizePrefixed" + Esc(struct_def.name) + "Buffer";
+ GenerateFunOneLine(
+ writer, method_name, params, "",
+ [&]() { writer += "builder.finishSizePrefixed(offset" + id + ")"; },
+ options.gen_jvmstatic);
+ }
+ void GenerateFinishStructBuffer(StructDef &struct_def,
+ const std::string &identifier,
+ CodeWriter &writer,
+ const IDLOptions options) const {
+ auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
+ auto params = "builder: FlatBufferBuilder, offset: Int";
+ auto method_name = "finish" + Esc(struct_def.name) + "Buffer";
+ GenerateFunOneLine(
+ writer, method_name, params, "",
+ [&]() { writer += "builder.finish(offset" + id + ")"; },
+ options.gen_jvmstatic);
+ }
+
+ void GenerateEndStructMethod(StructDef &struct_def, CodeWriter &writer,
+ const IDLOptions options) const {
+ // Generate end{{TableName}}(builder: FlatBufferBuilder) method
+ auto name = "end" + Esc(struct_def.name);
+ auto params = "builder: FlatBufferBuilder";
+ auto returns = "Int";
+ auto field_vec = struct_def.fields.vec;
+
+ GenerateFun(
+ writer, name, params, returns,
+ [&]() {
+ writer += "val o = builder.endTable()";
+ writer.IncrementIdentLevel();
+ for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated || !field.IsRequired()) { continue; }
+ writer.SetValue("offset", NumToString(field.value.offset));
+ writer += "builder.required(o, {{offset}})";
+ }
+ writer.DecrementIdentLevel();
+ writer += "return o";
+ },
+ options.gen_jvmstatic);
+ }
+
+ // Generate a method to create a vector from a Kotlin array.
+ 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 params = "builder: FlatBufferBuilder, data: " +
+ GenTypeBasic(vector_type.base_type) + "Array";
+ writer.SetValue("size", NumToString(InlineSize(vector_type)));
+ writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
+ writer.SetValue("root", GenMethod(vector_type));
+ writer.SetValue("cast", CastToSigned(vector_type));
+
+ GenerateFun(
+ writer, method_name, params, "Int",
+ [&]() {
+ writer += "builder.startVector({{size}}, data.size, {{align}})";
+ writer += "for (i in data.size - 1 downTo 0) {";
+ writer.IncrementIdentLevel();
+ writer += "builder.add{{root}}(data[i]{{cast}})";
+ writer.DecrementIdentLevel();
+ writer += "}";
+ writer += "return builder.endVector()";
+ },
+ options.gen_jvmstatic);
+ }
+
+ void GenerateStartVectorField(FieldDef &field, CodeWriter &writer,
+ const IDLOptions options) const {
+ // Generate a method to start a vector, data to be added manually
+ // after.
+ auto vector_type = field.value.type.VectorType();
+ auto params = "builder: FlatBufferBuilder, numElems: Int";
+ writer.SetValue("size", NumToString(InlineSize(vector_type)));
+ writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
+
+ GenerateFunOneLine(
+ writer, "start" + MakeCamel(Esc(field.name) + "Vector", true), params,
+ "",
+ [&]() {
+ writer += "builder.startVector({{size}}, numElems, {{align}})";
+ },
+ options.gen_jvmstatic);
+ }
+
+ 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;
+
+ GenerateFunOneLine(
+ writer, "add" + MakeCamel(Esc(field.name), true),
+ "builder: FlatBufferBuilder, " + secondArg, "",
+ [&]() {
+ auto method = GenMethod(field.value.type);
+ writer.SetValue("field_name", MakeCamel(Esc(field.name), false));
+ writer.SetValue("method_name", method);
+ writer.SetValue("pos", field_pos);
+ writer.SetValue("default", GenFBBDefaultValue(field));
+ writer.SetValue("cast", GenFBBValueCast(field));
+
+ writer += "builder.add{{method_name}}({{pos}}, \\";
+ writer += "{{field_name}}{{cast}}, {{default}})";
+ },
+ options.gen_jvmstatic);
+ }
+
+ static std::string ToSignedType(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_UINT: return GenTypeBasic(BASE_TYPE_INT);
+ case BASE_TYPE_ULONG: return GenTypeBasic(BASE_TYPE_LONG);
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_NONE:
+ case BASE_TYPE_UTYPE: return GenTypeBasic(BASE_TYPE_CHAR);
+ case BASE_TYPE_USHORT: return GenTypeBasic(BASE_TYPE_SHORT);
+ case BASE_TYPE_VECTOR: return ToSignedType(type.VectorType());
+ default: return GenTypeBasic(type.base_type);
+ }
+ }
+
+ static std::string FlexBufferBuilderCast(const std::string &method,
+ FieldDef &field, bool isFirst) {
+ auto field_type = GenTypeBasic(field.value.type.base_type);
+ std::string to_type;
+ if (method == "Boolean")
+ to_type = "Boolean";
+ else if (method == "Long")
+ to_type = "Long";
+ else if (method == "Int" || method == "Offset" || method == "Struct")
+ to_type = "Int";
+ else if (method == "Byte" || method.empty())
+ to_type = isFirst ? "Byte" : "Int";
+ else if (method == "Short")
+ to_type = isFirst ? "Short" : "Int";
+ else if (method == "Double")
+ to_type = "Double";
+ else if (method == "Float")
+ to_type = isFirst ? "Float" : "Double";
+ else if (method == "UByte")
+
+ if (field_type != to_type) return ".to" + to_type + "()";
+ return "";
+ }
+
+ // fun startMonster(builder: FlatBufferBuilder) = builder.startTable(11)
+ void GenerateStartStructMethod(StructDef &struct_def, CodeWriter &code,
+ const IDLOptions options) const {
+ GenerateFunOneLine(
+ code, "start" + Esc(struct_def.name), "builder: FlatBufferBuilder", "",
+ [&]() {
+ code += "builder.startTable(" +
+ NumToString(struct_def.fields.vec.size()) + ")";
+ },
+ options.gen_jvmstatic);
+ }
+
+ void GenerateTableCreator(StructDef &struct_def, CodeWriter &writer,
+ const IDLOptions options) const {
+ // Generate a method that creates a table in one go. This is only possible
+ // when the table has no struct fields, since those have to be created
+ // inline, and there's no way to do so in Java.
+ bool has_no_struct_fields = true;
+ int num_fields = 0;
+ auto fields_vec = struct_def.fields.vec;
+
+ for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (IsStruct(field.value.type)) {
+ has_no_struct_fields = false;
+ } else {
+ num_fields++;
+ }
+ }
+ // 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) {
+ // Generate a table constructor of the form:
+ // public static int createName(FlatBufferBuilder builder, args...)
+
+ auto name = "create" + Esc(struct_def.name);
+ std::stringstream params;
+ params << "builder: FlatBufferBuilder";
+ for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ params << ", " << MakeCamel(Esc(field.name), false);
+ if (!IsScalar(field.value.type.base_type)) {
+ params << "Offset: ";
+ } else {
+ params << ": ";
+ }
+ auto optional = field.IsScalarOptional() ? "?" : "";
+ params << GenTypeBasic(field.value.type.base_type) << optional;
+ }
+
+ GenerateFun(
+ writer, name, params.str(), "Int",
+ [&]() {
+ writer.SetValue("vec_size", NumToString(fields_vec.size()));
+
+ writer += "builder.startTable({{vec_size}})";
+
+ auto sortbysize = struct_def.sortbysize;
+ auto largest = sortbysize ? sizeof(largest_scalar_t) : 1;
+ for (size_t size = largest; size; size /= 2) {
+ for (auto it = fields_vec.rbegin(); it != fields_vec.rend();
+ ++it) {
+ auto &field = **it;
+ 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));
+
+ // we wrap on null check for scalar optionals
+ writer += field.IsScalarOptional()
+ ? "{{field_name}}?.run { \\"
+ : "\\";
+
+ writer += "add{{camel_field_name}}(builder, {{field_name}}\\";
+ if (!IsScalar(field.value.type.base_type)) {
+ writer += "Offset\\";
+ }
+ // we wrap on null check for scalar optionals
+ writer += field.IsScalarOptional() ? ") }" : ")";
+ }
+ }
+ }
+ writer += "return end{{struct_name}}(builder)";
+ },
+ options.gen_jvmstatic);
+ }
+ }
+ void GenerateBufferHasIdentifier(StructDef &struct_def, CodeWriter &writer,
+ IDLOptions options) const {
+ auto file_identifier = parser_.file_identifier_;
+ // 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);
+ GenerateFunOneLine(
+ writer, name + "BufferHasIdentifier", "_bb: ByteBuffer", "Boolean",
+ [&]() {
+ writer += "__has_identifier(_bb, \"" + file_identifier + "\")";
+ },
+ options.gen_jvmstatic);
+ }
+
+ void GenerateStructGetters(StructDef &struct_def, CodeWriter &writer) const {
+ auto fields_vec = struct_def.fields.vec;
+ FieldDef *key_field = nullptr;
+ for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.key) key_field = &field;
+
+ GenerateComment(field.doc_comment, writer, &comment_config);
+
+ auto field_name = MakeCamel(Esc(field.name), false);
+ auto field_type = GenTypeGet(field.value.type);
+ auto field_default_value = GenDefaultValue(field);
+ auto return_type = GetterReturnType(field);
+ auto bbgetter = ByteBufferGetter(field.value.type, "bb");
+ auto ucast = CastToUsigned(field);
+ auto offset_val = NumToString(field.value.offset);
+ auto offset_prefix =
+ "val o = __offset(" + offset_val + "); return o != 0 ? ";
+ auto value_base_type = field.value.type.base_type;
+ // Most field accessors need to retrieve and test the field offset
+ // first, this is the offset value for that:
+ writer.SetValue("offset", NumToString(field.value.offset));
+ writer.SetValue("return_type", return_type);
+ writer.SetValue("field_type", field_type);
+ writer.SetValue("field_name", field_name);
+ writer.SetValue("field_default", field_default_value);
+ writer.SetValue("bbgetter", bbgetter);
+ writer.SetValue("ucast", ucast);
+
+ // Generate the accessors that don't do object reuse.
+ if (value_base_type == BASE_TYPE_STRUCT) {
+ // Calls the accessor that takes an accessor object with a
+ // new object.
+ // val pos
+ // get() = pos(Vec3())
+ GenerateGetterOneLine(writer, field_name, return_type, [&]() {
+ writer += "{{field_name}}({{field_type}}())";
+ });
+ } else if (value_base_type == BASE_TYPE_VECTOR &&
+ field.value.type.element == BASE_TYPE_STRUCT) {
+ // Accessors for vectors of structs also take accessor objects,
+ // this generates a variant without that argument.
+ // ex: fun weapons(j: Int) = weapons(Weapon(), j)
+ GenerateFunOneLine(writer, field_name, "j: Int", return_type, [&]() {
+ writer += "{{field_name}}({{field_type}}(), j)";
+ });
+ }
+
+ if (IsScalar(value_base_type)) {
+ if (struct_def.fixed) {
+ GenerateGetterOneLine(writer, field_name, return_type, [&]() {
+ writer += "{{bbgetter}}(bb_pos + {{offset}}){{ucast}}";
+ });
+ } else {
+ GenerateGetter(writer, field_name, return_type, [&]() {
+ writer += "val o = __offset({{offset}})";
+ writer +=
+ "return if(o != 0) {{bbgetter}}"
+ "(o + bb_pos){{ucast}} else "
+ "{{field_default}}";
+ });
+ }
+ } else {
+ switch (value_base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ // create getter with object reuse
+ // ex:
+ // fun pos(obj: Vec3) : Vec3? = obj.__assign(bb_pos + 4, bb)
+ // ? adds nullability annotation
+ GenerateFunOneLine(
+ writer, field_name, "obj: " + field_type, return_type,
+ [&]() { writer += "obj.__assign(bb_pos + {{offset}}, bb)"; });
+ } else {
+ // create getter with object reuse
+ // ex:
+ // fun pos(obj: Vec3) : Vec3? {
+ // val o = __offset(4)
+ // return if(o != 0) {
+ // obj.__assign(o + bb_pos, bb)
+ // else {
+ // null
+ // }
+ // }
+ // ? adds nullability annotation
+ GenerateFun(
+ writer, field_name, "obj: " + field_type, return_type, [&]() {
+ auto fixed = field.value.type.struct_def->fixed;
+
+ writer.SetValue("seek", Indirect("o + bb_pos", fixed));
+ OffsetWrapper(
+ writer, offset_val,
+ [&]() { writer += "obj.__assign({{seek}}, bb)"; },
+ [&]() { writer += "null"; });
+ });
+ }
+ break;
+ case BASE_TYPE_STRING:
+ // create string getter
+ // e.g.
+ // val Name : String?
+ // get() = {
+ // val o = __offset(10)
+ // return if (o != 0) __string(o + bb_pos) else null
+ // }
+ // ? adds nullability annotation
+ GenerateGetter(writer, field_name, return_type, [&]() {
+ writer += "val o = __offset({{offset}})";
+ writer += "return if (o != 0) __string(o + bb_pos) else null";
+ });
+ break;
+ case BASE_TYPE_VECTOR: {
+ // e.g.
+ // fun inventory(j: Int) : UByte {
+ // val o = __offset(14)
+ // return if (o != 0) {
+ // bb.get(__vector(o) + j * 1).toUByte()
+ // } else {
+ // 0
+ // }
+ // }
+
+ auto vectortype = field.value.type.VectorType();
+ std::string params = "j: Int";
+
+ if (vectortype.base_type == BASE_TYPE_STRUCT ||
+ vectortype.base_type == BASE_TYPE_UNION) {
+ params = "obj: " + field_type + ", j: Int";
+ }
+
+ GenerateFun(writer, field_name, params, return_type, [&]() {
+ auto inline_size = NumToString(InlineSize(vectortype));
+ auto index = "__vector(o) + j * " + inline_size;
+ auto not_found = NotFoundReturn(field.value.type.element);
+ auto found = "";
+ writer.SetValue("index", index);
+ switch (vectortype.base_type) {
+ case BASE_TYPE_STRUCT: {
+ bool fixed = vectortype.struct_def->fixed;
+ writer.SetValue("index", Indirect(index, fixed));
+ found = "obj.__assign({{index}}, bb)";
+ break;
+ }
+ case BASE_TYPE_UNION:
+ found = "{{bbgetter}}(obj, {{index}}){{ucast}}";
+ break;
+ default: found = "{{bbgetter}}({{index}}){{ucast}}";
+ }
+ OffsetWrapper(
+ writer, offset_val, [&]() { writer += found; },
+ [&]() { writer += not_found; });
+ });
+ break;
+ }
+ case BASE_TYPE_UNION:
+ GenerateFun(
+ writer, field_name, "obj: " + field_type, return_type, [&]() {
+ writer += OffsetWrapperOneLine(
+ offset_val, bbgetter + "(obj, o + bb_pos)", "null");
+ });
+ break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+
+ if (value_base_type == BASE_TYPE_VECTOR) {
+ // Generate Lenght functions for vectors
+ GenerateGetter(writer, field_name + "Length", "Int", [&]() {
+ writer += OffsetWrapperOneLine(offset_val, "__vector_len(o)", "0");
+ });
+
+ // See if we should generate a by-key accessor.
+ if (field.value.type.element == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ auto &sd = *field.value.type.struct_def;
+ auto &fields = sd.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &kfield = **kit;
+ if (kfield.key) {
+ auto qualified_name = WrapInNameSpace(sd);
+ auto name = MakeCamel(Esc(field.name), false) + "ByKey";
+ auto params = "key: " + GenTypeGet(kfield.value.type);
+ auto rtype = qualified_name + "?";
+ GenerateFun(writer, name, params, rtype, [&]() {
+ OffsetWrapper(
+ writer, offset_val,
+ [&]() {
+ writer += qualified_name +
+ ".__lookup_by_key(null, __vector(o), key, bb)";
+ },
+ [&]() { writer += "null"; });
+ });
+
+ auto param2 = "obj: " + qualified_name +
+ ", key: " + GenTypeGet(kfield.value.type);
+ GenerateFun(writer, name, param2, rtype, [&]() {
+ OffsetWrapper(
+ writer, offset_val,
+ [&]() {
+ writer += qualified_name +
+ ".__lookup_by_key(obj, __vector(o), key, bb)";
+ },
+ [&]() { writer += "null"; });
+ });
+
+ break;
+ }
+ }
+ }
+ }
+
+ if ((value_base_type == BASE_TYPE_VECTOR &&
+ IsScalar(field.value.type.VectorType().base_type)) ||
+ value_base_type == BASE_TYPE_STRING) {
+ auto end_idx =
+ NumToString(value_base_type == BASE_TYPE_STRING
+ ? 1
+ : InlineSize(field.value.type.VectorType()));
+ // Generate a ByteBuffer accessor for strings & vectors of scalars.
+ // e.g.
+ // val inventoryByteBuffer: ByteBuffer
+ // get = __vector_as_bytebuffer(14, 1)
+
+ GenerateGetterOneLine(
+ writer, field_name + "AsByteBuffer", "ByteBuffer", [&]() {
+ writer.SetValue("end", end_idx);
+ writer += "__vector_as_bytebuffer({{offset}}, {{end}})";
+ });
+
+ // Generate a ByteBuffer accessor for strings & vectors of scalars.
+ // e.g.
+ // fun inventoryInByteBuffer(_bb: Bytebuffer):
+ // ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1)
+ GenerateFunOneLine(
+ writer, field_name + "InByteBuffer", "_bb: ByteBuffer",
+ "ByteBuffer", [&]() {
+ writer.SetValue("end", end_idx);
+ writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})";
+ });
+ }
+
+ // generate object accessors if is nested_flatbuffer
+ // fun testnestedflatbufferAsMonster() : Monster?
+ //{ return testnestedflatbufferAsMonster(new Monster()); }
+
+ if (field.nested_flatbuffer) {
+ auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
+ auto nested_method_name =
+ field_name + "As" + field.nested_flatbuffer->name;
+
+ GenerateGetterOneLine(
+ writer, nested_method_name, nested_type_name + "?", [&]() {
+ writer += nested_method_name + "(" + nested_type_name + "())";
+ });
+
+ GenerateFun(writer, nested_method_name, "obj: " + nested_type_name,
+ nested_type_name + "?", [&]() {
+ OffsetWrapper(
+ writer, offset_val,
+ [&]() {
+ writer +=
+ "obj.__assign(__indirect(__vector(o)), bb)";
+ },
+ [&]() { writer += "null"; });
+ });
+ }
+
+ // Generate mutators for scalar fields or vectors of scalars.
+ if (parser_.opts.mutable_buffer) {
+ auto value_type = field.value.type;
+ auto underlying_type = value_base_type == BASE_TYPE_VECTOR
+ ? value_type.VectorType()
+ : value_type;
+ auto name = "mutate" + MakeCamel(Esc(field.name), true);
+ 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
+ // mutate.
+ if (value_base_type == BASE_TYPE_VECTOR) params.insert(0, "j: Int, ");
+
+ // Boolean parameters have to be explicitly converted to byte
+ // representation.
+ auto setter_parameter =
+ underlying_type.base_type == BASE_TYPE_BOOL
+ ? "(if(" + Esc(field.name) + ") 1 else 0).toByte()"
+ : Esc(field.name);
+
+ auto setter_index =
+ value_base_type == BASE_TYPE_VECTOR
+ ? "__vector(o) + j * " + size
+ : (struct_def.fixed ? "bb_pos + " + offset_val : "o + bb_pos");
+ if (IsScalar(value_base_type) ||
+ (value_base_type == BASE_TYPE_VECTOR &&
+ IsScalar(value_type.VectorType().base_type))) {
+ auto statements = [&]() {
+ writer.SetValue("bbsetter", ByteBufferSetter(underlying_type));
+ writer.SetValue("index", setter_index);
+ writer.SetValue("params", setter_parameter);
+ writer.SetValue("cast", CastToSigned(field));
+ if (struct_def.fixed) {
+ writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
+ } else {
+ OffsetWrapper(
+ writer, offset_val,
+ [&]() {
+ writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
+ writer += "true";
+ },
+ [&]() { writer += "false"; });
+ }
+ };
+
+ if (struct_def.fixed) {
+ GenerateFunOneLine(writer, name, params, "ByteBuffer", statements);
+ } else {
+ GenerateFun(writer, name, params, "Boolean", statements);
+ }
+ }
+ }
+ }
+ if (struct_def.has_key && !struct_def.fixed) {
+ // Key Comparison method
+ GenerateOverrideFun(
+ writer, "keysCompare", "o1: Int, o2: Int, _bb: ByteBuffer", "Int",
+ [&]() {
+ if (IsString(key_field->value.type)) {
+ writer.SetValue("offset", NumToString(key_field->value.offset));
+ writer +=
+ " return compareStrings(__offset({{offset}}, o1, "
+ "_bb), __offset({{offset}}, o2, _bb), _bb)";
+
+ } else {
+ auto getter1 = GenLookupByKey(key_field, "_bb", "o1");
+ auto getter2 = GenLookupByKey(key_field, "_bb", "o2");
+ writer += "val val_1 = " + getter1;
+ writer += "val val_2 = " + getter2;
+ writer += "return (val_1 - val_2).sign";
+ }
+ });
+ }
+ }
+
+ static std::string CastToUsigned(const FieldDef &field) {
+ return CastToUsigned(field.value.type);
+ }
+
+ static std::string CastToUsigned(const Type type) {
+ switch (type.base_type) {
+ case BASE_TYPE_UINT: return ".toUInt()";
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_UTYPE: return ".toUByte()";
+ case BASE_TYPE_USHORT: return ".toUShort()";
+ case BASE_TYPE_ULONG: return ".toULong()";
+ case BASE_TYPE_VECTOR: return CastToUsigned(type.VectorType());
+ default: return "";
+ }
+ }
+
+ static std::string CastToSigned(const FieldDef &field) {
+ return CastToSigned(field.value.type);
+ }
+
+ static std::string CastToSigned(const Type type) {
+ switch (type.base_type) {
+ case BASE_TYPE_UINT: return ".toInt()";
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_UTYPE: return ".toByte()";
+ case BASE_TYPE_USHORT: return ".toShort()";
+ case BASE_TYPE_ULONG: return ".toLong()";
+ case BASE_TYPE_VECTOR: return CastToSigned(type.VectorType());
+ default: return "";
+ }
+ }
+
+ static std::string LiteralSuffix(const BaseType type) {
+ switch (type) {
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_UTYPE:
+ case BASE_TYPE_USHORT: return "u";
+ case BASE_TYPE_ULONG: return "UL";
+ case BASE_TYPE_LONG: return "L";
+ default: return "";
+ }
+ }
+
+ void GenerateCompanionObject(CodeWriter &code,
+ const std::function<void()> &callback) const {
+ code += "companion object {";
+ code.IncrementIdentLevel();
+ callback();
+ code.DecrementIdentLevel();
+ code += "}";
+ }
+
+ // Generate a documentation comment, if available.
+ void GenerateComment(const std::vector<std::string> &dc, CodeWriter &writer,
+ const CommentConfig *config) const {
+ if (dc.begin() == dc.end()) {
+ // Don't output empty comment blocks with 0 lines of comment content.
+ return;
+ }
+
+ if (config != nullptr && config->first_line != nullptr) {
+ writer += std::string(config->first_line);
+ }
+ std::string line_prefix =
+ ((config != nullptr && config->content_line_prefix != nullptr)
+ ? config->content_line_prefix
+ : "///");
+ for (auto it = dc.begin(); it != dc.end(); ++it) {
+ writer += line_prefix + *it;
+ }
+ if (config != nullptr && config->last_line != nullptr) {
+ writer += std::string(config->last_line);
+ }
+ }
+
+ static void GenerateGetRootAsAccessors(const std::string &struct_name,
+ CodeWriter &writer,
+ IDLOptions options) {
+ // Generate a special accessor for the table that when used as the root
+ // ex: fun getRootAsMonster(_bb: ByteBuffer): Monster {...}
+ writer.SetValue("gr_name", struct_name);
+ writer.SetValue("gr_method", "getRootAs" + struct_name);
+
+ // create convenience method that doesn't require an existing object
+ GenerateJvmStaticAnnotation(writer, options.gen_jvmstatic);
+ writer += "fun {{gr_method}}(_bb: ByteBuffer): {{gr_name}} = \\";
+ writer += "{{gr_method}}(_bb, {{gr_name}}())";
+
+ // create method that allows object reuse
+ // ex: fun Monster getRootAsMonster(_bb: ByteBuffer, obj: Monster) {...}
+ GenerateJvmStaticAnnotation(writer, options.gen_jvmstatic);
+ writer +=
+ "fun {{gr_method}}"
+ "(_bb: ByteBuffer, obj: {{gr_name}}): {{gr_name}} {";
+ writer.IncrementIdentLevel();
+ writer += "_bb.order(ByteOrder.LITTLE_ENDIAN)";
+ writer +=
+ "return (obj.__assign(_bb.getInt(_bb.position())"
+ " + _bb.position(), _bb))";
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ static void GenerateStaticConstructor(const StructDef &struct_def,
+ CodeWriter &code,
+ const IDLOptions options) {
+ // create a struct constructor function
+ auto params = StructConstructorParams(struct_def);
+ GenerateFun(
+ code, "create" + Esc(struct_def.name), params, "Int",
+ [&]() {
+ GenStructBody(struct_def, code, "");
+ code += "return builder.offset()";
+ },
+ options.gen_jvmstatic);
+ }
+
+ static std::string StructConstructorParams(const StructDef &struct_def,
+ const std::string &prefix = "") {
+ // builder: FlatBufferBuilder
+ std::stringstream out;
+ auto field_vec = struct_def.fields.vec;
+ if (prefix.empty()) { out << "builder: FlatBufferBuilder"; }
+ for (auto it = field_vec.begin(); it != field_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.
+ 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);
+ }
+ }
+ return out.str();
+ }
+
+ static void GeneratePropertyOneLine(CodeWriter &writer,
+ const std::string &name,
+ const std::string &type,
+ const std::function<void()> &body) {
+ // Generates Kotlin getter for properties
+ // e.g.:
+ // val prop: Mytype = x
+ writer.SetValue("_name", name);
+ writer.SetValue("_type", type);
+ writer += "val {{_name}} : {{_type}} = \\";
+ body();
+ }
+ static void GenerateGetterOneLine(CodeWriter &writer, const std::string &name,
+ const std::string &type,
+ const std::function<void()> &body) {
+ // Generates Kotlin getter for properties
+ // e.g.:
+ // val prop: Mytype get() = x
+ writer.SetValue("_name", name);
+ writer.SetValue("_type", type);
+ writer += "val {{_name}} : {{_type}} get() = \\";
+ body();
+ }
+
+ static void GenerateGetter(CodeWriter &writer, const std::string &name,
+ const std::string &type,
+ const std::function<void()> &body) {
+ // Generates Kotlin getter for properties
+ // e.g.:
+ // val prop: Mytype
+ // get() = {
+ // return x
+ // }
+ writer.SetValue("name", name);
+ writer.SetValue("type", type);
+ writer += "val {{name}} : {{type}}";
+ writer.IncrementIdentLevel();
+ writer += "get() {";
+ writer.IncrementIdentLevel();
+ body();
+ writer.DecrementIdentLevel();
+ writer += "}";
+ writer.DecrementIdentLevel();
+ }
+
+ static void GenerateFun(CodeWriter &writer, const std::string &name,
+ const std::string &params,
+ const std::string &returnType,
+ const std::function<void()> &body,
+ bool gen_jvmstatic = false) {
+ // Generates Kotlin function
+ // e.g.:
+ // fun path(j: Int): Vec3 {
+ // return path(Vec3(), j)
+ // }
+ auto noreturn = returnType.empty();
+ writer.SetValue("name", name);
+ writer.SetValue("params", params);
+ writer.SetValue("return_type", noreturn ? "" : ": " + returnType);
+ GenerateJvmStaticAnnotation(writer, gen_jvmstatic);
+ writer += "fun {{name}}({{params}}) {{return_type}} {";
+ writer.IncrementIdentLevel();
+ body();
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ static void GenerateFunOneLine(CodeWriter &writer, const std::string &name,
+ const std::string &params,
+ const std::string &returnType,
+ const std::function<void()> &body,
+ bool gen_jvmstatic = false) {
+ // Generates Kotlin function
+ // e.g.:
+ // fun path(j: Int): Vec3 = return path(Vec3(), j)
+ writer.SetValue("name", name);
+ writer.SetValue("params", params);
+ writer.SetValue("return_type_p",
+ returnType.empty() ? "" : " : " + returnType);
+ GenerateJvmStaticAnnotation(writer, gen_jvmstatic);
+ writer += "fun {{name}}({{params}}){{return_type_p}} = \\";
+ body();
+ }
+
+ static void GenerateOverrideFun(CodeWriter &writer, const std::string &name,
+ const std::string &params,
+ const std::string &returnType,
+ const std::function<void()> &body) {
+ // Generates Kotlin function
+ // e.g.:
+ // override fun path(j: Int): Vec3 = return path(Vec3(), j)
+ writer += "override \\";
+ GenerateFun(writer, name, params, returnType, body);
+ }
+
+ static void GenerateOverrideFunOneLine(CodeWriter &writer,
+ const std::string &name,
+ const std::string &params,
+ const std::string &returnType,
+ const std::string &statement) {
+ // Generates Kotlin function
+ // e.g.:
+ // override fun path(j: Int): Vec3 = return path(Vec3(), j)
+ writer.SetValue("name", name);
+ writer.SetValue("params", params);
+ writer.SetValue("return_type",
+ returnType.empty() ? "" : " : " + returnType);
+ writer += "override fun {{name}}({{params}}){{return_type}} = \\";
+ writer += statement;
+ }
+
+ static std::string OffsetWrapperOneLine(const std::string &offset,
+ const std::string &found,
+ const std::string &not_found) {
+ return "val o = __offset(" + offset + "); return if (o != 0) " + found +
+ " else " + not_found;
+ }
+
+ static void OffsetWrapper(CodeWriter &code, const std::string &offset,
+ const std::function<void()> &found,
+ const std::function<void()> &not_found) {
+ code += "val o = __offset(" + offset + ")";
+ code += "return if (o != 0) {";
+ code.IncrementIdentLevel();
+ found();
+ code.DecrementIdentLevel();
+ code += "} else {";
+ code.IncrementIdentLevel();
+ not_found();
+ code.DecrementIdentLevel();
+ code += "}";
+ }
+
+ static std::string Indirect(const std::string &index, bool fixed) {
+ // We apply __indirect() and struct is not fixed.
+ if (!fixed) return "__indirect(" + index + ")";
+ return index;
+ }
+
+ static std::string NotFoundReturn(BaseType el) {
+ switch (el) {
+ case BASE_TYPE_FLOAT: return "0.0f";
+ case BASE_TYPE_DOUBLE: return "0.0";
+ case BASE_TYPE_BOOL: return "false";
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_INT:
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_SHORT: return "0";
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_USHORT:
+ case BASE_TYPE_UTYPE: return "0u";
+ case BASE_TYPE_ULONG: return "0uL";
+ default: return "null";
+ }
+ }
+
+ // Prepend @JvmStatic to methods in companion object.
+ static void GenerateJvmStaticAnnotation(CodeWriter &code,
+ bool gen_jvmstatic) {
+ if (gen_jvmstatic) { code += "@JvmStatic"; }
+ }
+
+ // This tracks the current namespace used to determine if a type need to be
+ // prefixed by its namespace
+ const Namespace *cur_name_space_;
+};
+} // namespace kotlin
+
+bool GenerateKotlin(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ kotlin::KotlinGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_lobster.cpp b/contrib/libs/flatbuffers/src/idl_gen_lobster.cpp
new file mode 100644
index 0000000000..6fdd6dc26a
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_lobster.cpp
@@ -0,0 +1,391 @@
+/*
+ * Copyright 2018 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 <string>
+#include <unordered_set>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+namespace lobster {
+
+class LobsterGenerator : public BaseGenerator {
+ public:
+ LobsterGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "" /* not used */, "_",
+ "lobster") {
+ static const char *const keywords[] = {
+ "nil", "true", "false", "return", "struct", "class",
+ "import", "int", "float", "string", "any", "def",
+ "is", "from", "program", "private", "coroutine", "resource",
+ "enum", "typeof", "var", "let", "pakfile", "switch",
+ "case", "default", "namespace", "not", "and", "or",
+ "bool",
+ };
+ keywords_.insert(std::begin(keywords), std::end(keywords));
+ }
+
+ 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);
+ }
+
+ std::string NamespacedName(const Definition &def) {
+ return WrapInNameSpace(def.defined_namespace, NormalizedName(def));
+ }
+
+ std::string GenTypeName(const Type &type) {
+ auto bits = NumToString(SizeOf(type.base_type) * 8);
+ if (IsInteger(type.base_type)) 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";
+ return "none";
+ }
+
+ std::string LobsterType(const Type &type) {
+ if (IsFloat(type.base_type)) return "float";
+ if (IsScalar(type.base_type) && type.enum_def)
+ return NormalizedName(*type.enum_def);
+ if (!IsScalar(type.base_type)) return "flatbuffers_offset";
+ return "int";
+ }
+
+ // Returns the method name for use with add/put calls.
+ std::string GenMethod(const Type &type) {
+ return IsScalar(type.base_type)
+ ? MakeCamel(GenTypeBasic(type))
+ : (IsStruct(type) ? "Struct" : "UOffsetTRelative");
+ }
+
+ // This uses Python names for now..
+ std::string GenTypeBasic(const Type &type) {
+ // clang-format off
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
+ #PTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ return ctypename[type.base_type];
+ }
+
+ // Generate a struct field, conditioned on its child type(s).
+ void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, nullptr, " ");
+ std::string &code = *code_ptr;
+ auto offsets = NumToString(field.value.offset);
+ auto def = " def " + NormalizedName(field);
+ if (IsScalar(field.value.type.base_type)) {
+ std::string acc;
+ if (struct_def.fixed) {
+ acc = "buf_.read_" + GenTypeName(field.value.type) + "_le(pos_ + " +
+ offsets + ")";
+
+ } else {
+ 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.IsOptional())
+ acc += ", buf_.flatbuffers_field_present(pos_, " + offsets + ")";
+ code += def + "():\n return " + acc + "\n";
+ return;
+ }
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ auto name = NamespacedName(*field.value.type.struct_def);
+ code += def + "():\n ";
+ if (struct_def.fixed) {
+ code += "return " + name + "{ buf_, pos_ + " + offsets + " }\n";
+ } else {
+ code += std::string("let o = buf_.flatbuffers_field_") +
+ (field.value.type.struct_def->fixed ? "struct" : "table") +
+ "(pos_, " + offsets + ")\n return if o: " + name +
+ " { buf_, o } else: nil\n";
+ }
+ break;
+ }
+ case BASE_TYPE_STRING:
+ code += def +
+ "():\n return buf_.flatbuffers_field_string(pos_, " +
+ offsets + ")\n";
+ break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ code += def + "(i:int):\n return ";
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ auto start = "buf_.flatbuffers_field_vector(pos_, " + offsets +
+ ") + i * " + NumToString(InlineSize(vectortype));
+ if (!(vectortype.struct_def->fixed)) {
+ start = "buf_.flatbuffers_indirect(" + start + ")";
+ }
+ code += NamespacedName(*field.value.type.struct_def) + " { buf_, " +
+ start + " }\n";
+ } else {
+ if (IsString(vectortype))
+ code += "buf_.flatbuffers_string";
+ else
+ code += "buf_.read_" + GenTypeName(vectortype) + "_le";
+ code += "(buf_.flatbuffers_field_vector(pos_, " + offsets +
+ ") + i * " + NumToString(InlineSize(vectortype)) + ")\n";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ for (auto it = field.value.type.enum_def->Vals().begin();
+ it != field.value.type.enum_def->Vals().end(); ++it) {
+ auto &ev = **it;
+ if (ev.IsNonZero()) {
+ code += def + "_as_" + ev.name + "():\n return " +
+ NamespacedName(*ev.union_type.struct_def) +
+ " { buf_, buf_.flatbuffers_field_table(pos_, " + offsets +
+ ") }\n";
+ }
+ }
+ break;
+ }
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ if (IsVector(field.value.type)) {
+ code += def +
+ "_length():\n return "
+ "buf_.flatbuffers_field_vector_len(pos_, " +
+ offsets + ")\n";
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "struct " + NormalizedName(struct_def) +
+ "Builder:\n b_:flatbuffers_builder\n";
+ code += " def start():\n b_.StartObject(" +
+ NumToString(struct_def.fields.vec.size()) +
+ ")\n return this\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto offset = it - struct_def.fields.vec.begin();
+ code += " def add_" + NormalizedName(field) + "(" +
+ 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.IsOptional())
+ code += ", " + field.value.constant;
+ code += ")\n return this\n";
+ }
+ code += " def end():\n return b_.EndObject()\n\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (IsVector(field.value.type)) {
+ code += "def " + NormalizedName(struct_def) + "Start" +
+ MakeCamel(NormalizedName(field)) +
+ "Vector(b_:flatbuffers_builder, n_:int):\n b_.StartVector(";
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ code +=
+ NumToString(elem_size) + ", n_, " + NumToString(alignment) + ")\n";
+ if (vector_type.base_type != BASE_TYPE_STRUCT ||
+ !vector_type.struct_def->fixed) {
+ code += "def " + NormalizedName(struct_def) + "Create" +
+ MakeCamel(NormalizedName(field)) +
+ "Vector(b_:flatbuffers_builder, v_:[" +
+ LobsterType(vector_type) + "]):\n b_.StartVector(" +
+ NumToString(elem_size) + ", v_.length, " +
+ NumToString(alignment) + ")\n reverse(v_) e_: b_.Prepend" +
+ GenMethod(vector_type) +
+ "(e_)\n return b_.EndVector(v_.length)\n";
+ }
+ code += "\n";
+ }
+ }
+ }
+
+ void GenStructPreDecl(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+ CheckNameSpace(struct_def, &code);
+ code += "class " + NormalizedName(struct_def) + "\n\n";
+ }
+
+ // Generate struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+ CheckNameSpace(struct_def, &code);
+ GenComment(struct_def.doc_comment, code_ptr, nullptr, "");
+ code += "class " + NormalizedName(struct_def) + " : flatbuffers_handle\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ GenStructAccessor(struct_def, field, code_ptr);
+ }
+ code += "\n";
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ code += "def GetRootAs" + NormalizedName(struct_def) +
+ "(buf:string): return " + NormalizedName(struct_def) +
+ " { buf, buf.flatbuffers_indirect(0) }\n\n";
+ }
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ } else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
+ }
+ }
+
+ // Generate enum declarations.
+ void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+ std::string &code = *code_ptr;
+ CheckNameSpace(enum_def, &code);
+ GenComment(enum_def.doc_comment, code_ptr, nullptr, "");
+ code += "enum " + NormalizedName(enum_def) + ":\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, nullptr, " ");
+ code += " " + enum_def.name + "_" + NormalizedName(ev) + " = " +
+ enum_def.ToString(ev) + "\n";
+ }
+ code += "\n";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ 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.
+ StructBuilderArgs(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(),
+ code_ptr);
+ } else {
+ std::string &code = *code_ptr;
+ code += ", " + (nameprefix + NormalizedName(field)) + ":" +
+ LobsterType(field.value.type);
+ }
+ }
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += " b_.Prep(" + NumToString(struct_def.minalign) + ", " +
+ 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)
+ code += " b_.Pad(" + NumToString(field.padding) + ")\n";
+ if (IsStruct(field.value.type)) {
+ StructBuilderBody(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(),
+ code_ptr);
+ } else {
+ code += " b_.Prepend" + GenMethod(field.value.type) + "(" +
+ nameprefix + NormalizedName(field) + ")\n";
+ }
+ }
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code +=
+ "def Create" + NormalizedName(struct_def) + "(b_:flatbuffers_builder";
+ StructBuilderArgs(struct_def, "", code_ptr);
+ code += "):\n";
+ StructBuilderBody(struct_def, "", code_ptr);
+ code += " return b_.Offset()\n\n";
+ }
+
+ void CheckNameSpace(const Definition &def, std::string *code_ptr) {
+ auto ns = GetNameSpace(def);
+ if (ns == current_namespace_) return;
+ current_namespace_ = ns;
+ std::string &code = *code_ptr;
+ code += "namespace " + ns + "\n\n";
+ }
+
+ bool generate() {
+ std::string code;
+ code += std::string("// ") + FlatBuffersGeneratedWarning() +
+ "\nimport flatbuffers\n\n";
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ GenEnum(enum_def, &code);
+ }
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ GenStructPreDecl(struct_def, &code);
+ }
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ GenStruct(struct_def, &code);
+ }
+ return SaveFile(GeneratedFileName(path_, file_name_, parser_.opts).c_str(),
+ code, false);
+ }
+
+ private:
+ std::unordered_set<std::string> keywords_;
+ std::string current_namespace_;
+};
+
+} // namespace lobster
+
+bool GenerateLobster(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ lobster::LobsterGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_lua.cpp b/contrib/libs/flatbuffers/src/idl_gen_lua.cpp
new file mode 100644
index 0000000000..9efc435e24
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_lua.cpp
@@ -0,0 +1,745 @@
+/*
+ * 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 <string>
+#include <unordered_set>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+namespace lua {
+
+// Hardcode spaces per indentation.
+const CommentConfig def_comment = { nullptr, "--", nullptr };
+const char *Indent = " ";
+const char *Comment = "-- ";
+const char *End = "end\n";
+const char *EndFunc = "end\n";
+const char *SelfData = "self.view";
+const char *SelfDataPos = "self.view.pos";
+const char *SelfDataBytes = "self.view.bytes";
+
+class LuaGenerator : public BaseGenerator {
+ public:
+ LuaGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "" /* not used */,
+ "" /* not used */, "lua") {
+ 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));
+ }
+
+ // 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) {
+ return std::string(Indent) + "local o = " + SelfData + ":Offset(" +
+ NumToString(field.value.offset) + ")\n" + Indent +
+ "if o ~= 0 then\n";
+ }
+
+ // Begin a class declaration.
+ void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "local " + NormalizedName(struct_def) + " = {} -- the module\n";
+ code += "local " + NormalizedMetaName(struct_def) +
+ " = {} -- the class metatable\n";
+ code += "\n";
+ }
+
+ // Begin enum code with a class declaration.
+ void BeginEnum(const std::string &class_name, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "local " + class_name + " = {\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);
+ }
+
+ std::string NormalizedMetaName(const Definition &definition) const {
+ return EscapeKeyword(definition.name) + "_mt";
+ }
+
+ // A single enum member.
+ void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + NormalizedName(ev) + " = " +
+ enum_def.ToString(ev) + ",\n";
+ }
+
+ // End enum code.
+ void EndEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n";
+ }
+
+ void GenerateNewObjectPrototype(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "function " + NormalizedName(struct_def) + ".New()\n";
+ code += std::string(Indent) + "local o = {}\n";
+ code += std::string(Indent) +
+ "setmetatable(o, {__index = " + NormalizedMetaName(struct_def) +
+ "})\n";
+ code += std::string(Indent) + "return o\n";
+ code += EndFunc;
+ }
+
+ // Initialize a new struct or table from existing data.
+ void NewRootTypeFromBuffer(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ 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) +
+ ".New()\n";
+ code += std::string(Indent) + "o:Init(buf, n + offset)\n";
+ code += std::string(Indent) + "return o\n";
+ code += EndFunc;
+ }
+
+ // Initialize an existing object with other data, to avoid an allocation.
+ void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += "Init(buf, pos)\n";
+ code +=
+ std::string(Indent) + SelfData + " = flatbuffers.view.New(buf, pos)\n";
+ code += EndFunc;
+ }
+
+ // Get the length of a vector.
+ void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "Length()\n";
+ code += OffsetPrefix(field);
+ code +=
+ std::string(Indent) + Indent + "return " + SelfData + ":VectorLen(o)\n";
+ code += std::string(Indent) + End;
+ code += std::string(Indent) + "return 0\n";
+ code += EndFunc;
+ }
+
+ // Get the value of a struct's scalar.
+ void GetScalarFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += std::string(Indent) + "return " + getter;
+ code += std::string(SelfDataPos) + " + " + NumToString(field.value.offset) +
+ ")\n";
+ code += EndFunc;
+ }
+
+ // Get the value of a table's scalar.
+ void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ getter += std::string("o + ") + SelfDataPos + ")";
+ auto is_bool = field.value.type.base_type == BASE_TYPE_BOOL;
+ if (is_bool) { getter = "(" + getter + " ~= 0)"; }
+ code += std::string(Indent) + Indent + "return " + getter + "\n";
+ code += std::string(Indent) + End;
+ std::string default_value;
+ if (is_bool) {
+ default_value = field.value.constant == "0" ? "false" : "true";
+ } else {
+ default_value = field.value.constant;
+ }
+ code += std::string(Indent) + "return " + default_value + "\n";
+ code += EndFunc;
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Struct.
+ void GetStructFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(obj)\n";
+ code += std::string(Indent) + "obj:Init(" + SelfDataBytes + ", " +
+ SelfDataPos + " + ";
+ code += NumToString(field.value.offset) + ")\n";
+ code += std::string(Indent) + "return obj\n";
+ code += EndFunc;
+ }
+
+ // 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 = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ if (field.value.type.struct_def->fixed) {
+ code +=
+ std::string(Indent) + Indent + "local x = o + " + SelfDataPos + "\n";
+ } else {
+ code += std::string(Indent) + Indent + "local x = " + SelfData +
+ ":Indirect(o + " + SelfDataPos + ")\n";
+ }
+ code += std::string(Indent) + Indent + "local obj = require('" +
+ TypeNameWithNamespace(field) + "').New()\n";
+ code +=
+ std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a string.
+ void GetStringField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ code +=
+ std::string(Indent) + Indent + "return " + GenGetter(field.value.type);
+ code += std::string("o + ") + SelfDataPos + ")\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // 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 = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "()\n";
+ code += OffsetPrefix(field);
+
+ // TODO(rw): this works and is not the good way to it:
+ // bool is_native_table = TypeName(field) == "*flatbuffers.Table";
+ // if (is_native_table) {
+ // code += std::string(Indent) + Indent + "from flatbuffers.table import
+ // Table\n";
+ //} else {
+ // code += std::string(Indent) + Indent +
+ // code += "from ." + TypeName(field) + " import " + TypeName(field) +
+ // "\n";
+ //}
+ code +=
+ std::string(Indent) + Indent +
+ "local obj = "
+ "flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)\n";
+ code += std::string(Indent) + Indent + GenGetter(field.value.type) +
+ "obj, o)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a vector's struct member.
+ void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(j)\n";
+ code += OffsetPrefix(field);
+ code +=
+ std::string(Indent) + Indent + "local x = " + SelfData + ":Vector(o)\n";
+ code += std::string(Indent) + Indent + "x = x + ((j-1) * ";
+ code += NumToString(InlineSize(vectortype)) + ")\n";
+ if (!(vectortype.struct_def->fixed)) {
+ code +=
+ std::string(Indent) + Indent + "x = " + SelfData + ":Indirect(x)\n";
+ }
+ code += std::string(Indent) + Indent + "local obj = require('" +
+ TypeNameWithNamespace(field) + "').New()\n";
+ code +=
+ std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a vector's non-struct member. Uses a named return
+ // 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 = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(j)\n";
+ code += OffsetPrefix(field);
+ code +=
+ std::string(Indent) + Indent + "local a = " + SelfData + ":Vector(o)\n";
+ code += std::string(Indent) + Indent;
+ code += "return " + GenGetter(field.value.type);
+ code += "a + ((j-1) * ";
+ code += NumToString(InlineSize(vectortype)) + "))\n";
+ code += std::string(Indent) + End;
+ if (IsString(vectortype)) {
+ code += std::string(Indent) + "return ''\n";
+ } else {
+ code += std::string(Indent) + "return 0\n";
+ }
+ 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 += MakeCamel(NormalizedName(field));
+ 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;
+
+ code += "function " + NormalizedName(struct_def) + ".Create" +
+ NormalizedName(struct_def);
+ code += "(builder";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ 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.
+ StructBuilderArgs(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(),
+ code_ptr);
+ } else {
+ std::string &code = *code_ptr;
+ code += std::string(", ") + nameprefix;
+ code += MakeCamel(NormalizedName(field), false);
+ }
+ }
+ }
+
+ // End the creator function signature.
+ void EndBuilderArgs(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += ")\n";
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + "builder:Prep(" +
+ NumToString(struct_def.minalign) + ", ";
+ code += 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)
+ code += std::string(Indent) + "builder:Pad(" +
+ NumToString(field.padding) + ")\n";
+ if (IsStruct(field.value.type)) {
+ StructBuilderBody(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(),
+ code_ptr);
+ } else {
+ code +=
+ std::string(Indent) + "builder:Prepend" + GenMethod(field) + "(";
+ code += nameprefix + MakeCamel(NormalizedName(field), false) + ")\n";
+ }
+ }
+ }
+
+ void EndBuilderBody(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + "return builder:Offset()\n";
+ code += EndFunc;
+ }
+
+ // 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 += "function " + NormalizedName(struct_def) + ".Start";
+ code += "(builder) ";
+ code += "builder:StartObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ") end\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) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".Add" +
+ MakeCamel(NormalizedName(field));
+ code += "(builder, ";
+ code += MakeCamel(NormalizedName(field), false);
+ code += ") ";
+ code += "builder:Prepend";
+ code += GenMethod(field) + "Slot(";
+ code += NumToString(offset) + ", ";
+ // todo: i don't need to cast in Lua, but am I missing something?
+ // if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+ // code += "flatbuffers.N.UOffsetTFlags.py_type";
+ // code += "(";
+ // code += MakeCamel(NormalizedName(field), false) + ")";
+ // } else {
+ code += MakeCamel(NormalizedName(field), false);
+ // }
+ code += ", " + field.value.constant;
+ code += ") end\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 += "function " + NormalizedName(struct_def) + ".Start";
+ code += MakeCamel(NormalizedName(field));
+ code += "Vector(builder, numElems) return 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 += ", numElems, " + NumToString(alignment);
+ code += ") end\n";
+ }
+
+ // 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 += "function " + NormalizedName(struct_def) + ".End";
+ code += "(builder) ";
+ code += "return builder:EndObject() end\n";
+ }
+
+ // Generate the receiver for function signatures.
+ void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedMetaName(struct_def) + ":";
+ }
+
+ // Generate a struct field, conditioned on its child type(s).
+ void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, &def_comment);
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ GetScalarFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetScalarFieldOfTable(struct_def, field, code_ptr);
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ GetStructFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetStructFieldOfTable(struct_def, field, code_ptr);
+ }
+ break;
+ case BASE_TYPE_STRING:
+ GetStringField(struct_def, field, code_ptr);
+ break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ 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;
+ }
+ case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ if (IsVector(field.value.type)) {
+ GetVectorLen(struct_def, field, code_ptr);
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
+ GetStartOfTable(struct_def, code_ptr);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ BuildFieldOfTable(struct_def, field, offset, code_ptr);
+ if (IsVector(field.value.type)) {
+ BuildVectorOfTable(struct_def, field, code_ptr);
+ }
+ }
+
+ GetEndOffsetOnTable(struct_def, code_ptr);
+ }
+
+ // Generate struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ GenComment(struct_def.doc_comment, code_ptr, &def_comment);
+ BeginClass(struct_def, code_ptr);
+
+ GenerateNewObjectPrototype(struct_def, code_ptr);
+
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ NewRootTypeFromBuffer(struct_def, code_ptr);
+ }
+
+ // Generate the Init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ InitializeExisting(struct_def, code_ptr);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ GenStructAccessor(struct_def, field, code_ptr);
+ }
+
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ } else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
+ }
+ }
+
+ // Generate enum declarations.
+ void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+
+ GenComment(enum_def.doc_comment, code_ptr, &def_comment);
+ BeginEnum(NormalizedName(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);
+ 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) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return std::string(SelfData) + ":String(";
+ case BASE_TYPE_UNION: return std::string(SelfData) + ":Union(";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ default:
+ return std::string(SelfData) + ":Get(flatbuffers.N." +
+ MakeCamel(GenTypeGet(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))
+ : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
+ }
+
+ std::string GenTypeBasic(const Type &type) {
+ // clang-format off
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
+ #PTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ return ctypename[type.base_type];
+ }
+
+ std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "string";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return type.struct_def->name;
+ case BASE_TYPE_UNION:
+ // fall through
+ default: return "*flatbuffers.Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) {
+ return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+ }
+
+ std::string GetNamespace(const Type &type) {
+ return type.struct_def->defined_namespace->GetFullyQualifiedName(
+ type.struct_def->name);
+ }
+
+ std::string TypeName(const FieldDef &field) {
+ return GenTypeGet(field.value.type);
+ }
+
+ std::string TypeNameWithNamespace(const FieldDef &field) {
+ return GetNamespace(field.value.type);
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
+ BeginBuilderArgs(struct_def, code_ptr);
+ StructBuilderArgs(struct_def, "", code_ptr);
+ EndBuilderArgs(code_ptr);
+
+ StructBuilderBody(struct_def, "", code_ptr);
+ EndBuilderBody(code_ptr);
+ }
+
+ bool generate() {
+ if (!generateEnums()) return false;
+ if (!generateStructs()) return false;
+ return true;
+ }
+
+ private:
+ bool generateEnums() {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ std::string enumcode;
+ GenEnum(enum_def, &enumcode);
+ if (!SaveType(enum_def, enumcode, false)) return false;
+ }
+ return true;
+ }
+
+ bool generateStructs() {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ std::string declcode;
+ GenStruct(struct_def, &declcode);
+ if (!SaveType(struct_def, 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 = *code_ptr;
+ code += std::string(Comment) + FlatBuffersGeneratedWarning() + "\n\n";
+ code += std::string(Comment) + "namespace: " + name_space_name + "\n\n";
+ if (needs_imports) {
+ code += "local flatbuffers = require('flatbuffers')\n\n";
+ }
+ }
+
+ // Save out the generated code for a Lua Table type.
+ bool SaveType(const Definition &def, const std::string &classcode,
+ bool needs_imports) {
+ 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(*def.defined_namespace), needs_imports, &code);
+ code += classcode;
+ code += "\n";
+ code +=
+ "return " + NormalizedName(def) + " " + Comment + "return the module";
+ std::string filename =
+ NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".lua";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ private:
+ std::unordered_set<std::string> keywords_;
+};
+
+} // namespace lua
+
+bool GenerateLua(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ lua::LuaGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_php.cpp b/contrib/libs/flatbuffers/src/idl_gen_php.cpp
new file mode 100644
index 0000000000..dd3ed68189
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_php.cpp
@@ -0,0 +1,939 @@
+/*
+ * 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 <string>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+namespace php {
+// Hardcode spaces per indentation.
+const std::string Indent = " ";
+class PhpGenerator : public BaseGenerator {
+ public:
+ PhpGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "\\", "\\", "php") {}
+ bool generate() {
+ if (!GenerateEnums()) return false;
+ if (!GenerateStructs()) return false;
+ return true;
+ }
+
+ private:
+ bool GenerateEnums() {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ std::string enumcode;
+ GenEnum(enum_def, &enumcode);
+ if (!SaveType(enum_def, enumcode, false)) return false;
+ }
+ return true;
+ }
+
+ bool GenerateStructs() {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ std::string declcode;
+ GenStruct(struct_def, &declcode);
+ if (!SaveType(struct_def, 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) {
+ auto &code = *code_ptr;
+ code += "<?php\n";
+ code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
+
+ if (!name_space_name.empty()) {
+ code += "namespace " + name_space_name + ";\n\n";
+ }
+
+ if (needs_imports) {
+ code += "use \\Google\\FlatBuffers\\Struct;\n";
+ code += "use \\Google\\FlatBuffers\\Table;\n";
+ code += "use \\Google\\FlatBuffers\\ByteBuffer;\n";
+ code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n";
+ code += "\n";
+ }
+ }
+
+ // Save out the generated code for a Php Table type.
+ bool SaveType(const Definition &def, const std::string &classcode,
+ bool needs_imports) {
+ if (!classcode.length()) return true;
+
+ std::string code = "";
+ BeginFile(FullNamespace("\\", *def.defined_namespace), needs_imports,
+ &code);
+ code += classcode;
+
+ std::string filename =
+ NamespaceDir(*def.defined_namespace) + def.name + ".php";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ // Begin a class declaration.
+ static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ if (struct_def.fixed) {
+ code += "class " + struct_def.name + " extends Struct\n";
+ } else {
+ code += "class " + struct_def.name + " extends Table\n";
+ }
+ code += "{\n";
+ }
+
+ static void EndClass(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n";
+ }
+
+ // Begin enum code with a class declaration.
+ static void BeginEnum(const std::string &class_name, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "class " + class_name + "\n{\n";
+ }
+
+ // A single enum member.
+ static void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += Indent + "const ";
+ code += ev.name;
+ code += " = ";
+ code += enum_def.ToString(ev) + ";\n";
+ }
+
+ // End enum code.
+ static void EndEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n";
+ }
+
+ // Initialize a new struct or table from existing data.
+ static void NewRootTypeFromBuffer(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param ByteBuffer $bb\n";
+ code += Indent + " * @return " + struct_def.name + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function getRootAs";
+ code += struct_def.name;
+ code += "(ByteBuffer $bb)\n";
+ code += Indent + "{\n";
+
+ code += Indent + Indent + "$obj = new " + struct_def.name + "();\n";
+ code += Indent + Indent;
+ code += "return ($obj->init($bb->getInt($bb->getPosition())";
+ code += " + $bb->getPosition(), $bb));\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Initialize an existing object with other data, to avoid an allocation.
+ static void InitializeExisting(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param int $_i offset\n";
+ code += Indent + " * @param ByteBuffer $_bb\n";
+ code += Indent + " * @return " + struct_def.name + "\n";
+ code += Indent + " **/\n";
+ code += Indent + "public function init($_i, ByteBuffer $_bb)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$this->bb_pos = $_i;\n";
+ code += Indent + Indent + "$this->bb = $_bb;\n";
+ code += Indent + Indent + "return $this;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the length of a vector.
+ static void GetVectorLen(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return int\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name) + "Length()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(";
+ code += NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__vector_len($o) : 0;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get a [ubyte] vector as a byte array.
+ static void GetUByte(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return string\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name) + "Bytes()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return $this->__vector_as_bytes(";
+ code += NumToString(field.value.offset) + ");\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a struct's scalar.
+ static void GetScalarFieldOfStruct(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return ";
+ code += GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function " + getter;
+ code += MakeCamel(field.name) + "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return ";
+
+ code += "$this->bb->get";
+ code += MakeCamel(GenTypeGet(field.value.type));
+ code += "($this->bb_pos + ";
+ code += NumToString(field.value.offset) + ")";
+ code += ";\n";
+
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a table's scalar.
+ void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ 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 += " : " + GenDefaultValue(field.value) + ";\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Struct.
+ void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name) + "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$obj = new ";
+ code += GenTypeGet(field.value.type) + "();\n";
+ code += Indent + Indent + "$obj->init($this->bb_pos + ";
+ code += NumToString(field.value.offset) + ", $this->bb);";
+ code += "\n" + Indent + Indent + "return $obj;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Table.
+ void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$obj = new ";
+ code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $obj->init(";
+ if (field.value.type.struct_def->fixed) {
+ code += "$o + $this->bb_pos, $this->bb) : ";
+ } else {
+ code += "$this->__indirect($o + $this->bb_pos), $this->bb) : ";
+ }
+ code += GenDefaultValue(field.value) + ";\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a string.
+ void GetStringField(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__string($o + $this->bb_pos) : ";
+ code += GenDefaultValue(field.value) + ";\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a union from an object.
+ void GetUnionField(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name) + "($obj)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__union($obj, $o) : null;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a vector's struct member.
+ void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ 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";
+
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ code += Indent + Indent;
+ code += "return $o != 0 ? $obj->init($this->bb_pos +" +
+ NumToString(field.value.offset) + ", $this->bb) : null;\n";
+ } else {
+ code += Indent + Indent + "return $o != 0 ? $obj->init(";
+ code += field.value.type.struct_def->fixed
+ ? "$o + $this->bb_pos"
+ : "$this->__indirect($o + $this->bb_pos)";
+ code += ", $this->bb) : null;\n";
+ }
+ break;
+ case BASE_TYPE_STRING:
+ code += "// base_type_string\n";
+ // TODO(chobie): do we need this?
+ break;
+ case BASE_TYPE_VECTOR:
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += Indent + Indent + "return $o != 0 ? $obj->init(";
+ if (vectortype.struct_def->fixed) {
+ code += "$this->__vector($o) + $j *";
+ code += NumToString(InlineSize(vectortype));
+ } else {
+ code += "$this->__indirect($this->__vector($o) + $j * ";
+ code += NumToString(InlineSize(vectortype)) + ")";
+ }
+ code += ", $this->bb) : null;\n";
+ }
+ break;
+ case BASE_TYPE_UNION:
+ code += Indent + Indent + "return $o != 0 ? $this->";
+ code += GenGetter(field.value.type) + "($obj, $o); null;\n";
+ break;
+ default: break;
+ }
+
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a vector's non-struct member. Uses a named return
+ // argument to conveniently set the zero value for the result.
+ void GetMemberOfVectorOfNonStruct(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param int offset\n";
+ code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "($j)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n";
+
+ if (IsString(field.value.type.VectorType())) {
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__string($this->__vector($o) + $j * ";
+ code += NumToString(InlineSize(vectortype)) + ") : ";
+ code += GenDefaultValue(field.value) + ";\n";
+ } else {
+ code += Indent + Indent + "return $o != 0 ? $this->bb->get";
+ code += MakeCamel(GenTypeGet(field.value.type));
+ code += "($this->__vector($o) + $j * ";
+ code += NumToString(InlineSize(vectortype)) + ") : ";
+ code += GenDefaultValue(field.value) + ";\n";
+ }
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a vector's union member. Uses a named return
+ // argument to conveniently set the zero value for the result.
+ void GetMemberOfVectorOfUnion(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param int offset\n";
+ code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "($j, $obj)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent + "return $o != 0 ? ";
+ code += "$this->__union($obj, $this->__vector($o) + $j * ";
+ code += NumToString(InlineSize(vectortype)) + " - $this->bb_pos) : null;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ static void StructBuilderArgs(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ 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.
+ StructBuilderArgs(*field.value.type.struct_def,
+ (nameprefix + (field.name + "_")).c_str(), code_ptr);
+ } else {
+ std::string &code = *code_ptr;
+ code += std::string(", $") + nameprefix;
+ code += MakeCamel(field.name, false);
+ }
+ }
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ static void StructBuilderBody(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += Indent + Indent + "$builder->prep(";
+ code += NumToString(struct_def.minalign) + ", ";
+ code += 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) {
+ code += Indent + Indent + "$builder->pad(";
+ code += NumToString(field.padding) + ");\n";
+ }
+ if (IsStruct(field.value.type)) {
+ StructBuilderBody(*field.value.type.struct_def,
+ (nameprefix + (field.name + "_")).c_str(), code_ptr);
+ } else {
+ code += Indent + Indent + "$builder->put" + GenMethod(field) + "($";
+ code += nameprefix + MakeCamel(field.name, false) + ");\n";
+ }
+ }
+ }
+
+ // Get the value of a table's starting offset.
+ static void GetStartOfTable(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @return void\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function start" + struct_def.name;
+ code += "(FlatBufferBuilder $builder)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->StartObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ");\n";
+ code += Indent + "}\n\n";
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @return " + struct_def.name + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function create" + struct_def.name;
+ code += "(FlatBufferBuilder $builder, ";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+
+ if (field.deprecated) continue;
+ code += "$" + field.name;
+ if (it != struct_def.fields.vec.begin()) { code += ", "; }
+ }
+ code += ")\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->startObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ");\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ code += Indent + Indent + "self::add";
+ code += MakeCamel(field.name) + "($builder, $" + field.name + ");\n";
+ }
+
+ code += Indent + Indent + "$o = $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 += Indent + Indent + "$builder->required($o, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += Indent + Indent + "return $o;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Set the value of a table's field.
+ static void BuildFieldOfTable(const FieldDef &field, const size_t offset,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @param " + GenTypeBasic(field.value.type) + "\n";
+ code += Indent + " * @return void\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function ";
+ code += "add" + MakeCamel(field.name);
+ code += "(FlatBufferBuilder $builder, ";
+ code += "$" + MakeCamel(field.name, false);
+ code += ")\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->add";
+ code += GenMethod(field) + "X(";
+ code += NumToString(offset) + ", ";
+
+ code += "$" + MakeCamel(field.name, false);
+ code += ", ";
+
+ if (field.value.type.base_type == BASE_TYPE_BOOL) {
+ code += "false";
+ } else {
+ code += field.value.constant;
+ }
+ code += ");\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Set the value of one of the members of a table's vector.
+ static void BuildVectorOfTable(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @param array offset array\n";
+ code += Indent + " * @return int vector offset\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function create";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder $builder, array $data)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->startVector(";
+ code += NumToString(elem_size);
+ code += ", count($data), " + NumToString(alignment);
+ code += ");\n";
+ code += Indent + Indent;
+ code += "for ($i = count($data) - 1; $i >= 0; $i--) {\n";
+ if (IsScalar(field.value.type.VectorType().base_type)) {
+ code += Indent + Indent + Indent;
+ code += "$builder->put";
+ code += MakeCamel(GenTypeBasic(field.value.type.VectorType()));
+ code += "($data[$i]);\n";
+ } else {
+ code += Indent + Indent + Indent;
+ code += "$builder->putOffset($data[$i]);\n";
+ }
+ code += Indent + Indent + "}\n";
+ code += Indent + Indent + "return $builder->endVector();\n";
+ code += Indent + "}\n\n";
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @param int $numElems\n";
+ code += Indent + " * @return void\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function start";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder $builder, $numElems)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->startVector(";
+ code += NumToString(elem_size);
+ code += ", $numElems, " + NumToString(alignment);
+ code += ");\n";
+ code += Indent + "}\n\n";
+ }
+
+ // 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 += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @return int table offset\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function end" + struct_def.name;
+ code += "(FlatBufferBuilder $builder)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $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 += Indent + Indent + "$builder->required($o, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += Indent + Indent + "return $o;\n";
+ code += Indent + "}\n";
+
+ if (parser_.root_struct_def_ == &struct_def) {
+ code += "\n";
+ code += Indent + "public static function finish";
+ code += struct_def.name;
+ code += "Buffer(FlatBufferBuilder $builder, $offset)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->finish($offset";
+
+ if (parser_.file_identifier_.length())
+ code += ", \"" + parser_.file_identifier_ + "\"";
+ code += ");\n";
+ code += Indent + "}\n";
+ }
+ }
+
+ // Generate a struct field, conditioned on its child type(s).
+ void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, nullptr, Indent.c_str());
+
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ GetScalarFieldOfStruct(field, code_ptr);
+ } else {
+ GetScalarFieldOfTable(field, code_ptr);
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ GetStructFieldOfStruct(field, code_ptr);
+ } else {
+ GetStructFieldOfTable(field, code_ptr);
+ }
+ break;
+ case BASE_TYPE_STRING: GetStringField(field, code_ptr); break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ GetMemberOfVectorOfUnion(field, code_ptr);
+ } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetMemberOfVectorOfNonStruct(field, code_ptr);
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: GetUnionField(field, code_ptr); break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ if (IsVector(field.value.type)) {
+ GetVectorLen(field, code_ptr);
+ if (field.value.type.element == BASE_TYPE_UCHAR) {
+ GetUByte(field, code_ptr);
+ }
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
+ GetStartOfTable(struct_def, code_ptr);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ 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 += "(FlatBufferBuilder $builder, $offset)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->addOffsetX(";
+ code += NumToString(offset) + ", $offset, 0);\n";
+ code += Indent + "}\n\n";
+ } else {
+ BuildFieldOfTable(field, offset, code_ptr);
+ }
+ if (IsVector(field.value.type)) { BuildVectorOfTable(field, code_ptr); }
+ }
+
+ GetEndOffsetOnTable(struct_def, code_ptr);
+ }
+
+ // Generate struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ GenComment(struct_def.doc_comment, code_ptr, nullptr);
+ BeginClass(struct_def, code_ptr);
+
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ NewRootTypeFromBuffer(struct_def, code_ptr);
+ }
+
+ std::string &code = *code_ptr;
+ if (!struct_def.fixed) {
+ if (parser_.file_identifier_.length()) {
+ // Return the identifier
+ code += Indent + "public static function " + struct_def.name;
+ code += "Identifier()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return \"";
+ code += parser_.file_identifier_ + "\";\n";
+ code += Indent + "}\n\n";
+
+ // Check if a buffer has the identifier.
+ code += Indent + "public static function " + struct_def.name;
+ code += "BufferHasIdentifier(ByteBuffer $buf)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return self::";
+ code += "__has_identifier($buf, self::";
+ code += struct_def.name + "Identifier());\n";
+ code += Indent + "}\n\n";
+ }
+
+ if (parser_.file_extension_.length()) {
+ // Return the extension
+ code += Indent + "public static function " + struct_def.name;
+ code += "Extension()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return \"" + parser_.file_extension_;
+ code += "\";\n";
+ code += Indent + "}\n\n";
+ }
+ }
+
+ // Generate the Init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ InitializeExisting(struct_def, code_ptr);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ GenStructAccessor(struct_def, field, code_ptr);
+ }
+
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ } else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
+ }
+ EndClass(code_ptr);
+ }
+
+ // Generate enum declarations.
+ static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+
+ GenComment(enum_def.doc_comment, code_ptr, nullptr);
+ BeginEnum(enum_def.name, code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, nullptr, Indent.c_str());
+ EnumMember(enum_def, ev, code_ptr);
+ }
+
+ std::string &code = *code_ptr;
+ code += "\n";
+ code += Indent + "private static $names = array(\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ code += Indent + Indent + enum_def.name + "::" + ev.name + "=>" + "\"" +
+ ev.name + "\",\n";
+ }
+
+ code += Indent + ");\n\n";
+ code += Indent + "public static function Name($e)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "if (!isset(self::$names[$e])) {\n";
+ code += Indent + Indent + Indent + "throw new \\Exception();\n";
+ code += Indent + Indent + "}\n";
+ code += Indent + Indent + "return self::$names[$e];\n";
+ code += Indent + "}\n";
+ EndEnum(code_ptr);
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ static std::string GenGetter(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "__string";
+ case BASE_TYPE_STRUCT: return "__struct";
+ case BASE_TYPE_UNION: return "__union";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ default: return "Get";
+ }
+ }
+
+ // 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))
+ : (IsStruct(field.value.type) ? "Struct" : "Offset");
+ }
+
+ static std::string GenTypeBasic(const Type &type) {
+ // clang-format off
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, ...) \
+ #NTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ return ctypename[type.base_type];
+ }
+
+ std::string GenDefaultValue(const Value &value) {
+ if (value.type.enum_def) {
+ if (auto val = value.type.enum_def->FindByValue(value.constant)) {
+ return WrapInNameSpace(*value.type.enum_def) + "::" + val->name;
+ }
+ }
+
+ switch (value.type.base_type) {
+ case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
+
+ case BASE_TYPE_STRING: return "null";
+
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG:
+ if (value.constant != "0") {
+ int64_t constant = StringToInt(value.constant.c_str());
+ return NumToString(constant);
+ }
+ return "0";
+
+ default: return value.constant;
+ }
+ }
+
+ static std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "string";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return type.struct_def->name;
+ case BASE_TYPE_UNION:
+ // fall through
+ default: return "Table";
+ }
+ }
+
+ static std::string GenTypeGet(const Type &type) {
+ return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ static void GenStructBuilder(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\n";
+ code += Indent + "/**\n";
+ code += Indent + " * @return int offset\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function create" + struct_def.name;
+ code += "(FlatBufferBuilder $builder";
+ StructBuilderArgs(struct_def, "", code_ptr);
+ code += ")\n";
+ code += Indent + "{\n";
+
+ StructBuilderBody(struct_def, "", code_ptr);
+
+ code += Indent + Indent + "return $builder->offset();\n";
+ code += Indent + "}\n";
+ }
+};
+} // namespace php
+
+bool GeneratePhp(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ php::PhpGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_python.cpp b/contrib/libs/flatbuffers/src/idl_gen_python.cpp
new file mode 100644
index 0000000000..b3f394ebf9
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_python.cpp
@@ -0,0 +1,1782 @@
+/*
+ * 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 <cctype>
+#include <set>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+namespace python {
+
+// Hardcode spaces per indentation.
+const CommentConfig def_comment = { nullptr, "#", nullptr };
+const std::string Indent = " ";
+
+class PythonGenerator : public BaseGenerator {
+ public:
+ PythonGenerator(const Parser &parser, const std::string &path,
+ 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));
+ }
+
+ // 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) {
+ return "\n" + Indent + Indent +
+ "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
+ "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
+ Indent + Indent + "if o != 0:\n";
+ }
+
+ // Begin a class declaration.
+ void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += "class " + NormalizedName(struct_def) + "(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) {
+ 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;
+ }
+
+ // Starts a new line and then indents.
+ std::string GenIndents(int num) {
+ return "\n" + std::string(num * Indent.length(), ' ');
+ }
+
+ // A single enum member.
+ void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += Indent;
+ code += NormalizedName(ev);
+ 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) {
+ auto &code = *code_ptr;
+
+ code += Indent + "@classmethod\n";
+ code += Indent + "def GetRootAs";
+ 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.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";
+ code += NormalizedName(struct_def);
+ code += "(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) {
+ auto &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += "Init(self, buf, pos):\n";
+ code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
+ code += "\n";
+ }
+
+ // Get the length of a vector.
+ void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "Length(self";
+ code += "):" + OffsetPrefix(field);
+ code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
+ code += Indent + Indent + "return 0\n\n";
+ }
+
+ // Determines whether a vector is none or not.
+ void GetVectorIsNone(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "IsNone(self";
+ code += "):";
+ code += GenIndents(2) +
+ "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
+ "(self._tab.Offset(" + NumToString(field.value.offset) + "))";
+ code += GenIndents(2) + "return o == 0";
+ code += "\n\n";
+ }
+
+ // Get the value of a struct's scalar.
+ void GetScalarFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self): return " + getter;
+ code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
+ code += NumToString(field.value.offset) + "))\n";
+ }
+
+ // Get the value of a table's scalar.
+ void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self):";
+ code += OffsetPrefix(field);
+ getter += "o + self._tab.Pos)";
+ auto is_bool = IsBool(field.value.type.base_type);
+ if (is_bool) { getter = "bool(" + getter + ")"; }
+ code += Indent + Indent + Indent + "return " + getter + "\n";
+ std::string default_value;
+ if (is_bool) {
+ default_value = field.value.constant == "0" ? "False" : "True";
+ } else {
+ default_value = IsFloat(field.value.type.base_type)
+ ? float_const_gen_.GenFloatConstant(field)
+ : field.value.constant;
+ }
+ code += Indent + Indent + "return " + default_value + "\n\n";
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Struct.
+ void GetStructFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self, obj):\n";
+ code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
+ code += NumToString(field.value.offset) + ")";
+ code += "\n" + Indent + Indent + "return obj\n\n";
+ }
+
+ // Get the value of a fixed size array.
+ void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ const auto vec_type = field.value.type.VectorType();
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ if (IsStruct(vec_type)) {
+ code += "(self, obj, i):\n";
+ code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
+ code += NumToString(field.value.offset) + " + i * ";
+ code += NumToString(InlineSize(vec_type));
+ code += ")\n" + Indent + Indent + "return obj\n\n";
+ } else {
+ auto getter = GenGetter(vec_type);
+ code += "(self): return [" + getter;
+ code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
+ code += NumToString(field.value.offset) + " + i * ";
+ code += NumToString(InlineSize(vec_type));
+ code += ")) for i in range(";
+ code += NumToString(field.value.type.fixed_length) + ")]\n";
+ }
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Table.
+ void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self):";
+ code += OffsetPrefix(field);
+ if (field.value.type.struct_def->fixed) {
+ code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
+ } else {
+ code += Indent + Indent + Indent;
+ code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
+ }
+ if (parser_.opts.include_dependence_headers) {
+ code += Indent + Indent + Indent;
+ code += "from " + GenPackageReference(field.value.type) + " import " +
+ TypeName(field) + "\n";
+ }
+ code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
+ code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
+ code += Indent + Indent + Indent + "return obj\n";
+ code += Indent + Indent + "return None\n\n";
+ }
+
+ // Get the value of a string.
+ void GetStringField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self):";
+ code += OffsetPrefix(field);
+ code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
+ code += "o + self._tab.Pos)\n";
+ code += Indent + Indent + "return None\n\n";
+ }
+
+ // Get the value of a union from an object.
+ void GetUnionField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "(self):";
+ code += OffsetPrefix(field);
+
+ // TODO(rw): this works and is not the good way to it:
+ bool is_native_table = TypeName(field) == "*flatbuffers.Table";
+ if (is_native_table) {
+ code +=
+ Indent + Indent + Indent + "from flatbuffers.table import Table\n";
+ } else if (parser_.opts.include_dependence_headers) {
+ code += Indent + Indent + Indent;
+ code += "from " + GenPackageReference(field.value.type) + " import " +
+ TypeName(field) + "\n";
+ }
+ code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
+ code += Indent + Indent + Indent + GenGetter(field.value.type);
+ code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
+ code += Indent + Indent + "return None\n\n";
+ }
+
+ // Generate the package reference when importing a struct or enum from its
+ // module.
+ std::string GenPackageReference(const Type &type) {
+ Namespace *namespaces;
+ if (type.struct_def) {
+ namespaces = type.struct_def->defined_namespace;
+ } else if (type.enum_def) {
+ namespaces = type.enum_def->defined_namespace;
+ } else {
+ return "." + GenTypeGet(type);
+ }
+
+ return namespaces->GetFullyQualifiedName(GenTypeGet(type));
+ }
+
+ // Get the value of a vector's struct member.
+ void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self, j):" + OffsetPrefix(field);
+ code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
+ code += Indent + Indent + Indent;
+ code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
+ code += NumToString(InlineSize(vectortype)) + "\n";
+ if (!(vectortype.struct_def->fixed)) {
+ code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
+ }
+ if (parser_.opts.include_dependence_headers) {
+ code += Indent + Indent + Indent;
+ code += "from " + GenPackageReference(field.value.type) + " import " +
+ TypeName(field) + "\n";
+ }
+ code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
+ code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
+ code += Indent + Indent + Indent + "return obj\n";
+ code += Indent + Indent + "return None\n\n";
+ }
+
+ // Get the value of a vector's non-struct member. Uses a named return
+ // argument to conveniently set the zero value for the result.
+ void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self, j):";
+ code += OffsetPrefix(field);
+ code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
+ code += Indent + Indent + Indent;
+ code += "return " + GenGetter(field.value.type);
+ code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
+ code += NumToString(InlineSize(vectortype)) + "))\n";
+ if (IsString(vectortype)) {
+ code += Indent + Indent + "return \"\"\n";
+ } else {
+ code += Indent + Indent + "return 0\n";
+ }
+ code += "\n";
+ }
+
+ // Returns a non-struct vector as a numpy array. Much faster
+ // than iterating over the vector element by element.
+ void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ // Currently, we only support accessing as numpy array if
+ // the vector type is a scalar.
+ if (!(IsScalar(vectortype.base_type))) { return; }
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "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 += "Flags, o)\n";
+
+ if (IsString(vectortype)) {
+ code += Indent + Indent + "return \"\"\n";
+ } else {
+ code += Indent + Indent + "return 0\n";
+ }
+ code += "\n";
+ }
+
+ // Returns a nested flatbuffer as itself.
+ void GetVectorAsNestedFlatbuffer(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ auto nested = field.attributes.Lookup("nested_flatbuffer");
+ if (!nested) { return; } // There is no nested flatbuffer.
+
+ std::string unqualified_name = nested->constant;
+ 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;
+
+ auto &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "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";
+ 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) {
+ auto &code = *code_ptr;
+
+ code += "\n";
+ code += "def Create" + NormalizedName(struct_def);
+ code += "(builder";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void StructBuilderArgs(const StructDef &struct_def,
+ const std::string nameprefix,
+ const std::string namesuffix, bool has_field_name,
+ const std::string fieldname_suffix,
+ std::string *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;
+ const auto &type =
+ IsArray(field_type) ? field_type.VectorType() : field_type;
+ if (IsStruct(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.
+ auto subprefix = nameprefix;
+ if (has_field_name) {
+ subprefix += NormalizedName(field) + 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); }
+ code += namesuffix;
+ }
+ }
+ }
+
+ // End the creator function signature.
+ void EndBuilderArgs(std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += "):\n";
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr, size_t index = 0,
+ bool in_array = false) {
+ auto &code = *code_ptr;
+ std::string indent(index * 4, ' ');
+ code +=
+ indent + " builder.Prep(" + NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ")\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ const auto &type =
+ IsArray(field_type) ? field_type.VectorType() : field_type;
+ if (field.padding)
+ 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);
+ } else {
+ const auto index_var = "_idx" + NumToString(index);
+ if (IsArray(field_type)) {
+ code += indent + " for " + index_var + " in range(";
+ code += NumToString(field_type.fixed_length);
+ code += " , 0, -1):\n";
+ in_array = true;
+ }
+ if (IsStruct(type)) {
+ StructBuilderBody(
+ *field_type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).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);
+ 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]";
+ }
+ code += ")\n";
+ }
+ }
+ }
+ }
+
+ void EndBuilderBody(std::string *code_ptr) {
+ 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) {
+ auto &code = *code_ptr;
+ code += "def Start(builder): ";
+ code += "builder.StartObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ")\n";
+
+ // Add alias with the old name.
+ code += "def " + NormalizedName(struct_def) + "Start(builder):\n";
+ code += Indent + "\"\"\"This method is deprecated. Please switch to Start.\"\"\"\n";
+ code += Indent + "return 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) {
+ auto &code = *code_ptr;
+ code += "def Add" + MakeCamel(NormalizedName(field));
+ code += "(builder, ";
+ code += MakeCamel(NormalizedName(field), false);
+ 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) + ")";
+ } else {
+ code += MakeCamel(NormalizedName(field), false);
+ }
+ code += ", ";
+ code += IsFloat(field.value.type.base_type)
+ ? float_const_gen_.GenFloatConstant(field)
+ : field.value.constant;
+ code += ")\n";
+
+ // Add alias with the old name.
+ code += "def " + NormalizedName(struct_def) + "Add" + MakeCamel(NormalizedName(field));
+ code += "(builder, ";
+ code += MakeCamel(NormalizedName(field), false);
+ code += "):\n";
+ code += Indent + "\"\"\"This method is deprecated. Please switch to Add";
+ code += MakeCamel(NormalizedName(field)) + ".\"\"\"\n";
+ code += Indent + "return Add" + MakeCamel(NormalizedName(field));
+ code += "(builder, ";
+ code += MakeCamel(NormalizedName(field), false);
+ code += ")\n";
+
+ // Add alias with the old name.
+ }
+
+ // 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) {
+ auto &code = *code_ptr;
+ code += "def Start";
+ code += MakeCamel(NormalizedName(field));
+ code += "Vector(builder, numElems): return 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 += ", numElems, " + NumToString(alignment);
+ code += ")\n";
+
+ // Add alias with the old name.
+ code += "def " + NormalizedName(struct_def) + "Start";
+ code += MakeCamel(NormalizedName(field));
+ code += "Vector(builder, numElems):\n";
+ code += Indent + "\"\"\"This method is deprecated. Please switch to Start.\"\"\"\n";
+ code += Indent + "return Start";
+ code += MakeCamel(NormalizedName(field));
+ code += "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 FieldDef &field, std::string *code_ptr) {
+ auto nested = field.attributes.Lookup("nested_flatbuffer");
+ if (!nested) { return; } // There is no nested flatbuffer.
+
+ std::string unqualified_name = nested->constant;
+ 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;
+
+ auto &code = *code_ptr;
+ code += "def MakeVectorFromBytes(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";
+
+ // Add alias with the old name.
+ code += "def Make" + MakeCamel(NormalizedName(field));
+ code += "VectorFromBytes(builder, bytes):\n";
+ code += Indent + "builder.StartVector(";
+ 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";
+ }
+
+ // Get the offset of the end of a table.
+ void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += "def End(builder): return builder.EndObject()\n";
+
+ // Add alias with the old name.
+ code += "def " + NormalizedName(struct_def) + "End(builder):\n";
+ code += Indent + "\"\"\"This method is deprecated. Please switch to End.\"\"\"\n";
+ code += Indent + "return End(builder)";
+ }
+
+ // Generate the receiver for function signatures.
+ void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += Indent + "# " + NormalizedName(struct_def) + "\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) {
+ GenComment(field.doc_comment, code_ptr, &def_comment, Indent.c_str());
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ GetScalarFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetScalarFieldOfTable(struct_def, field, code_ptr);
+ }
+ } else if (IsArray(field.value.type)) {
+ GetArrayOfStruct(struct_def, field, code_ptr);
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ GetStructFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetStructFieldOfTable(struct_def, field, code_ptr);
+ }
+ break;
+ case BASE_TYPE_STRING:
+ GetStringField(struct_def, field, code_ptr);
+ break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+ GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
+ GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr);
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ if (IsVector(field.value.type) || IsArray(field.value.type)) {
+ GetVectorLen(struct_def, field, code_ptr);
+ GetVectorIsNone(struct_def, field, code_ptr);
+ }
+ }
+
+ // Generate struct sizeof.
+ void GenStructSizeOf(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += Indent + "@classmethod\n";
+ code += Indent + "def SizeOf(cls):\n";
+ code +=
+ Indent + Indent + "return " + NumToString(struct_def.bytesize) + "\n";
+ code += "\n";
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
+ GetStartOfTable(struct_def, code_ptr);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ BuildFieldOfTable(struct_def, field, offset, code_ptr);
+ if (IsVector(field.value.type)) {
+ BuildVectorOfTable(struct_def, field, code_ptr);
+ BuildVectorOfTableFromBytes(field, code_ptr);
+ }
+ }
+
+ GetEndOffsetOnTable(struct_def, code_ptr);
+ }
+
+ // Generate function to check for proper file identifier
+ void GenHasFileIdentifier(const StructDef &struct_def,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ std::string escapedID;
+ // In the event any of file_identifier characters are special(NULL, \, etc),
+ // problems occur. To prevent this, convert all chars to their hex-escaped
+ // equivalent.
+ for (auto it = parser_.file_identifier_.begin();
+ it != parser_.file_identifier_.end(); ++it) {
+ escapedID += "\\x" + IntToStringHex(*it, 2);
+ }
+
+ code += Indent + "@classmethod\n";
+ code += Indent + "def " + NormalizedName(struct_def);
+ code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):";
+ code += "\n";
+ code += Indent + Indent;
+ code += "return flatbuffers.util.BufferHasIdentifier(buf, offset, b\"";
+ code += escapedID;
+ code += "\", size_prefixed=size_prefixed)\n";
+ code += "\n";
+ }
+
+ // Generates struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ GenComment(struct_def.doc_comment, code_ptr, &def_comment);
+ BeginClass(struct_def, code_ptr);
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ NewRootTypeFromBuffer(struct_def, code_ptr);
+ if (parser_.file_identifier_.length()) {
+ // Generate a special function to test file_identifier
+ GenHasFileIdentifier(struct_def, code_ptr);
+ }
+ } else {
+ // Generates the SizeOf method for all structs.
+ GenStructSizeOf(struct_def, code_ptr);
+ }
+ // Generates the Init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ InitializeExisting(struct_def, code_ptr);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ GenStructAccessor(struct_def, field, code_ptr);
+ }
+
+ if (struct_def.fixed) {
+ // creates a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ } else {
+ // Creates a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
+ }
+ }
+
+ void GenReceiverForObjectAPI(const StructDef &struct_def,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += GenIndents(1) + "# " + NormalizedName(struct_def) + "T";
+ code += GenIndents(1) + "def ";
+ }
+
+ void BeginClassForObjectAPI(const StructDef &struct_def,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += "\n";
+ code += "class " + NormalizedName(struct_def) + "T(object):";
+ code += "\n";
+ }
+
+ // Gets the accoresponding python builtin type of a BaseType for scalars and
+ // string.
+ std::string GetBasePythonTypeForScalarAndString(const BaseType &base_type) {
+ if (IsBool(base_type)) {
+ return "bool";
+ } else if (IsFloat(base_type)) {
+ return "float";
+ } else if (IsInteger(base_type)) {
+ return "int";
+ } else if (base_type == BASE_TYPE_STRING) {
+ return "str";
+ } else {
+ FLATBUFFERS_ASSERT(false && "base_type is not a scalar or string type.");
+ return "";
+ }
+ }
+
+ std::string GetDefaultValue(const FieldDef &field) {
+ BaseType base_type = field.value.type.base_type;
+ if (IsBool(base_type)) {
+ return field.value.constant == "0" ? "False" : "True";
+ } else if (IsFloat(base_type)) {
+ return float_const_gen_.GenFloatConstant(field);
+ } else if (IsInteger(base_type)) {
+ return field.value.constant;
+ } else {
+ // For string, struct, and table.
+ return "None";
+ }
+ }
+
+ void GenUnionInit(const FieldDef &field, std::string *field_types_ptr,
+ std::set<std::string> *import_list,
+ std::set<std::string> *import_typing_list) {
+ // Gets all possible types in the union.
+ import_typing_list->insert("Union");
+ auto &field_types = *field_types_ptr;
+ field_types = "Union[";
+
+ std::string separator_string = ", ";
+ auto enum_def = field.value.type.enum_def;
+ for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
+ ++it) {
+ auto &ev = **it;
+ // Union only supports string and table.
+ std::string field_type;
+ switch (ev.union_type.base_type) {
+ case BASE_TYPE_STRUCT:
+ field_type = GenTypeGet(ev.union_type) + "T";
+ if (parser_.opts.include_dependence_headers) {
+ auto package_reference = GenPackageReference(ev.union_type);
+ field_type = package_reference + "." + field_type;
+ import_list->insert("import " + package_reference);
+ }
+ break;
+ case BASE_TYPE_STRING: field_type += "str"; break;
+ case BASE_TYPE_NONE: field_type += "None"; break;
+ default: break;
+ }
+ field_types += field_type + separator_string;
+ }
+
+ // Removes the last separator_string.
+ field_types.erase(field_types.length() - separator_string.size());
+ field_types += "]";
+
+ // 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));
+ import_list->insert("import " + package_reference);
+ }
+ }
+
+ void GenStructInit(const FieldDef &field, std::string *field_type_ptr,
+ std::set<std::string> *import_list,
+ std::set<std::string> *import_typing_list) {
+ import_typing_list->insert("Optional");
+ auto &field_type = *field_type_ptr;
+ if (parser_.opts.include_dependence_headers) {
+ auto package_reference = GenPackageReference(field.value.type);
+ field_type = package_reference + "." + TypeName(field) + "T]";
+ import_list->insert("import " + package_reference);
+ } else {
+ field_type = TypeName(field) + "T]";
+ }
+ field_type = "Optional[" + field_type;
+ }
+
+ void GenVectorInit(const FieldDef &field, std::string *field_type_ptr,
+ std::set<std::string> *import_list,
+ std::set<std::string> *import_typing_list) {
+ import_typing_list->insert("List");
+ auto &field_type = *field_type_ptr;
+ auto base_type = field.value.type.VectorType().base_type;
+ if (base_type == BASE_TYPE_STRUCT) {
+ field_type = GenTypeGet(field.value.type.VectorType()) + "T]";
+ if (parser_.opts.include_dependence_headers) {
+ auto package_reference =
+ GenPackageReference(field.value.type.VectorType());
+ field_type = package_reference + "." +
+ GenTypeGet(field.value.type.VectorType()) + "T]";
+ import_list->insert("import " + package_reference);
+ }
+ field_type = "List[" + field_type;
+ } else {
+ field_type =
+ "List[" + GetBasePythonTypeForScalarAndString(base_type) + "]";
+ }
+ }
+
+ void GenInitialize(const StructDef &struct_def, std::string *code_ptr,
+ std::set<std::string> *import_list) {
+ std::string code;
+ std::set<std::string> import_typing_list;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ // Determines field type, default value, and typing imports.
+ auto base_type = field.value.type.base_type;
+ std::string field_type;
+ switch (base_type) {
+ case BASE_TYPE_UNION: {
+ GenUnionInit(field, &field_type, import_list, &import_typing_list);
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ GenStructInit(field, &field_type, import_list, &import_typing_list);
+ break;
+ }
+ case BASE_TYPE_VECTOR:
+ case BASE_TYPE_ARRAY: {
+ GenVectorInit(field, &field_type, import_list, &import_typing_list);
+ break;
+ }
+ default:
+ // Scalar or sting fields.
+ field_type = GetBasePythonTypeForScalarAndString(base_type);
+ break;
+ }
+
+ 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;
+ }
+
+ // Writes __init__ method.
+ auto &code_base = *code_ptr;
+ GenReceiverForObjectAPI(struct_def, code_ptr);
+ code_base += "__init__(self):";
+ if (code.empty()) {
+ code_base += GenIndents(2) + "pass";
+ } else {
+ code_base += code;
+ }
+ code_base += "\n";
+
+ // Merges the typing imports into import_list.
+ if (!import_typing_list.empty()) {
+ // Adds the try statement.
+ std::string typing_imports = "try:";
+ typing_imports += GenIndents(1) + "from typing import ";
+ std::string separator_string = ", ";
+ for (auto it = import_typing_list.begin(); it != import_typing_list.end();
+ ++it) {
+ const std::string &im = *it;
+ typing_imports += im + separator_string;
+ }
+ // Removes the last separator_string.
+ typing_imports.erase(typing_imports.length() - separator_string.size());
+
+ // Adds the except statement.
+ typing_imports += "\n";
+ typing_imports += "except:";
+ typing_imports += GenIndents(1) + "pass";
+ import_list->insert(typing_imports);
+ }
+
+ // 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;
+ import_list->erase(struct_import);
+ }
+
+ void InitializeFromBuf(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto instance_name = MakeLowerCamel(struct_def);
+ auto struct_name = NormalizedName(struct_def);
+
+ 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 += "\n";
+ }
+
+ void InitializeFromObjForObject(const StructDef &struct_def,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto instance_name = MakeLowerCamel(struct_def);
+ auto struct_name = NormalizedName(struct_def);
+
+ 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(2) + "return x";
+ code += "\n";
+ }
+
+ void GenUnPackForStruct(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto field_type = TypeName(field);
+
+ if (parser_.opts.include_dependence_headers) {
+ auto package_reference = GenPackageReference(field.value.type);
+ field_type = package_reference + "." + TypeName(field);
+ }
+
+ code += GenIndents(2) + "if " + struct_instance_name + "." +
+ field_accessor_name + "(";
+ // 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 + "(";
+ // A struct's accessor requires a struct buf instance.
+ if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
+ code += field_type + "()";
+ }
+ code += "))";
+ }
+
+ void GenUnPackForUnion(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ 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));
+
+ 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;
+ }
+ code += GenIndents(2) + "self." + field_instance_name + " = " + union_name +
+ "Creator(" + "self." + field_instance_name + "Type, " +
+ struct_instance_name + "." + field_accessor_name + "())";
+ }
+
+ void GenUnPackForStructVector(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+
+ 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()):";
+
+ auto field_type_name = TypeName(field);
+ auto one_instance = field_type_name + "_";
+ 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);
+ }
+
+ 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) + "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 + ")";
+ }
+
+ void GenUnpackforScalarVectorHelper(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr, int indents) {
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+
+ 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))";
+ }
+
+ void GenUnPackForScalarVector(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+
+ code += GenIndents(2) + "if not " + struct_instance_name + "." +
+ field_accessor_name + "IsNone():";
+
+ // String does not have the AsNumpy method.
+ if (!(IsScalar(field.value.type.VectorType().base_type))) {
+ GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 3);
+ return;
+ }
+
+ code += GenIndents(3) + "if np is None:";
+ GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 4);
+
+ // 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()";
+ }
+
+ void GenUnPackForScalar(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto field_instance_name = MakeLowerCamel(field);
+ auto field_accessor_name = MakeUpperCamel(field);
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+
+ code += GenIndents(2) + "self." + field_instance_name + " = " +
+ struct_instance_name + "." + field_accessor_name + "()";
+ }
+
+ // Generates the UnPack method for the object class.
+ void GenUnPack(const StructDef &struct_def, std::string *code_ptr) {
+ std::string code;
+ // Items that needs to be imported. No duplicate modules will be imported.
+ std::set<std::string> import_list;
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto field_type = TypeName(field);
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ GenUnPackForStruct(struct_def, field, &code);
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ GenUnPackForUnion(struct_def, field, &code);
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GenUnPackForStructVector(struct_def, field, &code);
+ } else {
+ GenUnPackForScalarVector(struct_def, field, &code);
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ GenUnPackForScalarVector(struct_def, field, &code);
+ break;
+ }
+ default: GenUnPackForScalar(struct_def, field, &code);
+ }
+ }
+
+ // 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);
+
+ GenReceiverForObjectAPI(struct_def, code_ptr);
+ code_base += "_UnPack(self, " + struct_instance_name + "):";
+ code_base += GenIndents(2) + "if " + struct_instance_name + " is None:";
+ code_base += GenIndents(3) + "return";
+
+ // Write the import statements.
+ for (std::set<std::string>::iterator it = import_list.begin();
+ it != import_list.end(); ++it) {
+ code_base += GenIndents(2) + *it;
+ }
+
+ // Write the code.
+ code_base += code;
+ code_base += "\n";
+ }
+
+ void GenPackForStruct(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto struct_name = MakeUpperCamel(struct_def);
+
+ GenReceiverForObjectAPI(struct_def, code_ptr);
+ code += "Pack(self, builder):";
+ code += GenIndents(2) + "return Create" + struct_name + "(builder";
+
+ StructBuilderArgs(struct_def,
+ /* nameprefix = */ "self.",
+ /* namesuffix = */ "",
+ /* has_field_name = */ true,
+ /* fieldname_suffix = */ ".", code_ptr);
+ code += ")\n";
+ }
+
+ void GenPackForStructVectorField(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_prefix_ptr,
+ std::string *code_ptr) {
+ 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);
+
+ // Creates the field.
+ code_prefix +=
+ GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ if (field.value.type.struct_def->fixed) {
+ code_prefix += GenIndents(3) + "Start" +
+ field_accessor_name + "Vector(builder, len(self." +
+ field_instance_name + "))";
+ code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
+ field_instance_name + "))):";
+ code_prefix +=
+ GenIndents(4) + "self." + field_instance_name + "[i].Pack(builder)";
+ code_prefix +=
+ GenIndents(3) + field_instance_name + " = 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);
+ 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 += GenIndents(3) + "Start" +
+ field_accessor_name + "Vector(builder, len(self." +
+ field_instance_name + "))";
+ code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
+ field_instance_name + "))):";
+ code_prefix += GenIndents(4) + "builder.PrependUOffsetTRelative" + "(" +
+ field_instance_name + "list[i])";
+ code_prefix +=
+ GenIndents(3) + field_instance_name + " = builder.EndVector()";
+ }
+
+ // Adds the field into the struct.
+ code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ code += GenIndents(3) + "Add" + field_accessor_name +
+ "(builder, " + field_instance_name + ")";
+ }
+
+ void GenPackForScalarVectorFieldHelper(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr, int indents) {
+ 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();
+
+ code += GenIndents(indents) + "Start" + field_accessor_name +
+ "Vector(builder, len(self." + field_instance_name + "))";
+ code += GenIndents(indents) + "for i in reversed(range(len(self." +
+ field_instance_name + "))):";
+ code += GenIndents(indents + 1) + "builder.Prepend";
+
+ std::string type_name;
+ switch (vectortype.base_type) {
+ case BASE_TYPE_BOOL: type_name = "Bool"; break;
+ case BASE_TYPE_CHAR: type_name = "Byte"; break;
+ case BASE_TYPE_UCHAR: type_name = "Uint8"; break;
+ case BASE_TYPE_SHORT: type_name = "Int16"; break;
+ case BASE_TYPE_USHORT: type_name = "Uint16"; break;
+ case BASE_TYPE_INT: type_name = "Int32"; break;
+ case BASE_TYPE_UINT: type_name = "Uint32"; break;
+ case BASE_TYPE_LONG: type_name = "Int64"; break;
+ case BASE_TYPE_ULONG: type_name = "Uint64"; break;
+ case BASE_TYPE_FLOAT: type_name = "Float32"; break;
+ case BASE_TYPE_DOUBLE: type_name = "Float64"; break;
+ case BASE_TYPE_STRING: type_name = "UOffsetTRelative"; break;
+ default: type_name = "VOffsetT"; break;
+ }
+ code += type_name;
+ }
+
+ void GenPackForScalarVectorField(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_prefix_ptr,
+ std::string *code_ptr) {
+ 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);
+
+ // Adds the field into the struct.
+ code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
+ code += GenIndents(3) + "Add" + field_accessor_name +
+ "(builder, " + field_instance_name + ")";
+
+ // Creates the field.
+ code_prefix +=
+ GenIndents(2) + "if self." + field_instance_name + " 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]))";
+ GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
+ code_prefix += "(" + MakeLowerCamel(field) + "list[i])";
+ code_prefix +=
+ GenIndents(3) + field_instance_name + " = 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 +
+ ")";
+ 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()";
+ }
+
+ void GenPackForStructField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_prefix_ptr,
+ std::string *code_ptr) {
+ 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);
+
+ 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)";
+ } 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 += GenIndents(3) + "Add" + field_accessor_name +
+ "(builder, " + field_instance_name + ")";
+ }
+
+ void GenPackForUnionField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_prefix_ptr,
+ std::string *code_ptr) {
+ 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);
+
+ // 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) + "Add" + field_accessor_name +
+ "(builder, " + field_instance_name + ")";
+ }
+
+ void GenPackForTable(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code_base = *code_ptr;
+ std::string code, code_prefix;
+ auto struct_instance_name = MakeLowerCamel(struct_def);
+ auto struct_name = NormalizedName(struct_def);
+
+ GenReceiverForObjectAPI(struct_def, code_ptr);
+ code_base += "Pack(self, builder):";
+ code += GenIndents(2) + "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);
+
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ GenPackForStructField(struct_def, field, &code_prefix, &code);
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ GenPackForUnionField(struct_def, field, &code_prefix, &code);
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GenPackForStructVectorField(struct_def, field, &code_prefix, &code);
+ } else {
+ GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
+ }
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
+ 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) + "Add" + field_accessor_name +
+ "(builder, " + field_instance_name + ")";
+ 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) + "Add" + field_accessor_name +
+ "(builder, self." + field_instance_name + ")";
+ break;
+ }
+ }
+
+ code += GenIndents(2) + struct_instance_name + " = " + "End(builder)";
+ code += GenIndents(2) + "return " + struct_instance_name;
+
+ code_base += code_prefix + code;
+ code_base += "\n";
+ }
+
+ void GenStructForObjectAPI(const StructDef &struct_def,
+ std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ std::set<std::string> import_list;
+ std::string code;
+
+ // Creates an object class for a struct or a table
+ BeginClassForObjectAPI(struct_def, &code);
+
+ GenInitialize(struct_def, &code, &import_list);
+
+ InitializeFromBuf(struct_def, &code);
+
+ InitializeFromObjForObject(struct_def, &code);
+
+ GenUnPack(struct_def, &code);
+
+ if (struct_def.fixed) {
+ GenPackForStruct(struct_def, &code);
+ } else {
+ GenPackForTable(struct_def, &code);
+ }
+
+ // Adds the imports at top.
+ auto &code_base = *code_ptr;
+ code_base += "\n";
+ for (auto it = import_list.begin(); it != import_list.end(); it++) {
+ auto im = *it;
+ code_base += im + "\n";
+ }
+ code_base += code;
+ }
+
+ void GenUnionCreatorForStruct(const EnumDef &enum_def, const EnumVal &ev,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto union_name = NormalizedName(enum_def);
+ auto field_name = NormalizedName(ev);
+ auto field_type = GenTypeGet(ev.union_type) + "T";
+
+ code += GenIndents(1) + "if unionType == " + union_name + "()." +
+ field_name + ":";
+ if (parser_.opts.include_dependence_headers) {
+ auto package_reference = GenPackageReference(ev.union_type);
+ code += GenIndents(2) + "import " + package_reference;
+ field_type = package_reference + "." + field_type;
+ }
+ code += GenIndents(2) + "return " + field_type +
+ ".InitFromBuf(table.Bytes, table.Pos)";
+ }
+
+ void GenUnionCreatorForString(const EnumDef &enum_def, const EnumVal &ev,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto union_name = NormalizedName(enum_def);
+ auto field_name = NormalizedName(ev);
+
+ code += GenIndents(1) + "if unionType == " + union_name + "()." +
+ field_name + ":";
+ 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) {
+ auto &code = *code_ptr;
+ auto union_name = MakeUpperCamel(enum_def);
+
+ code += "\n";
+ code += "def " + union_name + "Creator(unionType, table):";
+ code += GenIndents(1) + "from flatbuffers.table import Table";
+ code += GenIndents(1) + "if not isinstance(table, Table):";
+ code += GenIndents(2) + "return None";
+
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ // Union only supports string and table.
+ switch (ev.union_type.base_type) {
+ case BASE_TYPE_STRUCT:
+ GenUnionCreatorForStruct(enum_def, ev, &code);
+ break;
+ case BASE_TYPE_STRING:
+ GenUnionCreatorForString(enum_def, ev, &code);
+ break;
+ default: break;
+ }
+ }
+ code += GenIndents(1) + "return None";
+ code += "\n";
+ }
+
+ // Generate enum declarations.
+ void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+
+ GenComment(enum_def.doc_comment, code_ptr, &def_comment);
+ BeginEnum(NormalizedName(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) {
+ 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, ";
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ std::string GenMethod(const FieldDef &field) {
+ return (IsScalar(field.value.type.base_type) || IsArray(field.value.type))
+ ? MakeCamel(GenTypeBasic(field.value.type))
+ : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
+ }
+
+ std::string GenTypeBasic(const Type &type) {
+ // clang-format off
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
+ #PTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ return ctypename[IsArray(type) ? type.VectorType().base_type
+ : type.base_type];
+ }
+
+ std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "string";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return type.struct_def->name;
+ case BASE_TYPE_UNION:
+ // fall through
+ default: return "*flatbuffers.Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) {
+ return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+ }
+
+ std::string TypeName(const FieldDef &field) {
+ 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) {
+ BeginBuilderArgs(struct_def, code_ptr);
+ StructBuilderArgs(struct_def,
+ /* nameprefix = */ "",
+ /* namesuffix = */ "",
+ /* has_field_name = */ true,
+ /* fieldname_suffix = */ "_", code_ptr);
+ EndBuilderArgs(code_ptr);
+
+ StructBuilderBody(struct_def, "", code_ptr);
+ EndBuilderBody(code_ptr);
+ }
+
+ bool generate() {
+ if (!generateEnums()) return false;
+ if (!generateStructs()) return false;
+ return true;
+ }
+
+ private:
+ bool generateEnums() {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ std::string enumcode;
+ GenEnum(enum_def, &enumcode);
+ if (parser_.opts.generate_object_based_api & enum_def.is_union) {
+ GenUnionCreator(enum_def, &enumcode);
+ }
+ if (!SaveType(enum_def, enumcode, false)) return false;
+ }
+ return true;
+ }
+
+ bool generateStructs() {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ std::string declcode;
+ GenStruct(struct_def, &declcode);
+ if (parser_.opts.generate_object_based_api) {
+ GenStructForObjectAPI(struct_def, &declcode);
+ }
+ if (!SaveType(struct_def, 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) {
+ auto &code = *code_ptr;
+ code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
+ code += "# namespace: " + name_space_name + "\n\n";
+ if (needs_imports) {
+ code += "import flatbuffers\n";
+ code += "from flatbuffers.compat import import_numpy\n";
+ code += "np = import_numpy()\n\n";
+ }
+ }
+
+ // Save out the generated code for a Python Table type.
+ bool SaveType(const Definition &def, const std::string &classcode,
+ bool needs_imports) {
+ 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(*def.defined_namespace), needs_imports, &code);
+ code += classcode;
+ std::string filename =
+ NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".py";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ private:
+ std::unordered_set<std::string> keywords_;
+ const SimpleFloatConstantGenerator float_const_gen_;
+};
+
+} // namespace python
+
+bool GeneratePython(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ python::PythonGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_rust.cpp b/contrib/libs/flatbuffers/src/idl_gen_rust.cpp
new file mode 100644
index 0000000000..455780cd94
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_rust.cpp
@@ -0,0 +1,2817 @@
+/*
+ * Copyright 2018 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 "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+// Convert a camelCaseIdentifier or CamelCaseIdentifier to a
+// snake_case_identifier.
+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;
+}
+
+// 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;
+}
+
+// Encapsulate all logical field types in this enum. This allows us to write
+// field logic based on type switches, instead of branches on the properties
+// set on the Type.
+// TODO(rw): for backwards compatibility, we can't use a strict `enum class`
+// declaration here. could we use the `-Wswitch-enum` warning to
+// achieve the same effect?
+enum FullType {
+ ftInteger = 0,
+ ftFloat = 1,
+ ftBool = 2,
+
+ ftStruct = 3,
+ ftTable = 4,
+
+ ftEnumKey = 5,
+ ftUnionKey = 6,
+
+ ftUnionValue = 7,
+
+ // TODO(rw): bytestring?
+ ftString = 8,
+
+ ftVectorOfInteger = 9,
+ ftVectorOfFloat = 10,
+ ftVectorOfBool = 11,
+ ftVectorOfEnumKey = 12,
+ ftVectorOfStruct = 13,
+ ftVectorOfTable = 14,
+ ftVectorOfString = 15,
+ ftVectorOfUnionValue = 16,
+
+ ftArrayOfBuiltin = 17,
+ ftArrayOfEnum = 18,
+ ftArrayOfStruct = 19,
+};
+
+// Convert a Type to a FullType (exhaustive).
+FullType GetFullType(const Type &type) {
+ // N.B. The order of these conditionals matters for some types.
+
+ if (IsString(type)) {
+ return ftString;
+ } else if (type.base_type == BASE_TYPE_STRUCT) {
+ if (type.struct_def->fixed) {
+ return ftStruct;
+ } else {
+ return ftTable;
+ }
+ } else if (IsVector(type)) {
+ switch (GetFullType(type.VectorType())) {
+ case ftInteger: {
+ return ftVectorOfInteger;
+ }
+ case ftFloat: {
+ return ftVectorOfFloat;
+ }
+ case ftBool: {
+ return ftVectorOfBool;
+ }
+ case ftStruct: {
+ return ftVectorOfStruct;
+ }
+ case ftTable: {
+ return ftVectorOfTable;
+ }
+ case ftString: {
+ return ftVectorOfString;
+ }
+ case ftEnumKey: {
+ return ftVectorOfEnumKey;
+ }
+ case ftUnionKey:
+ case ftUnionValue: {
+ FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
+ break;
+ }
+ default: {
+ 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) {
+ return ftUnionValue;
+ } else if (IsInteger(type.base_type)) {
+ return ftUnionKey;
+ } else {
+ FLATBUFFERS_ASSERT(false && "unknown union field type");
+ }
+ } else {
+ return ftEnumKey;
+ }
+ } else if (IsScalar(type.base_type)) {
+ if (IsBool(type.base_type)) {
+ return ftBool;
+ } else if (IsInteger(type.base_type)) {
+ return ftInteger;
+ } else if (IsFloat(type.base_type)) {
+ return ftFloat;
+ } else {
+ FLATBUFFERS_ASSERT(false && "unknown number type");
+ }
+ }
+
+ FLATBUFFERS_ASSERT(false && "completely unknown type");
+
+ // this is only to satisfy the compiler's return analysis.
+ 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);
+}
+
+namespace rust {
+
+class RustGenerator : public BaseGenerator {
+ public:
+ 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[] = {
+ // clang-format off
+ // 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);
+ }
+
+ // Iterate through all definitions we haven't generated code for (enums,
+ // structs, and tables) and output them to a single file.
+ bool generate() {
+ code_.Clear();
+ code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ assert(!cur_name_space_);
+
+ // Generate imports for the global scope in case no namespace is used
+ // in the schema file.
+ GenNamespaceImports(0);
+ code_ += "";
+
+ // Generate all code in their namespaces, once, because Rust does not
+ // permit re-opening modules.
+ //
+ // TODO(rw): Use a set data structure to reduce namespace evaluations from
+ // O(n**2) to O(n).
+ for (auto ns_it = parser_.namespaces_.begin();
+ ns_it != parser_.namespaces_.end(); ++ns_it) {
+ const auto &ns = *ns_it;
+
+ // Generate code for all the enum declarations.
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ const auto &enum_def = **it;
+ if (enum_def.defined_namespace == ns && !enum_def.generated) {
+ SetNameSpace(enum_def.defined_namespace);
+ GenEnum(enum_def);
+ }
+ }
+
+ // Generate code for all structs.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (struct_def.defined_namespace == ns && struct_def.fixed &&
+ !struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenStruct(struct_def);
+ }
+ }
+
+ // Generate code for all tables.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ 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);
+ }
+ }
+ }
+
+ // Generate global helper functions.
+ if (parser_.root_struct_def_) {
+ auto &struct_def = *parser_.root_struct_def_;
+ if (struct_def.defined_namespace != ns) { continue; }
+ SetNameSpace(struct_def.defined_namespace);
+ GenRootTableFuncs(struct_def);
+ }
+ }
+ if (cur_name_space_) SetNameSpace(nullptr);
+
+ const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts);
+ const auto final_code = code_.ToString();
+ return SaveFile(file_path.c_str(), final_code, false);
+ }
+
+ private:
+ CodeWriter code_;
+
+ std::set<std::string> keywords_;
+
+ // This tracks the current namespace so we can insert namespace declarations.
+ const Namespace *cur_name_space_;
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ // Determine if a Type needs a lifetime template parameter when used in the
+ // Rust builder args.
+ bool TableBuilderTypeNeedsLifetime(const Type &type) const {
+ switch (GetFullType(type)) {
+ case ftInteger:
+ case ftFloat:
+ case ftBool:
+ case ftEnumKey:
+ case ftUnionKey:
+ case ftUnionValue: {
+ return false;
+ }
+ default: {
+ return true;
+ }
+ }
+ }
+
+ // Determine if a table args rust type needs a lifetime template parameter.
+ bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
+ FLATBUFFERS_ASSERT(!struct_def.fixed);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) { continue; }
+
+ if (TableBuilderTypeNeedsLifetime(field.value.type)) { return true; }
+ }
+
+ 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, NativeName(def));
+ }
+
+ std::string NativeName(const Definition &def) {
+ return parser_.opts.object_prefix + Name(def) + parser_.opts.object_suffix;
+ }
+
+ 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));
+ }
+ std::string WrapInNameSpace(const Namespace *ns,
+ const std::string &name) const {
+ if (CurrentNameSpace() == ns) return name;
+ std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
+ 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
+ // namespace paths, that may require users to organize their Rust crates in a
+ // particular way.)
+ std::string GetRelativeNamespaceTraversal(const Namespace *src,
+ const Namespace *dst) const {
+ // calculate the path needed to reference dst from src.
+ // example: f(A::B::C, A::B::C) -> (none)
+ // example: f(A::B::C, A::B) -> super::
+ // example: f(A::B::C, A::B::D) -> super::D
+ // example: f(A::B::C, A) -> super::super::
+ // example: f(A::B::C, D) -> super::super::super::D
+ // example: f(A::B::C, D::E) -> super::super::super::D::E
+ // 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) + "::";
+ }
+ 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 + "\\";
+ }
+
+ // Return a Rust type from the table in idl.h.
+ std::string GetTypeBasic(const Type &type) const {
+ switch (GetFullType(type)) {
+ case ftInteger:
+ case ftFloat:
+ case ftBool:
+ case ftEnumKey:
+ case ftUnionKey: {
+ break;
+ }
+ default: {
+ FLATBUFFERS_ASSERT(false && "incorrect type given");
+ }
+ }
+
+ // clang-format off
+ static const char * const ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
+ RTYPE, ...) \
+ #RTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+
+ if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
+ return ctypename[type.base_type];
+ }
+
+ // Look up the native type for an enum. This will always be an integer like
+ // u8, i32, etc.
+ std::string GetEnumTypeForDecl(const Type &type) {
+ const auto ft = GetFullType(type);
+ if (!(ft == ftEnumKey || ft == ftUnionKey)) {
+ FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
+ }
+
+ // clang-format off
+ static const char *ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
+ RTYPE, ...) \
+ #RTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+
+ // Enums can be bools, but their Rust representation must be a u8, as used
+ // in the repr attribute (#[repr(bool)] is an invalid attribute).
+ if (type.base_type == BASE_TYPE_BOOL) return "u8";
+ return ctypename[type.base_type];
+ }
+
+ // Return a Rust type for any type (scalar, table, struct) specifically for
+ // using a FlatBuffer.
+ std::string GetTypeGet(const Type &type) const {
+ switch (GetFullType(type)) {
+ case ftInteger:
+ case ftFloat:
+ case ftBool:
+ case ftEnumKey:
+ 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) +
+ "<'a>";
+ }
+ default: {
+ return WrapInNameSpace(type.struct_def->defined_namespace,
+ type.struct_def->name);
+ }
+ }
+ }
+
+ std::string GetEnumValue(const EnumDef &enum_def,
+ const EnumVal &enum_val) const {
+ return Name(enum_def) + "::" + Name(enum_val);
+ }
+
+ // 1 suffix since old C++ can't figure out the overload.
+ void ForAllEnumValues1(const EnumDef &enum_def,
+ 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("VALUE", enum_def.ToString(ev));
+ cb(ev);
+ }
+ }
+ 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);
+ }
+ // 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("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))));
+ const EnumVal *minv = enum_def.MinValue();
+ const EnumVal *maxv = enum_def.MaxValue();
+ FLATBUFFERS_ASSERT(minv && maxv);
+ code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
+ 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.
+ code_ += "#[allow(non_upper_case_globals)]";
+ code_ += "mod bitflags_{{ENUM_NAME_SNAKE}} {";
+ code_ += " flatbuffers::bitflags::bitflags! {";
+ GenComment(enum_def.doc_comment, " ");
+ code_ += " #[derive(Default)]";
+ code_ += " pub struct {{ENUM_NAME}}: {{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_ += "";
+
+ 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_NAME_CAPS}}: {{BASE_TYPE}}"
+ " = {{ENUM_MIN_BASE_VALUE}};";
+ code_ += deprecation_warning;
+ code_ +=
+ "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{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_NAME_CAPS}}: [{{ENUM_NAME}}; " +
+ num_fields + "] = [";
+ ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
+ code_ += " " + GetEnumValue(enum_def, ev) + ",";
+ });
+ code_ += "];";
+ code_ += "";
+
+ 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_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_ += "}";
+
+ code_.SetValue("FROM_BASE", "Self(b)");
+ code_.SetValue("INTO_BASE", "self.0");
+ }
+
+ // 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 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_ += " #[inline]";
+ code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
+ code_ +=
+ " unsafe { flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
+ "(dst, {{INTO_BASE}}); }";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
+ code_ += " #[inline]";
+ code_ += " fn to_little_endian(self) -> Self {";
+ 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_ += " 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_NAME}} {";
+ 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_NAME}} {}";
+
+ if (enum_def.is_union) {
+ // Generate typesafe 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}} {}";
+ code_ += "";
+ if (parser_.opts.generate_object_based_api) { GenUnionObject(enum_def); }
+ }
+ }
+
+ // CASPER: 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", Name(enum_val));
+ code_.SetValue("NATIVE_VARIANT", MakeCamel(Name(enum_val)));
+ code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(enum_val)));
+ code_.SetValue("U_ELEMENT_TABLE_TYPE",
+ NamespacedNativeName(*enum_val.union_type.struct_def));
+ cb();
+ }
+ }
+ void GenUnionObject(const EnumDef &enum_def) {
+ code_.SetValue("ENUM_NAME", Name(enum_def));
+ code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
+ code_.SetValue("NATIVE_NAME", NativeName(enum_def));
+
+ // Generate native union.
+ code_ += "#[non_exhaustive]";
+ code_ += "#[derive(Debug, Clone, PartialEq)]";
+ code_ += "pub enum {{NATIVE_NAME}} {";
+ code_ += " NONE,";
+ ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
+ code_ += " {{NATIVE_VARIANT}}(Box<{{U_ELEMENT_TABLE_TYPE}}>),";
+ });
+ code_ += "}";
+ // Generate Default (NONE).
+ code_ += "impl Default for {{NATIVE_NAME}} {";
+ code_ += " fn default() -> Self {";
+ code_ += " Self::NONE";
+ code_ += " }";
+ code_ += "}";
+
+ // Generate native union methods.
+ code_ += "impl {{NATIVE_NAME}} {";
+
+ // Get flatbuffers union key.
+ // CASPER: add docstrings?
+ code_ += " pub fn {{ENUM_NAME_SNAKE}}_type(&self) -> {{ENUM_NAME}} {";
+ code_ += " match self {";
+ code_ += " Self::NONE => {{ENUM_NAME}}::NONE,";
+ ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
+ code_ +=
+ " Self::{{NATIVE_VARIANT}}(_) => {{ENUM_NAME}}::"
+ "{{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) => "
+ "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));
+ }
+
+ 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.value.constant;
+ }
+ case ftBool: {
+ return field.value.constant == "0" ? "false" : "true";
+ }
+ case ftUnionKey:
+ case ftEnumKey: {
+ auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
+ if (!ev) return "Default::default()"; // Bitflags enum.
+ return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
+ GetEnumValue(*field.value.type.enum_def, *ev));
+ }
+ 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("Unreachable.");
+ return "INVALID_CODE_GENERATION";
+ }
+
+ 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("Unreachable.");
+ return "INVALID_CODE_GENERATION";
+ }
+
+ // Create the return type for fields in the *BuilderArgs structs that are
+ // used to create Tables.
+ //
+ // Note: we could make all inputs to the BuilderArgs be an Option, as well
+ // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
+ // know if the value is default or not, because there are three ways to
+ // return a default value:
+ // 1) return a stored value that happens to be the default,
+ // 2) return a hardcoded value because the relevant vtable field is not in
+ // the vtable, or
+ // 3) return a hardcoded value because the vtable field value is set to zero.
+ 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: {
+ return WrapOption(GetTypeBasic(type));
+ }
+ case ftStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapOption("&" + lifetime + " " + typname);
+ }
+ case ftTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapOption("flatbuffers::WIPOffset<" + typname + "<" + lifetime +
+ ">>");
+ }
+ case ftString: {
+ return WrapOption("flatbuffers::WIPOffset<&" + lifetime + " str>");
+ }
+ case ftEnumKey:
+ case ftUnionKey: {
+ return WrapOption(WrapInNameSpace(*type.enum_def));
+ }
+ case ftUnionValue: {
+ return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
+ }
+
+ case ftVectorOfInteger:
+ case ftVectorOfBool:
+ case ftVectorOfFloat: {
+ const auto typname = GetTypeBasic(type.VectorType());
+ return WrapVector(typname);
+ }
+ case ftVectorOfEnumKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return WrapVector(typname);
+ }
+ case ftVectorOfStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapVector(typname);
+ }
+ case ftVectorOfTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapUOffsetsVector(typname + "<" + lifetime + ">");
+ }
+ case ftVectorOfString: {
+ return WrapUOffsetsVector("&" + lifetime + " str");
+ }
+ case ftVectorOfUnionValue: {
+ 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;
+
+ switch (GetFullType(field.value.type)) {
+ case ftVectorOfStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
+ typname + ">>";
+ }
+ case ftVectorOfTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
+ ">>>>";
+ }
+ case ftVectorOfInteger:
+ case ftVectorOfBool:
+ case ftVectorOfFloat: {
+ const auto typname = GetTypeBasic(type.VectorType());
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
+ typname + ">>";
+ }
+ case ftVectorOfString: {
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
+ }
+ case ftVectorOfEnumKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
+ typname + ">>";
+ }
+ case ftVectorOfUnionValue: {
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + lifetime +
+ ">>>";
+ }
+ case ftEnumKey:
+ case ftUnionKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return typname;
+ }
+ case ftStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "&" + typname + "";
+ }
+ case ftTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
+ }
+ case ftInteger:
+ case ftBool:
+ case ftFloat: {
+ return GetTypeBasic(type);
+ }
+ case ftString: {
+ return "flatbuffers::WIPOffset<&" + lifetime + " str>";
+ }
+ 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
+ }
+
+ std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
+ const Type &type = field.value.type;
+
+ switch (GetFullType(field.value.type)) {
+ case ftInteger:
+ case ftBool:
+ case ftFloat: {
+ const auto typname = GetTypeBasic(field.value.type);
+ 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.IsOptional() ? "self.fbb_.push_slot_always::<"
+ : "self.fbb_.push_slot::<") +
+ underlying_typname + ">";
+ }
+
+ case ftStruct: {
+ const std::string typname = WrapInNameSpace(*type.struct_def);
+ return "self.fbb_.push_slot_always::<&" + typname + ">";
+ }
+ case ftTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" +
+ typname + ">>";
+ }
+
+ case ftUnionValue:
+ case ftString:
+ case ftVectorOfInteger:
+ case ftVectorOfFloat:
+ case ftVectorOfBool:
+ case ftVectorOfEnumKey:
+ case ftVectorOfStruct:
+ case ftVectorOfTable:
+ case ftVectorOfString:
+ 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
+ }
+
+ 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: {
+ return WrapOption(GetTypeBasic(type));
+ }
+ case ftStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapOption("&" + lifetime + " " + typname);
+ }
+ case ftTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapOption(typname + "<" + lifetime + ">");
+ }
+ case ftEnumKey:
+ case ftUnionKey: {
+ return WrapOption(WrapInNameSpace(*type.enum_def));
+ }
+
+ case ftUnionValue: {
+ return WrapOption("flatbuffers::Table<" + lifetime + ">");
+ }
+ case ftString: {
+ return WrapOption("&" + lifetime + " str");
+ }
+ case ftVectorOfInteger:
+ case ftVectorOfBool:
+ case ftVectorOfFloat: {
+ const auto typname = GetTypeBasic(type.VectorType());
+ 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 WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname +
+ ">");
+ }
+ case ftVectorOfStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapOption("&" + lifetime + " [" + typname + "]");
+ }
+ case ftVectorOfTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapOption("flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<" + typname + "<" +
+ lifetime + ">>>");
+ }
+ case ftVectorOfString: {
+ return WrapOption("flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<&" + lifetime +
+ " str>>");
+ }
+ case ftVectorOfUnionValue: {
+ FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
+ // TODO(rw): when we do support these, we should consider using the
+ // 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 FollowType(const Type &type, const std::string &lifetime) {
+ // IsVector... This can be made iterative?
+
+ 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: {
+ return GetTypeBasic(type);
+ }
+ case ftStruct: {
+ return WrapInNameSpace(*type.struct_def);
+ }
+ case ftUnionKey:
+ case ftEnumKey: {
+ 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 WrapForwardsUOffset("&str");
+ }
+ case ftVectorOfInteger:
+ case ftVectorOfBool:
+ case ftVectorOfFloat: {
+ const auto typname = GetTypeBasic(type.VectorType());
+ return WrapForwardsUOffset(WrapVector(typname));
+ }
+ case ftVectorOfEnumKey: {
+ const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
+ return WrapForwardsUOffset(WrapVector(typname));
+ }
+ case ftVectorOfStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapForwardsUOffset(WrapVector(typname));
+ }
+ case ftVectorOfTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(typname)));
+ }
+ case ftVectorOfString: {
+ 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
+ }
+
+ 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_NAME}}::" + 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_ += " }";
+ code_ += "";
+ }
+
+ void ForAllUnionVariantsBesidesNone(
+ 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;
+ // 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, GetEnumValue(def, ev)));
+ code_.SetValue(
+ "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)));
+ cb(ev);
+ }
+ }
+
+ 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) {
+ 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("BLDR_DEF_VAL", GetDefaultValue(field, kBuilder));
+ cb(field);
+ };
+ const auto &fields = struct_def.fields.vec;
+ if (reversed) {
+ for (auto it = fields.rbegin(); it != fields.rend(); ++it) go(**it);
+ } else {
+ for (auto it = fields.begin(); it != fields.end(); ++it) go(**it);
+ }
+ }
+ // 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)));
+
+ // Generate an offset type, the base type, the Follow impl, and the
+ // init_from_table impl.
+ code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
+ code_ += "#[derive(Copy, Clone, PartialEq)]";
+ code_ += "";
+
+ GenComment(struct_def.doc_comment);
+
+ code_ += "pub struct {{STRUCT_NAME}}<'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_ += "}";
+ code_ += "";
+ code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
+
+ if (parser_.opts.generate_name_strings) {
+ GenFullyQualifiedNameGetter(struct_def, struct_def.name);
+ }
+
+ code_ += " #[inline]";
+ code_ +=
+ " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
+ "Self {";
+ code_ += " {{STRUCT_NAME}} { _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_ += " let mut builder = {{STRUCT_NAME}}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 (IsOptionalToBuilder(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);
+ }
+ 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("OBJECT_NAME", NativeName(struct_def));
+ code_ += " pub fn unpack(&self) -> {{OBJECT_NAME}} {";
+ 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_NAME}} = self.{{FIELD_NAME}}();";
+ return;
+ }
+ case ftUnionKey: return;
+ case ftUnionValue: {
+ const auto &enum_def = *type.enum_def;
+ code_.SetValue("ENUM_NAME", WrapInNameSpace(enum_def));
+ code_.SetValue("NATIVE_ENUM_NAME", NamespacedNativeName(enum_def));
+ code_ +=
+ " let {{FIELD_NAME}} = match "
+ "self.{{FIELD_NAME}}_type() {";
+ code_ +=
+ " {{ENUM_NAME}}::NONE =>"
+ " {{NATIVE_ENUM_NAME}}::NONE,";
+ ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
+ code_ +=
+ " {{ENUM_NAME}}::{{VARIANT_NAME}} => "
+ "{{NATIVE_ENUM_NAME}}::{{NATIVE_VARIANT}}(Box::new(";
+ code_ +=
+ " self.{{FIELD_NAME}}_as_"
+ "{{U_ELEMENT_NAME}}()";
+ code_ +=
+ " .expect(\"Invalid union table, "
+ "expected `{{ENUM_NAME}}::{{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_NAME}} = self.{{FIELD_NAME}}().map(|x| {";
+ code_ += " {{EXPR}}";
+ code_ += " });";
+ } else {
+ code_ += " let {{FIELD_NAME}} = {";
+ code_ += " let x = self.{{FIELD_NAME}}();";
+ code_ += " {{EXPR}}";
+ code_ += " };";
+ }
+ });
+ code_ += " {{OBJECT_NAME}} {";
+ ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
+ code_ += " {{FIELD_NAME}},";
+ });
+ 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:
+ //
+ // If a value can be None:
+ // pub fn name(&'a self) -> Option<user_facing_type> {
+ // self._tab.get::<internal_type>(offset, defaultval)
+ // }
+ //
+ // If a value is always Some:
+ // pub fn name(&'a self) -> user_facing_type {
+ // self._tab.get::<internal_type>(offset, defaultval).unwrap()
+ // }
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ code_.SetValue("RETURN_TYPE",
+ GenTableAccessorFuncReturnType(field, "'a"));
+
+ this->GenComment(field.doc_comment, " ");
+ code_ += " #[inline]";
+ code_ += " pub fn {{FIELD_NAME}}(&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); }
+
+ // Generate a nested flatbuffer field, if applicable.
+ 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.
+
+ code_.SetValue("NESTED", WrapInNameSpace(*nested_root));
+ code_ += " pub fn {{FIELD_NAME}}_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)";
+ } 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_ += " }";
+ }
+ });
+
+ // 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}} {";
+
+ // The following logic is not tested in the integration test,
+ // as of April 10, 2020
+ if (field.IsRequired()) {
+ 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_ += "";
+ });
+ });
+ code_ += "}"; // End of table impl.
+ code_ += "";
+
+ // Generate Verifier;
+ code_ += "impl flatbuffers::Verifiable for {{STRUCT_NAME}}<'_> {";
+ 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_NAME}}\", "
+ "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\";
+ return;
+ }
+ // Unions.
+ EnumDef &union_def = *field.value.type.enum_def;
+ code_.SetValue("UNION_TYPE", WrapInNameSpace(union_def));
+ code_ +=
+ "\n .visit_union::<{{UNION_TYPE}}, _>("
+ "&\"{{FIELD_NAME}}_type\", Self::{{OFFSET_NAME}}_TYPE, "
+ "&\"{{FIELD_NAME}}\", 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}} {";
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
+ code_ += " pub {{FIELD_NAME}}: {{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 {";
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ code_ += " {{FIELD_NAME}}: {{BLDR_DEF_VAL}},\\";
+ code_ += field.IsRequired() ? " // required field" : "";
+ });
+ code_ += " }";
+ code_ += " }";
+ code_ += "}";
+
+ // Generate a builder struct:
+ code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
+ code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
+ code_ +=
+ " start_: flatbuffers::WIPOffset<"
+ "flatbuffers::TableUnfinishedWIPOffset>,";
+ code_ += "}";
+
+ // Generate builder functions:
+ code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ const bool is_scalar = IsScalar(field.value.type.base_type);
+ std::string offset = GetFieldOffsetName(field);
+ // Generate functions to add data, which take one of two forms.
+ //
+ // If a value has a default:
+ // fn add_x(x_: type) {
+ // fbb_.push_slot::<type>(offset, x_, Some(default));
+ // }
+ //
+ // If a value does not have a default:
+ // fn add_x(x_: type) {
+ // fbb_.push_slot_always::<type>(offset, x_);
+ // }
+ code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + 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.IsOptional()) {
+ code_ +=
+ " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
+ "{{BLDR_DEF_VAL}});";
+ } else {
+ code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
+ }
+ code_ += " }";
+ });
+
+ // Struct initializer (all fields required);
+ code_ += " #[inline]";
+ code_ +=
+ " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
+ "{{STRUCT_NAME}}Builder<'a, 'b> {";
+ code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
+ code_ += " let start = _fbb.start_table();";
+ code_ += " {{STRUCT_NAME}}Builder {";
+ code_ += " fbb_: _fbb,";
+ code_ += " start_: start,";
+ code_ += " }";
+ code_ += " }";
+
+ // finish() function.
+ code_ += " #[inline]";
+ code_ +=
+ " pub fn finish(self) -> "
+ "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
+ code_ += " let o = self.fbb_.end_table(self.start_);";
+
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ if (!field.IsRequired()) return;
+ code_ +=
+ " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
+ "\"{{FIELD_NAME}}\");";
+ });
+ 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}}\");";
+ 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_ += " 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_ += " };";
+ } else {
+ // Most fields.
+ code_ += " ds.field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}());";
+ }
+ });
+ code_ += " ds.finish()";
+ code_ += " }";
+ code_ += "}";
+ }
+
+ void GenTableObject(const StructDef &table) {
+ code_.SetValue("OBJECT_NAME", NativeName(table));
+ code_.SetValue("STRUCT_NAME", Name(table));
+
+ // Generate the native object.
+ code_ += "#[non_exhaustive]";
+ code_ += "#[derive(Debug, Clone, PartialEq)]";
+ code_ += "pub struct {{OBJECT_NAME}} {";
+ 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_NAME}}: {{FIELD_OBJECT_TYPE}},";
+ });
+ code_ += "}";
+
+ code_ += "impl Default for {{OBJECT_NAME}} {";
+ 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_NAME}}: " + 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 {{OBJECT_NAME}} {";
+ code_ += " pub fn pack<'b>(";
+ code_ += " &self,";
+ code_ += " _fbb: &mut flatbuffers::FlatBufferBuilder<'b>";
+ code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'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_NAME}} = self.{{FIELD_NAME}};";
+ return;
+ }
+ case ftUnionKey: return; // Generate union type with union value.
+ case ftUnionValue: {
+ code_.SetValue("SNAKE_CASE_ENUM_NAME",
+ MakeSnakeCase(Name(*field.value.type.enum_def)));
+ code_ +=
+ " let {{FIELD_NAME}}_type = "
+ "self.{{FIELD_NAME}}.{{SNAKE_CASE_ENUM_NAME}}_type();";
+ code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}.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_NAME}}_tmp = "
+ "Some(self.{{FIELD_NAME}}.pack());";
+ } else {
+ code_ +=
+ " let {{FIELD_NAME}}_tmp = self.{{FIELD_NAME}}"
+ ".as_ref().map(|x| x.pack());";
+ }
+ code_ += " let {{FIELD_NAME}} = {{FIELD_NAME}}_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_NAME}}::create(_fbb, &{{STRUCT_NAME}}Args{";
+ ForAllObjectTableFields(table, [&](const FieldDef &field) {
+ (void)field; // Unused.
+ code_ += " {{FIELD_NAME}},";
+ });
+ 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_NAME", Name(field));
+ code_.SetValue("FIELD_OBJECT_TYPE", ObjectFieldType(field, true));
+ cb(field);
+ }
+ }
+ void MapNativeTableField(const FieldDef &field, const std::string &expr) {
+ if (field.IsOptional()) {
+ code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}.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_NAME}} = Some({";
+ code_ += " let x = &self.{{FIELD_NAME}};";
+ 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_ += " #[inline]";
+ code_ +=
+ " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
+ " bool {";
+ code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
+ code_ += " }";
+ code_ += "";
+ 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_ += " }";
+ }
+
+ // 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)));
+
+ // The root datatype accessors:
+ code_ += "#[inline]";
+ code_ +=
+ "#[deprecated(since=\"2.0.0\", "
+ "note=\"Deprecated in favor of `root_as...` methods.\")]";
+ code_ +=
+ "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
+ " -> {{STRUCT_NAME}}<'a> {";
+ code_ +=
+ " unsafe { flatbuffers::root_unchecked::<{{STRUCT_NAME}}"
+ "<'a>>(buf) }";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "#[inline]";
+ code_ +=
+ "#[deprecated(since=\"2.0.0\", "
+ "note=\"Deprecated in favor of `root_as...` methods.\")]";
+ code_ +=
+ "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
+ "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
+ code_ +=
+ " unsafe { flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}"
+ "<'a>>(buf) }";
+ code_ += "}";
+ code_ += "";
+ // Default verifier root fns.
+ code_ += "#[inline]";
+ code_ += "/// Verifies that a buffer of bytes contains a `{{STRUCT_NAME}}`";
+ 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_NAME_SNAKECASE}}_unchecked`.";
+ code_ +=
+ "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}(buf: &[u8]) "
+ "-> Result<{{STRUCT_NAME}}, flatbuffers::InvalidFlatbuffer> {";
+ code_ += " flatbuffers::root::<{{STRUCT_NAME}}>(buf)";
+ code_ += "}";
+ code_ += "#[inline]";
+ code_ += "/// Verifies that a buffer of bytes contains a size prefixed";
+ code_ += "/// `{{STRUCT_NAME}}` 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_NAME_SNAKECASE}}_unchecked`.";
+ code_ +=
+ "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
+ "(buf: &[u8]) -> Result<{{STRUCT_NAME}}, "
+ "flatbuffers::InvalidFlatbuffer> {";
+ code_ += " flatbuffers::size_prefixed_root::<{{STRUCT_NAME}}>(buf)";
+ code_ += "}";
+ // Verifier with options root fns.
+ code_ += "#[inline]";
+ code_ += "/// Verifies, with the given options, that a buffer of bytes";
+ code_ += "/// contains a `{{STRUCT_NAME}}` 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_NAME_SNAKECASE}}_unchecked`.";
+ code_ += "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts<'b, 'o>(";
+ code_ += " opts: &'o flatbuffers::VerifierOptions,";
+ code_ += " buf: &'b [u8],";
+ code_ +=
+ ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>"
+ " {";
+ code_ += " flatbuffers::root_with_opts::<{{STRUCT_NAME}}<'b>>(opts, buf)";
+ code_ += "}";
+ code_ += "#[inline]";
+ code_ += "/// Verifies, with the given verifier options, that a buffer of";
+ code_ += "/// bytes contains a size prefixed `{{STRUCT_NAME}}` 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_NAME_SNAKECASE}}_unchecked`.";
+ code_ +=
+ "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts"
+ "<'b, 'o>(";
+ code_ += " opts: &'o flatbuffers::VerifierOptions,";
+ code_ += " buf: &'b [u8],";
+ code_ +=
+ ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>"
+ " {";
+ code_ +=
+ " flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_NAME}}"
+ "<'b>>(opts, buf)";
+ code_ += "}";
+ // Unchecked root fns.
+ code_ += "#[inline]";
+ code_ +=
+ "/// Assumes, without verification, that a buffer of bytes "
+ "contains a {{STRUCT_NAME}} and returns it.";
+ code_ += "/// # Safety";
+ code_ +=
+ "/// Callers must trust the given bytes do indeed contain a valid"
+ " `{{STRUCT_NAME}}`.";
+ code_ +=
+ "pub unsafe fn root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked"
+ "(buf: &[u8]) -> {{STRUCT_NAME}} {";
+ code_ += " flatbuffers::root_unchecked::<{{STRUCT_NAME}}>(buf)";
+ code_ += "}";
+ code_ += "#[inline]";
+ code_ +=
+ "/// Assumes, without verification, that a buffer of bytes "
+ "contains a size prefixed {{STRUCT_NAME}} and returns it.";
+ code_ += "/// # Safety";
+ code_ +=
+ "/// Callers must trust the given bytes do indeed contain a valid"
+ " size prefixed `{{STRUCT_NAME}}`.";
+ code_ +=
+ "pub unsafe fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
+ "_unchecked(buf: &[u8]) -> {{STRUCT_NAME}} {";
+ code_ +=
+ " flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}>"
+ "(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_ += " = \"" + parser_.file_identifier_ + "\";";
+ code_ += "";
+
+ // Check if a buffer has the identifier.
+ code_ += "#[inline]";
+ code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
+ code_ += "(buf: &[u8]) -> bool {";
+ code_ += " flatbuffers::buffer_has_identifier(buf, \\";
+ code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false)";
+ code_ += "}";
+ code_ += "";
+ code_ += "#[inline]";
+ code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
+ code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
+ code_ += " flatbuffers::buffer_has_identifier(buf, \\";
+ code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true)";
+ code_ += "}";
+ code_ += "";
+ }
+
+ if (parser_.file_extension_.length()) {
+ // Return the extension
+ code_ += "pub const {{STRUCT_NAME_CAPS}}_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_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
+ code_ += " root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
+ if (parser_.file_identifier_.length()) {
+ code_ += " fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
+ } else {
+ code_ += " fbb.finish(root, None);";
+ }
+ code_ += "}";
+ code_ += "";
+ code_ += "#[inline]";
+ code_ +=
+ "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
+ "<'a, 'b>("
+ "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
+ "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
+ if (parser_.file_identifier_.length()) {
+ code_ +=
+ " fbb.finish_size_prefixed(root, "
+ "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
+ } else {
+ code_ += " fbb.finish_size_prefixed(root, None);";
+ }
+ code_ += "}";
+ }
+
+ static void GenPadding(
+ const FieldDef &field, std::string *code_ptr, int *id,
+ const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
+ if (field.padding) {
+ for (int i = 0; i < 4; i++) {
+ if (static_cast<int>(field.padding) & (1 << i)) {
+ f((1 << i) * 8, code_ptr, id);
+ }
+ }
+ assert(!(field.padding & ~0xF));
+ }
+ }
+
+ static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
+ *code_ptr +=
+ " padding" + NumToString((*id)++) + "__: u" + NumToString(bits) + ",";
+ }
+
+ static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
+ (void)bits;
+ *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
+ }
+
+ 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_OBJECT_TYPE", ObjectFieldType(field, false));
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("FIELD_OFFSET", NumToString(offset_to_field));
+ code_.SetValue(
+ "REF",
+ IsStruct(field.value.type) || IsArray(field.value.type) ? "&" : "");
+ cb(field);
+ const size_t size = InlineSize(field.value.type);
+ offset_to_field += size + field.padding;
+ }
+ }
+ // Generate an accessor struct with constructor for a flatbuffers struct.
+ void GenStruct(const StructDef &struct_def) {
+ // Generates manual padding and alignment.
+ // Variables are private because they contain little endian data on all
+ // platforms.
+ GenComment(struct_def.doc_comment);
+ code_.SetValue("ALIGN", NumToString(struct_def.minalign));
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+ code_.SetValue("STRUCT_SIZE", NumToString(struct_def.bytesize));
+
+ // 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_NAME}}, aligned to {{ALIGN}}";
+ code_ += "#[repr(transparent)]";
+ code_ += "#[derive(Clone, Copy, PartialEq)]";
+ code_ += "pub struct {{STRUCT_NAME}}(pub [u8; {{STRUCT_SIZE}}]);";
+ code_ += "impl Default for {{STRUCT_NAME}} { ";
+ 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}}\")";
+ ForAllStructFields(struct_def, [&](const FieldDef &unused) {
+ (void)unused;
+ code_ += " .field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}())";
+ });
+ 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::SimpleToVerifyInSlice for {{STRUCT_NAME}} {}";
+ code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
+ code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
+ code_ += " type Inner = &'a {{STRUCT_NAME}};";
+ code_ += " #[inline]";
+ code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+ code_ += " <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
+ code_ += " }";
+ code_ += "}";
+ code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
+ code_ += " type Inner = &'a {{STRUCT_NAME}};";
+ code_ += " #[inline]";
+ code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+ code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
+ code_ += " }";
+ code_ += "}";
+ code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
+ code_ += " type Output = {{STRUCT_NAME}};";
+ 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())";
+ code_ += " };";
+ code_ += " dst.copy_from_slice(src);";
+ code_ += " }";
+ code_ += "}";
+ code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
+ code_ += " type Output = {{STRUCT_NAME}};";
+ 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())";
+ 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_NAME}} {";
+ 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_ += "}";
+
+ // Generate a constructor that takes all fields as arguments.
+ code_ += "impl<'a> {{STRUCT_NAME}} {";
+ code_ += " #[allow(clippy::too_many_arguments)]";
+ code_ += " pub fn new(";
+ ForAllStructFields(struct_def, [&](const FieldDef &unused) {
+ (void)unused;
+ code_ += " {{FIELD_NAME}}: {{REF}}{{FIELD_TYPE}},";
+ });
+ code_ += " ) -> Self {";
+ code_ += " let mut s = Self([0; {{STRUCT_SIZE}}]);";
+ ForAllStructFields(struct_def, [&](const FieldDef &unused) {
+ (void)unused;
+ code_ += " s.set_{{FIELD_NAME}}({{REF}}{{FIELD_NAME}});";
+ });
+ code_ += " s";
+ code_ += " }";
+ code_ += "";
+
+ if (parser_.opts.generate_name_strings) {
+ GenFullyQualifiedNameGetter(struct_def, struct_def.name);
+ }
+
+ // Generate accessor methods for the struct.
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
+ this->GenComment(field.doc_comment, " ");
+ // Getter.
+ if (IsStruct(field.value.type)) {
+ code_ += " pub fn {{FIELD_NAME}}(&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_NAME}}(&'a self) -> "
+ "flatbuffers::Array<'a, {{ARRAY_ITEM}}, {{ARRAY_SIZE}}> {";
+ code_ += " flatbuffers::Array::follow(&self.0, {{FIELD_OFFSET}})";
+ } else {
+ code_ += " pub fn {{FIELD_NAME}}(&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_ += " pub fn set_{{FIELD_NAME}}(&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_NAME}}(&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_NAME}}(&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_NAME}}(&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); }
+ });
+
+ // Generate Object API unpack method.
+ if (parser_.opts.generate_object_based_api) {
+ code_.SetValue("NATIVE_STRUCT_NAME", NativeName(struct_def));
+ code_ += " pub fn unpack(&self) -> {{NATIVE_STRUCT_NAME}} {";
+ code_ += " {{NATIVE_STRUCT_NAME}} {";
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
+ if (IsArray(field.value.type)) {
+ if (GetFullType(field.value.type) == ftArrayOfStruct) {
+ code_ +=
+ " {{FIELD_NAME}}: { let {{FIELD_NAME}} = "
+ "self.{{FIELD_NAME}}(); flatbuffers::array_init(|i| "
+ "{{FIELD_NAME}}.get(i).unpack()) },";
+ } else {
+ code_ += " {{FIELD_NAME}}: self.{{FIELD_NAME}}().into(),";
+ }
+ } else {
+ std::string unpack = IsStruct(field.value.type) ? ".unpack()" : "";
+ code_ += " {{FIELD_NAME}}: self.{{FIELD_NAME}}()" + 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 {{NATIVE_STRUCT_NAME}} {";
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
+ (void)field; // unused.
+ code_ += " pub {{FIELD_NAME}}: {{FIELD_OBJECT_TYPE}},";
+ });
+ code_ += "}";
+ // The `pack` method that turns the native struct into its Flatbuffers
+ // counterpart.
+ code_ += "impl {{NATIVE_STRUCT_NAME}} {";
+ code_ += " pub fn pack(&self) -> {{STRUCT_NAME}} {";
+ code_ += " {{STRUCT_NAME}}::new(";
+ ForAllStructFields(struct_def, [&](const FieldDef &field) {
+ if (IsStruct(field.value.type)) {
+ code_ += " &self.{{FIELD_NAME}}.pack(),";
+ } else if (IsArray(field.value.type)) {
+ if (GetFullType(field.value.type) == ftArrayOfStruct) {
+ code_ +=
+ " &flatbuffers::array_init(|i| "
+ "self.{{FIELD_NAME}}[i].pack()),";
+ } else {
+ code_ += " &self.{{FIELD_NAME}},";
+ }
+ } else {
+ code_ += " self.{{FIELD_NAME}},";
+ }
+ });
+ code_ += " )";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ void GenNamespaceImports(const int white_spaces) {
+ // 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) {
+ for (auto it = parser_.included_files_.begin();
+ it != parser_.included_files_.end(); ++it) {
+ if (it->second.empty()) continue;
+ auto noext = flatbuffers::StripExtension(it->second);
+ auto basename = flatbuffers::StripPath(noext);
+
+ 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_ += "";
+ code_ += indent + "extern crate flatbuffers;";
+ code_ += indent + "use self::flatbuffers::{EndianScalar, Follow};";
+ }
+
+ // Set up the correct namespace. This opens a namespace if the current
+ // namespace is different from the target namespace. This function
+ // closes and opens the namespaces only as necessary.
+ //
+ // The file must start and end with an empty (or null) namespace so that
+ // namespaces are properly opened and closed.
+ void SetNameSpace(const Namespace *ns) {
+ if (cur_name_space_ == ns) { return; }
+
+ // Compute the size of the longest common namespace prefix.
+ // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
+ // the common prefix is A::B:: and we have old_size = 4, new_size = 5
+ // and common_prefix_size = 2
+ size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
+ size_t new_size = ns ? ns->components.size() : 0;
+
+ size_t common_prefix_size = 0;
+ while (common_prefix_size < old_size && common_prefix_size < new_size &&
+ ns->components[common_prefix_size] ==
+ cur_name_space_->components[common_prefix_size]) {
+ common_prefix_size++;
+ }
+
+ // Close cur_name_space in reverse order to reach the common prefix.
+ // In the previous example, D then C are closed.
+ for (size_t j = old_size; j > common_prefix_size; --j) {
+ code_ += "} // pub mod " + cur_name_space_->components[j - 1];
+ }
+ if (old_size != common_prefix_size) { code_ += ""; }
+
+ // open namespace parts to reach the ns namespace
+ // 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]) + " {";
+ // Generate local namespace imports.
+ GenNamespaceImports(2);
+ }
+ if (new_size != common_prefix_size) { code_ += ""; }
+
+ cur_name_space_ = ns;
+ }
+};
+
+} // namespace rust
+
+bool GenerateRust(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ rust::RustGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+std::string RustMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ rust::RustGenerator 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
+
+// TODO(rw): Generated code should import other generated files.
+// TODO(rw): Generated code should refer to namespaces in included files in a
+// way that makes them referrable.
+// TODO(rw): Generated code should indent according to nesting level.
+// TODO(rw): Generated code should generate endian-safe Debug impls.
+// TODO(rw): Generated code could use a Rust-only enum type to access unions,
+// instead of making the user use _type() to manually switch.
+// TODO(maxburke): There should be test schemas added that use language
+// keywords as fields of structs, tables, unions, enums, to make sure
+// that internal code generated references escaped names correctly.
+// TODO(maxburke): We should see if there is a more flexible way of resolving
+// module paths for use declarations. Right now if schemas refer to
+// other flatbuffer files, the include paths in emitted Rust bindings
+// are crate-relative which may undesirable.
diff --git a/contrib/libs/flatbuffers/src/idl_gen_swift.cpp b/contrib/libs/flatbuffers/src/idl_gen_swift.cpp
new file mode 100644
index 0000000000..3fffd39455
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_swift.cpp
@@ -0,0 +1,1575 @@
+/*
+ * Copyright 2020 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 <cctype>
+#include <unordered_set>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+namespace swift {
+
+inline std::string GenIndirect(const std::string &reading) {
+ return "{{ACCESS}}.indirect(" + reading + ")";
+}
+
+inline std::string GenArrayMainBody(const std::string &optional) {
+ return "{{ACCESS_TYPE}} func {{VALUENAME}}(at index: Int32) -> "
+ "{{VALUETYPE}}" +
+ optional + " { ";
+}
+
+class SwiftGenerator : public BaseGenerator {
+ private:
+ CodeWriter code_;
+ std::unordered_set<std::string> keywords_;
+ int namespace_depth;
+
+ public:
+ SwiftGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "_", "swift") {
+ namespace_depth = 0;
+ code_.SetPadding(" ");
+ static const char *const keywords[] = {
+ "associatedtype",
+ "class",
+ "deinit",
+ "enum",
+ "extension",
+ "fileprivate",
+ "func",
+ "import",
+ "init",
+ "inout",
+ "internal",
+ "let",
+ "open",
+ "operator",
+ "private",
+ "protocol",
+ "public",
+ "rethrows",
+ "static",
+ "struct",
+ "subscript",
+ "typealias",
+ "var",
+ "break",
+ "case",
+ "continue",
+ "default",
+ "defer",
+ "do",
+ "else",
+ "fallthrough",
+ "for",
+ "guard",
+ "if",
+ "in",
+ "repeat",
+ "return",
+ "switch",
+ "where",
+ "while",
+ "Any",
+ "catch",
+ "false",
+ "is",
+ "nil",
+ "super",
+ "self",
+ "Self",
+ "throw",
+ "throws",
+ "true",
+ "try",
+ "associativity",
+ "convenience",
+ "dynamic",
+ "didSet",
+ "final",
+ "get",
+ "infix",
+ "indirect",
+ "lazy",
+ "left",
+ "mutating",
+ "none",
+ "nonmutating",
+ "optional",
+ "override",
+ "postfix",
+ "precedence",
+ "prefix",
+ "Protocol",
+ "required",
+ "right",
+ "set",
+ "Type",
+ "unowned",
+ "weak",
+ "willSet",
+ "Void",
+ nullptr,
+ };
+ for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+ }
+
+ bool generate() {
+ code_.Clear();
+ code_.SetValue("ACCESS", "_accessor");
+ code_.SetValue("TABLEOFFSET", "VTOFFSET");
+ code_ += "// " + std::string(FlatBuffersGeneratedWarning());
+ code_ += "// swiftlint:disable all";
+ code_ += "// swiftformat:disable all\n";
+ code_ += "import FlatBuffers\n";
+ // Generate code for all the enum declarations.
+
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ const auto &enum_def = **it;
+ if (!enum_def.generated) { GenEnum(enum_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) {
+ GenStructReader(struct_def);
+ GenMutableStructReader(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) {
+ GenTable(struct_def);
+ if (parser_.opts.generate_object_based_api) {
+ GenObjectAPI(struct_def);
+ }
+ }
+ }
+
+ const auto filename = GeneratedFileName(path_, file_name_, parser_.opts);
+ const auto final_code = code_.ToString();
+ return SaveFile(filename.c_str(), final_code, false);
+ }
+
+ void mark(const std::string &str) {
+ code_.SetValue("MARKVALUE", str);
+ 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\\";
+ 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 base_value =
+ IsStruct(field.value.type) ? (type + "()") : 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_ += "";
+ 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}})! }";
+ }
+ }
+ 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");
+ code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
+ code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def));
+ code_.SetValue("SHORT_STRUCTNAME", Name(struct_def));
+ code_ += "extension {{STRUCTNAME}} {";
+ Indent();
+ code_ += "@discardableResult";
+ code_ +=
+ "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(builder: inout "
+ "FlatBufferBuilder, \\";
+ std::string func_header = "";
+ GenerateStructArgs(struct_def, &func_header, "", "");
+ code_ += func_header.substr(0, func_header.size() - 2) + "\\";
+ code_ += ") -> Offset {";
+ Indent();
+ code_ +=
+ "builder.createStructOf(size: {{STRUCTNAME}}.size, alignment: "
+ "{{STRUCTNAME}}.alignment)";
+ code_ += "return builder.endStruct()";
+ Outdent();
+ code_ += "}\n";
+ Outdent();
+ code_ += "}\n";
+ }
+
+ void GenerateStructArgs(const StructDef &struct_def, std::string *code_ptr,
+ const std::string &nameprefix,
+ const std::string &object_name,
+ const std::string &obj_api_named = "",
+ bool is_obj_api = false) {
+ auto &code = *code_ptr;
+ 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_type = field.value.type;
+ if (IsStruct(field.value.type)) {
+ GenerateStructArgs(
+ *field_type.struct_def, code_ptr, (nameprefix + field.name),
+ (object_name + "." + field.name), obj_api_named, is_obj_api);
+ } else {
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ if (!is_obj_api) {
+ code += nameprefix + name + ": " + type;
+ if (!IsEnum(field.value.type)) {
+ code += " = ";
+ auto is_bool = IsBool(field.value.type.base_type);
+ auto constant =
+ is_bool ? ("0" == field.value.constant ? "false" : "true")
+ : field.value.constant;
+ code += constant;
+ }
+ code += ", ";
+ continue;
+ }
+ code +=
+ nameprefix + name + ": " + obj_api_named + object_name + "." + name;
+ 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);
+ Outdent();
+ code_ += "}\n";
+ }
+
+ // Generates the reader for swift
+ void GenTableAccessors(const StructDef &struct_def) {
+ // Generate field id constants.
+ if (struct_def.fields.vec.size() > 0) {
+ code_ += "private enum {{TABLEOFFSET}}: VOffset {";
+ Indent();
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) { continue; }
+ code_.SetValue("OFFSET_NAME", Name(field));
+ code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
+ code_ += "case {{OFFSET_NAME}} = {{OFFSET_VALUE}}";
+ }
+ code_ += "var v: Int32 { Int32(self.rawValue) }";
+ code_ += "var p: VOffset { self.rawValue }";
+ Outdent();
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ 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("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
+ code_.SetValue("MUTABLE", struct_def.fixed ? Mutable() : "");
+ code_ +=
+ "{{ACCESS_TYPE}} struct {{STRUCTNAME}}{{MUTABLE}}: FlatBufferObject\\";
+ 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) {
+ flatbuffers::FieldDef *key_field = nullptr;
+ std::vector<std::string> require_fields;
+ std::vector<std::string> create_func_body;
+ std::vector<std::string> create_func_header;
+ auto should_generate_create = struct_def.fields.vec.size() != 0;
+
+ code_.SetValue("NUMBEROFFIELDS", NumToString(struct_def.fields.vec.size()));
+ code_ +=
+ "{{ACCESS_TYPE}} static func start{{SHORT_STRUCTNAME}}(_ fbb: inout "
+ "FlatBufferBuilder) -> "
+ "UOffset { fbb.startTable(with: {{NUMBEROFFIELDS}}) }";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.key) key_field = &field;
+ if (field.IsRequired())
+ require_fields.push_back(NumToString(field.value.offset));
+
+ GenTableWriterFields(field, &create_func_body, &create_func_header);
+ }
+ code_ +=
+ "{{ACCESS_TYPE}} static func end{{SHORT_STRUCTNAME}}(_ fbb: inout "
+ "FlatBufferBuilder, "
+ "start: "
+ "UOffset) -> Offset { let end = Offset(offset: "
+ "fbb.endTable(at: start))\\";
+ if (require_fields.capacity() != 0) {
+ std::string fields = "";
+ for (auto it = require_fields.begin(); it != require_fields.end(); ++it)
+ fields += *it + ", ";
+ code_.SetValue("FIELDS", fields.substr(0, fields.size() - 2));
+ code_ += "; fbb.require(table: end, fields: [{{FIELDS}}])\\";
+ }
+ code_ += "; return end }";
+
+ if (should_generate_create) {
+ code_ += "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(";
+ Indent();
+ code_ += "_ fbb: inout FlatBufferBuilder,";
+ for (auto it = create_func_header.begin(); it < create_func_header.end();
+ ++it) {
+ code_ += *it + "\\";
+ if (it < create_func_header.end() - 1) code_ += ",";
+ }
+ code_ += "";
+ Outdent();
+ code_ += ") -> Offset {";
+ Indent();
+ code_ += "let __start = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&fbb)";
+ for (auto it = create_func_body.begin(); it < create_func_body.end();
+ ++it) {
+ code_ += *it;
+ }
+ code_ +=
+ "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&fbb, start: __start)";
+ Outdent();
+ code_ += "}";
+ }
+
+ std::string spacing = "";
+
+ if (key_field != nullptr && !struct_def.fixed && struct_def.has_key) {
+ code_.SetValue("VALUENAME", NameWrappedInNameSpace(struct_def));
+ code_.SetValue("SHORT_VALUENAME", Name(struct_def));
+ code_.SetValue("VOFFSET", NumToString(key_field->value.offset));
+
+ code_ +=
+ "{{ACCESS_TYPE}} static func "
+ "sortVectorOf{{SHORT_VALUENAME}}(offsets:[Offset], "
+ "_ fbb: inout FlatBufferBuilder) -> Offset {";
+ Indent();
+ code_ += spacing + "var off = offsets";
+ code_ +=
+ spacing +
+ "off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: "
+ "{{VOFFSET}}, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: "
+ "{{VOFFSET}}, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } ";
+ code_ += spacing + "return fbb.createVector(ofOffsets: off)";
+ Outdent();
+ code_ += "}";
+ GenLookup(*key_field);
+ }
+ }
+
+ void GenTableWriterFields(const FieldDef &field,
+ std::vector<std::string> *create_body,
+ 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);
+ 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("
+ : "(";
+ auto body = "add" + check_if_vector + name + ": ";
+ code_ += "{{ACCESS_TYPE}} static func " + body + "\\";
+
+ create_func_body.push_back("{{STRUCTNAME}}." + body + name + ", &fbb)");
+
+ if (IsScalar(field.value.type.base_type) &&
+ !IsBool(field.value.type.base_type)) {
+ std::string is_enum = IsEnum(field.value.type) ? ".rawValue" : "";
+ std::string optional_enum =
+ IsEnum(field.value.type) ? ("?" + is_enum) : "";
+ code_ +=
+ "{{VALUETYPE}}" + builder_string + "fbb.add(element: {{VALUENAME}}\\";
+
+ code_ += field.IsOptional() ? (optional_enum + "\\")
+ : (is_enum + ", def: {{CONSTANT}}\\");
+
+ code_ += ", at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
+
+ auto default_value =
+ IsEnum(field.value.type)
+ ? (field.IsOptional() ? "nil" : GenEnumDefaultValue(field))
+ : field.value.constant;
+ create_func_header.push_back(
+ "" + name + ": " + nullable_type + " = " +
+ (field.IsOptional() ? "nil" : default_value));
+ return;
+ }
+
+ if (IsBool(field.value.type.base_type)) {
+ std::string default_value =
+ "0" == field.value.constant ? "false" : "true";
+
+ code_.SetValue("CONSTANT", default_value);
+ code_.SetValue("VALUETYPE", field.IsOptional() ? "Bool?" : "Bool");
+ code_ += "{{VALUETYPE}}" + builder_string +
+ "fbb.add(element: {{VALUENAME}},\\";
+ code_ += field.IsOptional() ? "\\" : " def: {{CONSTANT}},";
+ code_ += " at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
+ create_func_header.push_back(
+ name + ": " + nullable_type + " = " +
+ (field.IsOptional() ? "nil" : default_value));
+ return;
+ }
+
+ if (IsStruct(field.value.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 camel_case_name =
+ MakeCamel(name, false) +
+ (IsVector(field.value.type) || IsArray(field.value.type)
+ ? "VectorOffset"
+ : "Offset");
+ create_func_header.push_back(camel_case_name + " " + name + ": " +
+ "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" + 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))) {
+ auto field_name = NameWrappedInNameSpace(*vectortype.struct_def);
+ code_ += "public static func startVectorOf" + MakeCamel(name, true) +
+ "(_ size: Int, in builder: inout "
+ "FlatBufferBuilder) {";
+ Indent();
+ 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);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", type);
+ code_.SetValue("OFFSET", name);
+ code_.SetValue("CONSTANT", field.value.constant);
+ std::string def_Val = field.IsDefault() ? "{{CONSTANT}}" : "nil";
+ std::string optional = field.IsOptional() ? "?" : "";
+ auto const_string = "return o == 0 ? " + def_Val + " : ";
+ GenComment(field.doc_comment);
+ if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) &&
+ !IsBool(field.value.type.base_type)) {
+ code_ += GenReaderMainBody(optional) + GenOffset() + const_string +
+ GenReader("VALUETYPE", "o") + " }";
+ if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
+ return;
+ }
+
+ if (IsBool(field.value.type.base_type)) {
+ std::string default_value =
+ "0" == field.value.constant ? "false" : "true";
+ code_.SetValue("CONSTANT", default_value);
+ code_.SetValue("VALUETYPE", "Bool");
+ code_ += GenReaderMainBody(optional) + "\\";
+ code_.SetValue("VALUETYPE", "Byte");
+ code_ += GenOffset() + "return o == 0 ? {{CONSTANT}} : 0 != " +
+ GenReader("VALUETYPE", "o") + " }";
+ if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
+ return;
+ }
+
+ if (IsEnum(field.value.type)) {
+ 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 + " : " +
+ GenEnumConstructor("o") + "?? " + default_value + " }";
+ if (parser_.opts.mutable_buffer && !IsUnion(field.value.type))
+ code_ += GenMutate("o", GenOffset(), true);
+ return;
+ }
+
+ 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" + MakeCamel(name));
+ code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
+ code_.SetValue("CONSTANT", "nil");
+ code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader +
+ GenConstructor("o + {{ACCESS}}.postion");
+ return;
+ }
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ code_.SetValue("VALUETYPE", GenType(field.value.type));
+ code_.SetValue("CONSTANT", "nil");
+ code_ += GenReaderMainBody(is_required) + GenOffset() +
+ required_reader +
+ GenConstructor(GenIndirect("o + {{ACCESS}}.postion"));
+ break;
+
+ case BASE_TYPE_STRING: {
+ auto default_string = "\"" + field.value.constant + "\"";
+ code_.SetValue("VALUETYPE", GenType(field.value.type));
+ 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]" +
+ is_required +
+ " { return "
+ "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) }";
+ break;
+ }
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: GenTableReaderVectorFields(field); break;
+ case BASE_TYPE_UNION:
+ code_.SetValue("CONSTANT", "nil");
+ code_ +=
+ "{{ACCESS_TYPE}} func {{VALUENAME}}<T: "
+ "FlatbuffersInitializable>(type: "
+ "T.Type) -> T" +
+ is_required + " { " + GenOffset() + required_reader +
+ "{{ACCESS}}.union(o) }";
+ break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+
+ 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() +
+ "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: 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", "Bool");
+ }
+
+ if (!IsEnum(vectortype)) code_ += const_string + "\\";
+
+ if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) &&
+ !IsBool(field.value.type.base_type)) {
+ code_ +=
+ "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
+ "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
+ code_ +=
+ "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}] { return "
+ "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) ?? [] }";
+ if (parser_.opts.mutable_buffer) code_ += GenMutateArray();
+ return;
+ }
+
+ if (vectortype.base_type == BASE_TYPE_STRUCT &&
+ field.value.type.struct_def->fixed) {
+ code_ +=
+ "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
+ "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
+ code_.SetValue("VALUENAME", "mutable" + MakeCamel(Name(field)));
+ code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
+ code_ += GenArrayMainBody(nullable) + GenOffset() + const_string +
+ GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}");
+
+ return;
+ }
+
+ if (IsString(vectortype)) {
+ code_ +=
+ "{{ACCESS}}.directString(at: {{ACCESS}}.vector(at: o) + "
+ "index * {{SIZE}}) }";
+ return;
+ }
+
+ if (IsEnum(vectortype)) {
+ code_.SetValue("BASEVALUE", GenTypeBasic(vectortype, false));
+ code_ += "return o == 0 ? {{VALUETYPE}}" + GenEnumDefaultValue(field) +
+ " : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: "
+ "{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + "
+ "index * {{SIZE}})) }";
+ return;
+ }
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ code_ +=
+ "{{ACCESS}}.directUnion({{ACCESS}}.vector(at: o) + "
+ "index * {{SIZE}}) }";
+ return;
+ }
+
+ if (vectortype.base_type == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ code_ += GenConstructor(
+ "{{ACCESS}}.indirect({{ACCESS}}.vector(at: o) + index * "
+ "{{SIZE}})");
+ auto &sd = *field.value.type.struct_def;
+ auto &fields = sd.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ GenByKeyFunctions(key_field);
+ break;
+ }
+ }
+ }
+ }
+
+ void GenByKeyFunctions(const FieldDef &key_field) {
+ code_.SetValue("TYPE", GenType(key_field.value.type));
+ code_ +=
+ "{{ACCESS_TYPE}} func {{VALUENAME}}By(key: {{TYPE}}) -> {{VALUETYPE}}? "
+ "{ \\";
+ code_ += GenOffset() +
+ "return o == 0 ? nil : {{VALUETYPE}}.lookupByKey(vector: "
+ "{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }";
+ }
+
+ void GenEnum(const EnumDef &enum_def) {
+ if (enum_def.generated) return;
+ auto is_private_access = enum_def.attributes.Lookup("private");
+ 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 {";
+ Indent();
+ code_ += "{{ACCESS_TYPE}} typealias T = {{BASE_TYPE}}";
+ code_ +=
+ "{{ACCESS_TYPE}} static var byteSize: Int { return "
+ "MemoryLayout<{{BASE_TYPE}}>.size "
+ "}";
+ code_ +=
+ "{{ACCESS_TYPE}} var value: {{BASE_TYPE}} { return self.rawValue }";
+ 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("VALUE", enum_def.ToString(ev));
+ GenComment(ev.doc_comment);
+ code_ += "case {{KEY}} = {{VALUE}}";
+ }
+ code_ += "\n";
+ AddMinOrMaxEnumValue(Name(*enum_def.MaxValue()), "max");
+ AddMinOrMaxEnumValue(Name(*enum_def.MinValue()), "min");
+ Outdent();
+ code_ += "}\n";
+ 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: NativeObject?";
+ code_ +=
+ "{{ACCESS_TYPE}} init(_ v: NativeObject?, type: {{ENUM_NAME}}) {";
+ Indent();
+ code_ += "self.type = type";
+ code_ += "self.value = v";
+ Outdent();
+ code_ += "}";
+ code_ +=
+ "{{ACCESS_TYPE}} func pack(builder: inout FlatBufferBuilder) -> "
+ "Offset {";
+ Indent();
+ BuildUnionEnumSwitchCaseWritter(enum_def);
+ 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}}") +
+ ": NativeObject {\n";
+ std::vector<std::string> buffer_constructor;
+ std::vector<std::string> base_constructor;
+ Indent();
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ BuildObjectAPIConstructorBody(field, struct_def.fixed, buffer_constructor,
+ base_constructor);
+ }
+ code_ += "";
+ BuildObjectConstructor(buffer_constructor,
+ "_ _t: inout " + NameWrappedInNameSpace(struct_def));
+ BuildObjectConstructor(base_constructor);
+ if (!struct_def.fixed)
+ code_ +=
+ "{{ACCESS_TYPE}} func serialize() -> ByteBuffer { return "
+ "serialize(type: "
+ "{{STRUCTNAME}}.self) }\n";
+ Outdent();
+ code_ += "}";
+ }
+
+ void GenerateObjectAPITableExtension(const StructDef &struct_def) {
+ GenerateObjectAPIExtensionHeader(ObjectAPIName("{{STRUCTNAME}}"));
+ std::vector<std::string> unpack_body;
+ std::string builder = ", &builder)";
+ 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);
+ std::string check_if_vector =
+ (IsVector(field.value.type) || IsArray(field.value.type))
+ ? "VectorOf("
+ : "(";
+ std::string body = "add" + check_if_vector + name + ": ";
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
+ case BASE_TYPE_VECTOR: {
+ GenerateVectorObjectAPITableExtension(field, name, type);
+ unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
+ builder);
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ code_ += "let __" + name + " = obj." + name +
+ "?.pack(builder: &builder) ?? Offset()";
+ unpack_body.push_back("if let o = obj." + name + "?.type {");
+ unpack_body.push_back(" {{STRUCTNAME}}.add(" + name + "Type: o" +
+ builder);
+ unpack_body.push_back(" {{STRUCTNAME}}." + body + "__" + name +
+ builder);
+ unpack_body.push_back("}\n");
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (field.value.type.struct_def &&
+ field.value.type.struct_def->fixed) {
+ // This is a Struct (IsStruct), not a table. We create
+ // 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 +
+ builder);
+ } else {
+ code_ += "let __" + name + " = " + type +
+ ".pack(&builder, obj: &obj." + name + ")";
+ unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
+ builder);
+ }
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
+ builder);
+ if (field.IsRequired()) {
+ code_ +=
+ "let __" + name + " = builder.create(string: obj." + name + ")";
+ } else {
+ BuildingOptionalObjects(name, "builder.create(string: s)");
+ }
+ break;
+ }
+ case BASE_TYPE_UTYPE: break;
+ default:
+ unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." + name +
+ builder);
+ }
+ }
+ code_ += "let __root = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&builder)";
+ for (auto it = unpack_body.begin(); it < unpack_body.end(); it++)
+ code_ += *it;
+ code_ +=
+ "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&builder, start: "
+ "__root)";
+ Outdent();
+ code_ += "}";
+ }
+
+ void GenerateVectorObjectAPITableExtension(const FieldDef &field,
+ const std::string &name,
+ const std::string &type) {
+ auto vectortype = field.value.type.VectorType();
+ switch (vectortype.base_type) {
+ case BASE_TYPE_UNION: {
+ code_ += "var __" + name + "__: [Offset] = []";
+ code_ += "for i in obj." + name + " {";
+ Indent();
+ code_ += "guard let off = i?.pack(builder: &builder) else { continue }";
+ code_ += "__" + name + "__.append(off)";
+ Outdent();
+ code_ += "}";
+ code_ += "let __" + name + " = builder.createVector(ofOffsets: __" +
+ name + "__)";
+ code_ += "let __" + name + "Type = builder.createVector(obj." + name +
+ ".compactMap { $0?.type })";
+ break;
+ }
+ case BASE_TYPE_UTYPE: break;
+ case BASE_TYPE_STRUCT: {
+ if (field.value.type.struct_def &&
+ !field.value.type.struct_def->fixed) {
+ code_ += "var __" + name + "__: [Offset] = []";
+ code_ += "for var i in obj." + name + " {";
+ Indent();
+ code_ +=
+ "__" + name + "__.append(" + type + ".pack(&builder, obj: &i))";
+ Outdent();
+ code_ += "}";
+ code_ += "let __" + name + " = builder.createVector(ofOffsets: __" +
+ name + "__)";
+ } else {
+ code_ += "{{STRUCTNAME}}.startVectorOf" + MakeCamel(name, true) +
+ "(obj." + name + ".count, in: &builder)";
+ std::string code;
+ GenerateStructArgs(*field.value.type.struct_def, &code, "", "", "_o",
+ true);
+ code = code.substr(0, code.size() - 2);
+ code_ += "for i in obj." + name + " {";
+ Indent();
+ code_ += "guard let _o = i else { continue }";
+ code_ += "builder.create(struct: _o)";
+ Outdent();
+ code_ += "}";
+ code_ += "let __" + name + " = builder.endVector(len: obj." + name +
+ ".count)";
+ }
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ code_ += "let __" + name + " = builder.createVector(ofStrings: obj." +
+ name + ".compactMap({ $0 }) )";
+ break;
+ }
+ default: {
+ code_ += "let __" + name + " = builder.createVector(obj." + name + ")";
+ break;
+ }
+ }
+ }
+
+ void BuildingOptionalObjects(const std::string &name,
+ const std::string &body_front) {
+ code_ += "let __" + name + ": Offset";
+ code_ += "if let s = obj." + name + " {";
+ Indent();
+ code_ += "__" + name + " = " + body_front;
+ Outdent();
+ code_ += "} else {";
+ Indent();
+ code_ += "__" + name + " = Offset()";
+ Outdent();
+ code_ += "}";
+ code_ += "";
+ }
+
+ void BuildObjectConstructor(const std::vector<std::string> &body,
+ const std::string &header = "") {
+ code_.SetValue("HEADER", header);
+ code_ += "{{ACCESS_TYPE}} init({{HEADER}}) {";
+ Indent();
+ for (auto it = body.begin(); it < body.end(); ++it) code_ += *it;
+ Outdent();
+ code_ += "}\n";
+ }
+
+ void BuildObjectAPIConstructorBody(
+ const FieldDef &field, bool is_fixed,
+ std::vector<std::string> &buffer_constructor,
+ std::vector<std::string> &base_constructor) {
+ auto name = Name(field);
+ auto type = GenType(field.value.type);
+ code_.SetValue("VALUENAME", name);
+ code_.SetValue("VALUETYPE", type);
+ 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);
+ auto optional =
+ (field.value.type.struct_def && field.value.type.struct_def->fixed);
+ std::string question_mark =
+ (field.IsRequired() || (optional && is_fixed) ? "" : "?");
+
+ code_ +=
+ "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + question_mark;
+ 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();
+ case BASE_TYPE_VECTOR: {
+ BuildObjectAPIConstructorBodyVectors(field, name, buffer_constructor,
+ base_constructor, " ");
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: String" + is_required;
+ buffer_constructor.push_back(name + " = _t." + 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;
+ case BASE_TYPE_UNION: {
+ BuildUnionEnumSwitchCase(*field.value.type.enum_def, name,
+ buffer_constructor);
+ break;
+ }
+ default: {
+ buffer_constructor.push_back(name + " = _t." + name);
+ 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.IsOptional())
+ base_constructor.push_back(name + " = " + field.value.constant);
+ break;
+ }
+
+ if (IsEnum(field.value.type)) {
+ auto default_value = IsEnum(field.value.type)
+ ? GenEnumDefaultValue(field)
+ : field.value.constant;
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}";
+ base_constructor.push_back(name + " = " + default_value);
+ break;
+ }
+
+ if (IsBool(field.value.type.base_type)) {
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: Bool" + nullable;
+ std::string default_value =
+ "0" == field.value.constant ? "false" : "true";
+ if (!field.IsOptional())
+ base_constructor.push_back(name + " = " + default_value);
+ }
+ }
+ }
+ }
+
+ void BuildObjectAPIConstructorBodyVectors(
+ const FieldDef &field, const std::string &name,
+ std::vector<std::string> &buffer_constructor,
+ std::vector<std::string> &base_constructor,
+ const std::string &indentation) {
+ auto vectortype = field.value.type.VectorType();
+
+ if (vectortype.base_type != BASE_TYPE_UTYPE) {
+ buffer_constructor.push_back(name + " = []");
+ buffer_constructor.push_back("for index in 0..<_t." + name + "Count {");
+ base_constructor.push_back(name + " = []");
+ }
+
+ switch (vectortype.base_type) {
+ case BASE_TYPE_STRUCT: {
+ code_.SetValue("VALUETYPE", GenType(vectortype, true));
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}?]";
+ 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();
+ case BASE_TYPE_VECTOR: {
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ BuildUnionEnumSwitchCase(*field.value.type.enum_def, name,
+ buffer_constructor, indentation, true);
+ break;
+ }
+ case BASE_TYPE_UTYPE: break;
+ default: {
+ code_.SetValue(
+ "VALUETYPE",
+ (IsString(vectortype) ? "String?" : GenType(vectortype)));
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}]";
+
+ if (IsEnum(vectortype) && vectortype.base_type != BASE_TYPE_UNION) {
+ auto default_value = IsEnum(field.value.type)
+ ? GenEnumDefaultValue(field)
+ : field.value.constant;
+ buffer_constructor.push_back(indentation + name + ".append(_t." +
+ name + "(at: index)!)");
+ break;
+ }
+ buffer_constructor.push_back(indentation + name + ".append(_t." + name +
+ "(at: index))");
+ break;
+ }
+ }
+ if (vectortype.base_type != BASE_TYPE_UTYPE)
+ buffer_constructor.push_back("}");
+ }
+
+ void BuildUnionEnumSwitchCaseWritter(const EnumDef &ev) {
+ auto field_name = Name(ev);
+ code_.SetValue("VALUETYPE", field_name);
+ code_ += "switch type {";
+ for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) {
+ auto field = **it;
+ auto ev_name = Name(field);
+ auto type = GenType(field.union_type);
+ 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 " + is_struct + ".pack(&builder, obj: &__obj)";
+ Outdent();
+ }
+ code_ += "default: return Offset()";
+ code_ += "}";
+ }
+
+ void BuildUnionEnumSwitchCase(const EnumDef &ev, const std::string &name,
+ std::vector<std::string> &buffer_constructor,
+ const std::string &indentation = "",
+ const bool is_vector = false) {
+ auto field_name = NameWrappedInNameSpace(ev);
+ code_.SetValue("VALUETYPE", field_name);
+ code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: \\";
+ code_ += is_vector ? "[{{VALUETYPE}}Union?]" : "{{VALUETYPE}}Union?";
+
+ auto vector_reader = is_vector ? "(at: index" : "";
+ buffer_constructor.push_back(indentation + "switch _t." + name + "Type" +
+ vector_reader + (is_vector ? ")" : "") + " {");
+
+ 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) { 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: " + type + ".self)");
+ auto constructor =
+ field_name + "Union(_v?.unpack(), type: ." + ev_name + ")";
+ buffer_constructor.push_back(
+ indentation + " " + name +
+ (is_vector ? ".append(" + constructor + ")" : " = " + constructor));
+ }
+ buffer_constructor.push_back(indentation + "default: break");
+ buffer_constructor.push_back(indentation + "}");
+ }
+
+ void AddMinOrMaxEnumValue(const std::string &str, const std::string &type) {
+ auto current_value = str;
+ code_.SetValue(type, current_value);
+ code_ += "{{ACCESS_TYPE}} static var " + type +
+ ": {{ENUM_NAME}} { return .{{" + type + "}} }";
+ }
+
+ void GenLookup(const FieldDef &key_field) {
+ code_.SetValue("OFFSET", NumToString(key_field.value.offset));
+ std::string offset_reader =
+ "Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, "
+ "fbb: fbb)";
+
+ code_.SetValue("TYPE", GenType(key_field.value.type));
+ code_ +=
+ "fileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, "
+ "fbb: "
+ "ByteBuffer) -> {{VALUENAME}}? {";
+ Indent();
+ if (IsString(key_field.value.type))
+ code_ += "let key = key.utf8.map { $0 }";
+ code_ += "var span = fbb.read(def: Int32.self, position: Int(vector - 4))";
+ code_ += "var start: Int32 = 0";
+ code_ += "while span != 0 {";
+ Indent();
+ code_ += "var middle = span / 2";
+ code_ +=
+ "let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)";
+ if (IsString(key_field.value.type)) {
+ code_ += "let comp = Table.compare(" + offset_reader + ", key, fbb: fbb)";
+ } else {
+ code_ += "let comp = fbb.read(def: {{TYPE}}.self, position: Int(" +
+ offset_reader + "))";
+ }
+
+ code_ += "if comp > 0 {";
+ Indent();
+ code_ += "span = middle";
+ Outdent();
+ code_ += "} else if comp < 0 {";
+ Indent();
+ code_ += "middle += 1";
+ code_ += "start += middle";
+ code_ += "span -= middle";
+ Outdent();
+ code_ += "} else {";
+ Indent();
+ code_ += "return {{VALUENAME}}(fbb, o: tableOffset)";
+ Outdent();
+ code_ += "}";
+ Outdent();
+ code_ += "}";
+ code_ += "return nil";
+ Outdent();
+ 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.
+ return;
+ }
+ for (auto it = dc.begin(); it != dc.end(); ++it) { code_ += "/// " + *it; }
+ }
+
+ std::string GenOffset() {
+ return "let o = {{ACCESS}}.offset({{TABLEOFFSET}}.{{OFFSET}}.v); ";
+ }
+
+ std::string GenReaderMainBody(const std::string &optional = "") {
+ return "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + optional +
+ " { ";
+ }
+
+ std::string GenReader(const std::string &type,
+ const std::string &at = "{{OFFSET}}") {
+ return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")";
+ }
+
+ std::string GenConstructor(const std::string &offset) {
+ return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }";
+ }
+
+ std::string GenMutate(const std::string &offset,
+ const std::string &get_offset, bool isRaw = false) {
+ return "@discardableResult {{ACCESS_TYPE}} func mutate({{VALUENAME}}: "
+ "{{VALUETYPE}}) -> Bool {" +
+ get_offset + " return {{ACCESS}}.mutate({{VALUENAME}}" +
+ (isRaw ? ".rawValue" : "") + ", index: " + offset + ") }";
+ }
+
+ std::string GenMutateArray() {
+ return "{{ACCESS_TYPE}} func mutate({{VALUENAME}}: {{VALUETYPE}}, at "
+ "index: "
+ "Int32) -> Bool { " +
+ GenOffset() +
+ "return {{ACCESS}}.directMutate({{VALUENAME}}, index: "
+ "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
+ }
+
+ std::string GenEnumDefaultValue(const FieldDef &field) {
+ auto &value = field.value;
+ FLATBUFFERS_ASSERT(value.type.enum_def);
+ auto &enum_def = *value.type.enum_def;
+ // 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);
+ } else {
+ const auto &ev = **enum_def.Vals().begin();
+ name = Name(ev);
+ }
+ return "." + name;
+ }
+
+ std::string GenEnumConstructor(const std::string &at) {
+ return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") ";
+ }
+
+ std::string ValidateFunc() {
+ return "static func validateVersion() { FlatBuffersVersion_2_0_0() }";
+ }
+
+ std::string GenType(const Type &type,
+ const bool should_consider_suffix = false) const {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type)
+ : (IsArray(type) ? GenType(type.VectorType())
+ : GenTypePointer(type, should_consider_suffix));
+ }
+
+ std::string GenTypePointer(const Type &type,
+ const bool should_consider_suffix) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "String";
+ case BASE_TYPE_VECTOR: return GenType(type.VectorType());
+ case BASE_TYPE_STRUCT: {
+ auto &struct_ = *type.struct_def;
+ 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 "FlatbuffersInitializable";
+ }
+ }
+
+ std::string GenTypeBasic(const Type &type) const {
+ return GenTypeBasic(type, true);
+ }
+
+ std::string ObjectAPIName(const std::string &name) const {
+ return parser_.opts.object_prefix + name + parser_.opts.object_suffix;
+ }
+
+ void Indent() { code_.IncrementIdentLevel(); }
+
+ void Outdent() { code_.DecrementIdentLevel(); }
+
+ std::string NameWrappedInNameSpace(const EnumDef &enum_def) const {
+ return WrapInNameSpace(enum_def.defined_namespace, Name(enum_def));
+ }
+
+ std::string NameWrappedInNameSpace(const StructDef &struct_def) const {
+ return WrapInNameSpace(struct_def.defined_namespace, Name(struct_def));
+ }
+
+ std::string GenTypeBasic(const Type &type, bool can_override) const {
+ // clang-format off
+ static const char * const swift_type[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \
+ #STYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ if (can_override) {
+ if (type.enum_def) return NameWrappedInNameSpace(*type.enum_def);
+ if (type.base_type == BASE_TYPE_BOOL) return "Bool";
+ }
+ return swift_type[static_cast<int>(type.base_type)];
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ 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));
+ }
+
+ std::string Name(const Definition &def) const {
+ return EscapeKeyword(MakeCamel(def.name, false));
+ }
+};
+} // namespace swift
+bool GenerateSwift(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ swift::SwiftGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_text.cpp b/contrib/libs/flatbuffers/src/idl_gen_text.cpp
new file mode 100644
index 0000000000..903c41ecdb
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_text.cpp
@@ -0,0 +1,414 @@
+/*
+ * 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 "flatbuffers/flatbuffers.h"
+#include "flatbuffers/flexbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+struct PrintScalarTag {};
+struct PrintPointerTag {};
+template<typename T> struct PrintTag { typedef PrintScalarTag type; };
+template<> struct PrintTag<const void *> { typedef PrintPointerTag type; };
+
+struct JsonPrinter {
+ // If indentation is less than 0, that indicates we don't want any newlines
+ // either.
+ void AddNewLine() {
+ if (opts.indent_step >= 0) text += '\n';
+ }
+
+ void AddIndent(int ident) { text.append(ident, ' '); }
+
+ int Indent() const { return std::max(opts.indent_step, 0); }
+
+ // Output an identifier with or without quotes depending on strictness.
+ void OutputIdentifier(const std::string &name) {
+ if (opts.strict_json) text += '\"';
+ text += name;
+ if (opts.strict_json) text += '\"';
+ }
+
+ // Print (and its template specialization below for pointers) generate text
+ // for a single FlatBuffer value into JSON format.
+ // The general case for scalars:
+ template<typename T>
+ bool PrintScalar(T val, const Type &type, int /*indent*/) {
+ if (IsBool(type.base_type)) {
+ text += val != 0 ? "true" : "false";
+ return true; // done
+ }
+
+ if (opts.output_enum_identifiers && type.enum_def) {
+ const auto &enum_def = *type.enum_def;
+ if (auto ev = enum_def.ReverseLookup(static_cast<int64_t>(val))) {
+ text += '\"';
+ text += ev->name;
+ text += '\"';
+ return true; // done
+ } else if (val && enum_def.attributes.Lookup("bit_flags")) {
+ const auto entry_len = text.length();
+ const auto u64 = static_cast<uint64_t>(val);
+ uint64_t mask = 0;
+ text += '\"';
+ for (auto it = enum_def.Vals().begin(), e = enum_def.Vals().end();
+ it != e; ++it) {
+ auto f = (*it)->GetAsUInt64();
+ if (f & u64) {
+ mask |= f;
+ text += (*it)->name;
+ text += ' ';
+ }
+ }
+ // Don't slice if (u64 != mask)
+ if (mask && (u64 == mask)) {
+ text[text.length() - 1] = '\"';
+ return true; // done
+ }
+ text.resize(entry_len); // restore
+ }
+ // print as numeric value
+ }
+
+ text += NumToString(val);
+ return true;
+ }
+
+ void AddComma() {
+ if (!opts.protobuf_ascii_alike) text += ',';
+ }
+
+ // Print a vector or an array of JSON values, comma seperated, wrapped in
+ // "[]".
+ template<typename Container>
+ bool PrintContainer(PrintScalarTag, const Container &c, size_t size,
+ const Type &type, int indent, const uint8_t *) {
+ const auto elem_indent = indent + Indent();
+ text += '[';
+ AddNewLine();
+ for (uoffset_t i = 0; i < size; i++) {
+ if (i) {
+ AddComma();
+ AddNewLine();
+ }
+ AddIndent(elem_indent);
+ if (!PrintScalar(c[i], type, elem_indent)) { return false; }
+ }
+ AddNewLine();
+ AddIndent(indent);
+ text += ']';
+ return true;
+ }
+
+ // Print a vector or an array of JSON values, comma seperated, wrapped in
+ // "[]".
+ template<typename Container>
+ bool PrintContainer(PrintPointerTag, const Container &c, size_t size,
+ const Type &type, int indent, const uint8_t *prev_val) {
+ const auto is_struct = IsStruct(type);
+ const auto elem_indent = indent + Indent();
+ text += '[';
+ AddNewLine();
+ for (uoffset_t i = 0; i < size; i++) {
+ if (i) {
+ AddComma();
+ AddNewLine();
+ }
+ AddIndent(elem_indent);
+ auto ptr = is_struct ? reinterpret_cast<const void *>(
+ c.Data() + type.struct_def->bytesize * i)
+ : c[i];
+ if (!PrintOffset(ptr, type, elem_indent, prev_val,
+ static_cast<soffset_t>(i))) {
+ return false;
+ }
+ }
+ AddNewLine();
+ AddIndent(indent);
+ text += ']';
+ return true;
+ }
+
+ template<typename T>
+ bool PrintVector(const void *val, const Type &type, int indent,
+ const uint8_t *prev_val) {
+ typedef Vector<T> Container;
+ typedef typename PrintTag<typename Container::return_type>::type tag;
+ auto &vec = *reinterpret_cast<const Container *>(val);
+ return PrintContainer<Container>(tag(), vec, vec.size(), type, indent,
+ prev_val);
+ }
+
+ // Print an array a sequence of JSON values, comma separated, wrapped in "[]".
+ template<typename T>
+ bool PrintArray(const void *val, size_t size, const Type &type, int indent) {
+ typedef Array<T, 0xFFFF> Container;
+ typedef typename PrintTag<typename Container::return_type>::type tag;
+ auto &arr = *reinterpret_cast<const Container *>(val);
+ return PrintContainer<Container>(tag(), arr, size, type, indent, nullptr);
+ }
+
+ bool PrintOffset(const void *val, const Type &type, int indent,
+ const uint8_t *prev_val, soffset_t vector_index) {
+ switch (type.base_type) {
+ case BASE_TYPE_UNION: {
+ // If this assert hits, you have an corrupt buffer, a union type field
+ // was not present or was out of range.
+ FLATBUFFERS_ASSERT(prev_val);
+ auto union_type_byte = *prev_val; // Always a uint8_t.
+ if (vector_index >= 0) {
+ auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(
+ prev_val + ReadScalar<uoffset_t>(prev_val));
+ union_type_byte = type_vec->Get(static_cast<uoffset_t>(vector_index));
+ }
+ auto enum_val = type.enum_def->ReverseLookup(union_type_byte, true);
+ if (enum_val) {
+ return PrintOffset(val, enum_val->union_type, indent, nullptr, -1);
+ } else {
+ return false;
+ }
+ }
+ case BASE_TYPE_STRUCT:
+ return GenStruct(*type.struct_def, reinterpret_cast<const Table *>(val),
+ indent);
+ case BASE_TYPE_STRING: {
+ auto s = reinterpret_cast<const String *>(val);
+ return EscapeString(s->c_str(), s->size(), &text, opts.allow_non_utf8,
+ opts.natural_utf8);
+ }
+ case BASE_TYPE_VECTOR: {
+ const auto vec_type = type.VectorType();
+ // Call PrintVector above specifically for each element type:
+ // clang-format off
+ switch (vec_type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_ ## ENUM: \
+ if (!PrintVector<CTYPE>( \
+ val, vec_type, indent, prev_val)) { \
+ return false; \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ }
+ // clang-format on
+ return true;
+ }
+ case BASE_TYPE_ARRAY: {
+ const auto vec_type = type.VectorType();
+ // Call PrintArray above specifically for each element type:
+ // clang-format off
+ switch (vec_type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_ ## ENUM: \
+ if (!PrintArray<CTYPE>( \
+ val, type.fixed_length, vec_type, indent)) { \
+ return false; \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+ // Arrays of scalars or structs are only possible.
+ FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ case BASE_TYPE_ARRAY: FLATBUFFERS_ASSERT(0);
+ }
+ // clang-format on
+ return true;
+ }
+ default: FLATBUFFERS_ASSERT(0); return false;
+ }
+ }
+
+ template<typename T> static T GetFieldDefault(const FieldDef &fd) {
+ T val;
+ auto check = StringToNumber(fd.value.constant.c_str(), &val);
+ (void)check;
+ FLATBUFFERS_ASSERT(check);
+ return val;
+ }
+
+ // Generate text for a scalar field.
+ template<typename T>
+ bool GenField(const FieldDef &fd, const Table *table, bool fixed,
+ int indent) {
+ return PrintScalar(
+ fixed ? reinterpret_cast<const Struct *>(table)->GetField<T>(
+ fd.value.offset)
+ : table->GetField<T>(fd.value.offset, GetFieldDefault<T>(fd)),
+ fd.value.type, indent);
+ }
+
+ // Generate text for non-scalar field.
+ bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
+ int indent, const uint8_t *prev_val) {
+ const void *val = nullptr;
+ if (fixed) {
+ // The only non-scalar fields in structs are structs or arrays.
+ 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) {
+ 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) {
+ auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
+ auto root = GetRoot<Table>(vec->data());
+ return GenStruct(*fd.nested_flatbuffer, root, indent);
+ } else {
+ val = IsStruct(fd.value.type)
+ ? table->GetStruct<const void *>(fd.value.offset)
+ : table->GetPointer<const void *>(fd.value.offset);
+ }
+ return PrintOffset(val, fd.value.type, indent, prev_val, -1);
+ }
+
+ // Generate text for a struct or table, values separated by commas, indented,
+ // and bracketed by "{}"
+ bool GenStruct(const StructDef &struct_def, const Table *table, int indent) {
+ text += '{';
+ int fieldout = 0;
+ const uint8_t *prev_val = nullptr;
+ const auto elem_indent = indent + Indent();
+ for (auto it = struct_def.fields.vec.begin();
+ 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 || fd.key) &&
+ IsScalar(fd.value.type.base_type) && !fd.deprecated;
+ if (is_present || output_anyway) {
+ if (fieldout++) { AddComma(); }
+ AddNewLine();
+ AddIndent(elem_indent);
+ OutputIdentifier(fd.name);
+ if (!opts.protobuf_ascii_alike ||
+ (fd.value.type.base_type != BASE_TYPE_STRUCT &&
+ fd.value.type.base_type != BASE_TYPE_VECTOR))
+ text += ':';
+ text += ' ';
+ // clang-format off
+ switch (fd.value.type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_ ## ENUM: \
+ if (!GenField<CTYPE>(fd, table, struct_def.fixed, elem_indent)) { \
+ return false; \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // Generate drop-thru case statements for all pointer types:
+ #define FLATBUFFERS_TD(ENUM, ...) \
+ case BASE_TYPE_ ## ENUM:
+ FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
+ FLATBUFFERS_GEN_TYPE_ARRAY(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ if (!GenFieldOffset(fd, table, struct_def.fixed, elem_indent, prev_val)) {
+ return false;
+ }
+ break;
+ }
+ // clang-format on
+ // Track prev val for use with union types.
+ if (struct_def.fixed) {
+ prev_val = reinterpret_cast<const uint8_t *>(table) + fd.value.offset;
+ } else {
+ prev_val = table->GetAddressOf(fd.value.offset);
+ }
+ }
+ }
+ AddNewLine();
+ AddIndent(indent);
+ text += '}';
+ return true;
+ }
+
+ JsonPrinter(const Parser &parser, std::string &dest)
+ : opts(parser.opts), text(dest) {
+ text.reserve(1024); // Reduce amount of inevitable reallocs.
+ }
+
+ const IDLOptions &opts;
+ std::string &text;
+};
+
+static bool GenerateTextImpl(const Parser &parser, const Table *table,
+ const StructDef &struct_def, std::string *_text) {
+ JsonPrinter printer(parser, *_text);
+ if (!printer.GenStruct(struct_def, table, 0)) { return false; }
+ printer.AddNewLine();
+ return true;
+}
+
+// Generate a text representation of a flatbuffer in JSON format.
+bool GenerateTextFromTable(const Parser &parser, const void *table,
+ const std::string &table_name, std::string *_text) {
+ auto struct_def = parser.LookupStruct(table_name);
+ if (struct_def == nullptr) { return false; }
+ auto root = static_cast<const Table *>(table);
+ return GenerateTextImpl(parser, root, *struct_def, _text);
+}
+
+// Generate a text representation of a flatbuffer in JSON format.
+bool GenerateText(const Parser &parser, const void *flatbuffer,
+ std::string *_text) {
+ FLATBUFFERS_ASSERT(parser.root_struct_def_); // call SetRootType()
+ auto root = parser.opts.size_prefixed ? GetSizePrefixedRoot<Table>(flatbuffer)
+ : GetRoot<Table>(flatbuffer);
+ return GenerateTextImpl(parser, root, *parser.root_struct_def_, _text);
+}
+
+static std::string TextFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + ".json";
+}
+
+bool GenerateTextFile(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ if (parser.opts.use_flexbuffers) {
+ std::string json;
+ parser.flex_root_.ToString(true, parser.opts.strict_json, json);
+ return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(),
+ json.c_str(), json.size(), true);
+ }
+ if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
+ std::string text;
+ if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) {
+ return false;
+ }
+ return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(), text,
+ false);
+}
+
+std::string TextMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ if (!parser.builder_.GetSize() || !parser.root_struct_def_) return "";
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ std::string make_rule = TextFileName(path, filebase) + ": " + file_name;
+ auto included_files =
+ parser.GetIncludedFilesRecursive(parser.root_struct_def_->file);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/idl_gen_ts.cpp b/contrib/libs/flatbuffers/src/idl_gen_ts.cpp
new file mode 100644
index 0000000000..53e088fe13
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_gen_ts.cpp
@@ -0,0 +1,1583 @@
+/*
+ * 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 statement;
+ const Definition *dependent;
+ const Definition *dependency;
+};
+
+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") {}
+ bool generate() {
+ generateEnums();
+ generateStructs();
+ 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) const {
+ if (!classcode.length()) return true;
+
+ std::string code =
+ "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ for (auto it = bare_imports.begin(); it != bare_imports.end(); it++)
+ code += it->second.statement + "\n";
+ if (!bare_imports.empty()) code += "\n";
+
+ for (auto it = imports.begin(); it != imports.end(); it++)
+ if (it->second.dependency != &definition) // do not import itself
+ code += it->second.statement + "\n";
+ if (!imports.empty()) code += "\n\n";
+
+ code += classcode;
+ auto filename = NamespaceDir(*definition.defined_namespace, true) +
+ ToDasherizedCase(definition.name) + ".ts";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ private:
+ // 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);
+ }
+ }
+
+ // 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);
+ }
+ }
+
+ // 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);
+ std::string ns = GetNameSpace(enum_def);
+ std::string enum_def_name = enum_def.name + (reverse ? "Name" : "");
+ code += "export enum " + 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, " ");
+ }
+
+ // Generate mapping between EnumName: EnumValue(int)
+ if (reverse) {
+ code += " '" + enum_def.ToString(ev) + "'";
+ code += " = ";
+ code += "'" + ev.name + "'";
+ } else {
+ code += " " + ev.name;
+ code += " = ";
+ 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" + MakeCamel(GenType(type)) + 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, const std::string &context,
+ 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 (auto val = value.type.enum_def->FindByValue(value.constant)) {
+ return AddImport(imports, *value.type.enum_def, *value.type.enum_def) +
+ "." + 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: {
+ int64_t constant = StringToInt(value.constant.c_str());
+ std::string createLong = context + ".createLong";
+ return createLong + "(" + NumToString(static_cast<int32_t>(constant)) +
+ ", " + NumToString(static_cast<int32_t>(constant >> 32)) + ")";
+ }
+
+ 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 = 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 ? "flatbuffers.Long|null" : "flatbuffers.Long";
+ 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) ? 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) : "";
+ }
+
+ 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 " + 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;
+ }
+ }
+ std::string import_statement;
+ import_statement += "import { ";
+ if (long_import_name.empty()) {
+ import_statement += import_name;
+ if (parser_.opts.generate_object_based_api)
+ import_statement += ", " + import_name + "T";
+ } else {
+ import_statement += dependency.name + " as " + long_import_name;
+ if (parser_.opts.generate_object_based_api)
+ import_statement +=
+ ", " + dependency.name + "T as " + long_import_name + "T";
+ }
+ import_statement += " } from '";
+ std::string file_name;
+ const auto &dep_comps = dependent.defined_namespace->components;
+ for (size_t i = 0; i < dep_comps.size(); i++)
+ file_name += i == 0 ? ".." : (kPathSeparator + std::string(".."));
+ if (dep_comps.size() == 0) file_name += ".";
+ for (auto it = depc_comps.begin(); it != depc_comps.end(); it++)
+ file_name += kPathSeparator + ToDasherizedCase(*it);
+ file_name += kPathSeparator + ToDasherizedCase(dependency.name);
+ import_statement += file_name + "';";
+ ImportDefinition import;
+ import.name = long_import_name.empty() ? import_name : long_import_name;
+ import.statement = import_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 = 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;
+ }
+ }
+ std::string import_statement;
+ import_statement += "import { ";
+ if (long_import_name.empty())
+ import_statement += import_name;
+ else
+ import_statement += dependency.name + " as " + long_import_name;
+ if (dependency.is_union) {
+ import_statement += ", unionTo" + import_name;
+ import_statement += ", unionListTo" + import_name;
+ }
+ import_statement += " } from '";
+ std::string file_name;
+ const auto &dep_comps = dependent.defined_namespace->components;
+ for (size_t i = 0; i < dep_comps.size(); i++)
+ file_name += i == 0 ? ".." : (kPathSeparator + std::string(".."));
+ if (dep_comps.size() == 0) file_name += ".";
+ for (auto it = depc_comps.begin(); it != depc_comps.end(); it++)
+ file_name += kPathSeparator + ToDasherizedCase(*it);
+ file_name += kPathSeparator + ToDasherizedCase(dependency.name);
+ import_statement += file_name + "';";
+ ImportDefinition import;
+ import.name = long_import_name.empty() ? import_name : long_import_name;
+ import.statement = import_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.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 + "." + 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,
+ 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 = 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 = 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", 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;
+ } 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 += GetObjApiClassName(sd, parser.opts);
+
+ const std::string field_accessor = "this." + field_name + "()";
+ field_val = GenNullCheckConditional(field_accessor,
+ field_accessor + "!.unpack()");
+ auto packing = GenNullCheckConditional(
+ "this." + field_name, "this." + field_name + "!.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(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 +
+ ", " + AddImport(imports, struct_def, struct_def) +
+ ".start" + MakeCamel(field_name) + "Vector)";
+ } else {
+ field_offset_decl =
+ AddImport(imports, struct_def, struct_def) + ".create" +
+ MakeCamel(field_name) +
+ "Vector(builder, builder.createObjectOffsetList(" +
+ "this." + field_name + "))";
+ }
+
+ break;
+ }
+
+ case BASE_TYPE_STRING: {
+ field_type += "string)[]";
+ field_val = GenBBAccess() + ".createScalarList(" +
+ field_binded_method + ", this." + field_name +
+ "Length())";
+ field_offset_decl =
+ AddImport(imports, struct_def, struct_def) + ".create" +
+ MakeCamel(field_name) +
+ "Vector(builder, builder.createObjectOffsetList(" +
+ "this." + field_name + "))";
+ 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 =
+ AddImport(imports, struct_def, struct_def) + ".create" +
+ MakeCamel(field_name) +
+ "Vector(builder, builder.createObjectOffsetList(" +
+ "this." + field_name + "))";
+
+ 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 = AddImport(imports, struct_def, struct_def) +
+ ".create" + MakeCamel(field_name) +
+ "Vector(builder, this." + field_name + ")";
+
+ 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 + ")";
+ 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_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_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 = struct_def.name;
+ GenDocComment(struct_def.doc_comment, code_ptr);
+ code += "export class " + struct_def.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 = MakeCamel(field.name, false) + "(";
+ 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, GenBBAccess(), imports);
+ code += ";\n";
+ }
+ }
+
+ // Emit an object field
+ else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ const auto type =
+ AddImport(imports, struct_def, *field.value.type.struct_def);
+ GenDocComment(field.doc_comment, code_ptr);
+ code += MakeCamel(field.name, false);
+ 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 = MakeCamel(field.name, false);
+ // 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 += GenBBAccess() + ".createLong(0, 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 += 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";
+
+ 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" +
+ MakeCamel(GenType(field.value.type)) + "(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" +
+ MakeCamel(GenType(field.value.type)) +
+ "(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 += MakeCamel(field.name, false);
+ 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 += MakeCamel(field.name, false);
+ 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" + MakeCamel(field.name);
+ 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 += "builder.createLong(0, 0)";
+ } else {
+ code += "0";
+ }
+ } else {
+ if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; }
+ code += GenDefaultValue(field, "builder", 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" + MakeCamel(field.name) +
+ "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" + MakeCamel(field.name);
+ 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 += " " + struct_def.name + ".start" +
+ GetPrefixedName(struct_def) + "(builder);\n";
+
+ std::string methodPrefix = struct_def.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" + MakeCamel(field.name) + "(";
+ 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):" + name + " {\n";
+ code += " return " + 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());
+ }
+
+ 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 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) {
+ FLATBUFFERS_ASSERT(parser.opts.lang <= IDLOptions::kMAX);
+
+ 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/contrib/libs/flatbuffers/src/idl_parser.cpp b/contrib/libs/flatbuffers/src/idl_parser.cpp
new file mode 100644
index 0000000000..ad642d79a9
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/idl_parser.cpp
@@ -0,0 +1,3986 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <cmath>
+#include <list>
+#include <string>
+#include <utility>
+
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+// Reflects the version at the compiling time of binary(lib/dll/so).
+const char *FLATBUFFERS_VERSION() {
+ // clang-format off
+ return
+ FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "."
+ FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "."
+ FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION);
+ // clang-format on
+}
+
+const double kPi = 3.14159265358979323846;
+
+// clang-format off
+const char *const kTypeNames[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \
+ IDLTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ nullptr
+};
+
+const char kTypeSizes[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ sizeof(CTYPE),
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+};
+// clang-format on
+
+// 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),
+ "enums don't match");
+
+// Any parsing calls have to be wrapped in this macro, which automates
+// handling of recursive error checking a bit. It will check the received
+// CheckedError object, and return straight away on error.
+#define ECHECK(call) \
+ { \
+ auto ce = (call); \
+ if (ce.Check()) return ce; \
+ }
+
+// These two functions are called hundreds of times below, so define a short
+// form:
+#define NEXT() ECHECK(Next())
+#define EXPECT(tok) ECHECK(Expect(tok))
+
+static bool ValidateUTF8(const std::string &str) {
+ const char *s = &str[0];
+ const char *const sEnd = s + str.length();
+ while (s < sEnd) {
+ if (FromUTF8(&s) < 0) { return false; }
+ }
+ return true;
+}
+
+static bool IsLowerSnakeCase(const std::string &str) {
+ for (size_t i = 0; i < str.length(); i++) {
+ char c = str[i];
+ if (!check_ascii_range(c, 'a', 'z') && !is_digit(c) && c != '_') {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Convert an underscore_based_identifier 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;
+ for (uoffset_t index = 0; index < documentation->size(); index++)
+ doc.push_back(documentation->Get(index)->str());
+}
+
+void Parser::Message(const std::string &msg) {
+ if (!error_.empty()) error_ += "\n"; // log all warnings and errors
+ error_ += file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : "";
+ // clang-format off
+
+ #ifdef _WIN32 // MSVC alike
+ error_ +=
+ "(" + NumToString(line_) + ", " + NumToString(CursorPosition()) + ")";
+ #else // gcc alike
+ if (file_being_parsed_.length()) error_ += ":";
+ error_ += NumToString(line_) + ": " + NumToString(CursorPosition());
+ #endif
+ // clang-format on
+ error_ += ": " + msg;
+}
+
+void Parser::Warning(const std::string &msg) {
+ if (!opts.no_warnings) Message("warning: " + msg);
+}
+
+CheckedError Parser::Error(const std::string &msg) {
+ Message("error: " + msg);
+ return CheckedError(true);
+}
+
+inline CheckedError NoError() { return CheckedError(false); }
+
+CheckedError Parser::RecurseError() {
+ return Error("maximum parsing depth " + NumToString(parse_depth_counter_) +
+ " reached");
+}
+
+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)()) + "]";
+}
+
+// atot: template version of atoi/atof: convert a string to an instance of T.
+template<typename T>
+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) + "\"");
+ else
+ return parser.Error("invalid number: \"" + std::string(s) + "\"" +
+ ", constant does not fit " + TypeToIntervalString<T>());
+}
+template<>
+inline CheckedError atot<Offset<void>>(const char *s, Parser &parser,
+ Offset<void> *val) {
+ (void)parser;
+ *val = Offset<void>(atoi(s));
+ return NoError();
+}
+
+std::string Namespace::GetFullyQualifiedName(const std::string &name,
+ size_t max_components) const {
+ // Early exit if we don't have a defined namespace.
+ if (components.empty() || !max_components) { return name; }
+ std::string stream_str;
+ for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
+ stream_str += components[i];
+ stream_str += '.';
+ }
+ if (!stream_str.empty()) stream_str.pop_back();
+ if (name.length()) {
+ stream_str += '.';
+ stream_str += name;
+ }
+ return stream_str;
+}
+
+template<typename T>
+T *LookupTableByName(const SymbolTable<T> &table, const std::string &name,
+ const Namespace &current_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
+#define FLATBUFFERS_GEN_TOKENS(TD) \
+ TD(Eof, 256, "end of file") \
+ TD(StringConstant, 257, "string constant") \
+ TD(IntegerConstant, 258, "integer constant") \
+ TD(FloatConstant, 259, "float constant") \
+ TD(Identifier, 260, "identifier")
+#ifdef __GNUC__
+__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
+#endif
+enum {
+ #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
+ FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
+ #undef FLATBUFFERS_TOKEN
+};
+
+static std::string TokenToString(int t) {
+ static const char * const tokens[] = {
+ #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
+ FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
+ #undef FLATBUFFERS_TOKEN
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \
+ IDLTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ if (t < 256) { // A single ascii char token.
+ std::string s;
+ s.append(1, static_cast<char>(t));
+ return s;
+ } else { // Other tokens.
+ return tokens[t - 256];
+ }
+}
+// clang-format on
+
+std::string Parser::TokenToStringId(int t) const {
+ return t == kTokenIdentifier ? attribute_ : TokenToString(t);
+}
+
+// Parses exactly nibbles worth of hex digits into a number, or error.
+CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
+ FLATBUFFERS_ASSERT(nibbles > 0);
+ for (int i = 0; i < nibbles; i++)
+ if (!is_xdigit(cursor_[i]))
+ return Error("escape code must be followed by " + NumToString(nibbles) +
+ " hex digits");
+ std::string target(cursor_, cursor_ + nibbles);
+ *val = StringToUInt(target.c_str(), 16);
+ cursor_ += nibbles;
+ return NoError();
+}
+
+CheckedError Parser::SkipByteOrderMark() {
+ if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError();
+ cursor_++;
+ if (static_cast<unsigned char>(*cursor_) != 0xbb)
+ return Error("invalid utf-8 byte order mark");
+ cursor_++;
+ if (static_cast<unsigned char>(*cursor_) != 0xbf)
+ return Error("invalid utf-8 byte order mark");
+ cursor_++;
+ return NoError();
+}
+
+static inline bool IsIdentifierStart(char c) {
+ return is_alpha(c) || (c == '_');
+}
+
+CheckedError Parser::Next() {
+ doc_comment_.clear();
+ bool seen_newline = cursor_ == source_;
+ attribute_.clear();
+ attr_is_trivial_ascii_string_ = true;
+ for (;;) {
+ char c = *cursor_++;
+ token_ = c;
+ switch (c) {
+ case '\0':
+ cursor_--;
+ token_ = kTokenEof;
+ return NoError();
+ case ' ':
+ case '\r':
+ case '\t': break;
+ case '\n':
+ MarkNewLine();
+ seen_newline = true;
+ break;
+ case '{':
+ case '}':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case ',':
+ case ':':
+ case ';':
+ case '=': return NoError();
+ case '\"':
+ case '\'': {
+ int unicode_high_surrogate = -1;
+
+ while (*cursor_ != c) {
+ if (*cursor_ < ' ' && static_cast<signed char>(*cursor_) >= 0)
+ return Error("illegal character in string constant");
+ if (*cursor_ == '\\') {
+ attr_is_trivial_ascii_string_ = false; // has escape sequence
+ cursor_++;
+ if (unicode_high_surrogate != -1 && *cursor_ != 'u') {
+ return Error(
+ "illegal Unicode sequence (unpaired high surrogate)");
+ }
+ switch (*cursor_) {
+ case 'n':
+ attribute_ += '\n';
+ cursor_++;
+ break;
+ case 't':
+ attribute_ += '\t';
+ cursor_++;
+ break;
+ case 'r':
+ attribute_ += '\r';
+ cursor_++;
+ break;
+ case 'b':
+ attribute_ += '\b';
+ cursor_++;
+ break;
+ case 'f':
+ attribute_ += '\f';
+ cursor_++;
+ break;
+ case '\"':
+ attribute_ += '\"';
+ cursor_++;
+ break;
+ case '\'':
+ attribute_ += '\'';
+ cursor_++;
+ break;
+ case '\\':
+ attribute_ += '\\';
+ cursor_++;
+ break;
+ case '/':
+ attribute_ += '/';
+ cursor_++;
+ break;
+ case 'x': { // Not in the JSON standard
+ cursor_++;
+ uint64_t val;
+ ECHECK(ParseHexNum(2, &val));
+ attribute_ += static_cast<char>(val);
+ break;
+ }
+ case 'u': {
+ cursor_++;
+ uint64_t val;
+ ECHECK(ParseHexNum(4, &val));
+ if (val >= 0xD800 && val <= 0xDBFF) {
+ if (unicode_high_surrogate != -1) {
+ return Error(
+ "illegal Unicode sequence (multiple high surrogates)");
+ } else {
+ unicode_high_surrogate = static_cast<int>(val);
+ }
+ } else if (val >= 0xDC00 && val <= 0xDFFF) {
+ if (unicode_high_surrogate == -1) {
+ return Error(
+ "illegal Unicode sequence (unpaired low surrogate)");
+ } else {
+ int code_point = 0x10000 +
+ ((unicode_high_surrogate & 0x03FF) << 10) +
+ (val & 0x03FF);
+ ToUTF8(code_point, &attribute_);
+ unicode_high_surrogate = -1;
+ }
+ } else {
+ if (unicode_high_surrogate != -1) {
+ return Error(
+ "illegal Unicode sequence (unpaired high surrogate)");
+ }
+ ToUTF8(static_cast<int>(val), &attribute_);
+ }
+ break;
+ }
+ default: return Error("unknown escape code in string constant");
+ }
+ } else { // printable chars + UTF-8 bytes
+ if (unicode_high_surrogate != -1) {
+ return Error(
+ "illegal Unicode sequence (unpaired high surrogate)");
+ }
+ // reset if non-printable
+ attr_is_trivial_ascii_string_ &=
+ check_ascii_range(*cursor_, ' ', '~');
+
+ attribute_ += *cursor_++;
+ }
+ }
+ if (unicode_high_surrogate != -1) {
+ return Error("illegal Unicode sequence (unpaired high surrogate)");
+ }
+ cursor_++;
+ if (!attr_is_trivial_ascii_string_ && !opts.allow_non_utf8 &&
+ !ValidateUTF8(attribute_)) {
+ return Error("illegal UTF-8 sequence");
+ }
+ token_ = kTokenStringConstant;
+ return NoError();
+ }
+ case '/':
+ if (*cursor_ == '/') {
+ const char *start = ++cursor_;
+ while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++;
+ if (*start == '/') { // documentation comment
+ if (!seen_newline)
+ return Error(
+ "a documentation comment should be on a line on its own");
+ doc_comment_.push_back(std::string(start + 1, cursor_));
+ }
+ break;
+ } else if (*cursor_ == '*') {
+ cursor_++;
+ // TODO: make nested.
+ while (*cursor_ != '*' || cursor_[1] != '/') {
+ if (*cursor_ == '\n') MarkNewLine();
+ if (!*cursor_) return Error("end of file in comment");
+ cursor_++;
+ }
+ cursor_ += 2;
+ break;
+ }
+ FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ default:
+ 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_ = 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();
+ }
+
+ auto dot_lvl =
+ (c == '.') ? 0 : 1; // dot_lvl==0 <=> exactly one '.' seen
+ if (!dot_lvl && !is_digit(*cursor_)) return NoError(); // enum?
+ // Parser accepts hexadecimal-floating-literal (see C++ 5.13.4).
+ if (is_digit(c) || has_sign || !dot_lvl) {
+ const auto start = cursor_ - 1;
+ auto start_digits = !is_digit(c) ? cursor_ : cursor_ - 1;
+ if (!is_digit(c) && is_digit(*cursor_)) {
+ start_digits = cursor_; // see digit in cursor_ position
+ c = *cursor_++;
+ }
+ // hex-float can't begind with '.'
+ auto use_hex = dot_lvl && (c == '0') && is_alpha_char(*cursor_, 'X');
+ if (use_hex) start_digits = ++cursor_; // '0x' is the prefix, skip it
+ // Read an integer number or mantisa of float-point number.
+ do {
+ if (use_hex) {
+ while (is_xdigit(*cursor_)) cursor_++;
+ } else {
+ while (is_digit(*cursor_)) cursor_++;
+ }
+ } while ((*cursor_ == '.') && (++cursor_) && (--dot_lvl >= 0));
+ // Exponent of float-point number.
+ if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
+ // The exponent suffix of hexadecimal float number is mandatory.
+ if (use_hex && !dot_lvl) start_digits = cursor_;
+ if ((use_hex && is_alpha_char(*cursor_, 'P')) ||
+ is_alpha_char(*cursor_, 'E')) {
+ dot_lvl = 0; // Emulate dot to signal about float-point number.
+ cursor_++;
+ if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
+ start_digits = cursor_; // the exponent-part has to have digits
+ // Exponent is decimal integer number
+ while (is_digit(*cursor_)) cursor_++;
+ if (*cursor_ == '.') {
+ cursor_++; // If see a dot treat it as part of invalid number.
+ dot_lvl = -1; // Fall thru to Error().
+ }
+ }
+ }
+ // Finalize.
+ if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
+ attribute_.append(start, cursor_);
+ token_ = dot_lvl ? kTokenIntegerConstant : kTokenFloatConstant;
+ return NoError();
+ } else {
+ return Error("invalid number: " + std::string(start, cursor_));
+ }
+ }
+ std::string ch;
+ ch = c;
+ if (false == check_ascii_range(c, ' ', '~'))
+ ch = "code: " + NumToString(c);
+ return Error("illegal character: " + ch);
+ }
+ }
+}
+
+// Check if a given token is next.
+bool Parser::Is(int t) const { return t == token_; }
+
+bool Parser::IsIdent(const char *id) const {
+ return token_ == kTokenIdentifier && attribute_ == id;
+}
+
+// Expect a given token to be next, consume it, or error if not present.
+CheckedError Parser::Expect(int t) {
+ if (t != token_) {
+ return Error("expecting: " + TokenToString(t) +
+ " instead got: " + TokenToStringId(token_));
+ }
+ NEXT();
+ return NoError();
+}
+
+CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) {
+ while (Is('.')) {
+ NEXT();
+ *id += ".";
+ *id += attribute_;
+ if (last) *last = attribute_;
+ EXPECT(kTokenIdentifier);
+ }
+ return NoError();
+}
+
+EnumDef *Parser::LookupEnum(const std::string &id) {
+ // Search thru parent namespaces.
+ return LookupTableByName(enums_, id, *current_namespace_, 0);
+}
+
+StructDef *Parser::LookupStruct(const std::string &id) const {
+ auto sd = structs_.Lookup(id);
+ if (sd) sd->refcount++;
+ 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);
+ ECHECK(ParseNamespacing(&id, nullptr));
+ auto enum_def = LookupEnum(id);
+ if (enum_def) {
+ type = enum_def->underlying_type;
+ if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
+ } else {
+ type.base_type = BASE_TYPE_STRUCT;
+ type.struct_def = LookupCreateStruct(id);
+ }
+ return NoError();
+}
+
+// Parse any IDL type.
+CheckedError Parser::ParseType(Type &type) {
+ if (token_ == kTokenIdentifier) {
+ if (IsIdent("bool")) {
+ type.base_type = BASE_TYPE_BOOL;
+ NEXT();
+ } else if (IsIdent("byte") || IsIdent("int8")) {
+ type.base_type = BASE_TYPE_CHAR;
+ NEXT();
+ } else if (IsIdent("ubyte") || IsIdent("uint8")) {
+ type.base_type = BASE_TYPE_UCHAR;
+ NEXT();
+ } else if (IsIdent("short") || IsIdent("int16")) {
+ type.base_type = BASE_TYPE_SHORT;
+ NEXT();
+ } else if (IsIdent("ushort") || IsIdent("uint16")) {
+ type.base_type = BASE_TYPE_USHORT;
+ NEXT();
+ } else if (IsIdent("int") || IsIdent("int32")) {
+ type.base_type = BASE_TYPE_INT;
+ NEXT();
+ } else if (IsIdent("uint") || IsIdent("uint32")) {
+ type.base_type = BASE_TYPE_UINT;
+ NEXT();
+ } else if (IsIdent("long") || IsIdent("int64")) {
+ type.base_type = BASE_TYPE_LONG;
+ NEXT();
+ } else if (IsIdent("ulong") || IsIdent("uint64")) {
+ type.base_type = BASE_TYPE_ULONG;
+ NEXT();
+ } else if (IsIdent("float") || IsIdent("float32")) {
+ type.base_type = BASE_TYPE_FLOAT;
+ NEXT();
+ } else if (IsIdent("double") || IsIdent("float64")) {
+ type.base_type = BASE_TYPE_DOUBLE;
+ NEXT();
+ } else if (IsIdent("string")) {
+ type.base_type = BASE_TYPE_STRING;
+ NEXT();
+ } else {
+ ECHECK(ParseTypeIdent(type));
+ }
+ } else if (token_ == '[') {
+ ParseDepthGuard depth_guard(this);
+ ECHECK(depth_guard.Check());
+ NEXT();
+ Type 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.
+ return Error("nested vector types not supported (wrap in table first)");
+ }
+ if (token_ == ':') {
+ NEXT();
+ if (token_ != kTokenIntegerConstant) {
+ return Error("length of fixed-length array must be an integer value");
+ }
+ uint16_t fixed_length = 0;
+ bool check = StringToNumber(attribute_.c_str(), &fixed_length);
+ if (!check || fixed_length < 1) {
+ return Error(
+ "length of fixed-length array must be positive and fit to "
+ "uint16_t type");
+ }
+ type = Type(BASE_TYPE_ARRAY, subtype.struct_def, subtype.enum_def,
+ fixed_length);
+ NEXT();
+ } else {
+ type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
+ }
+ type.element = subtype.base_type;
+ EXPECT(']');
+ } else {
+ return Error("illegal type syntax");
+ }
+ return NoError();
+}
+
+CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
+ const Type &type, FieldDef **dest) {
+ auto &field = *new FieldDef();
+ field.value.offset =
+ FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
+ field.name = name;
+ field.file = struct_def.file;
+ field.value.type = type;
+ if (struct_def.fixed) { // statically compute the field offset
+ auto size = InlineSize(type);
+ auto alignment = InlineAlignment(type);
+ // structs_ need to have a predictable format, so we need to align to
+ // the largest scalar
+ struct_def.minalign = std::max(struct_def.minalign, alignment);
+ struct_def.PadLastField(alignment);
+ field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
+ struct_def.bytesize += size;
+ }
+ if (struct_def.fields.Add(name, &field))
+ return Error("field already exists: " + name);
+ *dest = &field;
+ return NoError();
+}
+
+CheckedError Parser::ParseField(StructDef &struct_def) {
+ std::string name = attribute_;
+
+ if (LookupCreateStruct(name, false, false))
+ return Error("field name can not be the same as table/struct name");
+
+ if (!IsLowerSnakeCase(name)) {
+ Warning("field names should be lowercase snake_case, got: " + name);
+ }
+
+ std::vector<std::string> dc = doc_comment_;
+ EXPECT(kTokenIdentifier);
+ EXPECT(':');
+ Type type;
+ ECHECK(ParseType(type));
+
+ if (struct_def.fixed) {
+ auto valid = IsScalar(type.base_type) || IsStruct(type);
+ if (!valid && IsArray(type)) {
+ const auto &elem_type = type.VectorType();
+ valid |= IsScalar(elem_type.base_type) || IsStruct(elem_type);
+ }
+ if (!valid)
+ return Error("structs may contain only scalar or struct fields");
+ }
+
+ if (!struct_def.fixed && IsArray(type))
+ return Error("fixed-length array in table must be wrapped in struct");
+
+ if (IsArray(type)) {
+ advanced_features_ |= reflection::AdvancedArrayFeatures;
+ if (!SupportsAdvancedArrayFeatures()) {
+ return Error(
+ "Arrays are not yet supported in all "
+ "the specified programming languages.");
+ }
+ }
+
+ FieldDef *typefield = nullptr;
+ if (type.base_type == BASE_TYPE_UNION) {
+ // For union fields, add a second auto-generated field to hold the type,
+ // with a special suffix.
+ ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
+ type.enum_def->underlying_type, &typefield));
+ } else if (IsVector(type) && type.element == BASE_TYPE_UNION) {
+ advanced_features_ |= reflection::AdvancedUnionFeatures;
+ // Only cpp, js and ts supports the union vector feature so far.
+ if (!SupportsAdvancedUnionFeatures()) {
+ return Error(
+ "Vectors of unions are not yet supported in at least one of "
+ "the specified programming languages.");
+ }
+ // For vector of union fields, add a second auto-generated vector field to
+ // hold the types, with a special suffix.
+ Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
+ union_vector.element = BASE_TYPE_UTYPE;
+ ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), union_vector,
+ &typefield));
+ }
+
+ FieldDef *field;
+ ECHECK(AddField(struct_def, name, type, &field));
+
+ if (token_ == '=') {
+ NEXT();
+ ECHECK(ParseSingleValue(&field->name, field->value, true));
+ if (IsStruct(type) || (struct_def.fixed && field->value.constant != "0"))
+ return Error(
+ "default values are not supported for struct fields, table fields, "
+ "or in structs.");
+ if (IsString(type) || IsVector(type)) {
+ advanced_features_ |= reflection::DefaultVectorsAndStrings;
+ if (field->value.constant != "0" && field->value.constant != "null" &&
+ !SupportsDefaultVectorsAndStrings()) {
+ return Error(
+ "Default values for strings and vectors are not supported in one "
+ "of the specified programming languages");
+ }
+ }
+
+ if (IsVector(type) && field->value.constant != "0" &&
+ field->value.constant != "[]") {
+ return Error("The only supported default for vectors is `[]`.");
+ }
+ }
+
+ // Append .0 if the value has not it (skip hex and scientific floats).
+ // This suffix needed for generated C++ code.
+ if (IsFloat(type.base_type)) {
+ auto &text = field->value.constant;
+ FLATBUFFERS_ASSERT(false == text.empty());
+ auto s = text.c_str();
+ while (*s == ' ') s++;
+ if (*s == '-' || *s == '+') s++;
+ // 1) A float constants (nan, inf, pi, etc) is a kind of identifier.
+ // 2) A float number needn't ".0" at the end if it has exponent.
+ if ((false == IsIdentifierStart(*s)) &&
+ (std::string::npos == field->value.constant.find_first_of(".eEpP"))) {
+ field->value.constant += ".0";
+ }
+ }
+
+ field->doc_comment = dc;
+ ECHECK(ParseMetaData(&field->attributes));
+ field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
+ auto hash_name = field->attributes.Lookup("hash");
+ if (hash_name) {
+ switch ((IsVector(type)) ? type.element : type.base_type) {
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT: {
+ if (FindHashFunction16(hash_name->constant.c_str()) == nullptr)
+ return Error("Unknown hashing algorithm for 16 bit types: " +
+ hash_name->constant);
+ break;
+ }
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT: {
+ if (FindHashFunction32(hash_name->constant.c_str()) == nullptr)
+ return Error("Unknown hashing algorithm for 32 bit types: " +
+ hash_name->constant);
+ break;
+ }
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG: {
+ if (FindHashFunction64(hash_name->constant.c_str()) == nullptr)
+ return Error("Unknown hashing algorithm for 64 bit types: " +
+ hash_name->constant);
+ break;
+ }
+ default:
+ return Error(
+ "only short, ushort, int, uint, long and ulong data types support "
+ "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_ |= reflection::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 the 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)
+ return Error("cpp_type can only be used with a hashed field");
+ /// forcing cpp_ptr_type to 'naked' if unset
+ auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type");
+ if (!cpp_ptr_type) {
+ auto val = new Value();
+ val->type = cpp_type->type;
+ val->constant = "naked";
+ field->attributes.Add("cpp_ptr_type", val);
+ }
+ }
+
+ 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");
+
+ auto field_native_custom_alloc =
+ field->attributes.Lookup("native_custom_alloc");
+ if (field_native_custom_alloc)
+ return Error(
+ "native_custom_alloc can only be used with a table or struct "
+ "definition");
+
+ field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
+ if (field->native_inline && !IsStruct(field->value.type))
+ return Error("native_inline can only be defined on structs");
+
+ auto nested = field->attributes.Lookup("nested_flatbuffer");
+ if (nested) {
+ if (nested->type.base_type != BASE_TYPE_STRING)
+ return Error(
+ "nested_flatbuffer attribute must be a string (the root type)");
+ if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR)
+ return Error(
+ "nested_flatbuffer attribute may only apply to a vector of ubyte");
+ // This will cause an error if the root type of the nested flatbuffer
+ // wasn't defined elsewhere.
+ field->nested_flatbuffer = LookupCreateStruct(nested->constant);
+ }
+
+ if (field->attributes.Lookup("flexbuffer")) {
+ field->flexbuffer = true;
+ uses_flexbuffers_ = true;
+ if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR)
+ return Error("flexbuffer attribute may only apply to a vector of ubyte");
+ }
+
+ if (typefield) {
+ if (!IsScalar(typefield->value.type.base_type)) {
+ // this is a union vector field
+ 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) {
+ 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
+ if (field->deprecated) { typefield->deprecated = true; }
+ }
+
+ EXPECT(';');
+ return NoError();
+}
+
+CheckedError Parser::ParseString(Value &val, bool use_string_pooling) {
+ auto s = attribute_;
+ EXPECT(kTokenStringConstant);
+ if (use_string_pooling) {
+ val.constant = NumToString(builder_.CreateSharedString(s).o);
+ } else {
+ val.constant = NumToString(builder_.CreateString(s).o);
+ }
+ return NoError();
+}
+
+CheckedError Parser::ParseComma() {
+ if (!opts.protobuf_ascii_alike) EXPECT(',');
+ return NoError();
+}
+
+CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
+ size_t parent_fieldn,
+ const StructDef *parent_struct_def,
+ uoffset_t count, bool inside_vector) {
+ switch (val.type.base_type) {
+ case BASE_TYPE_UNION: {
+ FLATBUFFERS_ASSERT(field);
+ std::string constant;
+ Vector<uint8_t> *vector_of_union_types = nullptr;
+ // Find corresponding type field we may have already parsed.
+ for (auto elem = field_stack_.rbegin() + count;
+ elem != field_stack_.rbegin() + parent_fieldn + count; ++elem) {
+ auto &type = elem->second->value.type;
+ if (type.enum_def == val.type.enum_def) {
+ if (inside_vector) {
+ if (IsVector(type) && type.element == BASE_TYPE_UTYPE) {
+ // Vector of union type field.
+ uoffset_t offset;
+ ECHECK(atot(elem->first.constant.c_str(), *this, &offset));
+ vector_of_union_types = reinterpret_cast<Vector<uint8_t> *>(
+ builder_.GetCurrentBufferPointer() + builder_.GetSize() -
+ offset);
+ break;
+ }
+ } else {
+ if (type.base_type == BASE_TYPE_UTYPE) {
+ // Union type field.
+ constant = elem->first.constant;
+ break;
+ }
+ }
+ }
+ }
+ if (constant.empty() && !inside_vector) {
+ // We haven't seen the type field yet. Sadly a lot of JSON writers
+ // output these in alphabetical order, meaning it comes after this
+ // value. So we scan past the value to find it, then come back here.
+ // We currently don't do this for vectors of unions because the
+ // scanning/serialization logic would get very complicated.
+ auto type_name = field->name + UnionTypeFieldSuffix();
+ FLATBUFFERS_ASSERT(parent_struct_def);
+ auto type_field = parent_struct_def->fields.Lookup(type_name);
+ FLATBUFFERS_ASSERT(type_field); // Guaranteed by ParseField().
+ // Remember where we are in the source file, so we can come back here.
+ auto backup = *static_cast<ParserState *>(this);
+ ECHECK(SkipAnyJsonValue()); // The table.
+ ECHECK(ParseComma());
+ auto next_name = attribute_;
+ if (Is(kTokenStringConstant)) {
+ NEXT();
+ } else {
+ EXPECT(kTokenIdentifier);
+ }
+ 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;
+ // Got the information we needed, now rewind:
+ *static_cast<ParserState *>(this) = backup;
+ }
+ }
+ if (constant.empty() && !vector_of_union_types) {
+ return Error("missing type field for this union value: " + field->name);
+ }
+ uint8_t enum_idx;
+ if (vector_of_union_types) {
+ enum_idx = vector_of_union_types->Get(count);
+ } else {
+ ECHECK(atot(constant.c_str(), *this, &enum_idx));
+ }
+ auto enum_val = val.type.enum_def->ReverseLookup(enum_idx, true);
+ if (!enum_val) return Error("illegal type id for: " + field->name);
+ if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
+ ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
+ nullptr));
+ if (enum_val->union_type.struct_def->fixed) {
+ // All BASE_TYPE_UNION values are offsets, so turn this into one.
+ SerializeStruct(*enum_val->union_type.struct_def, val);
+ builder_.ClearOffsets();
+ val.constant = NumToString(builder_.GetSize());
+ }
+ } else if (IsString(enum_val->union_type)) {
+ ECHECK(ParseString(val, field->shared));
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ break;
+ }
+ case BASE_TYPE_STRUCT:
+ ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
+ break;
+ case BASE_TYPE_STRING: {
+ ECHECK(ParseString(val, field->shared));
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ uoffset_t off;
+ ECHECK(ParseVector(val.type.VectorType(), &off, field, parent_fieldn));
+ val.constant = NumToString(off);
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ ECHECK(ParseArray(val));
+ break;
+ }
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG: {
+ if (field && field->attributes.Lookup("hash") &&
+ (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
+ ECHECK(ParseHash(val, field));
+ } else {
+ ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
+ }
+ break;
+ }
+ default:
+ ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
+ break;
+ }
+ return NoError();
+}
+
+void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
+ SerializeStruct(builder_, struct_def, val);
+}
+
+void Parser::SerializeStruct(FlatBufferBuilder &builder,
+ const StructDef &struct_def, const Value &val) {
+ FLATBUFFERS_ASSERT(val.constant.length() == struct_def.bytesize);
+ builder.Align(struct_def.minalign);
+ builder.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()),
+ struct_def.bytesize);
+ builder.AddStructOffset(val.offset, builder.GetSize());
+}
+
+template<typename F>
+CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
+ const StructDef *struct_def, F body) {
+ // We allow tables both as JSON object{ .. } with field names
+ // or vector[..] with all fields in order
+ char terminator = '}';
+ bool is_nested_vector = struct_def && Is('[');
+ if (is_nested_vector) {
+ NEXT();
+ terminator = ']';
+ } else {
+ EXPECT('{');
+ }
+ for (;;) {
+ if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
+ std::string name;
+ if (is_nested_vector) {
+ if (fieldn >= struct_def->fields.vec.size()) {
+ return Error("too many unnamed fields in nested array");
+ }
+ name = struct_def->fields.vec[fieldn]->name;
+ } else {
+ name = attribute_;
+ if (Is(kTokenStringConstant)) {
+ NEXT();
+ } else {
+ EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
+ }
+ if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
+ }
+ ECHECK(body(name, fieldn, struct_def));
+ if (Is(terminator)) break;
+ ECHECK(ParseComma());
+ }
+ NEXT();
+ if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
+ return Error("wrong number of unnamed fields in table vector");
+ }
+ return NoError();
+}
+
+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,
+ [&](const std::string &name, size_t &fieldn,
+ const StructDef *struct_def_inner) -> CheckedError {
+ if (name == "$schema") {
+ ECHECK(Expect(kTokenStringConstant));
+ return NoError();
+ }
+ auto field = struct_def_inner->fields.Lookup(name);
+ if (!field) {
+ if (!opts.skip_unexpected_fields_in_json) {
+ return Error("unknown field: " + name);
+ } else {
+ ECHECK(SkipAnyJsonValue());
+ }
+ } else {
+ if (IsIdent("null") && !IsScalar(field->value.type.base_type)) {
+ ECHECK(Next()); // Ignore this field.
+ } else {
+ Value val = field->value;
+ if (field->flexbuffer) {
+ flexbuffers::Builder builder(1024,
+ flexbuffers::BUILDER_FLAG_SHARE_ALL);
+ ECHECK(ParseFlexBufferValue(&builder));
+ builder.Finish();
+ // Force alignment for nested flexbuffer
+ builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t),
+ sizeof(largest_scalar_t));
+ auto off = builder_.CreateVector(builder.GetBuffer());
+ val.constant = NumToString(off.o);
+ } else if (field->nested_flatbuffer) {
+ ECHECK(
+ ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
+ } else {
+ 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
+ // immediately.
+ auto elem = field_stack_.rbegin();
+ for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
+ auto existing_field = elem->second;
+ if (existing_field == field)
+ return Error("field set more than once: " + field->name);
+ if (existing_field->value.offset < field->value.offset) break;
+ }
+ // Note: elem points to before the insertion point, thus .base()
+ // points to the correct spot.
+ field_stack_.insert(elem.base(), std::make_pair(val, field));
+ fieldn++;
+ }
+ }
+ return NoError();
+ });
+ ECHECK(err);
+
+ // Check if all required fields are parsed.
+ 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->IsRequired()) { continue; }
+ bool found = false;
+ for (auto pf_it = field_stack_.end() - fieldn_outer;
+ pf_it != field_stack_.end(); ++pf_it) {
+ auto parsed_field = pf_it->second;
+ if (parsed_field == required_field) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return Error("required field is missing: " + required_field->name +
+ " in " + struct_def.name);
+ }
+ }
+
+ if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size())
+ return Error("struct: wrong number of initializers: " + struct_def.name);
+
+ auto start = struct_def.fixed ? builder_.StartStruct(struct_def.minalign)
+ : builder_.StartTable();
+
+ for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; size;
+ size /= 2) {
+ // Go through elements in reverse, since we're building the data backwards.
+ for (auto it = field_stack_.rbegin();
+ it != field_stack_.rbegin() + fieldn_outer; ++it) {
+ auto &field_value = it->first;
+ auto field = it->second;
+ if (!struct_def.sortbysize ||
+ size == SizeOf(field_value.type.base_type)) {
+ switch (field_value.type.base_type) {
+ // clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_ ## ENUM: \
+ builder_.Pad(field->padding); \
+ if (struct_def.fixed) { \
+ CTYPE val; \
+ ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
+ builder_.PushElement(val); \
+ } else { \
+ CTYPE val, valdef; \
+ ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
+ ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \
+ builder_.AddElement(field_value.offset, val, valdef); \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_ ## ENUM: \
+ builder_.Pad(field->padding); \
+ if (IsStruct(field->value.type)) { \
+ SerializeStruct(*field->value.type.struct_def, field_value); \
+ } else { \
+ CTYPE val; \
+ ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
+ builder_.AddOffset(field_value.offset, val); \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ case BASE_TYPE_ARRAY:
+ builder_.Pad(field->padding);
+ builder_.PushBytes(
+ reinterpret_cast<const uint8_t*>(field_value.constant.c_str()),
+ InlineSize(field_value.type));
+ break;
+ // clang-format on
+ }
+ }
+ }
+ }
+ for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back();
+
+ if (struct_def.fixed) {
+ builder_.ClearOffsets();
+ builder_.EndStruct();
+ FLATBUFFERS_ASSERT(value);
+ // Temporarily store this struct in the value string, since it is to
+ // be serialized in-place elsewhere.
+ value->assign(
+ reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()),
+ struct_def.bytesize);
+ builder_.PopBytes(struct_def.bytesize);
+ FLATBUFFERS_ASSERT(!ovalue);
+ } else {
+ auto val = builder_.EndTable(start);
+ if (ovalue) *ovalue = val;
+ if (value) *value = NumToString(val);
+ }
+ return NoError();
+}
+
+template<typename F>
+CheckedError Parser::ParseVectorDelimiters(uoffset_t &count, F body) {
+ EXPECT('[');
+ for (;;) {
+ if ((!opts.strict_json || !count) && Is(']')) break;
+ ECHECK(body(count));
+ count++;
+ if (Is(']')) break;
+ ECHECK(ParseComma());
+ }
+ NEXT();
+ return NoError();
+}
+
+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
+ 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) {
+ if (end - begin <= static_cast<ptrdiff_t>(width)) return;
+ auto l = begin + width;
+ auto r = end;
+ while (l < r) {
+ if (comparator(begin, l)) {
+ r -= width;
+ swapper(l, r);
+ } else {
+ l += width;
+ }
+ }
+ l -= width;
+ swapper(begin, l);
+ SimpleQsort(begin, l, width, comparator, swapper);
+ 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(ParseAnyValue(val, field, fieldn, nullptr, count, true));
+ field_stack_.push_back(std::make_pair(val, nullptr));
+ return NoError();
+ });
+ ECHECK(err);
+
+ const size_t len = count * InlineSize(type) / InlineAlignment(type);
+ const size_t elemsize = InlineAlignment(type);
+ 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
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE,...) \
+ case BASE_TYPE_ ## ENUM: \
+ if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
+ else { \
+ CTYPE elem; \
+ ECHECK(atot(val.constant.c_str(), *this, &elem)); \
+ builder_.PushElement(elem); \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+ }
+ field_stack_.pop_back();
+ }
+
+ builder_.ClearOffsets();
+ *ovalue = builder_.EndVector(count);
+
+ if (type.base_type == BASE_TYPE_STRUCT && type.struct_def->has_key) {
+ // We should sort this vector. Find the key first.
+ const FieldDef *key = nullptr;
+ for (auto it = type.struct_def->fields.vec.begin();
+ it != type.struct_def->fields.vec.end(); ++it) {
+ if ((*it)->key) {
+ key = (*it);
+ break;
+ }
+ }
+ FLATBUFFERS_ASSERT(key);
+ // Now sort it.
+ // We can't use std::sort because for structs the size is not known at
+ // compile time, and for tables our iterators dereference offsets, so can't
+ // be used to swap elements.
+ // And we can't use C qsort either, since that would force use to use
+ // globals, making parsing thread-unsafe.
+ // So for now, we use SimpleQsort above.
+ // TODO: replace with something better, preferably not recursive.
+
+ 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,
+ [offset, key](const uint8_t *a, const uint8_t *b) -> bool {
+ return CompareSerializedScalars(a + offset, b + offset, *key);
+ },
+ [struct_size](uint8_t *a, uint8_t *b) {
+ // FIXME: faster?
+ for (size_t i = 0; i < struct_size; i++) { std::swap(a[i], b[i]); }
+ });
+ } else {
+ auto v = reinterpret_cast<Vector<Offset<Table>> *>(
+ builder_.GetCurrentBufferPointer());
+ // 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.
+ 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();
+}
+
+CheckedError Parser::ParseArray(Value &array) {
+ std::vector<Value> stack;
+ FlatBufferBuilder builder;
+ const auto &type = array.type.VectorType();
+ auto length = array.type.fixed_length;
+ uoffset_t count = 0;
+ auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
+ vector_emplace_back(&stack, Value());
+ auto &val = stack.back();
+ val.type = type;
+ if (IsStruct(type)) {
+ ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
+ } else {
+ ECHECK(ParseSingleValue(nullptr, val, false));
+ }
+ return NoError();
+ });
+ ECHECK(err);
+ if (length != count) return Error("Fixed-length array size is incorrect.");
+
+ for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
+ auto &val = *it;
+ // clang-format off
+ switch (val.type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_ ## ENUM: \
+ if (IsStruct(val.type)) { \
+ SerializeStruct(builder, *val.type.struct_def, val); \
+ } else { \
+ CTYPE elem; \
+ ECHECK(atot(val.constant.c_str(), *this, &elem)); \
+ builder.PushElement(elem); \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ // clang-format on
+ }
+
+ array.constant.assign(
+ reinterpret_cast<const char *>(builder.GetCurrentBufferPointer()),
+ InlineSize(array.type));
+ return NoError();
+}
+
+CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field,
+ 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));
+ } else {
+ auto cursor_at_value_begin = cursor_;
+ ECHECK(SkipAnyJsonValue());
+ std::string substring(cursor_at_value_begin - 1, cursor_ - 1);
+
+ // Create and initialize new parser
+ Parser nested_parser;
+ FLATBUFFERS_ASSERT(field->nested_flatbuffer);
+ nested_parser.root_struct_def_ = field->nested_flatbuffer;
+ 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);
+
+ // Clean nested_parser to avoid deleting the elements in
+ // the SymbolTables on destruction
+ nested_parser.enums_.dict.clear();
+ nested_parser.enums_.vec.clear();
+
+ if (!ok) { ECHECK(Error(nested_parser.error_)); }
+ // Force alignment for nested flatbuffer
+ builder_.ForceVectorAlignment(
+ nested_parser.builder_.GetSize(), sizeof(uint8_t),
+ nested_parser.builder_.GetBufferMinAlignment());
+
+ auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(),
+ nested_parser.builder_.GetSize());
+ val.constant = NumToString(off.o);
+ }
+ return NoError();
+}
+
+CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) {
+ if (Is('(')) {
+ NEXT();
+ for (;;) {
+ auto name = attribute_;
+ if (false == (Is(kTokenIdentifier) || Is(kTokenStringConstant)))
+ return Error("attribute name must be either identifier or string: " +
+ name);
+ if (known_attributes_.find(name) == known_attributes_.end())
+ return Error("user define attributes must be declared before use: " +
+ name);
+ NEXT();
+ auto e = new Value();
+ if (attributes->Add(name, e)) Warning("attribute already found: " + name);
+ if (Is(':')) {
+ NEXT();
+ ECHECK(ParseSingleValue(&name, *e, true));
+ }
+ if (Is(')')) {
+ NEXT();
+ break;
+ }
+ EXPECT(',');
+ }
+ }
+ return NoError();
+}
+
+CheckedError Parser::ParseEnumFromString(const Type &type,
+ std::string *result) {
+ const auto base_type =
+ type.enum_def ? type.enum_def->underlying_type.base_type : type.base_type;
+ if (!IsInteger(base_type)) return Error("not a valid value for this field");
+ uint64_t u64 = 0;
+ for (size_t pos = 0; pos != std::string::npos;) {
+ const auto delim = attribute_.find_first_of(' ', pos);
+ const auto last = (std::string::npos == delim);
+ auto word = attribute_.substr(pos, !last ? delim - pos : std::string::npos);
+ pos = !last ? delim + 1 : std::string::npos;
+ const EnumVal *ev = nullptr;
+ if (type.enum_def) {
+ ev = type.enum_def->Lookup(word);
+ } else {
+ auto dot = word.find_first_of('.');
+ if (std::string::npos == dot)
+ return Error("enum values need to be qualified by an enum type");
+ auto enum_def_str = word.substr(0, dot);
+ const auto enum_def = LookupEnum(enum_def_str);
+ if (!enum_def) return Error("unknown enum: " + enum_def_str);
+ auto enum_val_str = word.substr(dot + 1);
+ ev = enum_def->Lookup(enum_val_str);
+ }
+ if (!ev) return Error("unknown enum value: " + word);
+ u64 |= ev->GetAsUInt64();
+ }
+ *result = IsUnsigned(base_type) ? NumToString(u64)
+ : NumToString(static_cast<int64_t>(u64));
+ return NoError();
+}
+
+CheckedError Parser::ParseHash(Value &e, FieldDef *field) {
+ FLATBUFFERS_ASSERT(field);
+ Value *hash_name = field->attributes.Lookup("hash");
+ switch (e.type.base_type) {
+ case BASE_TYPE_SHORT: {
+ auto hash = FindHashFunction16(hash_name->constant.c_str());
+ int16_t hashed_value = static_cast<int16_t>(hash(attribute_.c_str()));
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ case BASE_TYPE_USHORT: {
+ auto hash = FindHashFunction16(hash_name->constant.c_str());
+ uint16_t hashed_value = hash(attribute_.c_str());
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ case BASE_TYPE_INT: {
+ auto hash = FindHashFunction32(hash_name->constant.c_str());
+ int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ case BASE_TYPE_UINT: {
+ auto hash = FindHashFunction32(hash_name->constant.c_str());
+ uint32_t hashed_value = hash(attribute_.c_str());
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ case BASE_TYPE_LONG: {
+ auto hash = FindHashFunction64(hash_name->constant.c_str());
+ int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ case BASE_TYPE_ULONG: {
+ auto hash = FindHashFunction64(hash_name->constant.c_str());
+ uint64_t hashed_value = hash(attribute_.c_str());
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ NEXT();
+ return NoError();
+}
+
+CheckedError Parser::TokenError() {
+ return Error("cannot parse value starting with: " + TokenToStringId(token_));
+}
+
+// Re-pack helper (ParseSingleValue) to normalize defaults of scalars.
+template<typename T> inline void SingleValueRepack(Value &e, T val) {
+ // Remove leading zeros.
+ if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); }
+}
+#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
+// Normalize defaults NaN to unsigned quiet-NaN(0) if value was parsed from
+// hex-float literal.
+static inline void SingleValueRepack(Value &e, float val) {
+ if (val != val) e.constant = "nan";
+}
+static inline void SingleValueRepack(Value &e, double val) {
+ if (val != val) e.constant = "nan";
+}
+#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)) {
+ return Error(functionname + ": type of argument mismatch, expecting: " +
+ kTypeNames[BASE_TYPE_DOUBLE] +
+ ", found: " + kTypeNames[e.type.base_type] +
+ ", name: " + (name ? *name : "") + ", value: " + e.constant);
+ }
+ NEXT();
+ EXPECT('(');
+ ECHECK(ParseSingleValue(name, e, false));
+ EXPECT(')');
+ // calculate with double precision
+ double x, y = 0.0;
+ ECHECK(atot(e.constant.c_str(), *this, &x));
+ // clang-format off
+ auto func_match = false;
+ #define FLATBUFFERS_FN_DOUBLE(name, op) \
+ if (!func_match && functionname == name) { y = op; func_match = true; }
+ FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180);
+ FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180);
+ FLATBUFFERS_FN_DOUBLE("sin", sin(x));
+ FLATBUFFERS_FN_DOUBLE("cos", cos(x));
+ FLATBUFFERS_FN_DOUBLE("tan", tan(x));
+ FLATBUFFERS_FN_DOUBLE("asin", asin(x));
+ FLATBUFFERS_FN_DOUBLE("acos", acos(x));
+ FLATBUFFERS_FN_DOUBLE("atan", atan(x));
+ // TODO(wvo): add more useful conversion functions here.
+ #undef FLATBUFFERS_FN_DOUBLE
+ // clang-format on
+ if (true != func_match) {
+ return Error(std::string("Unknown conversion function: ") + functionname +
+ ", field name: " + (name ? *name : "") +
+ ", value: " + e.constant);
+ }
+ e.constant = NumToString(y);
+ return NoError();
+}
+
+CheckedError Parser::TryTypedValue(const std::string *name, int dtoken,
+ bool check, Value &e, BaseType req,
+ bool *destmatch) {
+ 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();
+ 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(size_t(0), size_t(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.
+ if (is_tok_ident && *cursor_ == '(') { return ParseFunction(name, e); }
+
+ // clang-format off
+ auto match = false;
+
+ #define IF_ECHECK_(force, dtoken, check, req) \
+ 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
+
+ if (is_tok_ident || is_tok_string) {
+ const auto kTokenStringOrIdent = token_;
+ // The string type is a most probable type, check it first.
+ TRY_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
+ BASE_TYPE_STRING);
+
+ // avoid escaped and non-ascii in the string
+ if (!match && is_tok_string && IsScalar(in_type) &&
+ !attr_is_trivial_ascii_string_) {
+ return Error(
+ std::string("type mismatch or invalid value, an initializer of "
+ "non-string field must be trivial ASCII string: type: ") +
+ kTypeNames[in_type] + ", name: " + (name ? *name : "") +
+ ", value: " + attribute_);
+ }
+
+ // A boolean as true/false. Boolean as Integer check below.
+ if (!match && IsBool(in_type)) {
+ auto is_true = attribute_ == "true";
+ if (is_true || attribute_ == "false") {
+ attribute_ = is_true ? "1" : "0";
+ // accepts both kTokenStringConstant and kTokenIdentifier
+ TRY_ECHECK(kTokenStringOrIdent, IsBool(in_type), BASE_TYPE_BOOL);
+ }
+ }
+ // Check for optional scalars.
+ if (!match && IsScalar(in_type) && attribute_ == "null") {
+ e.constant = "null";
+ NEXT();
+ match = true;
+ }
+ // Check if this could be a string/identifier enum value.
+ // Enum can have only true integer base type.
+ if (!match && IsInteger(in_type) && !IsBool(in_type) &&
+ IsIdentifierStart(*attribute_.c_str())) {
+ ECHECK(ParseEnumFromString(e.type, &e.constant));
+ NEXT();
+ match = true;
+ }
+ // Parse a float/integer number from the string.
+ // A "scalar-in-string" value needs extra checks.
+ if (!match && is_tok_string && IsScalar(in_type)) {
+ // Strip trailing whitespaces from attribute_.
+ auto last_non_ws = attribute_.find_last_not_of(' ');
+ if (std::string::npos != last_non_ws) attribute_.resize(last_non_ws + 1);
+ if (IsFloat(e.type.base_type)) {
+ // The functions strtod() and strtof() accept both 'nan' and
+ // 'nan(number)' literals. While 'nan(number)' is rejected by the parser
+ // as an unsupported function if is_tok_ident is true.
+ if (attribute_.find_last_of(')') != std::string::npos) {
+ return Error("invalid number: " + attribute_);
+ }
+ }
+ }
+ // Float numbers or nan, inf, pi, etc.
+ TRY_ECHECK(kTokenStringOrIdent, IsFloat(in_type), BASE_TYPE_FLOAT);
+ // An integer constant in string.
+ TRY_ECHECK(kTokenStringOrIdent, IsInteger(in_type), BASE_TYPE_INT);
+ // Unknown tokens will be interpreted as string type.
+ // An attribute value may be a scalar or string constant.
+ FORCE_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
+ BASE_TYPE_STRING);
+ } else {
+ // Try a float number.
+ TRY_ECHECK(kTokenFloatConstant, IsFloat(in_type), BASE_TYPE_FLOAT);
+ // 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_
+
+ if (!match) {
+ std::string msg;
+ msg += "Cannot assign token starting with '" + TokenToStringId(token_) +
+ "' to value of <" + std::string(kTypeNames[in_type]) + "> type.";
+ return Error(msg);
+ }
+ const auto match_type = e.type.base_type; // may differ from in_type
+ // The check_now flag must be true when parse a fbs-schema.
+ // This flag forces to check default scalar values or metadata of field.
+ // For JSON parser the flag should be false.
+ // If it is set for JSON each value will be checked twice (see ParseTable).
+ // Special case 'null' since atot can't handle that.
+ if (check_now && IsScalar(match_type) && e.constant != "null") {
+ // clang-format off
+ switch (match_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_ ## ENUM: {\
+ CTYPE val; \
+ ECHECK(atot(e.constant.c_str(), *this, &val)); \
+ SingleValueRepack(e, val); \
+ break; }
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ default: break;
+ }
+ // clang-format on
+ }
+ return NoError();
+}
+
+StructDef *Parser::LookupCreateStruct(const std::string &name,
+ bool create_if_new, bool definition) {
+ std::string qualified_name = current_namespace_->GetFullyQualifiedName(name);
+ // See if it exists pre-declared by an unqualified use.
+ auto struct_def = LookupStruct(name);
+ if (struct_def && struct_def->predecl) {
+ if (definition) {
+ // Make sure it has the current namespace, and is registered under its
+ // qualified name.
+ struct_def->defined_namespace = current_namespace_;
+ structs_.Move(name, qualified_name);
+ }
+ return struct_def;
+ }
+ // See if it exists pre-declared by an qualified use.
+ struct_def = LookupStruct(qualified_name);
+ if (struct_def && struct_def->predecl) {
+ if (definition) {
+ // Make sure it has the current namespace.
+ struct_def->defined_namespace = current_namespace_;
+ }
+ return struct_def;
+ }
+ if (!definition && !struct_def) {
+ struct_def = LookupStructThruParentNamespaces(name);
+ }
+ if (!struct_def && create_if_new) {
+ struct_def = new StructDef();
+ if (definition) {
+ structs_.Add(qualified_name, struct_def);
+ struct_def->name = name;
+ struct_def->defined_namespace = current_namespace_;
+ } else {
+ // Not a definition.
+ // Rather than failing, we create a "pre declared" StructDef, due to
+ // circular references, and check for errors at the end of parsing.
+ // It is defined in the current namespace, as the best guess what the
+ // final namespace will be.
+ structs_.Add(name, struct_def);
+ struct_def->name = name;
+ struct_def->defined_namespace = current_namespace_;
+ struct_def->original_location.reset(
+ new std::string(file_being_parsed_ + ":" + NumToString(line_)));
+ }
+ }
+ return struct_def;
+}
+
+const EnumVal *EnumDef::MinValue() const {
+ return vals.vec.empty() ? nullptr : vals.vec.front();
+}
+const EnumVal *EnumDef::MaxValue() const {
+ return vals.vec.empty() ? nullptr : vals.vec.back();
+}
+
+template<typename T> static uint64_t EnumDistanceImpl(T e1, T e2) {
+ if (e1 < e2) { std::swap(e1, e2); } // use std for scalars
+ // Signed overflow may occur, use unsigned calculation.
+ // The unsigned overflow is well-defined by C++ standard (modulo 2^n).
+ return static_cast<uint64_t>(e1) - static_cast<uint64_t>(e2);
+}
+
+uint64_t EnumDef::Distance(const EnumVal *v1, const EnumVal *v2) const {
+ return IsUInt64() ? EnumDistanceImpl(v1->GetAsUInt64(), v2->GetAsUInt64())
+ : EnumDistanceImpl(v1->GetAsInt64(), v2->GetAsInt64());
+}
+
+std::string EnumDef::AllFlags() const {
+ FLATBUFFERS_ASSERT(attributes.Lookup("bit_flags"));
+ uint64_t u64 = 0;
+ for (auto it = Vals().begin(); it != Vals().end(); ++it) {
+ u64 |= (*it)->GetAsUInt64();
+ }
+ return IsUInt64() ? NumToString(u64) : NumToString(static_cast<int64_t>(u64));
+}
+
+EnumVal *EnumDef::ReverseLookup(int64_t enum_idx,
+ bool skip_union_default) const {
+ auto skip_first = static_cast<int>(is_union && skip_union_default);
+ for (auto it = Vals().begin() + skip_first; it != Vals().end(); ++it) {
+ if ((*it)->GetAsInt64() == enum_idx) { return *it; }
+ }
+ return nullptr;
+}
+
+EnumVal *EnumDef::FindByValue(const std::string &constant) const {
+ int64_t i64;
+ auto done = false;
+ if (IsUInt64()) {
+ uint64_t u64; // avoid reinterpret_cast of pointers
+ done = StringToNumber(constant.c_str(), &u64);
+ i64 = static_cast<int64_t>(u64);
+ } else {
+ done = StringToNumber(constant.c_str(), &i64);
+ }
+ FLATBUFFERS_ASSERT(done);
+ if (!done) return nullptr;
+ return ReverseLookup(i64, false);
+}
+
+void EnumDef::SortByValue() {
+ auto &v = vals.vec;
+ if (IsUInt64())
+ std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) {
+ return e1->GetAsUInt64() < e2->GetAsUInt64();
+ });
+ else
+ std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) {
+ return e1->GetAsInt64() < e2->GetAsInt64();
+ });
+}
+
+void EnumDef::RemoveDuplicates() {
+ // This method depends form SymbolTable implementation!
+ // 1) vals.vec - owner (raw pointer)
+ // 2) vals.dict - access map
+ auto first = vals.vec.begin();
+ auto last = vals.vec.end();
+ if (first == last) return;
+ auto result = first;
+ while (++first != last) {
+ if ((*result)->value != (*first)->value) {
+ *(++result) = *first;
+ } else {
+ auto ev = *first;
+ for (auto it = vals.dict.begin(); it != vals.dict.end(); ++it) {
+ if (it->second == ev) it->second = *result; // reassign
+ }
+ delete ev; // delete enum value
+ *first = nullptr;
+ }
+ }
+ vals.vec.erase(++result, last);
+}
+
+template<typename T> void EnumDef::ChangeEnumValue(EnumVal *ev, T new_value) {
+ ev->value = static_cast<int64_t>(new_value);
+}
+
+namespace EnumHelper {
+template<BaseType E> struct EnumValType { typedef int64_t type; };
+template<> struct EnumValType<BASE_TYPE_ULONG> { typedef uint64_t type; };
+} // namespace EnumHelper
+
+struct EnumValBuilder {
+ EnumVal *CreateEnumerator(const std::string &ev_name) {
+ FLATBUFFERS_ASSERT(!temp);
+ auto first = enum_def.vals.vec.empty();
+ user_value = first;
+ temp = new EnumVal(ev_name, first ? 0 : enum_def.vals.vec.back()->value);
+ return temp;
+ }
+
+ EnumVal *CreateEnumerator(const std::string &ev_name, int64_t val) {
+ FLATBUFFERS_ASSERT(!temp);
+ user_value = true;
+ temp = new EnumVal(ev_name, val);
+ return temp;
+ }
+
+ FLATBUFFERS_CHECKED_ERROR AcceptEnumerator(const std::string &name) {
+ FLATBUFFERS_ASSERT(temp);
+ ECHECK(ValidateValue(&temp->value, false == user_value));
+ FLATBUFFERS_ASSERT((temp->union_type.enum_def == nullptr) ||
+ (temp->union_type.enum_def == &enum_def));
+ auto not_unique = enum_def.vals.Add(name, temp);
+ temp = nullptr;
+ if (not_unique) return parser.Error("enum value already exists: " + name);
+ return NoError();
+ }
+
+ FLATBUFFERS_CHECKED_ERROR AcceptEnumerator() {
+ return AcceptEnumerator(temp->name);
+ }
+
+ FLATBUFFERS_CHECKED_ERROR AssignEnumeratorValue(const std::string &value) {
+ user_value = true;
+ auto fit = false;
+ if (enum_def.IsUInt64()) {
+ uint64_t u64;
+ fit = StringToNumber(value.c_str(), &u64);
+ temp->value = static_cast<int64_t>(u64); // well-defined since C++20.
+ } else {
+ int64_t i64;
+ fit = StringToNumber(value.c_str(), &i64);
+ temp->value = i64;
+ }
+ if (!fit) return parser.Error("enum value does not fit, \"" + value + "\"");
+ return NoError();
+ }
+
+ template<BaseType E, typename CTYPE>
+ inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) {
+ typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t
+ static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
+ const auto v = static_cast<T>(*ev);
+ auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
+ auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
+ if (v < dn || v > (up - m)) {
+ return parser.Error("enum value does not fit, \"" + NumToString(v) +
+ (m ? " + 1\"" : "\"") + " out of " +
+ TypeToIntervalString<CTYPE>());
+ }
+ *ev = static_cast<int64_t>(v + m); // well-defined since C++20.
+ return NoError();
+ }
+
+ FLATBUFFERS_CHECKED_ERROR ValidateValue(int64_t *ev, bool next) {
+ // clang-format off
+ switch (enum_def.underlying_type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
+ case BASE_TYPE_##ENUM: { \
+ if (!IsInteger(BASE_TYPE_##ENUM)) break; \
+ return ValidateImpl<BASE_TYPE_##ENUM, CTYPE>(ev, next ? 1 : 0); \
+ }
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ default: break;
+ }
+ // clang-format on
+ return parser.Error("fatal: invalid enum underlying type");
+ }
+
+ EnumValBuilder(Parser &_parser, EnumDef &_enum_def)
+ : parser(_parser),
+ enum_def(_enum_def),
+ temp(nullptr),
+ user_value(false) {}
+
+ ~EnumValBuilder() { delete temp; }
+
+ Parser &parser;
+ EnumDef &enum_def;
+ EnumVal *temp;
+ bool user_value;
+};
+
+CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest) {
+ 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));
+ enum_def->doc_comment = enum_comment;
+ if (!is_union && !opts.proto_mode) {
+ // Give specialized error message, since this type spec used to
+ // be optional in the first FlatBuffers release.
+ if (!Is(':')) {
+ return Error(
+ "must specify the underlying integer type for this"
+ " enum (e.g. \': short\', which was the default).");
+ } else {
+ NEXT();
+ }
+ // Specify the integer type underlying this enum.
+ ECHECK(ParseType(enum_def->underlying_type));
+ if (!IsInteger(enum_def->underlying_type.base_type) ||
+ IsBool(enum_def->underlying_type.base_type))
+ return Error("underlying enum type must be integral");
+ // Make this type refer back to the enum it was derived from.
+ enum_def->underlying_type.enum_def = enum_def;
+ }
+ ECHECK(ParseMetaData(&enum_def->attributes));
+ const auto underlying_type = enum_def->underlying_type.base_type;
+ if (enum_def->attributes.Lookup("bit_flags") &&
+ !IsUnsigned(underlying_type)) {
+ // todo: Convert to the Error in the future?
+ Warning("underlying type of bit_flags enum must be unsigned");
+ }
+ EnumValBuilder evb(*this, *enum_def);
+ EXPECT('{');
+ // A lot of code generatos expect that an enum is not-empty.
+ if ((is_union || Is('}')) && !opts.proto_mode) {
+ evb.CreateEnumerator("NONE");
+ ECHECK(evb.AcceptEnumerator());
+ }
+ std::set<std::pair<BaseType, StructDef *>> union_types;
+ while (!Is('}')) {
+ if (opts.proto_mode && attribute_ == "option") {
+ ECHECK(ParseProtoOption());
+ } else {
+ auto &ev = *evb.CreateEnumerator(attribute_);
+ auto full_name = ev.name;
+ ev.doc_comment = doc_comment_;
+ EXPECT(kTokenIdentifier);
+ if (is_union) {
+ ECHECK(ParseNamespacing(&full_name, &ev.name));
+ if (opts.union_value_namespacing) {
+ // Since we can't namespace the actual enum identifiers, turn
+ // namespace parts into part of the identifier.
+ ev.name = full_name;
+ std::replace(ev.name.begin(), ev.name.end(), '.', '_');
+ }
+ if (Is(':')) {
+ NEXT();
+ ECHECK(ParseType(ev.union_type));
+ if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
+ ev.union_type.base_type != BASE_TYPE_STRING)
+ return Error("union value type may only be table/struct/string");
+ } else {
+ ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
+ }
+ if (!enum_def->uses_multiple_type_instances) {
+ auto ins = union_types.insert(std::make_pair(
+ ev.union_type.base_type, ev.union_type.struct_def));
+ enum_def->uses_multiple_type_instances = (false == ins.second);
+ }
+ }
+
+ if (Is('=')) {
+ NEXT();
+ ECHECK(evb.AssignEnumeratorValue(attribute_));
+ EXPECT(kTokenIntegerConstant);
+ }
+
+ ECHECK(evb.AcceptEnumerator());
+
+ if (opts.proto_mode && Is('[')) {
+ NEXT();
+ // ignore attributes on enums.
+ while (token_ != ']') NEXT();
+ NEXT();
+ }
+ }
+ if (!Is(opts.proto_mode ? ';' : ',')) break;
+ NEXT();
+ }
+ EXPECT('}');
+
+ // At this point, the enum can be empty if input is invalid proto-file.
+ if (!enum_def->size())
+ return Error("incomplete enum declaration, values not found");
+
+ if (enum_def->attributes.Lookup("bit_flags")) {
+ const auto base_width = static_cast<uint64_t>(8 * SizeOf(underlying_type));
+ for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
+ ++it) {
+ auto ev = *it;
+ const auto u = ev->GetAsUInt64();
+ // Stop manipulations with the sign.
+ if (!IsUnsigned(underlying_type) && u == (base_width - 1))
+ return Error("underlying type of bit_flags enum must be unsigned");
+ if (u >= base_width)
+ return Error("bit flag out of range of underlying integral type");
+ enum_def->ChangeEnumValue(ev, 1ULL << u);
+ }
+ }
+
+ enum_def->SortByValue(); // Must be sorted to use MinValue/MaxValue.
+
+ // Ensure enum value uniqueness.
+ auto prev_it = enum_def->Vals().begin();
+ for (auto it = prev_it + 1; it != enum_def->Vals().end(); ++it) {
+ auto prev_ev = *prev_it;
+ auto ev = *it;
+ if (prev_ev->GetAsUInt64() == ev->GetAsUInt64())
+ return Error("all enum values must be unique: " + prev_ev->name +
+ " and " + ev->name + " are both " +
+ NumToString(ev->GetAsInt64()));
+ }
+
+ if (dest) *dest = enum_def;
+ types_.Add(current_namespace_->GetFullyQualifiedName(enum_def->name),
+ new Type(BASE_TYPE_UNION, nullptr, enum_def));
+ 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);
+ struct_def.predecl = false;
+ struct_def.name = name;
+ struct_def.file = file_being_parsed_;
+ // Move this struct to the back of the vector just in case it was predeclared,
+ // to preserve declaration order.
+ *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) =
+ &struct_def;
+ *dest = &struct_def;
+ return NoError();
+}
+
+CheckedError Parser::CheckClash(std::vector<FieldDef *> &fields,
+ StructDef *struct_def, const char *suffix,
+ BaseType basetype) {
+ auto len = strlen(suffix);
+ for (auto it = fields.begin(); it != fields.end(); ++it) {
+ auto &fname = (*it)->name;
+ if (fname.length() > len &&
+ fname.compare(fname.length() - len, len, suffix) == 0 &&
+ (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
+ auto field =
+ struct_def->fields.Lookup(fname.substr(0, fname.length() - len));
+ if (field && field->value.type.base_type == basetype)
+ return Error("Field " + fname +
+ " would clash with generated functions for field " +
+ field->name);
+ }
+ }
+ return NoError();
+}
+
+bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions &opts) {
+ static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
+ IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
+ IDLOptions::kKotlin | IDLOptions::kCpp | IDLOptions::kJava |
+ IDLOptions::kCSharp | IDLOptions::kTs | IDLOptions::kBinary;
+ 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::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 | IDLOptions::kRust)) == 0;
+}
+
+Namespace *Parser::UniqueNamespace(Namespace *ns) {
+ for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
+ if (ns->components == (*it)->components) {
+ delete ns;
+ return *it;
+ }
+ }
+ namespaces_.push_back(ns);
+ return ns;
+}
+
+std::string Parser::UnqualifiedName(const std::string &full_qualified_name) {
+ Namespace *ns = new Namespace();
+
+ std::size_t current, previous = 0;
+ current = full_qualified_name.find('.');
+ while (current != std::string::npos) {
+ ns->components.push_back(
+ full_qualified_name.substr(previous, current - previous));
+ previous = current + 1;
+ current = full_qualified_name.find('.', previous);
+ }
+ current_namespace_ = UniqueNamespace(ns);
+ return full_qualified_name.substr(previous, current - previous);
+}
+
+static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
+ auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
+ auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
+ return a_id < b_id;
+}
+
+CheckedError Parser::ParseDecl() {
+ std::vector<std::string> dc = doc_comment_;
+ bool fixed = IsIdent("struct");
+ if (!fixed && !IsIdent("table")) return Error("declaration expected");
+ NEXT();
+ std::string name = attribute_;
+ EXPECT(kTokenIdentifier);
+ StructDef *struct_def;
+ ECHECK(StartStruct(name, &struct_def));
+ struct_def->doc_comment = dc;
+ struct_def->fixed = fixed;
+ ECHECK(ParseMetaData(&struct_def->attributes));
+ struct_def->sortbysize =
+ struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
+ EXPECT('{');
+ while (token_ != '}') ECHECK(ParseField(*struct_def));
+ if (fixed) {
+ const auto force_align = struct_def->attributes.Lookup("force_align");
+ if (force_align) {
+ 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");
+ }
+ struct_def->PadLastField(struct_def->minalign);
+ // Check if this is a table that has manual id assignments
+ auto &fields = struct_def->fields.vec;
+ if (!fixed && fields.size()) {
+ size_t num_id_fields = 0;
+ for (auto it = fields.begin(); it != fields.end(); ++it) {
+ if ((*it)->attributes.Lookup("id")) num_id_fields++;
+ }
+ // If any fields have ids..
+ if (num_id_fields || opts.require_explicit_ids) {
+ // Then all fields must have them.
+ if (num_id_fields != fields.size()) {
+ if (opts.require_explicit_ids) {
+ return Error(
+ "all fields must have an 'id' attribute when "
+ "--require-explicit-ids is used");
+ } else {
+ return Error(
+ "either all fields or no fields must have an 'id' attribute");
+ }
+ }
+ // Simply sort by id, then the fields are the same as if no ids had
+ // been specified.
+ std::sort(fields.begin(), fields.end(), compareFieldDefs);
+ // Verify we have a contiguous set, and reassign vtable offsets.
+ 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, field: " +
+ field.name + ", id: " + id_str);
+ field.value.offset = FieldIndexToOffset(i);
+ }
+ }
+ }
+
+ ECHECK(
+ CheckClash(fields, struct_def, UnionTypeFieldSuffix(), BASE_TYPE_UNION));
+ ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
+ ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
+ ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
+ 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));
+ return NoError();
+}
+
+CheckedError Parser::ParseService() {
+ std::vector<std::string> service_comment = doc_comment_;
+ NEXT();
+ auto service_name = attribute_;
+ EXPECT(kTokenIdentifier);
+ auto &service_def = *new ServiceDef();
+ service_def.name = service_name;
+ service_def.file = file_being_parsed_;
+ service_def.doc_comment = service_comment;
+ service_def.defined_namespace = current_namespace_;
+ if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
+ &service_def))
+ return Error("service already exists: " + service_name);
+ ECHECK(ParseMetaData(&service_def.attributes));
+ EXPECT('{');
+ do {
+ std::vector<std::string> doc_comment = doc_comment_;
+ auto rpc_name = attribute_;
+ EXPECT(kTokenIdentifier);
+ EXPECT('(');
+ Type reqtype, resptype;
+ ECHECK(ParseTypeIdent(reqtype));
+ EXPECT(')');
+ EXPECT(':');
+ ECHECK(ParseTypeIdent(resptype));
+ if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed ||
+ resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed)
+ return Error("rpc request and response types must be tables");
+ auto &rpc = *new RPCCall();
+ rpc.name = rpc_name;
+ rpc.request = reqtype.struct_def;
+ rpc.response = resptype.struct_def;
+ rpc.doc_comment = doc_comment;
+ if (service_def.calls.Add(rpc_name, &rpc))
+ return Error("rpc already exists: " + rpc_name);
+ ECHECK(ParseMetaData(&rpc.attributes));
+ EXPECT(';');
+ } while (token_ != '}');
+ NEXT();
+ return NoError();
+}
+
+bool Parser::SetRootType(const char *name) {
+ root_struct_def_ = LookupStruct(name);
+ if (!root_struct_def_)
+ root_struct_def_ =
+ LookupStruct(current_namespace_->GetFullyQualifiedName(name));
+ return root_struct_def_ != nullptr;
+}
+
+void Parser::MarkGenerated() {
+ // This function marks all existing definitions as having already
+ // been generated, which signals no code for included files should be
+ // generated.
+ for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
+ (*it)->generated = true;
+ }
+ for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
+ if (!(*it)->predecl) { (*it)->generated = true; }
+ }
+ for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
+ (*it)->generated = true;
+ }
+}
+
+CheckedError Parser::ParseNamespace() {
+ NEXT();
+ auto ns = new Namespace();
+ namespaces_.push_back(ns); // Store it here to not leak upon error.
+ if (token_ != ';') {
+ for (;;) {
+ ns->components.push_back(attribute_);
+ EXPECT(kTokenIdentifier);
+ if (Is('.')) NEXT() else break;
+ }
+ }
+ namespaces_.pop_back();
+ current_namespace_ = UniqueNamespace(ns);
+ EXPECT(';');
+ return NoError();
+}
+
+// Best effort parsing of .proto declarations, with the aim to turn them
+// in the closest corresponding FlatBuffer equivalent.
+// We parse everything as identifiers instead of keywords, since we don't
+// want protobuf keywords to become invalid identifiers in FlatBuffers.
+CheckedError Parser::ParseProtoDecl() {
+ bool isextend = IsIdent("extend");
+ if (IsIdent("package")) {
+ // These are identical in syntax to FlatBuffer's namespace decl.
+ ECHECK(ParseNamespace());
+ } else if (IsIdent("message") || isextend) {
+ std::vector<std::string> struct_comment = doc_comment_;
+ NEXT();
+ StructDef *struct_def = nullptr;
+ Namespace *parent_namespace = nullptr;
+ if (isextend) {
+ if (Is('.')) NEXT(); // qualified names may start with a . ?
+ auto id = attribute_;
+ EXPECT(kTokenIdentifier);
+ ECHECK(ParseNamespacing(&id, nullptr));
+ struct_def = LookupCreateStruct(id, false);
+ if (!struct_def)
+ return Error("cannot extend unknown message type: " + id);
+ } else {
+ std::string name = attribute_;
+ EXPECT(kTokenIdentifier);
+ ECHECK(StartStruct(name, &struct_def));
+ // Since message definitions can be nested, we create a new namespace.
+ auto ns = new Namespace();
+ // Copy of current namespace.
+ *ns = *current_namespace_;
+ // But with current message name.
+ ns->components.push_back(name);
+ ns->from_table++;
+ parent_namespace = current_namespace_;
+ current_namespace_ = UniqueNamespace(ns);
+ }
+ struct_def->doc_comment = struct_comment;
+ ECHECK(ParseProtoFields(struct_def, isextend, false));
+ if (!isextend) { current_namespace_ = parent_namespace; }
+ if (Is(';')) NEXT();
+ } else if (IsIdent("enum")) {
+ // These are almost the same, just with different terminator:
+ EnumDef *enum_def;
+ ECHECK(ParseEnum(false, &enum_def));
+ if (Is(';')) NEXT();
+ // Temp: remove any duplicates, as .fbs files can't handle them.
+ enum_def->RemoveDuplicates();
+ } else if (IsIdent("syntax")) { // Skip these.
+ NEXT();
+ EXPECT('=');
+ EXPECT(kTokenStringConstant);
+ EXPECT(';');
+ } else if (IsIdent("option")) { // Skip these.
+ ECHECK(ParseProtoOption());
+ EXPECT(';');
+ } else if (IsIdent("service")) { // Skip these.
+ NEXT();
+ EXPECT(kTokenIdentifier);
+ ECHECK(ParseProtoCurliesOrIdent());
+ } else {
+ return Error("don\'t know how to parse .proto declaration starting with " +
+ TokenToStringId(token_));
+ }
+ return NoError();
+}
+
+CheckedError Parser::StartEnum(const std::string &enum_name, bool is_union,
+ EnumDef **dest) {
+ auto &enum_def = *new EnumDef();
+ enum_def.name = enum_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);
+ enum_def.underlying_type.base_type =
+ is_union ? BASE_TYPE_UTYPE : BASE_TYPE_INT;
+ enum_def.underlying_type.enum_def = &enum_def;
+ if (dest) *dest = &enum_def;
+ return NoError();
+}
+
+CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
+ bool inside_oneof) {
+ EXPECT('{');
+ while (token_ != '}') {
+ if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) {
+ // Nested declarations.
+ ECHECK(ParseProtoDecl());
+ } else if (IsIdent("extensions")) { // Skip these.
+ NEXT();
+ EXPECT(kTokenIntegerConstant);
+ if (Is(kTokenIdentifier)) {
+ NEXT(); // to
+ NEXT(); // num
+ }
+ EXPECT(';');
+ } else if (IsIdent("option")) { // Skip these.
+ ECHECK(ParseProtoOption());
+ EXPECT(';');
+ } else if (IsIdent("reserved")) { // Skip these.
+ NEXT();
+ while (!Is(';')) { NEXT(); } // A variety of formats, just skip.
+ NEXT();
+ } else {
+ std::vector<std::string> field_comment = doc_comment_;
+ // Parse the qualifier.
+ bool required = false;
+ bool repeated = false;
+ bool oneof = false;
+ if (!inside_oneof) {
+ if (IsIdent("optional")) {
+ // This is the default.
+ NEXT();
+ } else if (IsIdent("required")) {
+ required = true;
+ NEXT();
+ } else if (IsIdent("repeated")) {
+ repeated = true;
+ NEXT();
+ } else if (IsIdent("oneof")) {
+ oneof = true;
+ NEXT();
+ } else {
+ // can't error, proto3 allows decls without any of the above.
+ }
+ }
+ StructDef *anonymous_struct = nullptr;
+ EnumDef *oneof_union = nullptr;
+ Type type;
+ if (IsIdent("group") || oneof) {
+ if (!oneof) NEXT();
+ if (oneof && opts.proto_oneof_union) {
+ auto name = MakeCamel(attribute_, true) + "Union";
+ ECHECK(StartEnum(name, true, &oneof_union));
+ type = Type(BASE_TYPE_UNION, nullptr, oneof_union);
+ } else {
+ auto name = "Anonymous" + NumToString(anonymous_counter_++);
+ ECHECK(StartStruct(name, &anonymous_struct));
+ type = Type(BASE_TYPE_STRUCT, anonymous_struct);
+ }
+ } else {
+ ECHECK(ParseTypeFromProtoType(&type));
+ }
+ // Repeated elements get mapped to a vector.
+ if (repeated) {
+ type.element = type.base_type;
+ type.base_type = BASE_TYPE_VECTOR;
+ if (type.element == BASE_TYPE_VECTOR) {
+ // We have a vector or vectors, which FlatBuffers doesn't support.
+ // For now make it a vector of string (since the source is likely
+ // "repeated bytes").
+ // TODO(wvo): A better solution would be to wrap this in a table.
+ type.element = BASE_TYPE_STRING;
+ }
+ }
+ std::string name = attribute_;
+ EXPECT(kTokenIdentifier);
+ if (!oneof) {
+ // Parse the field id. Since we're just translating schemas, not
+ // any kind of binary compatibility, we can safely ignore these, and
+ // assign our own.
+ EXPECT('=');
+ EXPECT(kTokenIntegerConstant);
+ }
+ FieldDef *field = nullptr;
+ if (isextend) {
+ // We allow a field to be re-defined when extending.
+ // TODO: are there situations where that is problematic?
+ field = struct_def->fields.Lookup(name);
+ }
+ if (!field) ECHECK(AddField(*struct_def, name, type, &field));
+ field->doc_comment = field_comment;
+ if (!IsScalar(type.base_type) && required) {
+ field->presence = FieldDef::kRequired;
+ }
+ // See if there's a default specified.
+ if (Is('[')) {
+ NEXT();
+ for (;;) {
+ auto key = attribute_;
+ ECHECK(ParseProtoKey());
+ EXPECT('=');
+ auto val = attribute_;
+ ECHECK(ParseProtoCurliesOrIdent());
+ if (key == "default") {
+ // Temp: skip non-numeric and non-boolean defaults (enums).
+ auto numeric = strpbrk(val.c_str(), "0123456789-+.");
+ if (IsScalar(type.base_type) && numeric == val.c_str()) {
+ field->value.constant = val;
+ } else if (val == "true") {
+ field->value.constant = val;
+ } // "false" is default, no need to handle explicitly.
+ } else if (key == "deprecated") {
+ field->deprecated = val == "true";
+ }
+ if (!Is(',')) break;
+ NEXT();
+ }
+ EXPECT(']');
+ }
+ if (anonymous_struct) {
+ ECHECK(ParseProtoFields(anonymous_struct, false, oneof));
+ if (Is(';')) NEXT();
+ } else if (oneof_union) {
+ // Parse into a temporary StructDef, then transfer fields into an
+ // EnumDef describing the oneof as a union.
+ StructDef oneof_struct;
+ ECHECK(ParseProtoFields(&oneof_struct, false, oneof));
+ if (Is(';')) NEXT();
+ for (auto field_it = oneof_struct.fields.vec.begin();
+ field_it != oneof_struct.fields.vec.end(); ++field_it) {
+ const auto &oneof_field = **field_it;
+ const auto &oneof_type = oneof_field.value.type;
+ if (oneof_type.base_type != BASE_TYPE_STRUCT ||
+ !oneof_type.struct_def || oneof_type.struct_def->fixed)
+ return Error("oneof '" + name +
+ "' cannot be mapped to a union because member '" +
+ oneof_field.name + "' is not a table type.");
+ EnumValBuilder evb(*this, *oneof_union);
+ auto ev = evb.CreateEnumerator(oneof_type.struct_def->name);
+ ev->union_type = oneof_type;
+ ev->doc_comment = oneof_field.doc_comment;
+ ECHECK(evb.AcceptEnumerator(oneof_field.name));
+ }
+ } else {
+ EXPECT(';');
+ }
+ }
+ }
+ NEXT();
+ return NoError();
+}
+
+CheckedError Parser::ParseProtoKey() {
+ if (token_ == '(') {
+ NEXT();
+ // Skip "(a.b)" style custom attributes.
+ while (token_ == '.' || token_ == kTokenIdentifier) NEXT();
+ EXPECT(')');
+ while (Is('.')) {
+ NEXT();
+ EXPECT(kTokenIdentifier);
+ }
+ } else {
+ EXPECT(kTokenIdentifier);
+ }
+ return NoError();
+}
+
+CheckedError Parser::ParseProtoCurliesOrIdent() {
+ if (Is('{')) {
+ NEXT();
+ for (int nesting = 1; nesting;) {
+ if (token_ == '{')
+ nesting++;
+ else if (token_ == '}')
+ nesting--;
+ NEXT();
+ }
+ } else {
+ NEXT(); // Any single token.
+ }
+ return NoError();
+}
+
+CheckedError Parser::ParseProtoOption() {
+ NEXT();
+ ECHECK(ParseProtoKey());
+ EXPECT('=');
+ ECHECK(ParseProtoCurliesOrIdent());
+ return NoError();
+}
+
+// Parse a protobuf type, and map it to the corresponding FlatBuffer one.
+CheckedError Parser::ParseTypeFromProtoType(Type *type) {
+ struct type_lookup {
+ const char *proto_type;
+ BaseType fb_type, element;
+ };
+ static type_lookup lookup[] = {
+ { "float", BASE_TYPE_FLOAT, BASE_TYPE_NONE },
+ { "double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE },
+ { "int32", BASE_TYPE_INT, BASE_TYPE_NONE },
+ { "int64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+ { "uint32", BASE_TYPE_UINT, BASE_TYPE_NONE },
+ { "uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
+ { "sint32", BASE_TYPE_INT, BASE_TYPE_NONE },
+ { "sint64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+ { "fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE },
+ { "fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
+ { "sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE },
+ { "sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+ { "bool", BASE_TYPE_BOOL, BASE_TYPE_NONE },
+ { "string", BASE_TYPE_STRING, BASE_TYPE_NONE },
+ { "bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR },
+ { nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE }
+ };
+ for (auto tl = lookup; tl->proto_type; tl++) {
+ if (attribute_ == tl->proto_type) {
+ type->base_type = tl->fb_type;
+ type->element = tl->element;
+ NEXT();
+ return NoError();
+ }
+ }
+ if (Is('.')) NEXT(); // qualified names may start with a . ?
+ ECHECK(ParseTypeIdent(*type));
+ return NoError();
+}
+
+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(SkipAnyJsonValue());
+ fieldn++;
+ return NoError();
+ });
+ }
+ case '[': {
+ uoffset_t count = 0;
+ return ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
+ return SkipAnyJsonValue();
+ });
+ }
+ case kTokenStringConstant:
+ case kTokenIntegerConstant:
+ case kTokenFloatConstant: NEXT(); break;
+ default:
+ if (IsIdent("true") || IsIdent("false") || IsIdent("null")) {
+ NEXT();
+ } else
+ return TokenError();
+ }
+ 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();
+ size_t fieldn_outer = 0;
+ auto err =
+ ParseTableDelimiters(fieldn_outer, nullptr,
+ [&](const std::string &name, size_t &fieldn,
+ const StructDef *) -> CheckedError {
+ builder->Key(name);
+ ECHECK(ParseFlexBufferValue(builder));
+ fieldn++;
+ return NoError();
+ });
+ ECHECK(err);
+ builder->EndMap(start);
+ if (builder->HasDuplicateKeys())
+ return Error("FlexBuffers map has duplicate keys");
+ break;
+ }
+ case '[': {
+ auto start = builder->StartVector();
+ uoffset_t count = 0;
+ ECHECK(ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
+ return ParseFlexBufferValue(builder);
+ }));
+ builder->EndVector(start, false, false);
+ break;
+ }
+ case kTokenStringConstant:
+ builder->String(attribute_);
+ EXPECT(kTokenStringConstant);
+ break;
+ case kTokenIntegerConstant:
+ builder->Int(StringToInt(attribute_.c_str()));
+ EXPECT(kTokenIntegerConstant);
+ break;
+ case kTokenFloatConstant: {
+ double d;
+ StringToNumber(attribute_.c_str(), &d);
+ builder->Double(d);
+ 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(size_t(0), size_t(1), sign);
+ ECHECK(ParseFlexBufferNumericConstant(builder));
+ NEXT();
+ break;
+ }
+ default:
+ if (IsIdent("true")) {
+ builder->Bool(true);
+ NEXT();
+ } else if (IsIdent("false")) {
+ builder->Bool(false);
+ NEXT();
+ } else if (IsIdent("null")) {
+ builder->Null();
+ NEXT();
+ } else if (IsIdent("inf") || IsIdent("infinity") || IsIdent("nan")) {
+ ECHECK(ParseFlexBufferNumericConstant(builder));
+ NEXT();
+ } else
+ return TokenError();
+ }
+ return NoError();
+}
+
+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) {
+ const auto initial_depth = parse_depth_counter_;
+ (void)initial_depth;
+ bool r;
+
+ if (opts.use_flexbuffers) {
+ r = ParseFlexBuffer(source, source_filename, &flex_builder_);
+ } else {
+ r = !ParseRoot(source, include_paths, source_filename).Check();
+ }
+ FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
+ return r;
+}
+
+bool Parser::ParseJson(const char *json, const char *json_filename) {
+ const auto initial_depth = parse_depth_counter_;
+ (void)initial_depth;
+ builder_.Clear();
+ const auto done =
+ !StartParseFile(json, json_filename).Check() && !DoParseJson().Check();
+ FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
+ return done;
+}
+
+CheckedError Parser::StartParseFile(const char *source,
+ const char *source_filename) {
+ file_being_parsed_ = source_filename ? source_filename : "";
+ source_ = source;
+ ResetState(source_);
+ error_.clear();
+ ECHECK(SkipByteOrderMark());
+ NEXT();
+ if (Is(kTokenEof)) return Error("input file is empty");
+ return NoError();
+}
+
+CheckedError Parser::ParseRoot(const char *source, const char **include_paths,
+ const char *source_filename) {
+ ECHECK(DoParse(source, include_paths, source_filename, nullptr));
+
+ // Check that all types were defined.
+ for (auto it = structs_.vec.begin(); it != structs_.vec.end();) {
+ auto &struct_def = **it;
+ if (struct_def.predecl) {
+ if (opts.proto_mode) {
+ // Protos allow enums to be used before declaration, so check if that
+ // is the case here.
+ EnumDef *enum_def = nullptr;
+ for (size_t components =
+ struct_def.defined_namespace->components.size() + 1;
+ components && !enum_def; components--) {
+ auto qualified_name =
+ struct_def.defined_namespace->GetFullyQualifiedName(
+ struct_def.name, components - 1);
+ enum_def = LookupEnum(qualified_name);
+ }
+ if (enum_def) {
+ // This is pretty slow, but a simple solution for now.
+ auto initial_count = struct_def.refcount;
+ for (auto struct_it = structs_.vec.begin();
+ struct_it != structs_.vec.end(); ++struct_it) {
+ auto &sd = **struct_it;
+ for (auto field_it = sd.fields.vec.begin();
+ field_it != sd.fields.vec.end(); ++field_it) {
+ auto &field = **field_it;
+ if (field.value.type.struct_def == &struct_def) {
+ field.value.type.struct_def = nullptr;
+ field.value.type.enum_def = enum_def;
+ auto &bt = IsVector(field.value.type)
+ ? field.value.type.element
+ : field.value.type.base_type;
+ FLATBUFFERS_ASSERT(bt == BASE_TYPE_STRUCT);
+ bt = enum_def->underlying_type.base_type;
+ struct_def.refcount--;
+ enum_def->refcount++;
+ }
+ }
+ }
+ if (struct_def.refcount)
+ return Error("internal: " + NumToString(struct_def.refcount) + "/" +
+ NumToString(initial_count) +
+ " use(s) of pre-declaration enum not accounted for: " +
+ enum_def->name);
+ structs_.dict.erase(structs_.dict.find(struct_def.name));
+ it = structs_.vec.erase(it);
+ delete &struct_def;
+ continue; // Skip error.
+ }
+ }
+ auto err = "type referenced but not defined (check namespace): " +
+ struct_def.name;
+ if (struct_def.original_location)
+ err += ", originally at: " + *struct_def.original_location;
+ return Error(err);
+ }
+ ++it;
+ }
+
+ // This check has to happen here and not earlier, because only now do we
+ // know for sure what the type of these are.
+ for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
+ auto &enum_def = **it;
+ if (enum_def.is_union) {
+ for (auto val_it = enum_def.Vals().begin();
+ val_it != enum_def.Vals().end(); ++val_it) {
+ auto &val = **val_it;
+ if (!SupportsAdvancedUnionFeatures() &&
+ (IsStruct(val.union_type) || IsString(val.union_type)))
+ return Error(
+ "only tables can be union elements in the generated language: " +
+ val.name);
+ }
+ }
+ }
+ // 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 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();
+ }
+ }
+ if (!include_paths) {
+ static const char *current_directory[] = { "", nullptr };
+ include_paths = current_directory;
+ }
+ field_stack_.clear();
+ builder_.Clear();
+ // Start with a blank namespace just in case this file doesn't have one.
+ current_namespace_ = empty_namespace_;
+
+ ECHECK(StartParseFile(source, source_filename));
+
+ // Includes must come before type declarations:
+ for (;;) {
+ // Parse pre-include proto statements if any:
+ if (opts.proto_mode && (attribute_ == "option" || attribute_ == "syntax" ||
+ attribute_ == "package")) {
+ ECHECK(ParseProtoDecl());
+ } else if (IsIdent("native_include")) {
+ NEXT();
+ vector_emplace_back(&native_included_files_, attribute_);
+ EXPECT(kTokenStringConstant);
+ EXPECT(';');
+ } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) {
+ NEXT();
+ if (opts.proto_mode && attribute_ == "public") NEXT();
+ auto name = flatbuffers::PosixPath(attribute_.c_str());
+ EXPECT(kTokenStringConstant);
+ // Look for the file relative to the directory of the current file.
+ std::string filepath;
+ 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);
+
+ 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.
+ // 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:
+ if (!opts.generate_all) MarkGenerated();
+ // Reset these just in case the included file had them, and the
+ // parent doesn't.
+ root_struct_def_ = nullptr;
+ file_identifier_.clear();
+ file_extension_.clear();
+ // This is the easiest way to continue this file after an include:
+ // instead of saving and restoring all the state, we simply start the
+ // file anew. This will cause it to encounter the same include
+ // statement again, but this time it will skip it, because it was
+ // entered into included_files_.
+ // This is recursive, but only go as deep as the number of include
+ // statements.
+ included_files_.erase(source_hash);
+ return DoParse(source, include_paths, source_filename,
+ include_filename);
+ }
+ EXPECT(';');
+ } else {
+ break;
+ }
+ }
+ // Now parse all other kinds of declarations:
+ while (token_ != kTokenEof) {
+ if (opts.proto_mode) {
+ ECHECK(ParseProtoDecl());
+ } else if (IsIdent("namespace")) {
+ ECHECK(ParseNamespace());
+ } else if (token_ == '{') {
+ return NoError();
+ } else if (IsIdent("enum")) {
+ ECHECK(ParseEnum(false, nullptr));
+ } else if (IsIdent("union")) {
+ ECHECK(ParseEnum(true, nullptr));
+ } else if (IsIdent("root_type")) {
+ NEXT();
+ auto root_type = attribute_;
+ EXPECT(kTokenIdentifier);
+ ECHECK(ParseNamespacing(&root_type, nullptr));
+ if (opts.root_type.empty()) {
+ if (!SetRootType(root_type.c_str()))
+ return Error("unknown root type: " + root_type);
+ if (root_struct_def_->fixed) return Error("root type must be a table");
+ }
+ EXPECT(';');
+ } else if (IsIdent("file_identifier")) {
+ NEXT();
+ file_identifier_ = attribute_;
+ EXPECT(kTokenStringConstant);
+ if (file_identifier_.length() != FlatBufferBuilder::kFileIdentifierLength)
+ return Error("file_identifier must be exactly " +
+ NumToString(FlatBufferBuilder::kFileIdentifierLength) +
+ " characters");
+ EXPECT(';');
+ } else if (IsIdent("file_extension")) {
+ NEXT();
+ file_extension_ = attribute_;
+ EXPECT(kTokenStringConstant);
+ EXPECT(';');
+ } else if (IsIdent("include")) {
+ return Error("includes must come before declarations");
+ } else if (IsIdent("attribute")) {
+ NEXT();
+ auto name = attribute_;
+ if (Is(kTokenIdentifier)) {
+ NEXT();
+ } else {
+ EXPECT(kTokenStringConstant);
+ }
+ EXPECT(';');
+ known_attributes_[name] = false;
+ } else if (IsIdent("rpc_service")) {
+ ECHECK(ParseService());
+ } else {
+ ECHECK(ParseDecl());
+ }
+ }
+ return NoError();
+}
+
+CheckedError Parser::DoParseJson() {
+ if (token_ != '{') {
+ EXPECT('{');
+ } else {
+ 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");
+ }
+ uoffset_t toff;
+ ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
+ if (opts.size_prefixed) {
+ builder_.FinishSizePrefixed(
+ Offset<Table>(toff),
+ file_identifier_.length() ? file_identifier_.c_str() : nullptr);
+ } else {
+ builder_.Finish(Offset<Table>(toff), file_identifier_.length()
+ ? file_identifier_.c_str()
+ : nullptr);
+ }
+ }
+ // Check that JSON file doesn't contain more objects or IDL directives.
+ // Comments after JSON are allowed.
+ EXPECT(kTokenEof);
+ return NoError();
+}
+
+std::set<std::string> Parser::GetIncludedFilesRecursive(
+ const std::string &file_name) const {
+ std::set<std::string> included_files;
+ std::list<std::string> to_process;
+
+ if (file_name.empty()) return included_files;
+ to_process.push_back(file_name);
+
+ while (!to_process.empty()) {
+ std::string current = to_process.front();
+ to_process.pop_front();
+ included_files.insert(current);
+
+ // Workaround the lack of const accessor in C++98 maps.
+ auto &new_files =
+ (*const_cast<std::map<std::string, std::set<std::string>> *>(
+ &files_included_per_file_))[current];
+ for (auto it = new_files.begin(); it != new_files.end(); ++it) {
+ if (included_files.find(*it) == included_files.end())
+ to_process.push_back(*it);
+ }
+ }
+
+ return included_files;
+}
+
+// Schema serialization functionality:
+
+template<typename T> bool compareName(const T *a, const T *b) {
+ return a->defined_namespace->GetFullyQualifiedName(a->name) <
+ b->defined_namespace->GetFullyQualifiedName(b->name);
+}
+
+template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
+ // Pre-sort these vectors, such that we can set the correct indices for them.
+ auto vec = defvec;
+ std::sort(vec.begin(), vec.end(), compareName<T>);
+ for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
+}
+
+void Parser::Serialize() {
+ builder_.Clear();
+ AssignIndices(structs_.vec);
+ AssignIndices(enums_.vec);
+ std::vector<Offset<reflection::Object>> object_offsets;
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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(
+ builder_, objs__, enum__, fiid__, fext__,
+ (root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__,
+ static_cast<reflection::AdvancedFeatures>(advanced_features_));
+ if (opts.size_prefixed) {
+ builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
+ } else {
+ builder_.Finish(schema_offset, reflection::SchemaIdentifier());
+ }
+}
+
+static Namespace *GetNamespace(
+ const std::string &qualified_name, std::vector<Namespace *> &namespaces,
+ std::map<std::string, Namespace *> &namespaces_index) {
+ size_t dot = qualified_name.find_last_of('.');
+ std::string namespace_name = (dot != std::string::npos)
+ ? std::string(qualified_name.c_str(), dot)
+ : "";
+ Namespace *&ns = namespaces_index[namespace_name];
+
+ if (!ns) {
+ ns = new Namespace();
+ namespaces.push_back(ns);
+
+ size_t pos = 0;
+
+ for (;;) {
+ dot = qualified_name.find('.', pos);
+ if (dot == std::string::npos) { break; }
+ ns->components.push_back(qualified_name.substr(pos, dot - pos));
+ pos = dot + 1;
+ }
+ }
+
+ return ns;
+}
+
+Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ std::vector<Offset<reflection::Field>> field_offsets;
+ for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
+ 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__);
+}
+
+bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) {
+ if (!DeserializeAttributes(parser, object->attributes())) return false;
+ DeserializeDoc(doc_comment, object->documentation());
+ name = parser.UnqualifiedName(object->name()->str());
+ predecl = false;
+ sortbysize = attributes.Lookup("original_order") == nullptr && !fixed;
+ const auto &of = *(object->fields());
+ auto indexes = std::vector<uoffset_t>(of.size());
+ for (uoffset_t i = 0; i < of.size(); i++) indexes[of.Get(i)->id()] = i;
+ size_t tmp_struct_size = 0;
+ for (size_t i = 0; i < indexes.size(); i++) {
+ auto field = of.Get(indexes[i]);
+ auto field_def = new FieldDef();
+ if (!field_def->Deserialize(parser, field) ||
+ fields.Add(field_def->name, field_def)) {
+ delete field_def;
+ return false;
+ }
+ if (fixed) {
+ // Recompute padding since that's currently not serialized.
+ auto size = InlineSize(field_def->value.type);
+ auto next_field =
+ i + 1 < indexes.size() ? of.Get(indexes[i + 1]) : nullptr;
+ tmp_struct_size += size;
+ field_def->padding =
+ next_field ? (next_field->offset() - field_def->value.offset) - size
+ : PaddingBytes(tmp_struct_size, minalign);
+ tmp_struct_size += field_def->padding;
+ }
+ }
+ FLATBUFFERS_ASSERT(static_cast<int>(tmp_struct_size) == object->bytesize());
+ return true;
+}
+
+Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
+ uint16_t id,
+ const Parser &parser) const {
+ auto name__ = builder->CreateString(name);
+ auto type__ = value.type.Serialize(builder);
+ auto attr__ = SerializeAttributes(builder, parser);
+ auto docs__ = parser.opts.binary_schema_comments
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ double d;
+ StringToNumber(value.constant.c_str(), &d);
+ return reflection::CreateField(
+ *builder, name__, type__, id, value.offset,
+ // 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, IsRequired(), key,
+ attr__, docs__, IsOptional());
+ // 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.
+}
+
+bool FieldDef::Deserialize(Parser &parser, const reflection::Field *field) {
+ name = field->name()->str();
+ defined_namespace = parser.current_namespace_;
+ if (!value.type.Deserialize(parser, field->type())) return false;
+ value.offset = field->offset();
+ if (IsInteger(value.type.base_type)) {
+ value.constant = NumToString(field->default_integer());
+ } else if (IsFloat(value.type.base_type)) {
+ value.constant = FloatToString(field->default_real(), 16);
+ }
+ presence = FieldDef::MakeFieldPresence(field->optional(), field->required());
+ key = field->key();
+ if (!DeserializeAttributes(parser, field->attributes())) return false;
+ // TODO: this should probably be handled by a separate attribute
+ if (attributes.Lookup("flexbuffer")) {
+ flexbuffer = true;
+ parser.uses_flexbuffers_ = true;
+ if (value.type.base_type != BASE_TYPE_VECTOR ||
+ value.type.element != BASE_TYPE_UCHAR)
+ return false;
+ }
+ if (auto nested = attributes.Lookup("nested_flatbuffer")) {
+ auto nested_qualified_name =
+ parser.current_namespace_->GetFullyQualifiedName(nested->constant);
+ nested_flatbuffer = parser.LookupStruct(nested_qualified_name);
+ if (!nested_flatbuffer) return false;
+ }
+ shared = attributes.Lookup("shared") != nullptr;
+ DeserializeDoc(doc_comment, field->documentation());
+ return true;
+}
+
+Offset<reflection::RPCCall> RPCCall::Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ auto name__ = builder->CreateString(name);
+ auto attr__ = SerializeAttributes(builder, parser);
+ auto docs__ = parser.opts.binary_schema_comments
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ return reflection::CreateRPCCall(
+ *builder, name__, request->serialized_location,
+ response->serialized_location, attr__, docs__);
+}
+
+bool RPCCall::Deserialize(Parser &parser, const reflection::RPCCall *call) {
+ name = call->name()->str();
+ if (!DeserializeAttributes(parser, call->attributes())) return false;
+ DeserializeDoc(doc_comment, call->documentation());
+ request = parser.structs_.Lookup(call->request()->name()->str());
+ response = parser.structs_.Lookup(call->response()->name()->str());
+ if (!request || !response) { return false; }
+ return true;
+}
+
+Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ std::vector<Offset<reflection::RPCCall>> servicecall_offsets;
+ 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__);
+}
+
+bool ServiceDef::Deserialize(Parser &parser,
+ const reflection::Service *service) {
+ name = parser.UnqualifiedName(service->name()->str());
+ if (service->calls()) {
+ for (uoffset_t i = 0; i < service->calls()->size(); ++i) {
+ auto call = new RPCCall();
+ if (!call->Deserialize(parser, service->calls()->Get(i)) ||
+ calls.Add(call->name, call)) {
+ delete call;
+ return false;
+ }
+ }
+ }
+ if (!DeserializeAttributes(parser, service->attributes())) return false;
+ DeserializeDoc(doc_comment, service->documentation());
+ return true;
+}
+
+Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ std::vector<Offset<reflection::EnumVal>> enumval_offsets;
+ 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;
+ return reflection::CreateEnum(*builder, name__, vals__, is_union, type__,
+ attr__, docs__);
+}
+
+bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) {
+ name = parser.UnqualifiedName(_enum->name()->str());
+ for (uoffset_t i = 0; i < _enum->values()->size(); ++i) {
+ auto val = new EnumVal();
+ if (!val->Deserialize(parser, _enum->values()->Get(i)) ||
+ vals.Add(val->name, val)) {
+ delete val;
+ return false;
+ }
+ }
+ is_union = _enum->is_union();
+ if (!underlying_type.Deserialize(parser, _enum->underlying_type())) {
+ return false;
+ }
+ if (!DeserializeAttributes(parser, _enum->attributes())) return false;
+ DeserializeDoc(doc_comment, _enum->documentation());
+ return true;
+}
+
+Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ auto name__ = builder->CreateString(name);
+ auto type__ = union_type.Serialize(builder);
+ 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__);
+}
+
+bool EnumVal::Deserialize(const Parser &parser,
+ const reflection::EnumVal *val) {
+ name = val->name()->str();
+ value = val->value();
+ if (!union_type.Deserialize(parser, val->union_type())) return false;
+ DeserializeDoc(doc_comment, val->documentation());
+ return true;
+}
+
+Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
+ return reflection::CreateType(
+ *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);
+}
+
+bool Type::Deserialize(const Parser &parser, const reflection::Type *type) {
+ if (type == nullptr) return true;
+ base_type = static_cast<BaseType>(type->base_type());
+ 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)) {
+ if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) {
+ struct_def = parser.structs_.vec[type->index()];
+ struct_def->refcount++;
+ } else {
+ return false;
+ }
+ } else {
+ if (static_cast<size_t>(type->index()) < parser.enums_.vec.size()) {
+ enum_def = parser.enums_.vec[type->index()];
+ } else {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+flatbuffers::Offset<
+ flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
+Definition::SerializeAttributes(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
+ for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
+ auto it = parser.known_attributes_.find(kv->first);
+ FLATBUFFERS_ASSERT(it != parser.known_attributes_.end());
+ if (parser.opts.binary_schema_builtins || !it->second) {
+ auto key = builder->CreateString(kv->first);
+ auto val = builder->CreateString(kv->second->constant);
+ attrs.push_back(reflection::CreateKeyValue(*builder, key, val));
+ }
+ }
+ if (attrs.size()) {
+ return builder->CreateVectorOfSortedTables(&attrs);
+ } else {
+ return 0;
+ }
+}
+
+bool Definition::DeserializeAttributes(
+ Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) {
+ if (attrs == nullptr) return true;
+ for (uoffset_t i = 0; i < attrs->size(); ++i) {
+ auto kv = attrs->Get(i);
+ auto value = new Value();
+ if (kv->value()) { value->constant = kv->value()->str(); }
+ if (attributes.Add(kv->key()->str(), value)) {
+ delete value;
+ return false;
+ }
+ parser.known_attributes_[kv->key()->str()];
+ }
+ return true;
+}
+
+/************************************************************************/
+/* DESERIALIZATION */
+/************************************************************************/
+bool Parser::Deserialize(const uint8_t *buf, const size_t size) {
+ flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t *>(buf), size);
+ bool size_prefixed = false;
+ if (!reflection::SchemaBufferHasIdentifier(buf)) {
+ if (!flatbuffers::BufferHasIdentifier(buf, reflection::SchemaIdentifier(),
+ true))
+ return false;
+ else
+ size_prefixed = true;
+ }
+ auto verify_fn = size_prefixed ? &reflection::VerifySizePrefixedSchemaBuffer
+ : &reflection::VerifySchemaBuffer;
+ if (!verify_fn(verifier)) { return false; }
+ auto schema = size_prefixed ? reflection::GetSizePrefixedSchema(buf)
+ : reflection::GetSchema(buf);
+ return Deserialize(schema);
+}
+
+bool Parser::Deserialize(const reflection::Schema *schema) {
+ file_identifier_ = schema->file_ident() ? schema->file_ident()->str() : "";
+ file_extension_ = schema->file_ext() ? schema->file_ext()->str() : "";
+ std::map<std::string, Namespace *> namespaces_index;
+
+ // Create defs without deserializing so references from fields to structs and
+ // enums can be resolved.
+ for (auto it = schema->objects()->begin(); it != schema->objects()->end();
+ ++it) {
+ auto struct_def = new StructDef();
+ struct_def->bytesize = it->bytesize();
+ struct_def->fixed = it->is_struct();
+ struct_def->minalign = it->minalign();
+ if (structs_.Add(it->name()->str(), struct_def)) {
+ delete struct_def;
+ return false;
+ }
+ auto type = new Type(BASE_TYPE_STRUCT, struct_def, nullptr);
+ if (types_.Add(it->name()->str(), type)) {
+ delete type;
+ return false;
+ }
+ }
+ for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
+ auto enum_def = new EnumDef();
+ if (enums_.Add(it->name()->str(), enum_def)) {
+ delete enum_def;
+ return false;
+ }
+ auto type = new Type(BASE_TYPE_UNION, nullptr, enum_def);
+ if (types_.Add(it->name()->str(), type)) {
+ delete type;
+ return false;
+ }
+ }
+
+ // Now fields can refer to structs and enums by index.
+ for (auto it = schema->objects()->begin(); it != schema->objects()->end();
+ ++it) {
+ std::string qualified_name = it->name()->str();
+ auto struct_def = structs_.Lookup(qualified_name);
+ struct_def->defined_namespace =
+ GetNamespace(qualified_name, namespaces_, namespaces_index);
+ if (!struct_def->Deserialize(*this, *it)) { return false; }
+ if (schema->root_table() == *it) { root_struct_def_ = struct_def; }
+ }
+ for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
+ std::string qualified_name = it->name()->str();
+ auto enum_def = enums_.Lookup(qualified_name);
+ enum_def->defined_namespace =
+ GetNamespace(qualified_name, namespaces_, namespaces_index);
+ if (!enum_def->Deserialize(*this, *it)) { return false; }
+ }
+
+ if (schema->services()) {
+ for (auto it = schema->services()->begin(); it != schema->services()->end();
+ ++it) {
+ std::string qualified_name = it->name()->str();
+ auto service_def = new ServiceDef();
+ service_def->defined_namespace =
+ GetNamespace(qualified_name, namespaces_, namespaces_index);
+ if (!service_def->Deserialize(*this, *it) ||
+ services_.Add(qualified_name, service_def)) {
+ delete service_def;
+ return false;
+ }
+ }
+ }
+ advanced_features_ = schema->advanced_features();
+ return true;
+}
+
+std::string Parser::ConformTo(const Parser &base) {
+ for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) {
+ auto &struct_def = **sit;
+ auto qualified_name =
+ struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
+ auto struct_def_base = base.LookupStruct(qualified_name);
+ if (!struct_def_base) continue;
+ for (auto fit = struct_def.fields.vec.begin();
+ fit != struct_def.fields.vec.end(); ++fit) {
+ auto &field = **fit;
+ auto field_base = struct_def_base->fields.Lookup(field.name);
+ if (field_base) {
+ if (field.value.offset != field_base->value.offset)
+ return "offsets differ for field: " + field.name;
+ if (field.value.constant != field_base->value.constant)
+ return "defaults differ for field: " + field.name;
+ if (!EqualByName(field.value.type, field_base->value.type))
+ return "types differ for field: " + field.name;
+ } else {
+ // Doesn't have to exist, deleting fields is fine.
+ // But we should check if there is a field that has the same offset
+ // but is incompatible (in the case of field renaming).
+ for (auto fbit = struct_def_base->fields.vec.begin();
+ fbit != struct_def_base->fields.vec.end(); ++fbit) {
+ field_base = *fbit;
+ if (field.value.offset == field_base->value.offset) {
+ if (!EqualByName(field.value.type, field_base->value.type))
+ return "field renamed to different type: " + field.name;
+ break;
+ }
+ }
+ }
+ }
+ }
+ for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
+ auto &enum_def = **eit;
+ auto qualified_name =
+ enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name);
+ auto enum_def_base = base.enums_.Lookup(qualified_name);
+ if (!enum_def_base) continue;
+ for (auto evit = enum_def.Vals().begin(); evit != enum_def.Vals().end();
+ ++evit) {
+ auto &enum_val = **evit;
+ auto enum_val_base = enum_def_base->Lookup(enum_val.name);
+ if (enum_val_base) {
+ if (enum_val != *enum_val_base)
+ return "values differ for enum: " + enum_val.name;
+ }
+ }
+ }
+ return "";
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/reflection.cpp b/contrib/libs/flatbuffers/src/reflection.cpp
new file mode 100644
index 0000000000..2dedcb4f18
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/reflection.cpp
@@ -0,0 +1,713 @@
+/*
+ * Copyright 2015 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 "flatbuffers/reflection.h"
+
+#include "flatbuffers/util.h"
+
+// Helper functionality for reflection.
+
+namespace flatbuffers {
+
+int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
+// 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: {
+ auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
+ data);
+ return s ? StringToInt(s->c_str()) : 0;
+ }
+ default: return 0; // Tables & vectors do not make sense.
+ }
+ #undef FLATBUFFERS_GET
+ // clang-format on
+}
+
+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: {
+ auto s =
+ reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
+ if (s) {
+ double d;
+ StringToNumber(s->c_str(), &d);
+ return d;
+ } else {
+ return 0.0;
+ }
+ }
+ default: return static_cast<double>(GetAnyValueI(type, data));
+ }
+}
+
+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: {
+ auto s =
+ reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
+ return s ? s->c_str() : "";
+ }
+ case reflection::Obj:
+ if (schema) {
+ // Convert the table to a string. This is mostly for debugging purposes,
+ // and does NOT promise to be JSON compliant.
+ // Also prefixes the type.
+ auto &objectdef = *schema->objects()->Get(type_index);
+ auto s = objectdef.name()->str();
+ if (objectdef.is_struct()) {
+ s += "(struct)"; // TODO: implement this as well.
+ } else {
+ auto table_field = reinterpret_cast<const Table *>(
+ ReadScalar<uoffset_t>(data) + data);
+ s += " { ";
+ auto fielddefs = objectdef.fields();
+ for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+ auto &fielddef = **it;
+ if (!table_field->CheckField(fielddef.offset())) continue;
+ auto val = GetAnyFieldS(*table_field, fielddef, schema);
+ if (fielddef.type()->base_type() == reflection::String) {
+ std::string esc;
+ flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true,
+ false);
+ val = esc;
+ }
+ s += fielddef.name()->str();
+ s += ": ";
+ s += val;
+ s += ", ";
+ }
+ s += "}";
+ }
+ return s;
+ } else {
+ return "(table)";
+ }
+ case reflection::Vector:
+ return "[(elements)]"; // TODO: implement this as well.
+ case reflection::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
+ #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;
+ // TODO: support strings
+ default: break;
+ }
+ #undef FLATBUFFERS_SET
+ // clang-format on
+}
+
+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;
+ // TODO: support strings.
+ default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break;
+ }
+}
+
+void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
+ switch (type) {
+ case reflection::Float:
+ case reflection::Double: {
+ double d;
+ StringToNumber(val, &d);
+ SetAnyValueF(type, data, d);
+ break;
+ }
+ // TODO: support strings.
+ default: SetAnyValueI(type, data, StringToInt(val)); break;
+ }
+}
+
+// Resize a FlatBuffer in-place by iterating through all offsets in the buffer
+// and adjusting them by "delta" if they straddle the start offset.
+// Once that is done, bytes can now be inserted/deleted safely.
+// "delta" may be negative (shrinking).
+// Unless "delta" is a multiple of the largest alignment, you'll create a small
+// amount of garbage space in the buffer (usually 0..7 bytes).
+// If your FlatBuffer's root table is not the schema's root table, you should
+// pass in your root_table type as well.
+class ResizeContext {
+ public:
+ ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
+ std::vector<uint8_t> *flatbuf,
+ const reflection::Object *root_table = nullptr)
+ : schema_(schema),
+ startptr_(vector_data(*flatbuf) + start),
+ delta_(delta),
+ buf_(*flatbuf),
+ dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
+ auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
+ 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_));
+ ResizeTable(root_table ? *root_table : *schema.root_table(), root);
+ // We can now add or remove bytes at start.
+ if (delta_ > 0)
+ buf_.insert(buf_.begin() + start, delta_, 0);
+ else
+ buf_.erase(buf_.begin() + start + delta_, buf_.begin() + start);
+ }
+
+ // Check if the range between first (lower address) and second straddles
+ // the insertion point. If it does, change the offset at offsetloc (of
+ // type T, with direction D).
+ template<typename T, int D>
+ void Straddle(const void *first, const void *second, void *offsetloc) {
+ if (first <= startptr_ && second >= startptr_) {
+ WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
+ DagCheck(offsetloc) = true;
+ }
+ }
+
+ // This returns a boolean that records if the corresponding offset location
+ // has been modified already. If so, we can't even read the corresponding
+ // offset, since it is pointing to a location that is illegal until the
+ // resize actually happens.
+ // This must be checked for every offset, since we can't know which offsets
+ // 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_));
+ return dag_check_[dag_idx];
+ }
+
+ void ResizeTable(const reflection::Object &objectdef, Table *table) {
+ if (DagCheck(table)) return; // Table already visited.
+ auto vtable = table->GetVTable();
+ // Early out: since all fields inside the table must point forwards in
+ // memory, if the insertion point is before the table we can stop here.
+ auto tableloc = reinterpret_cast<uint8_t *>(table);
+ if (startptr_ <= tableloc) {
+ // Check if insertion point is between the table and a vtable that
+ // precedes it. This can't happen in current construction code, but check
+ // just in case we ever change the way flatbuffers are built.
+ Straddle<soffset_t, -1>(vtable, table, table);
+ } else {
+ // Check each field.
+ auto fielddefs = objectdef.fields();
+ for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+ auto &fielddef = **it;
+ auto base_type = fielddef.type()->base_type();
+ // Ignore scalars.
+ if (base_type <= reflection::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
+ ? schema_.objects()->Get(fielddef.type()->index())
+ : nullptr;
+ if (subobjectdef && subobjectdef->is_struct()) continue;
+ // Get this fields' offset, and read it if safe.
+ auto offsetloc = tableloc + offset;
+ if (DagCheck(offsetloc)) continue; // This offset already visited.
+ auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
+ Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
+ // Recurse.
+ switch (base_type) {
+ case reflection::Obj: {
+ ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
+ break;
+ }
+ case reflection::Vector: {
+ auto elem_type = fielddef.type()->element();
+ if (elem_type != reflection::Obj && elem_type != reflection::String)
+ break;
+ auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
+ auto elemobjectdef =
+ elem_type == reflection::Obj
+ ? schema_.objects()->Get(fielddef.type()->index())
+ : nullptr;
+ if (elemobjectdef && elemobjectdef->is_struct()) break;
+ for (uoffset_t i = 0; i < vec->size(); i++) {
+ auto loc = vec->Data() + i * sizeof(uoffset_t);
+ if (DagCheck(loc)) continue; // This offset already visited.
+ auto dest = loc + vec->Get(i);
+ Straddle<uoffset_t, 1>(loc, dest, loc);
+ if (elemobjectdef)
+ ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
+ }
+ break;
+ }
+ case reflection::Union: {
+ ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
+ reinterpret_cast<Table *>(ref));
+ break;
+ }
+ case reflection::String: break;
+ default: FLATBUFFERS_ASSERT(false);
+ }
+ }
+ // Check if the vtable offset points beyond the insertion point.
+ // Must do this last, since GetOptionalFieldOffset above still reads
+ // this value.
+ Straddle<soffset_t, -1>(table, vtable, table);
+ }
+ }
+
+ private:
+ const reflection::Schema &schema_;
+ uint8_t *startptr_;
+ int delta_;
+ std::vector<uint8_t> &buf_;
+ std::vector<uint8_t> dag_check_;
+};
+
+void SetString(const reflection::Schema &schema, const std::string &val,
+ const String *str, std::vector<uint8_t> *flatbuf,
+ 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));
+ 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());
+ // Different size, we must expand (or contract).
+ ResizeContext(schema, start, delta, flatbuf, root_table);
+ // Set the new length.
+ WriteScalar(vector_data(*flatbuf) + 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);
+}
+
+uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
+ const VectorOfAny *vec, uoffset_t num_elems,
+ uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
+ 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);
+ 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);
+ }
+ ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
+ WriteScalar(vector_data(*flatbuf) + 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);
+ }
+ }
+ return vector_data(*flatbuf) + start;
+}
+
+const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
+ const uint8_t *newbuf, size_t newlen) {
+ // Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
+ // going to chop off the root offset.
+ while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
+ !(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
+ flatbuf.push_back(0);
+ }
+ auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
+ // 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;
+}
+
+void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
+ const Table &table, size_t align, size_t size) {
+ fbb.Align(align);
+ fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
+ fbb.TrackField(fielddef.offset(), fbb.GetSize());
+}
+
+Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
+ const reflection::Schema &schema,
+ const reflection::Object &objectdef,
+ const Table &table, bool use_string_pooling) {
+ // Before we can construct the table, we have to first generate any
+ // subobjects, and collect their offsets.
+ std::vector<uoffset_t> offsets;
+ auto fielddefs = objectdef.fields();
+ for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+ auto &fielddef = **it;
+ // Skip if field is not present in the source.
+ if (!table.CheckField(fielddef.offset())) continue;
+ uoffset_t offset = 0;
+ switch (fielddef.type()->base_type()) {
+ case reflection::String: {
+ offset = use_string_pooling
+ ? fbb.CreateSharedString(GetFieldS(table, fielddef)).o
+ : fbb.CreateString(GetFieldS(table, fielddef)).o;
+ break;
+ }
+ case reflection::Obj: {
+ auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
+ if (!subobjectdef.is_struct()) {
+ offset = CopyTable(fbb, schema, subobjectdef,
+ *GetFieldT(table, fielddef), use_string_pooling)
+ .o;
+ }
+ break;
+ }
+ case reflection::Union: {
+ auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
+ offset = CopyTable(fbb, schema, subobjectdef,
+ *GetFieldT(table, fielddef), use_string_pooling)
+ .o;
+ break;
+ }
+ case reflection::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
+ ? schema.objects()->Get(fielddef.type()->index())
+ : nullptr;
+ switch (element_base_type) {
+ case reflection::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++) {
+ elements[i] = use_string_pooling
+ ? fbb.CreateSharedString(vec_s->Get(i)).o
+ : fbb.CreateString(vec_s->Get(i)).o;
+ }
+ offset = fbb.CreateVector(elements).o;
+ break;
+ }
+ case reflection::Obj: {
+ if (!elemobjectdef->is_struct()) {
+ std::vector<Offset<const Table *>> elements(vec->size());
+ for (uoffset_t i = 0; i < vec->size(); i++) {
+ elements[i] = CopyTable(fbb, schema, *elemobjectdef,
+ *vec->Get(i), use_string_pooling);
+ }
+ offset = fbb.CreateVector(elements).o;
+ break;
+ }
+ }
+ FLATBUFFERS_FALLTHROUGH(); // fall thru
+ default: { // Scalars and structs.
+ auto element_size = GetTypeSize(element_base_type);
+ if (elemobjectdef && elemobjectdef->is_struct())
+ element_size = elemobjectdef->bytesize();
+ fbb.StartVector(vec->size(), element_size);
+ fbb.PushBytes(vec->Data(), element_size * vec->size());
+ offset = fbb.EndVector(vec->size());
+ break;
+ }
+ }
+ break;
+ }
+ default: // Scalars.
+ break;
+ }
+ if (offset) { offsets.push_back(offset); }
+ }
+ // Now we can build the actual table from either offsets or scalar data.
+ auto start = objectdef.is_struct() ? fbb.StartStruct(objectdef.minalign())
+ : fbb.StartTable();
+ size_t offset_idx = 0;
+ for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+ auto &fielddef = **it;
+ if (!table.CheckField(fielddef.offset())) continue;
+ auto base_type = fielddef.type()->base_type();
+ switch (base_type) {
+ case reflection::Obj: {
+ auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
+ if (subobjectdef.is_struct()) {
+ CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
+ subobjectdef.bytesize());
+ break;
+ }
+ }
+ FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case reflection::Union:
+ case reflection::String:
+ case reflection::Vector:
+ fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
+ break;
+ default: { // Scalars.
+ auto size = GetTypeSize(base_type);
+ CopyInline(fbb, fielddef, table, size, size);
+ break;
+ }
+ }
+ }
+ FLATBUFFERS_ASSERT(offset_idx == offsets.size());
+ if (objectdef.is_struct()) {
+ fbb.ClearOffsets();
+ return fbb.EndStruct();
+ } else {
+ return fbb.EndTable(start);
+ }
+}
+
+bool VerifyStruct(flatbuffers::Verifier &v,
+ const flatbuffers::Table &parent_table,
+ voffset_t field_offset, const reflection::Object &obj,
+ bool required) {
+ 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());
+}
+
+bool VerifyVectorOfStructs(flatbuffers::Verifier &v,
+ const flatbuffers::Table &parent_table,
+ voffset_t field_offset,
+ const reflection::Object &obj, bool required) {
+ auto p = parent_table.GetPointer<const uint8_t *>(field_offset);
+ if (required && !p) { return false; }
+
+ return !p || v.VerifyVectorOrString(p, obj.bytesize());
+}
+
+// forward declare to resolve cyclic deps between VerifyObject and VerifyVector
+bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
+ const reflection::Object &obj,
+ const flatbuffers::Table *table, bool required);
+
+bool VerifyUnion(flatbuffers::Verifier &v, const reflection::Schema &schema,
+ uint8_t utype, const uint8_t *elem,
+ const reflection::Field &union_field) {
+ if (!utype) return true; // Not present.
+ auto fb_enum = schema.enums()->Get(union_field.type()->index());
+ 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: {
+ auto elem_obj = schema.objects()->Get(elem_type->index());
+ if (elem_obj->is_struct()) {
+ return v.VerifyFromPointer(elem, elem_obj->bytesize());
+ } else {
+ return VerifyObject(v, schema, *elem_obj,
+ reinterpret_cast<const flatbuffers::Table *>(elem),
+ true);
+ }
+ }
+ case reflection::String:
+ return v.VerifyString(
+ reinterpret_cast<const flatbuffers::String *>(elem));
+ default: return false;
+ }
+}
+
+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;
+
+ switch (vec_field.type()->element()) {
+ case reflection::UType:
+ return v.VerifyVector(flatbuffers::GetFieldV<uint8_t>(table, vec_field));
+ case reflection::Bool:
+ case reflection::Byte:
+ case reflection::UByte:
+ return v.VerifyVector(flatbuffers::GetFieldV<int8_t>(table, vec_field));
+ case reflection::Short:
+ case reflection::UShort:
+ return v.VerifyVector(flatbuffers::GetFieldV<int16_t>(table, vec_field));
+ case reflection::Int:
+ case reflection::UInt:
+ return v.VerifyVector(flatbuffers::GetFieldV<int32_t>(table, vec_field));
+ case reflection::Long:
+ case reflection::ULong:
+ return v.VerifyVector(flatbuffers::GetFieldV<int64_t>(table, vec_field));
+ case reflection::Float:
+ return v.VerifyVector(flatbuffers::GetFieldV<float>(table, vec_field));
+ case reflection::Double:
+ return v.VerifyVector(flatbuffers::GetFieldV<double>(table, vec_field));
+ case reflection::String: {
+ auto vec_string =
+ flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
+ table, vec_field);
+ if (v.VerifyVector(vec_string) && v.VerifyVectorOfStrings(vec_string)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ case reflection::Obj: {
+ auto obj = schema.objects()->Get(vec_field.type()->index());
+ if (obj->is_struct()) {
+ return VerifyVectorOfStructs(v, table, vec_field.offset(), *obj,
+ vec_field.required());
+ } else {
+ auto vec =
+ flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::Table>>(
+ table, vec_field);
+ if (!v.VerifyVector(vec)) return false;
+ if (!vec) return true;
+ for (uoffset_t j = 0; j < vec->size(); j++) {
+ if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ case reflection::Union: {
+ auto vec = flatbuffers::GetFieldV<flatbuffers::Offset<uint8_t>>(
+ table, vec_field);
+ if (!v.VerifyVector(vec)) return false;
+ if (!vec) return true;
+ auto type_vec = table.GetPointer<Vector<uint8_t> *>(vec_field.offset() -
+ sizeof(voffset_t));
+ if (!v.VerifyVector(type_vec)) return false;
+ for (uoffset_t j = 0; j < vec->size(); j++) {
+ // get union type from the prev field
+ auto utype = type_vec->Get(j);
+ auto elem = vec->Get(j);
+ if (!VerifyUnion(v, schema, utype, elem, vec_field)) return false;
+ }
+ return true;
+ }
+ case reflection::Vector:
+ case reflection::None:
+ default: FLATBUFFERS_ASSERT(false); return false;
+ }
+}
+
+bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
+ const reflection::Object &obj,
+ const flatbuffers::Table *table, bool required) {
+ if (!table) return !required;
+ if (!table->VerifyTableStart(v)) return false;
+ 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;
+ break;
+ case reflection::Bool:
+ case reflection::Byte:
+ case reflection::UByte:
+ if (!table->VerifyField<int8_t>(v, field_def->offset())) return false;
+ break;
+ case reflection::Short:
+ case reflection::UShort:
+ if (!table->VerifyField<int16_t>(v, field_def->offset())) return false;
+ break;
+ case reflection::Int:
+ case reflection::UInt:
+ if (!table->VerifyField<int32_t>(v, field_def->offset())) return false;
+ break;
+ case reflection::Long:
+ case reflection::ULong:
+ if (!table->VerifyField<int64_t>(v, field_def->offset())) return false;
+ break;
+ case reflection::Float:
+ if (!table->VerifyField<float>(v, field_def->offset())) return false;
+ break;
+ case reflection::Double:
+ if (!table->VerifyField<double>(v, field_def->offset())) return false;
+ break;
+ case reflection::String:
+ if (!table->VerifyField<uoffset_t>(v, field_def->offset()) ||
+ !v.VerifyString(flatbuffers::GetFieldS(*table, *field_def))) {
+ return false;
+ }
+ break;
+ case reflection::Vector:
+ if (!VerifyVector(v, schema, *table, *field_def)) return false;
+ break;
+ case reflection::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,
+ field_def->required())) {
+ return false;
+ }
+ } else {
+ if (!VerifyObject(v, schema, *child_obj,
+ flatbuffers::GetFieldT(*table, *field_def),
+ field_def->required())) {
+ return false;
+ }
+ }
+ break;
+ }
+ case reflection::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);
+ auto uval = reinterpret_cast<const uint8_t *>(
+ flatbuffers::GetFieldT(*table, *field_def));
+ if (!VerifyUnion(v, schema, utype, uval, *field_def)) { return false; }
+ break;
+ }
+ default: FLATBUFFERS_ASSERT(false); break;
+ }
+ }
+
+ if (!v.EndTable()) return false;
+
+ return true;
+}
+
+bool Verify(const reflection::Schema &schema, const reflection::Object &root,
+ const uint8_t *buf, size_t length, uoffset_t max_depth /*= 64*/,
+ uoffset_t max_tables /*= 1000000*/) {
+ Verifier v(buf, length, max_depth, max_tables);
+ return VerifyObject(v, schema, root, flatbuffers::GetAnyRoot(buf), true);
+}
+
+} // namespace flatbuffers
diff --git a/contrib/libs/flatbuffers/src/util.cpp b/contrib/libs/flatbuffers/src/util.cpp
new file mode 100644
index 0000000000..3670a01939
--- /dev/null
+++ b/contrib/libs/flatbuffers/src/util.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2016 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.
+ */
+
+// clang-format off
+// Dont't remove `format off`, it prevent reordering of win-includes.
+
+#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__) || \
+ defined(__QNXNTO__)
+# define _POSIX_C_SOURCE 200809L
+# define _XOPEN_SOURCE 700L
+#endif
+
+#ifdef _WIN32
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
+# ifdef _MSC_VER
+# include <crtdbg.h>
+# endif
+# include <windows.h> // Must be included before <direct.h>
+# include <direct.h>
+# include <winbase.h>
+# undef interface // This is also important because of reasons
+#endif
+// clang-format on
+
+#include "flatbuffers/base.h"
+#include "flatbuffers/util.h"
+
+#include <sys/stat.h>
+#include <clocale>
+#include <cstdlib>
+#include <fstream>
+
+namespace flatbuffers {
+
+bool FileExistsRaw(const char *name) {
+ std::ifstream ifs(name);
+ return ifs.good();
+}
+
+bool LoadFileRaw(const char *name, bool binary, std::string *buf) {
+ if (DirExists(name)) return false;
+ std::ifstream ifs(name, binary ? std::ifstream::binary : std::ifstream::in);
+ if (!ifs.is_open()) return false;
+ if (binary) {
+ // The fastest way to read a file into a string.
+ ifs.seekg(0, std::ios::end);
+ auto size = ifs.tellg();
+ (*buf).resize(static_cast<size_t>(size));
+ ifs.seekg(0, std::ios::beg);
+ ifs.read(&(*buf)[0], (*buf).size());
+ } else {
+ // This is slower, but works correctly on all platforms for text files.
+ std::ostringstream oss;
+ oss << ifs.rdbuf();
+ *buf = oss.str();
+ }
+ return !ifs.bad();
+}
+
+static LoadFileFunction g_load_file_function = LoadFileRaw;
+static FileExistsFunction g_file_exists_function = FileExistsRaw;
+
+bool LoadFile(const char *name, bool binary, std::string *buf) {
+ FLATBUFFERS_ASSERT(g_load_file_function);
+ return g_load_file_function(name, binary, buf);
+}
+
+bool FileExists(const char *name) {
+ FLATBUFFERS_ASSERT(g_file_exists_function);
+ return g_file_exists_function(name);
+}
+
+bool DirExists(const char *name) {
+ // clang-format off
+
+ #ifdef _WIN32
+ #define flatbuffers_stat _stat
+ #define FLATBUFFERS_S_IFDIR _S_IFDIR
+ #else
+ #define flatbuffers_stat stat
+ #define FLATBUFFERS_S_IFDIR S_IFDIR
+ #endif
+ // clang-format on
+ struct flatbuffers_stat file_info;
+ if (flatbuffers_stat(name, &file_info) != 0) return false;
+ return (file_info.st_mode & FLATBUFFERS_S_IFDIR) != 0;
+}
+
+LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function) {
+ LoadFileFunction previous_function = g_load_file_function;
+ g_load_file_function = load_file_function ? load_file_function : LoadFileRaw;
+ return previous_function;
+}
+
+FileExistsFunction SetFileExistsFunction(
+ FileExistsFunction file_exists_function) {
+ FileExistsFunction previous_function = g_file_exists_function;
+ g_file_exists_function =
+ file_exists_function ? file_exists_function : FileExistsRaw;
+ return previous_function;
+}
+
+bool SaveFile(const char *name, const char *buf, size_t len, bool binary) {
+ std::ofstream ofs(name, binary ? std::ofstream::binary : std::ofstream::out);
+ if (!ofs.is_open()) return false;
+ ofs.write(buf, len);
+ return !ofs.bad();
+}
+
+// We internally store paths in posix format ('/'). Paths supplied
+// by the user should go through PosixPath to ensure correct behavior
+// on Windows when paths are string-compared.
+
+static const char kPathSeparatorWindows = '\\';
+static const char *PathSeparatorSet = "\\/"; // Intentionally no ':'
+
+std::string StripExtension(const std::string &filepath) {
+ size_t i = filepath.find_last_of('.');
+ return i != std::string::npos ? filepath.substr(0, i) : filepath;
+}
+
+std::string GetExtension(const std::string &filepath) {
+ size_t i = filepath.find_last_of('.');
+ return i != std::string::npos ? filepath.substr(i + 1) : "";
+}
+
+std::string StripPath(const std::string &filepath) {
+ size_t i = filepath.find_last_of(PathSeparatorSet);
+ return i != std::string::npos ? filepath.substr(i + 1) : filepath;
+}
+
+std::string StripFileName(const std::string &filepath) {
+ size_t i = filepath.find_last_of(PathSeparatorSet);
+ return i != std::string::npos ? filepath.substr(0, i) : "";
+}
+
+std::string ConCatPathFileName(const std::string &path,
+ const std::string &filename) {
+ std::string filepath = path;
+ if (filepath.length()) {
+ char &filepath_last_character = string_back(filepath);
+ if (filepath_last_character == kPathSeparatorWindows) {
+ filepath_last_character = kPathSeparator;
+ } else if (filepath_last_character != kPathSeparator) {
+ filepath += kPathSeparator;
+ }
+ }
+ filepath += filename;
+ // Ignore './' at the start of filepath.
+ if (filepath[0] == '.' && filepath[1] == kPathSeparator) {
+ filepath.erase(0, 2);
+ }
+ return filepath;
+}
+
+std::string PosixPath(const char *path) {
+ std::string p = path;
+ std::replace(p.begin(), p.end(), '\\', '/');
+ return p;
+}
+
+void EnsureDirExists(const std::string &filepath) {
+ auto parent = StripFileName(filepath);
+ if (parent.length()) EnsureDirExists(parent);
+ // clang-format off
+
+ #ifdef _WIN32
+ (void)_mkdir(filepath.c_str());
+ #else
+ mkdir(filepath.c_str(), S_IRWXU|S_IRGRP|S_IXGRP);
+ #endif
+ // clang-format on
+}
+
+std::string AbsolutePath(const std::string &filepath) {
+ // clang-format off
+
+ #ifdef FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
+ return filepath;
+ #else
+ #ifdef _WIN32
+ char abs_path[MAX_PATH];
+ return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr)
+ #else
+ char *abs_path_temp = realpath(filepath.c_str(), nullptr);
+ bool success = abs_path_temp != nullptr;
+ std::string abs_path;
+ if(success) {
+ abs_path = abs_path_temp;
+ free(abs_path_temp);
+ }
+ return success
+ #endif
+ ? abs_path
+ : filepath;
+ #endif // FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
+ // clang-format on
+}
+
+// Locale-independent code.
+#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && \
+ (FLATBUFFERS_LOCALE_INDEPENDENT > 0)
+
+// clang-format off
+// Allocate locale instance at startup of application.
+ClassicLocale ClassicLocale::instance_;
+
+#ifdef _MSC_VER
+ ClassicLocale::ClassicLocale()
+ : locale_(_create_locale(LC_ALL, "C")) {}
+ ClassicLocale::~ClassicLocale() { _free_locale(locale_); }
+#else
+ ClassicLocale::ClassicLocale()
+ : locale_(newlocale(LC_ALL, "C", nullptr)) {}
+ ClassicLocale::~ClassicLocale() { freelocale(locale_); }
+#endif
+// clang-format on
+
+#endif // !FLATBUFFERS_LOCALE_INDEPENDENT
+
+std::string RemoveStringQuotes(const std::string &s) {
+ auto ch = *s.c_str();
+ return ((s.size() >= 2) && (ch == '\"' || ch == '\'') &&
+ (ch == string_back(s)))
+ ? s.substr(1, s.length() - 2)
+ : s;
+}
+
+bool SetGlobalTestLocale(const char *locale_name, std::string *_value) {
+ const auto the_locale = setlocale(LC_ALL, locale_name);
+ if (!the_locale) return false;
+ if (_value) *_value = std::string(the_locale);
+ return true;
+}
+
+bool ReadEnvironmentVariable(const char *var_name, std::string *_value) {
+#ifdef _MSC_VER
+ __pragma(warning(disable : 4996)); // _CRT_SECURE_NO_WARNINGS
+#endif
+ auto env_str = std::getenv(var_name);
+ if (!env_str) return false;
+ if (_value) *_value = std::string(env_str);
+ return true;
+}
+
+void SetupDefaultCRTReportMode() {
+ // clang-format off
+
+ #ifdef _MSC_VER
+ // By default, send all reports to STDOUT to prevent CI hangs.
+ // Enable assert report box [Abort|Retry|Ignore] if a debugger is present.
+ const int dbg_mode = (_CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG) |
+ (IsDebuggerPresent() ? _CRTDBG_MODE_WNDW : 0);
+ (void)dbg_mode; // release mode fix
+ // CrtDebug reports to _CRT_WARN channel.
+ _CrtSetReportMode(_CRT_WARN, dbg_mode);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
+ // The assert from <assert.h> reports to _CRT_ERROR channel
+ _CrtSetReportMode(_CRT_ERROR, dbg_mode);
+ _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
+ // Internal CRT assert channel?
+ _CrtSetReportMode(_CRT_ASSERT, dbg_mode);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);
+ #endif
+
+ // clang-format on
+}
+
+} // namespace flatbuffers