2 * Copyright 2018 Google Inc. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 // independent from idl_parser, since this code is not needed for most clients
19 #include "flatbuffers/code_generators.h"
20 #include "flatbuffers/flatbuffers.h"
21 #include "flatbuffers/idl.h"
22 #include "flatbuffers/util.h"
24 namespace flatbuffers {
26 static std::string GeneratedFileName(const std::string &path,
27 const std::string &file_name) {
28 return path + file_name + "_generated.rs";
31 // Convert a camelCaseIdentifier or CamelCaseIdentifier to a
32 // snake_case_indentifier.
33 std::string MakeSnakeCase(const std::string &in) {
35 for (size_t i = 0; i < in.length(); i++) {
37 s += static_cast<char>(tolower(in[0]));
38 } else if (in[i] == '_') {
40 } else if (!islower(in[i])) {
41 // Prevent duplicate underscores for Upper_Snake_Case strings
42 // and UPPERCASE strings.
43 if (islower(in[i - 1])) {
46 s += static_cast<char>(tolower(in[i]));
54 // Convert a string to all uppercase.
55 std::string MakeUpper(const std::string &in) {
57 for (size_t i = 0; i < in.length(); i++) {
58 s += static_cast<char>(toupper(in[i]));
63 // Encapsulate all logical field types in this enum. This allows us to write
64 // field logic based on type switches, instead of branches on the properties
66 // TODO(rw): for backwards compatibility, we can't use a strict `enum class`
67 // declaration here. could we use the `-Wswitch-enum` warning to
68 // achieve the same effect?
82 // TODO(rw): bytestring?
85 ftVectorOfInteger = 9,
88 ftVectorOfEnumKey = 12,
89 ftVectorOfStruct = 13,
91 ftVectorOfString = 15,
92 ftVectorOfUnionValue = 16,
95 // Convert a Type to a FullType (exhaustive).
96 FullType GetFullType(const Type &type) {
97 // N.B. The order of these conditionals matters for some types.
99 if (type.base_type == BASE_TYPE_STRING) {
101 } else if (type.base_type == BASE_TYPE_STRUCT) {
102 if (type.struct_def->fixed) {
107 } else if (type.base_type == BASE_TYPE_VECTOR) {
108 switch (GetFullType(type.VectorType())) {
110 return ftVectorOfInteger;
113 return ftVectorOfFloat;
116 return ftVectorOfBool;
119 return ftVectorOfStruct;
122 return ftVectorOfTable;
125 return ftVectorOfString;
128 return ftVectorOfEnumKey;
132 FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
136 FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
139 } else if (type.enum_def != nullptr) {
140 if (type.enum_def->is_union) {
141 if (type.base_type == BASE_TYPE_UNION) {
143 } else if (IsInteger(type.base_type)) {
146 FLATBUFFERS_ASSERT(false && "unknown union field type");
151 } else if (IsScalar(type.base_type)) {
152 if (IsBool(type.base_type)) {
154 } else if (IsInteger(type.base_type)) {
156 } else if (IsFloat(type.base_type)) {
159 FLATBUFFERS_ASSERT(false && "unknown number type");
163 FLATBUFFERS_ASSERT(false && "completely unknown type");
165 // this is only to satisfy the compiler's return analysis.
169 // If the second parameter is false then wrap the first with Option<...>
170 std::string WrapInOptionIfNotRequired(std::string s, bool required) {
174 return "Option<" + s + ">";
178 // If the second parameter is false then add .unwrap()
179 std::string AddUnwrapIfRequired(std::string s, bool required) {
181 return s + ".unwrap()";
189 class RustGenerator : public BaseGenerator {
191 RustGenerator(const Parser &parser, const std::string &path,
192 const std::string &file_name)
193 : BaseGenerator(parser, path, file_name, "", "::"),
194 cur_name_space_(nullptr) {
195 const char *keywords[] = {
197 // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
199 // we write keywords one per line so that we can easily compare them with
200 // changes to that webpage in the future.
202 // currently-used keywords
239 // future possible keywords
258 // other rust terms we should not use
275 // These are terms the code generator can implement on types.
277 // In Rust, the trait resolution rules (as described at
278 // https://github.com/rust-lang/rust/issues/26007) mean that, as long
279 // as we impl table accessors as inherent methods, we'll never create
280 // conflicts with these keywords. However, that's a fairly nuanced
281 // implementation detail, and how we implement methods could change in
282 // the future. as a result, we proactively block these out as reserved
289 "from_little_endian",
291 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
294 // Iterate through all definitions we haven't generated code for (enums,
295 // structs, and tables) and output them to a single file.
298 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
300 assert(!cur_name_space_);
302 // Generate imports for the global scope in case no namespace is used
303 // in the schema file.
304 GenNamespaceImports(0);
307 // Generate all code in their namespaces, once, because Rust does not
308 // permit re-opening modules.
310 // TODO(rw): Use a set data structure to reduce namespace evaluations from
312 for (auto ns_it = parser_.namespaces_.begin();
313 ns_it != parser_.namespaces_.end();
315 const auto &ns = *ns_it;
317 // Generate code for all the enum declarations.
318 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
320 const auto &enum_def = **it;
321 if (enum_def.defined_namespace != ns) { continue; }
322 if (!enum_def.generated) {
323 SetNameSpace(enum_def.defined_namespace);
328 // Generate code for all structs.
329 for (auto it = parser_.structs_.vec.begin();
330 it != parser_.structs_.vec.end(); ++it) {
331 const auto &struct_def = **it;
332 if (struct_def.defined_namespace != ns) { continue; }
333 if (struct_def.fixed && !struct_def.generated) {
334 SetNameSpace(struct_def.defined_namespace);
335 GenStruct(struct_def);
339 // Generate code for all tables.
340 for (auto it = parser_.structs_.vec.begin();
341 it != parser_.structs_.vec.end(); ++it) {
342 const auto &struct_def = **it;
343 if (struct_def.defined_namespace != ns) { continue; }
344 if (!struct_def.fixed && !struct_def.generated) {
345 SetNameSpace(struct_def.defined_namespace);
346 GenTable(struct_def);
350 // Generate global helper functions.
351 if (parser_.root_struct_def_) {
352 auto &struct_def = *parser_.root_struct_def_;
353 if (struct_def.defined_namespace != ns) { continue; }
354 SetNameSpace(struct_def.defined_namespace);
355 GenRootTableFuncs(struct_def);
358 if (cur_name_space_) SetNameSpace(nullptr);
360 const auto file_path = GeneratedFileName(path_, file_name_);
361 const auto final_code = code_.ToString();
362 return SaveFile(file_path.c_str(), final_code, false);
368 std::set<std::string> keywords_;
370 // This tracks the current namespace so we can insert namespace declarations.
371 const Namespace *cur_name_space_;
373 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
375 // Determine if a Type needs a lifetime template parameter when used in the
376 // Rust builder args.
377 bool TableBuilderTypeNeedsLifetime(const Type &type) const {
378 switch (GetFullType(type)) {
384 case ftUnionValue: { return false; }
385 default: { return true; }
389 // Determine if a table args rust type needs a lifetime template parameter.
390 bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
391 FLATBUFFERS_ASSERT(!struct_def.fixed);
393 for (auto it = struct_def.fields.vec.begin();
394 it != struct_def.fields.vec.end(); ++it) {
395 const auto &field = **it;
396 if (field.deprecated) {
400 if (TableBuilderTypeNeedsLifetime(field.value.type)) {
408 // Determine if a Type needs to be copied (for endian safety) when used in a
410 bool StructMemberAccessNeedsCopy(const Type &type) const {
411 switch (GetFullType(type)) {
412 case ftInteger: // requires endian swap
413 case ftFloat: // requires endian swap
414 case ftBool: // no endian-swap, but do the copy for UX consistency
415 case ftEnumKey: { return true; } // requires endian swap
416 case ftStruct: { return false; } // no endian swap
418 // logic error: no other types can be struct members.
419 FLATBUFFERS_ASSERT(false && "invalid struct member type");
420 return false; // only to satisfy compiler's return analysis
425 std::string EscapeKeyword(const std::string &name) const {
426 return keywords_.find(name) == keywords_.end() ? name : name + "_";
429 std::string Name(const Definition &def) const {
430 return EscapeKeyword(def.name);
433 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
435 std::string WrapInNameSpace(const Definition &def) const {
436 return WrapInNameSpace(def.defined_namespace, Name(def));
438 std::string WrapInNameSpace(const Namespace *ns,
439 const std::string &name) const {
440 if (CurrentNameSpace() == ns) return name;
441 std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
442 return prefix + name;
445 // Determine the namespace traversal needed from the Rust crate root.
446 // This may be useful in the future for referring to included files, but is
448 std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const {
449 std::stringstream stream;
452 for (auto d = dst->components.begin(); d != dst->components.end(); ++d) {
453 stream << MakeSnakeCase(*d) + "::";
458 // Determine the relative namespace traversal needed to reference one
459 // namespace from another namespace. This is useful because it does not force
460 // the user to have a particular file layout. (If we output absolute
461 // namespace paths, that may require users to organize their Rust crates in a
463 std::string GetRelativeNamespaceTraversal(const Namespace *src,
464 const Namespace *dst) const {
465 // calculate the path needed to reference dst from src.
466 // example: f(A::B::C, A::B::C) -> (none)
467 // example: f(A::B::C, A::B) -> super::
468 // example: f(A::B::C, A::B::D) -> super::D
469 // example: f(A::B::C, A) -> super::super::
470 // example: f(A::B::C, D) -> super::super::super::D
471 // example: f(A::B::C, D::E) -> super::super::super::D::E
472 // example: f(A, D::E) -> super::D::E
473 // does not include leaf object (typically a struct type).
476 std::stringstream stream;
478 auto s = src->components.begin();
479 auto d = dst->components.begin();
481 if (s == src->components.end()) { break; }
482 if (d == dst->components.end()) { break; }
483 if (*s != *d) { break; }
489 for (; s != src->components.end(); ++s) {
492 for (; d != dst->components.end(); ++d) {
493 stream << MakeSnakeCase(*d) + "::";
498 // Generate a comment from the schema.
499 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
501 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
502 code_ += text + "\\";
505 // Return a Rust type from the table in idl.h.
506 std::string GetTypeBasic(const Type &type) const {
507 switch (GetFullType(type)) {
512 case ftUnionKey: { break; }
513 default: { FLATBUFFERS_ASSERT(false && "incorrect type given");}
517 static const char * const ctypename[] = {
518 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
521 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
522 #undef FLATBUFFERS_TD
526 if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
527 return ctypename[type.base_type];
530 // Look up the native type for an enum. This will always be an integer like
532 std::string GetEnumTypeForDecl(const Type &type) {
533 const auto ft = GetFullType(type);
534 if (!(ft == ftEnumKey || ft == ftUnionKey)) {
535 FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
538 static const char *ctypename[] = {
540 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
543 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
544 #undef FLATBUFFERS_TD
548 // Enums can be bools, but their Rust representation must be a u8, as used
549 // in the repr attribute (#[repr(bool)] is an invalid attribute).
550 if (type.base_type == BASE_TYPE_BOOL) return "u8";
551 return ctypename[type.base_type];
554 // Return a Rust type for any type (scalar, table, struct) specifically for
555 // using a FlatBuffer.
556 std::string GetTypeGet(const Type &type) const {
557 switch (GetFullType(type)) {
563 return GetTypeBasic(type); }
565 return WrapInNameSpace(type.struct_def->defined_namespace,
566 type.struct_def->name) + "<'a>"; }
568 return WrapInNameSpace(type.struct_def->defined_namespace,
569 type.struct_def->name); }
573 std::string GetEnumValUse(const EnumDef &enum_def,
574 const EnumVal &enum_val) const {
575 return Name(enum_def) + "::" + Name(enum_val);
578 // Generate an enum declaration,
579 // an enum string lookup table,
580 // an enum match function,
581 // and an enum array of values
582 void GenEnum(const EnumDef &enum_def) {
583 code_.SetValue("ENUM_NAME", Name(enum_def));
584 code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
586 GenComment(enum_def.doc_comment);
587 code_ += "#[allow(non_camel_case_types)]";
588 code_ += "#[repr({{BASE_TYPE}})]";
589 code_ += "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]";
590 code_ += "pub enum " + Name(enum_def) + " {";
592 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
593 const auto &ev = **it;
595 GenComment(ev.doc_comment, " ");
596 code_.SetValue("KEY", Name(ev));
597 code_.SetValue("VALUE", enum_def.ToString(ev));
598 code_ += " {{KEY}} = {{VALUE}},";
600 const EnumVal *minv = enum_def.MinValue();
601 const EnumVal *maxv = enum_def.MaxValue();
602 FLATBUFFERS_ASSERT(minv && maxv);
608 code_.SetValue("ENUM_NAME", Name(enum_def));
609 code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
610 code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
611 code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
612 code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
614 // Generate enum constants, and impls for Follow, EndianScalar, and Push.
615 code_ += "const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
616 code_ += "{{ENUM_MIN_BASE_VALUE}};";
617 code_ += "const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
618 code_ += "{{ENUM_MAX_BASE_VALUE}};";
620 code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
621 code_ += " type Inner = Self;";
622 code_ += " #[inline]";
623 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
624 code_ += " flatbuffers::read_scalar_at::<Self>(buf, loc)";
628 code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
629 code_ += " #[inline]";
630 code_ += " fn to_little_endian(self) -> Self {";
631 code_ += " let n = {{BASE_TYPE}}::to_le(self as {{BASE_TYPE}});";
632 code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
633 code_ += " unsafe { *p }";
635 code_ += " #[inline]";
636 code_ += " fn from_little_endian(self) -> Self {";
637 code_ += " let n = {{BASE_TYPE}}::from_le(self as {{BASE_TYPE}});";
638 code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
639 code_ += " unsafe { *p }";
643 code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
644 code_ += " type Output = {{ENUM_NAME}};";
645 code_ += " #[inline]";
646 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
647 code_ += " flatbuffers::emplace_scalar::<{{ENUM_NAME}}>"
653 // Generate an array of all enumeration values.
654 auto num_fields = NumToString(enum_def.size());
655 code_ += "#[allow(non_camel_case_types)]";
656 code_ += "const ENUM_VALUES_{{ENUM_NAME_CAPS}}:[{{ENUM_NAME}}; " +
657 num_fields + "] = [";
658 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
659 const auto &ev = **it;
660 auto value = GetEnumValUse(enum_def, ev);
661 auto suffix = *it != enum_def.Vals().back() ? "," : "";
662 code_ += " " + value + suffix;
667 // Generate a string table for enum values.
668 // Problem is, if values are very sparse that could generate really big
669 // tables. Ideally in that case we generate a map lookup instead, but for
670 // the moment we simply don't output a table at all.
671 auto range = enum_def.Distance();
672 // Average distance between values above which we consider a table
673 // "too sparse". Change at will.
674 static const uint64_t kMaxSparseness = 5;
675 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
676 code_ += "#[allow(non_camel_case_types)]";
677 code_ += "const ENUM_NAMES_{{ENUM_NAME_CAPS}}:[&'static str; " +
678 NumToString(range + 1) + "] = [";
680 auto val = enum_def.Vals().front();
681 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
684 for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
688 auto suffix = *it != enum_def.Vals().back() ? "," : "";
689 code_ += " \"" + Name(*ev) + "\"" + suffix;
695 "pub fn enum_name_{{ENUM_NAME_SNAKE}}(e: {{ENUM_NAME}}) -> "
698 code_ += " let index = e as {{BASE_TYPE}}\\";
699 if (enum_def.MinValue()->IsNonZero()) {
700 auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
701 code_ += " - " + vals + " as {{BASE_TYPE}}\\";
705 code_ += " ENUM_NAMES_{{ENUM_NAME_CAPS}}[index as usize]";
710 if (enum_def.is_union) {
711 // Generate tyoesafe offset(s) for unions
712 code_.SetValue("NAME", Name(enum_def));
713 code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
714 code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
718 std::string GetFieldOffsetName(const FieldDef &field) {
719 return "VT_" + MakeUpper(Name(field));
722 std::string GetDefaultConstant(const FieldDef &field) {
723 return field.value.type.base_type == BASE_TYPE_FLOAT
724 ? field.value.constant + ""
725 : field.value.constant;
728 std::string GetDefaultScalarValue(const FieldDef &field) {
729 switch (GetFullType(field.value.type)) {
730 case ftInteger: { return GetDefaultConstant(field); }
731 case ftFloat: { return GetDefaultConstant(field); }
733 return field.value.constant == "0" ? "false" : "true";
737 auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
739 return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
740 GetEnumValUse(*field.value.type.enum_def, *ev));
743 // All pointer-ish types have a default value of None, because they are
744 // wrapped in Option.
745 default: { return "None"; }
749 // Create the return type for fields in the *BuilderArgs structs that are
750 // used to create Tables.
752 // Note: we could make all inputs to the BuilderArgs be an Option, as well
753 // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
754 // know if the value is default or not, because there are three ways to
755 // return a default value:
756 // 1) return a stored value that happens to be the default,
757 // 2) return a hardcoded value because the relevant vtable field is not in
759 // 3) return a hardcoded value because the vtable field value is set to zero.
760 std::string TableBuilderArgsDefnType(const FieldDef &field,
761 const std::string &lifetime) {
762 const Type& type = field.value.type;
764 switch (GetFullType(type)) {
768 const auto typname = GetTypeBasic(type);
772 const auto typname = WrapInNameSpace(*type.struct_def);
773 return "Option<&" + lifetime + " " + typname + ">";
776 const auto typname = WrapInNameSpace(*type.struct_def);
777 return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime + \
781 return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
785 const auto typname = WrapInNameSpace(*type.enum_def);
789 return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
792 case ftVectorOfInteger:
793 case ftVectorOfFloat: {
794 const auto typname = GetTypeBasic(type.VectorType());
795 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
796 lifetime + ", " + typname + ">>>";
798 case ftVectorOfBool: {
799 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
800 lifetime + ", bool>>>";
802 case ftVectorOfEnumKey: {
803 const auto typname = WrapInNameSpace(*type.enum_def);
804 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
805 lifetime + ", " + typname + ">>>";
807 case ftVectorOfStruct: {
808 const auto typname = WrapInNameSpace(*type.struct_def);
809 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
810 lifetime + ", " + typname + ">>>";
812 case ftVectorOfTable: {
813 const auto typname = WrapInNameSpace(*type.struct_def);
814 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
815 lifetime + ", flatbuffers::ForwardsUOffset<" + typname + \
816 "<" + lifetime + ">>>>>";
818 case ftVectorOfString: {
819 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
820 lifetime + ", flatbuffers::ForwardsUOffset<&" + lifetime + \
823 case ftVectorOfUnionValue: {
824 const auto typname = WrapInNameSpace(*type.enum_def) + \
826 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
827 lifetime + ", flatbuffers::ForwardsUOffset<"
828 "flatbuffers::Table<" + lifetime + ">>>>";
831 return "INVALID_CODE_GENERATION"; // for return analysis
834 std::string TableBuilderArgsDefaultValue(const FieldDef &field) {
835 return GetDefaultScalarValue(field);
837 std::string TableBuilderAddFuncDefaultValue(const FieldDef &field) {
838 // All branches of switch do the same action!
839 switch (GetFullType(field.value.type)) {
842 const std::string basetype = GetTypeBasic(field.value.type); //<- never used
843 return GetDefaultScalarValue(field);
846 default: { return GetDefaultScalarValue(field); }
850 std::string TableBuilderArgsAddFuncType(const FieldDef &field,
851 const std::string &lifetime) {
852 const Type& type = field.value.type;
854 switch (GetFullType(field.value.type)) {
855 case ftVectorOfStruct: {
856 const auto typname = WrapInNameSpace(*type.struct_def);
857 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
858 ", " + typname + ">>";
860 case ftVectorOfTable: {
861 const auto typname = WrapInNameSpace(*type.struct_def);
862 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
863 ", flatbuffers::ForwardsUOffset<" + typname + \
864 "<" + lifetime + ">>>>";
866 case ftVectorOfInteger:
867 case ftVectorOfFloat: {
868 const auto typname = GetTypeBasic(type.VectorType());
869 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
870 ", " + typname + ">>";
872 case ftVectorOfBool: {
873 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
876 case ftVectorOfString: {
877 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
878 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
880 case ftVectorOfEnumKey: {
881 const auto typname = WrapInNameSpace(*type.enum_def);
882 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
883 ", " + typname + ">>";
885 case ftVectorOfUnionValue: {
886 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
887 ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + \
891 const auto typname = WrapInNameSpace(*type.enum_def);
895 const auto typname = WrapInNameSpace(*type.struct_def);
896 return "&" + lifetime + " " + typname + "";
899 const auto typname = WrapInNameSpace(*type.struct_def);
900 return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
904 const auto typname = GetTypeBasic(type);
911 return "flatbuffers::WIPOffset<&" + lifetime + " str>";
914 const auto typname = WrapInNameSpace(*type.enum_def);
918 return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
922 return "INVALID_CODE_GENERATION"; // for return analysis
925 std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
926 const Type& type = field.value.type;
928 switch (GetFullType(field.value.type)) {
931 const auto typname = GetTypeBasic(field.value.type);
932 return "self.fbb_.push_slot::<" + typname + ">";
935 return "self.fbb_.push_slot::<bool>";
940 const auto underlying_typname = GetTypeBasic(type);
941 return "self.fbb_.push_slot::<" + underlying_typname + ">";
945 const std::string typname = WrapInNameSpace(*type.struct_def);
946 return "self.fbb_.push_slot_always::<&" + typname + ">";
949 const auto typname = WrapInNameSpace(*type.struct_def);
950 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" + \
956 case ftVectorOfInteger:
957 case ftVectorOfFloat:
959 case ftVectorOfEnumKey:
960 case ftVectorOfStruct:
961 case ftVectorOfTable:
962 case ftVectorOfString:
963 case ftVectorOfUnionValue: {
964 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
967 return "INVALID_CODE_GENERATION"; // for return analysis
970 std::string GenTableAccessorFuncReturnType(const FieldDef &field,
971 const std::string &lifetime) {
972 const Type& type = field.value.type;
974 switch (GetFullType(field.value.type)) {
977 const auto typname = GetTypeBasic(type);
984 const auto typname = WrapInNameSpace(*type.struct_def);
985 return WrapInOptionIfNotRequired("&" + lifetime + " " + typname, field.required);
988 const auto typname = WrapInNameSpace(*type.struct_def);
989 return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">", field.required);
993 const auto typname = WrapInNameSpace(*type.enum_def);
998 return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">", field.required);
1001 return WrapInOptionIfNotRequired("&" + lifetime + " str", field.required);
1003 case ftVectorOfInteger:
1004 case ftVectorOfFloat: {
1005 const auto typname = GetTypeBasic(type.VectorType());
1006 if (IsOneByte(type.VectorType().base_type)) {
1007 return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
1009 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
1011 case ftVectorOfBool: {
1012 return WrapInOptionIfNotRequired("&" + lifetime + " [bool]", field.required);
1014 case ftVectorOfEnumKey: {
1015 const auto typname = WrapInNameSpace(*type.enum_def);
1016 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
1018 case ftVectorOfStruct: {
1019 const auto typname = WrapInNameSpace(*type.struct_def);
1020 return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
1022 case ftVectorOfTable: {
1023 const auto typname = WrapInNameSpace(*type.struct_def);
1024 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<" + \
1025 typname + "<" + lifetime + ">>>", field.required);
1027 case ftVectorOfString: {
1028 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<&" + \
1029 lifetime + " str>>", field.required);
1031 case ftVectorOfUnionValue: {
1032 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1033 // TODO(rw): when we do support these, we should consider using the
1034 // Into trait to convert tables to typesafe union values.
1035 return "INVALID_CODE_GENERATION"; // for return analysis
1038 return "INVALID_CODE_GENERATION"; // for return analysis
1041 std::string GenTableAccessorFuncBody(const FieldDef &field,
1042 const std::string &lifetime,
1043 const std::string &offset_prefix) {
1044 const std::string offset_name = offset_prefix + "::" + \
1045 GetFieldOffsetName(field);
1046 const Type& type = field.value.type;
1048 switch (GetFullType(field.value.type)) {
1052 const auto typname = GetTypeBasic(type);
1053 const auto default_value = GetDefaultScalarValue(field);
1054 return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + \
1055 default_value + ")).unwrap()";
1058 const auto typname = WrapInNameSpace(*type.struct_def);
1059 return AddUnwrapIfRequired("self._tab.get::<" + typname + ">(" + offset_name + ", None)", field.required);
1062 const auto typname = WrapInNameSpace(*type.struct_def);
1063 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + \
1064 typname + "<" + lifetime + ">>>(" + offset_name + ", None)", field.required);
1066 case ftUnionValue: {
1067 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1068 "flatbuffers::Table<" + lifetime + ">>>(" + offset_name + \
1069 ", None)", field.required);
1073 const auto underlying_typname = GetTypeBasic(type); //<- never used
1074 const auto typname = WrapInNameSpace(*type.enum_def);
1075 const auto default_value = GetDefaultScalarValue(field);
1076 return "self._tab.get::<" + typname + ">(" + offset_name + \
1077 ", Some(" + default_value + ")).unwrap()";
1080 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" + \
1081 offset_name + ", None)", field.required);
1084 case ftVectorOfInteger:
1085 case ftVectorOfFloat: {
1086 const auto typname = GetTypeBasic(type.VectorType());
1087 std::string s = "self._tab.get::<flatbuffers::ForwardsUOffset<"
1088 "flatbuffers::Vector<" + lifetime + ", " + typname + \
1089 ">>>(" + offset_name + ", None)";
1090 // single-byte values are safe to slice
1091 if (IsOneByte(type.VectorType().base_type)) {
1092 s += ".map(|v| v.safe_slice())";
1094 return AddUnwrapIfRequired(s, field.required);
1096 case ftVectorOfBool: {
1097 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1098 "flatbuffers::Vector<" + lifetime + ", bool>>>(" + \
1099 offset_name + ", None).map(|v| v.safe_slice())", field.required);
1101 case ftVectorOfEnumKey: {
1102 const auto typname = WrapInNameSpace(*type.enum_def);
1103 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1104 "flatbuffers::Vector<" + lifetime + ", " + typname + ">>>(" + \
1105 offset_name + ", None)", field.required);
1107 case ftVectorOfStruct: {
1108 const auto typname = WrapInNameSpace(*type.struct_def);
1109 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1110 "flatbuffers::Vector<" + typname + ">>>(" + \
1111 offset_name + ", None).map(|v| v.safe_slice() )", field.required);
1113 case ftVectorOfTable: {
1114 const auto typname = WrapInNameSpace(*type.struct_def);
1115 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1116 "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + typname + \
1117 "<" + lifetime + ">>>>>(" + offset_name + ", None)", field.required);
1119 case ftVectorOfString: {
1120 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1121 "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \
1122 lifetime + " str>>>>(" + offset_name + ", None)", field.required);
1124 case ftVectorOfUnionValue: {
1125 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1126 return "INVALID_CODE_GENERATION"; // for return analysis
1129 return "INVALID_CODE_GENERATION"; // for return analysis
1132 bool TableFieldReturnsOption(const Type& type) {
1133 switch (GetFullType(type)) {
1140 default: return true;
1144 // Generate an accessor struct, builder struct, and create function for a
1146 void GenTable(const StructDef &struct_def) {
1147 code_.SetValue("STRUCT_NAME", Name(struct_def));
1148 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1149 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
1151 // Generate an offset type, the base type, the Follow impl, and the
1152 // init_from_table impl.
1153 code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
1154 code_ += "#[derive(Copy, Clone, Debug, PartialEq)]";
1157 GenComment(struct_def.doc_comment);
1159 code_ += "pub struct {{STRUCT_NAME}}<'a> {";
1160 code_ += " pub _tab: flatbuffers::Table<'a>,";
1163 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
1164 code_ += " type Inner = {{STRUCT_NAME}}<'a>;";
1165 code_ += " #[inline]";
1166 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1168 code_ += " _tab: flatbuffers::Table { buf: buf, loc: loc },";
1173 code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
1174 code_ += " #[inline]";
1175 code_ += " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
1177 code_ += " {{STRUCT_NAME}} {";
1178 code_ += " _tab: table,";
1182 // Generate a convenient create* function that uses the above builder
1183 // to create a table in one function call.
1184 code_.SetValue("MAYBE_US",
1185 struct_def.fields.vec.size() == 0 ? "_" : "");
1186 code_.SetValue("MAYBE_LT",
1187 TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
1188 code_ += " #[allow(unused_mut)]";
1189 code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
1191 "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1192 code_ += " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
1193 " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
1195 code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
1196 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1198 for (auto it = struct_def.fields.vec.rbegin();
1199 it != struct_def.fields.vec.rend(); ++it) {
1200 const auto &field = **it;
1201 // TODO(rw): fully understand this sortbysize usage
1202 if (!field.deprecated && (!struct_def.sortbysize ||
1203 size == SizeOf(field.value.type.base_type))) {
1204 code_.SetValue("FIELD_NAME", Name(field));
1205 if (TableFieldReturnsOption(field.value.type)) {
1206 code_ += " if let Some(x) = args.{{FIELD_NAME}} "
1207 "{ builder.add_{{FIELD_NAME}}(x); }";
1209 code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
1214 code_ += " builder.finish()";
1218 // Generate field id constants.
1219 if (struct_def.fields.vec.size() > 0) {
1220 for (auto it = struct_def.fields.vec.begin();
1221 it != struct_def.fields.vec.end(); ++it) {
1222 const auto &field = **it;
1223 if (field.deprecated) {
1224 // Deprecated fields won't be accessible.
1228 code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1229 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
1230 code_ += " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1231 "{{OFFSET_VALUE}};";
1236 // Generate the accessors. Each has one of two forms:
1238 // If a value can be None:
1239 // pub fn name(&'a self) -> Option<user_facing_type> {
1240 // self._tab.get::<internal_type>(offset, defaultval)
1243 // If a value is always Some:
1244 // pub fn name(&'a self) -> user_facing_type {
1245 // self._tab.get::<internal_type>(offset, defaultval).unwrap()
1247 const auto offset_prefix = Name(struct_def);
1248 for (auto it = struct_def.fields.vec.begin();
1249 it != struct_def.fields.vec.end(); ++it) {
1250 const auto &field = **it;
1251 if (field.deprecated) {
1252 // Deprecated fields won't be accessible.
1256 code_.SetValue("FIELD_NAME", Name(field));
1257 code_.SetValue("RETURN_TYPE",
1258 GenTableAccessorFuncReturnType(field, "'a"));
1259 code_.SetValue("FUNC_BODY",
1260 GenTableAccessorFuncBody(field, "'a", offset_prefix));
1262 GenComment(field.doc_comment, " ");
1263 code_ += " #[inline]";
1264 code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
1265 code_ += " {{FUNC_BODY}}";
1268 // Generate a comparison function for this field if it is a key.
1270 GenKeyFieldMethods(field);
1273 // Generate a nested flatbuffer field, if applicable.
1274 auto nested = field.attributes.Lookup("nested_flatbuffer");
1276 std::string qualified_name = nested->constant;
1277 auto nested_root = parser_.LookupStruct(nested->constant);
1278 if (nested_root == nullptr) {
1279 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1281 nested_root = parser_.LookupStruct(qualified_name);
1283 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
1286 code_.SetValue("OFFSET_NAME",
1287 offset_prefix + "::" + GetFieldOffsetName(field));
1288 code_ += " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> "
1289 " Option<{{STRUCT_NAME}}<'a>> {";
1290 code_ += " match self.{{FIELD_NAME}}() {";
1291 code_ += " None => { None }";
1292 code_ += " Some(data) => {";
1293 code_ += " use self::flatbuffers::Follow;";
1294 code_ += " Some(<flatbuffers::ForwardsUOffset"
1295 "<{{STRUCT_NAME}}<'a>>>::follow(data, 0))";
1302 // Explicit specializations for union accessors
1303 for (auto it = struct_def.fields.vec.begin();
1304 it != struct_def.fields.vec.end(); ++it) {
1305 const auto &field = **it;
1306 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
1310 auto u = field.value.type.enum_def;
1312 code_.SetValue("FIELD_NAME", Name(field));
1314 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
1316 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1318 auto table_init_type = WrapInNameSpace(
1319 ev.union_type.struct_def->defined_namespace,
1320 ev.union_type.struct_def->name);
1322 code_.SetValue("U_ELEMENT_ENUM_TYPE",
1323 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
1324 code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type);
1325 code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
1327 code_ += " #[inline]";
1328 code_ += " #[allow(non_snake_case)]";
1329 code_ += " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
1330 "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
1331 code_ += " if self.{{FIELD_NAME}}_type() == {{U_ELEMENT_ENUM_TYPE}} {";
1332 code_ += " self.{{FIELD_NAME}}().map(|u| "
1333 "{{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
1334 code_ += " } else {";
1342 code_ += "}"; // End of table impl.
1345 // Generate an args struct:
1346 code_.SetValue("MAYBE_LT",
1347 TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
1348 code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1349 for (auto it = struct_def.fields.vec.begin();
1350 it != struct_def.fields.vec.end(); ++it) {
1351 const auto &field = **it;
1352 if (!field.deprecated) {
1353 code_.SetValue("PARAM_NAME", Name(field));
1354 code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a "));
1355 code_ += " pub {{PARAM_NAME}}: {{PARAM_TYPE}},";
1360 // Generate an impl of Default for the *Args type:
1361 code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1362 code_ += " #[inline]";
1363 code_ += " fn default() -> Self {";
1364 code_ += " {{STRUCT_NAME}}Args {";
1365 for (auto it = struct_def.fields.vec.begin();
1366 it != struct_def.fields.vec.end(); ++it) {
1367 const auto &field = **it;
1368 if (!field.deprecated) {
1369 code_.SetValue("PARAM_VALUE", TableBuilderArgsDefaultValue(field));
1370 code_.SetValue("REQ", field.required ? " // required field" : "");
1371 code_.SetValue("PARAM_NAME", Name(field));
1372 code_ += " {{PARAM_NAME}}: {{PARAM_VALUE}},{{REQ}}";
1379 // Generate a builder struct:
1380 code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
1381 code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1382 code_ += " start_: flatbuffers::WIPOffset<"
1383 "flatbuffers::TableUnfinishedWIPOffset>,";
1386 // Generate builder functions:
1387 code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
1388 for (auto it = struct_def.fields.vec.begin();
1389 it != struct_def.fields.vec.end(); ++it) {
1390 const auto &field = **it;
1391 if (!field.deprecated) {
1392 const bool is_scalar = IsScalar(field.value.type.base_type);
1394 std::string offset = GetFieldOffsetName(field);
1396 // Generate functions to add data, which take one of two forms.
1398 // If a value has a default:
1399 // fn add_x(x_: type) {
1400 // fbb_.push_slot::<type>(offset, x_, Some(default));
1403 // If a value does not have a default:
1404 // fn add_x(x_: type) {
1405 // fbb_.push_slot_always::<type>(offset, x_);
1407 code_.SetValue("FIELD_NAME", Name(field));
1408 code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
1409 code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
1410 code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
1411 code_ += " #[inline]";
1412 code_ += " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
1413 "{{FIELD_TYPE}}) {";
1415 code_.SetValue("FIELD_DEFAULT_VALUE",
1416 TableBuilderAddFuncDefaultValue(field));
1417 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
1418 "{{FIELD_DEFAULT_VALUE}});";
1420 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
1426 // Struct initializer (all fields required);
1427 code_ += " #[inline]";
1429 " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
1430 "{{STRUCT_NAME}}Builder<'a, 'b> {";
1431 code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
1432 code_ += " let start = _fbb.start_table();";
1433 code_ += " {{STRUCT_NAME}}Builder {";
1434 code_ += " fbb_: _fbb,";
1435 code_ += " start_: start,";
1439 // finish() function.
1440 code_ += " #[inline]";
1441 code_ += " pub fn finish(self) -> "
1442 "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
1443 code_ += " let o = self.fbb_.end_table(self.start_);";
1445 for (auto it = struct_def.fields.vec.begin();
1446 it != struct_def.fields.vec.end(); ++it) {
1447 const auto &field = **it;
1448 if (!field.deprecated && field.required) {
1449 code_.SetValue("FIELD_NAME", MakeSnakeCase(Name(field)));
1450 code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1451 code_ += " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
1452 "\"{{FIELD_NAME}}\");";
1455 code_ += " flatbuffers::WIPOffset::new(o.value())";
1461 // Generate functions to compare tables and structs by key. This function
1462 // must only be called if the field key is defined.
1463 void GenKeyFieldMethods(const FieldDef &field) {
1464 FLATBUFFERS_ASSERT(field.key);
1466 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
1468 code_ += " #[inline]";
1469 code_ += " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
1471 code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
1474 code_ += " #[inline]";
1475 code_ += " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
1476 " ::std::cmp::Ordering {";
1477 code_ += " let key = self.{{FIELD_NAME}}();";
1478 code_ += " key.cmp(&val)";
1482 // Generate functions for accessing the root table object. This function
1483 // must only be called if the root table is defined.
1484 void GenRootTableFuncs(const StructDef &struct_def) {
1485 FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
1486 auto name = Name(struct_def);
1488 code_.SetValue("STRUCT_NAME", name);
1489 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
1490 code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
1492 // The root datatype accessors:
1493 code_ += "#[inline]";
1495 "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
1496 " -> {{STRUCT_NAME}}<'a> {";
1497 code_ += " flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)";
1501 code_ += "#[inline]";
1502 code_ += "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
1503 "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
1504 code_ += " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
1509 if (parser_.file_identifier_.length()) {
1510 // Declare the identifier
1511 code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &'static str\\";
1512 code_ += " = \"" + parser_.file_identifier_ + "\";";
1515 // Check if a buffer has the identifier.
1516 code_ += "#[inline]";
1517 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
1518 code_ += "(buf: &[u8]) -> bool {";
1519 code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
1520 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false);";
1523 code_ += "#[inline]";
1524 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
1525 code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
1526 code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
1527 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true);";
1532 if (parser_.file_extension_.length()) {
1533 // Return the extension
1534 code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &'static str = \\";
1535 code_ += "\"" + parser_.file_extension_ + "\";";
1539 // Finish a buffer with a given root object:
1540 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1541 code_ += "#[inline]";
1542 code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
1543 code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1544 code_ += " root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1545 if (parser_.file_identifier_.length()) {
1546 code_ += " fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1548 code_ += " fbb.finish(root, None);";
1552 code_ += "#[inline]";
1553 code_ += "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
1555 "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
1556 "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1557 if (parser_.file_identifier_.length()) {
1558 code_ += " fbb.finish_size_prefixed(root, "
1559 "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1561 code_ += " fbb.finish_size_prefixed(root, None);";
1566 static void GenPadding(
1567 const FieldDef &field, std::string *code_ptr, int *id,
1568 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
1569 if (field.padding) {
1570 for (int i = 0; i < 4; i++) {
1571 if (static_cast<int>(field.padding) & (1 << i)) {
1572 f((1 << i) * 8, code_ptr, id);
1575 assert(!(field.padding & ~0xF));
1579 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
1580 *code_ptr += " padding" + NumToString((*id)++) + "__: u" + \
1581 NumToString(bits) + ",";
1584 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
1586 *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
1589 // Generate an accessor struct with constructor for a flatbuffers struct.
1590 void GenStruct(const StructDef &struct_def) {
1591 // Generates manual padding and alignment.
1592 // Variables are private because they contain little endian data on all
1594 GenComment(struct_def.doc_comment);
1595 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
1596 code_.SetValue("STRUCT_NAME", Name(struct_def));
1598 code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
1599 code_ += "#[repr(C, align({{ALIGN}}))]";
1601 // PartialEq is useful to derive because we can correctly compare structs
1602 // for equality by just comparing their underlying byte data. This doesn't
1603 // hold for PartialOrd/Ord.
1604 code_ += "#[derive(Clone, Copy, Debug, PartialEq)]";
1605 code_ += "pub struct {{STRUCT_NAME}} {";
1608 for (auto it = struct_def.fields.vec.begin();
1609 it != struct_def.fields.vec.end(); ++it) {
1610 const auto &field = **it;
1611 code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
1612 code_.SetValue("FIELD_NAME", Name(field));
1613 code_ += " {{FIELD_NAME}}_: {{FIELD_TYPE}},";
1615 if (field.padding) {
1616 std::string padding;
1617 GenPadding(field, &padding, &padding_id, PaddingDefinition);
1622 code_ += "} // pub struct {{STRUCT_NAME}}";
1624 // Generate impls for SafeSliceAccess (because all structs are endian-safe),
1625 // Follow for the value type, Follow for the reference type, Push for the
1626 // value type, and Push for the reference type.
1627 code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
1628 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
1629 code_ += " type Inner = &'a {{STRUCT_NAME}};";
1630 code_ += " #[inline]";
1631 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1632 code_ += " <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
1635 code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
1636 code_ += " type Inner = &'a {{STRUCT_NAME}};";
1637 code_ += " #[inline]";
1638 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1639 code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
1642 code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
1643 code_ += " type Output = {{STRUCT_NAME}};";
1644 code_ += " #[inline]";
1645 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1646 code_ += " let src = unsafe {";
1647 code_ += " ::std::slice::from_raw_parts("
1648 "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1650 code_ += " dst.copy_from_slice(src);";
1653 code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
1654 code_ += " type Output = {{STRUCT_NAME}};";
1656 code_ += " #[inline]";
1657 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1658 code_ += " let src = unsafe {";
1659 code_ += " ::std::slice::from_raw_parts("
1660 "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1662 code_ += " dst.copy_from_slice(src);";
1668 // Generate a constructor that takes all fields as arguments.
1669 code_ += "impl {{STRUCT_NAME}} {";
1670 std::string arg_list;
1671 std::string init_list;
1673 for (auto it = struct_def.fields.vec.begin();
1674 it != struct_def.fields.vec.end(); ++it) {
1675 const auto &field = **it;
1676 const auto member_name = Name(field) + "_";
1677 const auto reference = StructMemberAccessNeedsCopy(field.value.type)
1679 const auto arg_name = "_" + Name(field);
1680 const auto arg_type = reference + GetTypeGet(field.value.type);
1682 if (it != struct_def.fields.vec.begin()) {
1685 arg_list += arg_name + ": ";
1686 arg_list += arg_type;
1687 init_list += " " + member_name;
1688 if (StructMemberAccessNeedsCopy(field.value.type)) {
1689 init_list += ": " + arg_name + ".to_little_endian(),\n";
1691 init_list += ": *" + arg_name + ",\n";
1695 code_.SetValue("ARG_LIST", arg_list);
1696 code_.SetValue("INIT_LIST", init_list);
1697 code_ += " pub fn new<'a>({{ARG_LIST}}) -> Self {";
1698 code_ += " {{STRUCT_NAME}} {";
1699 code_ += "{{INIT_LIST}}";
1701 for (auto it = struct_def.fields.vec.begin();
1702 it != struct_def.fields.vec.end(); ++it) {
1703 const auto &field = **it;
1704 if (field.padding) {
1705 std::string padding;
1706 GenPadding(field, &padding, &padding_id, PaddingInitializer);
1707 code_ += " " + padding;
1713 // Generate accessor methods for the struct.
1714 for (auto it = struct_def.fields.vec.begin();
1715 it != struct_def.fields.vec.end(); ++it) {
1716 const auto &field = **it;
1718 auto field_type = TableBuilderArgsAddFuncType(field, "'a");
1719 auto member = "self." + Name(field) + "_";
1720 auto value = StructMemberAccessNeedsCopy(field.value.type) ?
1721 member + ".from_little_endian()" : member;
1723 code_.SetValue("FIELD_NAME", Name(field));
1724 code_.SetValue("FIELD_TYPE", field_type);
1725 code_.SetValue("FIELD_VALUE", value);
1726 code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
1728 GenComment(field.doc_comment, " ");
1729 code_ += " pub fn {{FIELD_NAME}}<'a>(&'a self) -> {{FIELD_TYPE}} {";
1730 code_ += " {{REF}}{{FIELD_VALUE}}";
1733 // Generate a comparison function for this field if it is a key.
1735 GenKeyFieldMethods(field);
1742 void GenNamespaceImports(const int white_spaces) {
1743 std::string indent = std::string(white_spaces, ' ');
1745 code_ += indent + "use std::mem;";
1746 code_ += indent + "use std::cmp::Ordering;";
1748 code_ += indent + "extern crate flatbuffers;";
1749 code_ += indent + "use self::flatbuffers::EndianScalar;";
1752 // Set up the correct namespace. This opens a namespace if the current
1753 // namespace is different from the target namespace. This function
1754 // closes and opens the namespaces only as necessary.
1756 // The file must start and end with an empty (or null) namespace so that
1757 // namespaces are properly opened and closed.
1758 void SetNameSpace(const Namespace *ns) {
1759 if (cur_name_space_ == ns) { return; }
1761 // Compute the size of the longest common namespace prefix.
1762 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
1763 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
1764 // and common_prefix_size = 2
1765 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
1766 size_t new_size = ns ? ns->components.size() : 0;
1768 size_t common_prefix_size = 0;
1769 while (common_prefix_size < old_size && common_prefix_size < new_size &&
1770 ns->components[common_prefix_size] ==
1771 cur_name_space_->components[common_prefix_size]) {
1772 common_prefix_size++;
1775 // Close cur_name_space in reverse order to reach the common prefix.
1776 // In the previous example, D then C are closed.
1777 for (size_t j = old_size; j > common_prefix_size; --j) {
1778 code_ += "} // pub mod " + cur_name_space_->components[j - 1];
1780 if (old_size != common_prefix_size) { code_ += ""; }
1782 // open namespace parts to reach the ns namespace
1783 // in the previous example, E, then F, then G are opened
1784 for (auto j = common_prefix_size; j != new_size; ++j) {
1785 code_ += "#[allow(unused_imports, dead_code)]";
1786 code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
1787 // Generate local namespace imports.
1788 GenNamespaceImports(2);
1790 if (new_size != common_prefix_size) { code_ += ""; }
1792 cur_name_space_ = ns;
1798 bool GenerateRust(const Parser &parser, const std::string &path,
1799 const std::string &file_name) {
1800 rust::RustGenerator generator(parser, path, file_name);
1801 return generator.generate();
1804 std::string RustMakeRule(const Parser &parser, const std::string &path,
1805 const std::string &file_name) {
1806 std::string filebase =
1807 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
1808 std::string make_rule = GeneratedFileName(path, filebase) + ": ";
1810 auto included_files = parser.GetIncludedFilesRecursive(file_name);
1811 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1812 make_rule += " " + *it;
1817 } // namespace flatbuffers
1819 // TODO(rw): Generated code should import other generated files.
1820 // TODO(rw): Generated code should refer to namespaces in included files in a
1821 // way that makes them referrable.
1822 // TODO(rw): Generated code should indent according to nesting level.
1823 // TODO(rw): Generated code should generate endian-safe Debug impls.
1824 // TODO(rw): Generated code could use a Rust-only enum type to access unions,
1825 // instead of making the user use _type() to manually switch.