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])) { s += '_'; }
44 s += static_cast<char>(tolower(in[i]));
52 // Convert a string to all uppercase.
53 std::string MakeUpper(const std::string &in) {
55 for (size_t i = 0; i < in.length(); i++) {
56 s += static_cast<char>(toupper(in[i]));
61 // Encapsulate all logical field types in this enum. This allows us to write
62 // field logic based on type switches, instead of branches on the properties
64 // TODO(rw): for backwards compatibility, we can't use a strict `enum class`
65 // declaration here. could we use the `-Wswitch-enum` warning to
66 // achieve the same effect?
80 // TODO(rw): bytestring?
83 ftVectorOfInteger = 9,
86 ftVectorOfEnumKey = 12,
87 ftVectorOfStruct = 13,
89 ftVectorOfString = 15,
90 ftVectorOfUnionValue = 16,
93 // Convert a Type to a FullType (exhaustive).
94 FullType GetFullType(const Type &type) {
95 // N.B. The order of these conditionals matters for some types.
97 if (type.base_type == BASE_TYPE_STRING) {
99 } else if (type.base_type == BASE_TYPE_STRUCT) {
100 if (type.struct_def->fixed) {
105 } else if (type.base_type == BASE_TYPE_VECTOR) {
106 switch (GetFullType(type.VectorType())) {
108 return ftVectorOfInteger;
111 return ftVectorOfFloat;
114 return ftVectorOfBool;
117 return ftVectorOfStruct;
120 return ftVectorOfTable;
123 return ftVectorOfString;
126 return ftVectorOfEnumKey;
130 FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
134 FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
137 } else if (type.enum_def != nullptr) {
138 if (type.enum_def->is_union) {
139 if (type.base_type == BASE_TYPE_UNION) {
141 } else if (IsInteger(type.base_type)) {
144 FLATBUFFERS_ASSERT(false && "unknown union field type");
149 } else if (IsScalar(type.base_type)) {
150 if (IsBool(type.base_type)) {
152 } else if (IsInteger(type.base_type)) {
154 } else if (IsFloat(type.base_type)) {
157 FLATBUFFERS_ASSERT(false && "unknown number type");
161 FLATBUFFERS_ASSERT(false && "completely unknown type");
163 // this is only to satisfy the compiler's return analysis.
167 // If the second parameter is false then wrap the first with Option<...>
168 std::string WrapInOptionIfNotRequired(std::string s, bool required) {
172 return "Option<" + s + ">";
176 // If the second parameter is false then add .unwrap()
177 std::string AddUnwrapIfRequired(std::string s, bool required) {
179 return s + ".unwrap()";
187 class RustGenerator : public BaseGenerator {
189 RustGenerator(const Parser &parser, const std::string &path,
190 const std::string &file_name)
191 : BaseGenerator(parser, path, file_name, "", "::"),
192 cur_name_space_(nullptr) {
193 const char *keywords[] = {
195 // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
197 // we write keywords one per line so that we can easily compare them with
198 // changes to that webpage in the future.
200 // currently-used keywords
201 "as", "break", "const", "continue", "crate", "else", "enum", "extern",
202 "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod",
203 "move", "mut", "pub", "ref", "return", "Self", "self", "static", "struct",
204 "super", "trait", "true", "type", "unsafe", "use", "where", "while",
206 // future possible keywords
207 "abstract", "alignof", "become", "box", "do", "final", "macro",
208 "offsetof", "override", "priv", "proc", "pure", "sizeof", "typeof",
209 "unsized", "virtual", "yield",
211 // other rust terms we should not use
212 "std", "usize", "isize", "u8", "i8", "u16", "i16", "u32", "i32", "u64",
213 "i64", "u128", "i128", "f32", "f64",
215 // These are terms the code generator can implement on types.
217 // In Rust, the trait resolution rules (as described at
218 // https://github.com/rust-lang/rust/issues/26007) mean that, as long
219 // as we impl table accessors as inherent methods, we'll never create
220 // conflicts with these keywords. However, that's a fairly nuanced
221 // implementation detail, and how we implement methods could change in
222 // the future. as a result, we proactively block these out as reserved
224 "follow", "push", "size", "alignment", "to_little_endian",
225 "from_little_endian", nullptr
227 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
230 // Iterate through all definitions we haven't generated code for (enums,
231 // structs, and tables) and output them to a single file.
234 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
236 assert(!cur_name_space_);
238 // Generate imports for the global scope in case no namespace is used
239 // in the schema file.
240 GenNamespaceImports(0);
243 // Generate all code in their namespaces, once, because Rust does not
244 // permit re-opening modules.
246 // TODO(rw): Use a set data structure to reduce namespace evaluations from
248 for (auto ns_it = parser_.namespaces_.begin();
249 ns_it != parser_.namespaces_.end(); ++ns_it) {
250 const auto &ns = *ns_it;
252 // Generate code for all the enum declarations.
253 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
255 const auto &enum_def = **it;
256 if (enum_def.defined_namespace != ns) { continue; }
257 if (!enum_def.generated) {
258 SetNameSpace(enum_def.defined_namespace);
263 // Generate code for all structs.
264 for (auto it = parser_.structs_.vec.begin();
265 it != parser_.structs_.vec.end(); ++it) {
266 const auto &struct_def = **it;
267 if (struct_def.defined_namespace != ns) { continue; }
268 if (struct_def.fixed && !struct_def.generated) {
269 SetNameSpace(struct_def.defined_namespace);
270 GenStruct(struct_def);
274 // Generate code for all tables.
275 for (auto it = parser_.structs_.vec.begin();
276 it != parser_.structs_.vec.end(); ++it) {
277 const auto &struct_def = **it;
278 if (struct_def.defined_namespace != ns) { continue; }
279 if (!struct_def.fixed && !struct_def.generated) {
280 SetNameSpace(struct_def.defined_namespace);
281 GenTable(struct_def);
285 // Generate global helper functions.
286 if (parser_.root_struct_def_) {
287 auto &struct_def = *parser_.root_struct_def_;
288 if (struct_def.defined_namespace != ns) { continue; }
289 SetNameSpace(struct_def.defined_namespace);
290 GenRootTableFuncs(struct_def);
293 if (cur_name_space_) SetNameSpace(nullptr);
295 const auto file_path = GeneratedFileName(path_, file_name_);
296 const auto final_code = code_.ToString();
297 return SaveFile(file_path.c_str(), final_code, false);
303 std::set<std::string> keywords_;
305 // This tracks the current namespace so we can insert namespace declarations.
306 const Namespace *cur_name_space_;
308 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
310 // Determine if a Type needs a lifetime template parameter when used in the
311 // Rust builder args.
312 bool TableBuilderTypeNeedsLifetime(const Type &type) const {
313 switch (GetFullType(type)) {
328 // Determine if a table args rust type needs a lifetime template parameter.
329 bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
330 FLATBUFFERS_ASSERT(!struct_def.fixed);
332 for (auto it = struct_def.fields.vec.begin();
333 it != struct_def.fields.vec.end(); ++it) {
334 const auto &field = **it;
335 if (field.deprecated) { continue; }
337 if (TableBuilderTypeNeedsLifetime(field.value.type)) { return true; }
343 // Determine if a Type needs to be copied (for endian safety) when used in a
345 bool StructMemberAccessNeedsCopy(const Type &type) const {
346 switch (GetFullType(type)) {
347 case ftInteger: // requires endian swap
348 case ftFloat: // requires endian swap
349 case ftBool: // no endian-swap, but do the copy for UX consistency
352 } // requires endian swap
357 // logic error: no other types can be struct members.
358 FLATBUFFERS_ASSERT(false && "invalid struct member type");
359 return false; // only to satisfy compiler's return analysis
364 std::string EscapeKeyword(const std::string &name) const {
365 return keywords_.find(name) == keywords_.end() ? name : name + "_";
368 std::string Name(const Definition &def) const {
369 return EscapeKeyword(def.name);
372 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
374 std::string WrapInNameSpace(const Definition &def) const {
375 return WrapInNameSpace(def.defined_namespace, Name(def));
377 std::string WrapInNameSpace(const Namespace *ns,
378 const std::string &name) const {
379 if (CurrentNameSpace() == ns) return name;
380 std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
381 return prefix + name;
384 // Determine the namespace traversal needed from the Rust crate root.
385 // This may be useful in the future for referring to included files, but is
387 std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const {
388 std::stringstream stream;
391 for (auto d = dst->components.begin(); d != dst->components.end(); ++d) {
392 stream << MakeSnakeCase(*d) + "::";
397 // Determine the relative namespace traversal needed to reference one
398 // namespace from another namespace. This is useful because it does not force
399 // the user to have a particular file layout. (If we output absolute
400 // namespace paths, that may require users to organize their Rust crates in a
402 std::string GetRelativeNamespaceTraversal(const Namespace *src,
403 const Namespace *dst) const {
404 // calculate the path needed to reference dst from src.
405 // example: f(A::B::C, A::B::C) -> (none)
406 // example: f(A::B::C, A::B) -> super::
407 // example: f(A::B::C, A::B::D) -> super::D
408 // example: f(A::B::C, A) -> super::super::
409 // example: f(A::B::C, D) -> super::super::super::D
410 // example: f(A::B::C, D::E) -> super::super::super::D::E
411 // example: f(A, D::E) -> super::D::E
412 // does not include leaf object (typically a struct type).
415 std::stringstream stream;
417 auto s = src->components.begin();
418 auto d = dst->components.begin();
420 if (s == src->components.end()) { break; }
421 if (d == dst->components.end()) { break; }
422 if (*s != *d) { break; }
428 for (; s != src->components.end(); ++s) { stream << "super::"; }
429 for (; d != dst->components.end(); ++d) {
430 stream << MakeSnakeCase(*d) + "::";
435 // Generate a comment from the schema.
436 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
438 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
439 code_ += text + "\\";
442 // Return a Rust type from the table in idl.h.
443 std::string GetTypeBasic(const Type &type) const {
444 switch (GetFullType(type)) {
453 FLATBUFFERS_ASSERT(false && "incorrect type given");
458 static const char * const ctypename[] = {
459 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
462 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
463 #undef FLATBUFFERS_TD
467 if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
468 return ctypename[type.base_type];
471 // Look up the native type for an enum. This will always be an integer like
473 std::string GetEnumTypeForDecl(const Type &type) {
474 const auto ft = GetFullType(type);
475 if (!(ft == ftEnumKey || ft == ftUnionKey)) {
476 FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
479 static const char *ctypename[] = {
481 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
484 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
485 #undef FLATBUFFERS_TD
489 // Enums can be bools, but their Rust representation must be a u8, as used
490 // in the repr attribute (#[repr(bool)] is an invalid attribute).
491 if (type.base_type == BASE_TYPE_BOOL) return "u8";
492 return ctypename[type.base_type];
495 // Return a Rust type for any type (scalar, table, struct) specifically for
496 // using a FlatBuffer.
497 std::string GetTypeGet(const Type &type) const {
498 switch (GetFullType(type)) {
504 return GetTypeBasic(type);
507 return WrapInNameSpace(type.struct_def->defined_namespace,
508 type.struct_def->name) +
512 return WrapInNameSpace(type.struct_def->defined_namespace,
513 type.struct_def->name);
518 std::string GetEnumValUse(const EnumDef &enum_def,
519 const EnumVal &enum_val) const {
520 return Name(enum_def) + "::" + Name(enum_val);
523 // Generate an enum declaration,
524 // an enum string lookup table,
525 // an enum match function,
526 // and an enum array of values
527 void GenEnum(const EnumDef &enum_def) {
528 code_.SetValue("ENUM_NAME", Name(enum_def));
529 code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
531 GenComment(enum_def.doc_comment);
532 code_ += "#[allow(non_camel_case_types)]";
533 code_ += "#[repr({{BASE_TYPE}})]";
535 "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]";
536 code_ += "pub enum " + Name(enum_def) + " {";
538 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
539 const auto &ev = **it;
541 GenComment(ev.doc_comment, " ");
542 code_.SetValue("KEY", Name(ev));
543 code_.SetValue("VALUE", enum_def.ToString(ev));
544 code_ += " {{KEY}} = {{VALUE}},";
546 const EnumVal *minv = enum_def.MinValue();
547 const EnumVal *maxv = enum_def.MaxValue();
548 FLATBUFFERS_ASSERT(minv && maxv);
554 code_.SetValue("ENUM_NAME", Name(enum_def));
555 code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
556 code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
557 code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
558 code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
560 // Generate enum constants, and impls for Follow, EndianScalar, and Push.
561 code_ += "const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
562 code_ += "{{ENUM_MIN_BASE_VALUE}};";
563 code_ += "const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
564 code_ += "{{ENUM_MAX_BASE_VALUE}};";
566 code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
567 code_ += " type Inner = Self;";
568 code_ += " #[inline]";
569 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
570 code_ += " flatbuffers::read_scalar_at::<Self>(buf, loc)";
574 code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
575 code_ += " #[inline]";
576 code_ += " fn to_little_endian(self) -> Self {";
577 code_ += " let n = {{BASE_TYPE}}::to_le(self as {{BASE_TYPE}});";
578 code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
579 code_ += " unsafe { *p }";
581 code_ += " #[inline]";
582 code_ += " fn from_little_endian(self) -> Self {";
583 code_ += " let n = {{BASE_TYPE}}::from_le(self as {{BASE_TYPE}});";
584 code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
585 code_ += " unsafe { *p }";
589 code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
590 code_ += " type Output = {{ENUM_NAME}};";
591 code_ += " #[inline]";
592 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
594 " flatbuffers::emplace_scalar::<{{ENUM_NAME}}>"
600 // Generate an array of all enumeration values.
601 auto num_fields = NumToString(enum_def.size());
602 code_ += "#[allow(non_camel_case_types)]";
603 code_ += "const ENUM_VALUES_{{ENUM_NAME_CAPS}}:[{{ENUM_NAME}}; " +
604 num_fields + "] = [";
605 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
606 const auto &ev = **it;
607 auto value = GetEnumValUse(enum_def, ev);
608 auto suffix = *it != enum_def.Vals().back() ? "," : "";
609 code_ += " " + value + suffix;
614 // Generate a string table for enum values.
615 // Problem is, if values are very sparse that could generate really big
616 // tables. Ideally in that case we generate a map lookup instead, but for
617 // the moment we simply don't output a table at all.
618 auto range = enum_def.Distance();
619 // Average distance between values above which we consider a table
620 // "too sparse". Change at will.
621 static const uint64_t kMaxSparseness = 5;
622 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
623 code_ += "#[allow(non_camel_case_types)]";
624 code_ += "const ENUM_NAMES_{{ENUM_NAME_CAPS}}:[&'static str; " +
625 NumToString(range + 1) + "] = [";
627 auto val = enum_def.Vals().front();
628 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
631 for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
635 auto suffix = *it != enum_def.Vals().back() ? "," : "";
636 code_ += " \"" + Name(*ev) + "\"" + suffix;
642 "pub fn enum_name_{{ENUM_NAME_SNAKE}}(e: {{ENUM_NAME}}) -> "
645 code_ += " let index = e as {{BASE_TYPE}}\\";
646 if (enum_def.MinValue()->IsNonZero()) {
647 auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
648 code_ += " - " + vals + " as {{BASE_TYPE}}\\";
652 code_ += " ENUM_NAMES_{{ENUM_NAME_CAPS}}[index as usize]";
657 if (enum_def.is_union) {
658 // Generate tyoesafe offset(s) for unions
659 code_.SetValue("NAME", Name(enum_def));
660 code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
661 code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
665 std::string GetFieldOffsetName(const FieldDef &field) {
666 return "VT_" + MakeUpper(Name(field));
669 std::string GetDefaultConstant(const FieldDef &field) {
670 return field.value.type.base_type == BASE_TYPE_FLOAT
671 ? field.value.constant + ""
672 : field.value.constant;
675 std::string GetDefaultScalarValue(const FieldDef &field) {
676 switch (GetFullType(field.value.type)) {
678 return GetDefaultConstant(field);
681 return GetDefaultConstant(field);
684 return field.value.constant == "0" ? "false" : "true";
688 auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
690 return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
691 GetEnumValUse(*field.value.type.enum_def, *ev));
694 // All pointer-ish types have a default value of None, because they are
695 // wrapped in Option.
702 // Create the return type for fields in the *BuilderArgs structs that are
703 // used to create Tables.
705 // Note: we could make all inputs to the BuilderArgs be an Option, as well
706 // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
707 // know if the value is default or not, because there are three ways to
708 // return a default value:
709 // 1) return a stored value that happens to be the default,
710 // 2) return a hardcoded value because the relevant vtable field is not in
712 // 3) return a hardcoded value because the vtable field value is set to zero.
713 std::string TableBuilderArgsDefnType(const FieldDef &field,
714 const std::string &lifetime) {
715 const Type &type = field.value.type;
717 switch (GetFullType(type)) {
721 const auto typname = GetTypeBasic(type);
725 const auto typname = WrapInNameSpace(*type.struct_def);
726 return "Option<&" + lifetime + " " + typname + ">";
729 const auto typname = WrapInNameSpace(*type.struct_def);
730 return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime +
734 return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
738 const auto typname = WrapInNameSpace(*type.enum_def);
742 return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
745 case ftVectorOfInteger:
746 case ftVectorOfFloat: {
747 const auto typname = GetTypeBasic(type.VectorType());
748 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
749 ", " + typname + ">>>";
751 case ftVectorOfBool: {
752 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
755 case ftVectorOfEnumKey: {
756 const auto typname = WrapInNameSpace(*type.enum_def);
757 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
758 ", " + typname + ">>>";
760 case ftVectorOfStruct: {
761 const auto typname = WrapInNameSpace(*type.struct_def);
762 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
763 ", " + typname + ">>>";
765 case ftVectorOfTable: {
766 const auto typname = WrapInNameSpace(*type.struct_def);
767 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
768 ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
771 case ftVectorOfString: {
772 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
773 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>>";
775 case ftVectorOfUnionValue: {
777 WrapInNameSpace(*type.enum_def) + "UnionTableOffset";
778 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
779 ", flatbuffers::ForwardsUOffset<"
780 "flatbuffers::Table<" +
784 return "INVALID_CODE_GENERATION"; // for return analysis
787 std::string TableBuilderArgsDefaultValue(const FieldDef &field) {
788 return GetDefaultScalarValue(field);
790 std::string TableBuilderAddFuncDefaultValue(const FieldDef &field) {
791 // All branches of switch do the same action!
792 switch (GetFullType(field.value.type)) {
795 const std::string basetype =
796 GetTypeBasic(field.value.type); //<- never used
797 return GetDefaultScalarValue(field);
801 return GetDefaultScalarValue(field);
806 std::string TableBuilderArgsAddFuncType(const FieldDef &field,
807 const std::string &lifetime) {
808 const Type &type = field.value.type;
810 switch (GetFullType(field.value.type)) {
811 case ftVectorOfStruct: {
812 const auto typname = WrapInNameSpace(*type.struct_def);
813 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
816 case ftVectorOfTable: {
817 const auto typname = WrapInNameSpace(*type.struct_def);
818 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
819 ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
822 case ftVectorOfInteger:
823 case ftVectorOfFloat: {
824 const auto typname = GetTypeBasic(type.VectorType());
825 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
828 case ftVectorOfBool: {
829 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
832 case ftVectorOfString: {
833 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
834 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
836 case ftVectorOfEnumKey: {
837 const auto typname = WrapInNameSpace(*type.enum_def);
838 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
841 case ftVectorOfUnionValue: {
842 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
843 ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + lifetime +
847 const auto typname = WrapInNameSpace(*type.enum_def);
851 const auto typname = WrapInNameSpace(*type.struct_def);
852 return "&" + lifetime + " " + typname + "";
855 const auto typname = WrapInNameSpace(*type.struct_def);
856 return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
860 const auto typname = GetTypeBasic(type);
867 return "flatbuffers::WIPOffset<&" + lifetime + " str>";
870 const auto typname = WrapInNameSpace(*type.enum_def);
874 return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
878 return "INVALID_CODE_GENERATION"; // for return analysis
881 std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
882 const Type &type = field.value.type;
884 switch (GetFullType(field.value.type)) {
887 const auto typname = GetTypeBasic(field.value.type);
888 return "self.fbb_.push_slot::<" + typname + ">";
891 return "self.fbb_.push_slot::<bool>";
896 const auto underlying_typname = GetTypeBasic(type);
897 return "self.fbb_.push_slot::<" + underlying_typname + ">";
901 const std::string typname = WrapInNameSpace(*type.struct_def);
902 return "self.fbb_.push_slot_always::<&" + typname + ">";
905 const auto typname = WrapInNameSpace(*type.struct_def);
906 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" +
912 case ftVectorOfInteger:
913 case ftVectorOfFloat:
915 case ftVectorOfEnumKey:
916 case ftVectorOfStruct:
917 case ftVectorOfTable:
918 case ftVectorOfString:
919 case ftVectorOfUnionValue: {
920 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
923 return "INVALID_CODE_GENERATION"; // for return analysis
926 std::string GenTableAccessorFuncReturnType(const FieldDef &field,
927 const std::string &lifetime) {
928 const Type &type = field.value.type;
930 switch (GetFullType(field.value.type)) {
933 const auto typname = GetTypeBasic(type);
940 const auto typname = WrapInNameSpace(*type.struct_def);
941 return WrapInOptionIfNotRequired("&" + lifetime + " " + typname,
945 const auto typname = WrapInNameSpace(*type.struct_def);
946 return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">",
951 const auto typname = WrapInNameSpace(*type.enum_def);
956 return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">",
960 return WrapInOptionIfNotRequired("&" + lifetime + " str",
963 case ftVectorOfInteger:
964 case ftVectorOfFloat: {
965 const auto typname = GetTypeBasic(type.VectorType());
966 if (IsOneByte(type.VectorType().base_type)) {
967 return WrapInOptionIfNotRequired(
968 "&" + lifetime + " [" + typname + "]", field.required);
970 return WrapInOptionIfNotRequired(
971 "flatbuffers::Vector<" + lifetime + ", " + typname + ">",
974 case ftVectorOfBool: {
975 return WrapInOptionIfNotRequired("&" + lifetime + " [bool]",
978 case ftVectorOfEnumKey: {
979 const auto typname = WrapInNameSpace(*type.enum_def);
980 return WrapInOptionIfNotRequired(
981 "flatbuffers::Vector<" + lifetime + ", " + typname + ">",
984 case ftVectorOfStruct: {
985 const auto typname = WrapInNameSpace(*type.struct_def);
986 return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]",
989 case ftVectorOfTable: {
990 const auto typname = WrapInNameSpace(*type.struct_def);
991 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime +
992 ", flatbuffers::ForwardsUOffset<" +
993 typname + "<" + lifetime + ">>>",
996 case ftVectorOfString: {
997 return WrapInOptionIfNotRequired(
998 "flatbuffers::Vector<" + lifetime +
999 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>",
1002 case ftVectorOfUnionValue: {
1003 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1004 // TODO(rw): when we do support these, we should consider using the
1005 // Into trait to convert tables to typesafe union values.
1006 return "INVALID_CODE_GENERATION"; // for return analysis
1009 return "INVALID_CODE_GENERATION"; // for return analysis
1012 std::string GenTableAccessorFuncBody(const FieldDef &field,
1013 const std::string &lifetime,
1014 const std::string &offset_prefix) {
1015 const std::string offset_name =
1016 offset_prefix + "::" + GetFieldOffsetName(field);
1017 const Type &type = field.value.type;
1019 switch (GetFullType(field.value.type)) {
1023 const auto typname = GetTypeBasic(type);
1024 const auto default_value = GetDefaultScalarValue(field);
1025 return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" +
1026 default_value + ")).unwrap()";
1029 const auto typname = WrapInNameSpace(*type.struct_def);
1030 return AddUnwrapIfRequired(
1031 "self._tab.get::<" + typname + ">(" + offset_name + ", None)",
1035 const auto typname = WrapInNameSpace(*type.struct_def);
1036 return AddUnwrapIfRequired(
1037 "self._tab.get::<flatbuffers::ForwardsUOffset<" + typname + "<" +
1038 lifetime + ">>>(" + offset_name + ", None)",
1041 case ftUnionValue: {
1042 return AddUnwrapIfRequired(
1043 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1044 "flatbuffers::Table<" +
1045 lifetime + ">>>(" + offset_name + ", None)",
1050 const auto underlying_typname = GetTypeBasic(type); //<- never used
1051 const auto typname = WrapInNameSpace(*type.enum_def);
1052 const auto default_value = GetDefaultScalarValue(field);
1053 return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" +
1054 default_value + ")).unwrap()";
1057 return AddUnwrapIfRequired(
1058 "self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" +
1059 offset_name + ", None)",
1063 case ftVectorOfInteger:
1064 case ftVectorOfFloat: {
1065 const auto typname = GetTypeBasic(type.VectorType());
1067 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1068 "flatbuffers::Vector<" +
1069 lifetime + ", " + typname + ">>>(" + offset_name + ", None)";
1070 // single-byte values are safe to slice
1071 if (IsOneByte(type.VectorType().base_type)) {
1072 s += ".map(|v| v.safe_slice())";
1074 return AddUnwrapIfRequired(s, field.required);
1076 case ftVectorOfBool: {
1077 return AddUnwrapIfRequired(
1078 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1079 "flatbuffers::Vector<" +
1080 lifetime + ", bool>>>(" + offset_name +
1081 ", None).map(|v| v.safe_slice())",
1084 case ftVectorOfEnumKey: {
1085 const auto typname = WrapInNameSpace(*type.enum_def);
1086 return AddUnwrapIfRequired(
1087 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1088 "flatbuffers::Vector<" +
1089 lifetime + ", " + typname + ">>>(" + offset_name + ", None)",
1092 case ftVectorOfStruct: {
1093 const auto typname = WrapInNameSpace(*type.struct_def);
1094 return AddUnwrapIfRequired(
1095 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1096 "flatbuffers::Vector<" +
1097 typname + ">>>(" + offset_name +
1098 ", None).map(|v| v.safe_slice() )",
1101 case ftVectorOfTable: {
1102 const auto typname = WrapInNameSpace(*type.struct_def);
1103 return AddUnwrapIfRequired(
1104 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1105 "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" +
1106 typname + "<" + lifetime + ">>>>>(" + offset_name + ", None)",
1109 case ftVectorOfString: {
1110 return AddUnwrapIfRequired(
1111 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1112 "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" +
1113 lifetime + " str>>>>(" + offset_name + ", None)",
1116 case ftVectorOfUnionValue: {
1117 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1118 return "INVALID_CODE_GENERATION"; // for return analysis
1121 return "INVALID_CODE_GENERATION"; // for return analysis
1124 bool TableFieldReturnsOption(const Type &type) {
1125 switch (GetFullType(type)) {
1130 case ftUnionKey: return false;
1131 default: return true;
1135 // Generate an accessor struct, builder struct, and create function for a
1137 void GenTable(const StructDef &struct_def) {
1138 code_.SetValue("STRUCT_NAME", Name(struct_def));
1139 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1140 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
1142 // Generate an offset type, the base type, the Follow impl, and the
1143 // init_from_table impl.
1144 code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
1145 code_ += "#[derive(Copy, Clone, Debug, PartialEq)]";
1148 GenComment(struct_def.doc_comment);
1150 code_ += "pub struct {{STRUCT_NAME}}<'a> {";
1151 code_ += " pub _tab: flatbuffers::Table<'a>,";
1154 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
1155 code_ += " type Inner = {{STRUCT_NAME}}<'a>;";
1156 code_ += " #[inline]";
1157 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1159 code_ += " _tab: flatbuffers::Table { buf: buf, loc: loc },";
1164 code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
1165 code_ += " #[inline]";
1167 " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
1169 code_ += " {{STRUCT_NAME}} {";
1170 code_ += " _tab: table,";
1174 // Generate a convenient create* function that uses the above builder
1175 // to create a table in one function call.
1176 code_.SetValue("MAYBE_US", struct_def.fields.vec.size() == 0 ? "_" : "");
1177 code_.SetValue("MAYBE_LT",
1178 TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
1179 code_ += " #[allow(unused_mut)]";
1180 code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
1183 "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1185 " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
1186 " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
1188 code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
1189 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1191 for (auto it = struct_def.fields.vec.rbegin();
1192 it != struct_def.fields.vec.rend(); ++it) {
1193 const auto &field = **it;
1194 // TODO(rw): fully understand this sortbysize usage
1195 if (!field.deprecated && (!struct_def.sortbysize ||
1196 size == SizeOf(field.value.type.base_type))) {
1197 code_.SetValue("FIELD_NAME", Name(field));
1198 if (TableFieldReturnsOption(field.value.type)) {
1200 " if let Some(x) = args.{{FIELD_NAME}} "
1201 "{ builder.add_{{FIELD_NAME}}(x); }";
1203 code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
1208 code_ += " builder.finish()";
1212 // Generate field id constants.
1213 if (struct_def.fields.vec.size() > 0) {
1214 for (auto it = struct_def.fields.vec.begin();
1215 it != struct_def.fields.vec.end(); ++it) {
1216 const auto &field = **it;
1217 if (field.deprecated) {
1218 // Deprecated fields won't be accessible.
1222 code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1223 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
1225 " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1226 "{{OFFSET_VALUE}};";
1231 // Generate the accessors. Each has one of two forms:
1233 // If a value can be None:
1234 // pub fn name(&'a self) -> Option<user_facing_type> {
1235 // self._tab.get::<internal_type>(offset, defaultval)
1238 // If a value is always Some:
1239 // pub fn name(&'a self) -> user_facing_type {
1240 // self._tab.get::<internal_type>(offset, defaultval).unwrap()
1242 const auto offset_prefix = Name(struct_def);
1243 for (auto it = struct_def.fields.vec.begin();
1244 it != struct_def.fields.vec.end(); ++it) {
1245 const auto &field = **it;
1246 if (field.deprecated) {
1247 // Deprecated fields won't be accessible.
1251 code_.SetValue("FIELD_NAME", Name(field));
1252 code_.SetValue("RETURN_TYPE",
1253 GenTableAccessorFuncReturnType(field, "'a"));
1254 code_.SetValue("FUNC_BODY",
1255 GenTableAccessorFuncBody(field, "'a", offset_prefix));
1257 GenComment(field.doc_comment, " ");
1258 code_ += " #[inline]";
1259 code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
1260 code_ += " {{FUNC_BODY}}";
1263 // Generate a comparison function for this field if it is a key.
1264 if (field.key) { GenKeyFieldMethods(field); }
1266 // Generate a nested flatbuffer field, if applicable.
1267 auto nested = field.attributes.Lookup("nested_flatbuffer");
1269 std::string qualified_name = nested->constant;
1270 auto nested_root = parser_.LookupStruct(nested->constant);
1271 if (nested_root == nullptr) {
1272 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1274 nested_root = parser_.LookupStruct(qualified_name);
1276 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
1279 code_.SetValue("OFFSET_NAME",
1280 offset_prefix + "::" + GetFieldOffsetName(field));
1282 " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> "
1283 " Option<{{STRUCT_NAME}}<'a>> {";
1284 code_ += " match self.{{FIELD_NAME}}() {";
1285 code_ += " None => { None }";
1286 code_ += " Some(data) => {";
1287 code_ += " use self::flatbuffers::Follow;";
1289 " Some(<flatbuffers::ForwardsUOffset"
1290 "<{{STRUCT_NAME}}<'a>>>::follow(data, 0))";
1297 // Explicit specializations for union accessors
1298 for (auto it = struct_def.fields.vec.begin();
1299 it != struct_def.fields.vec.end(); ++it) {
1300 const auto &field = **it;
1301 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
1305 auto u = field.value.type.enum_def;
1307 code_.SetValue("FIELD_NAME", Name(field));
1309 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
1311 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1313 auto table_init_type =
1314 WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
1315 ev.union_type.struct_def->name);
1318 "U_ELEMENT_ENUM_TYPE",
1319 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
1320 code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type);
1321 code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
1323 code_ += " #[inline]";
1324 code_ += " #[allow(non_snake_case)]";
1326 " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
1327 "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
1329 " if self.{{FIELD_NAME}}_type() == {{U_ELEMENT_ENUM_TYPE}} {";
1331 " self.{{FIELD_NAME}}().map(|u| "
1332 "{{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
1333 code_ += " } else {";
1341 code_ += "}"; // End of table impl.
1344 // Generate an args struct:
1345 code_.SetValue("MAYBE_LT",
1346 TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
1347 code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1348 for (auto it = struct_def.fields.vec.begin();
1349 it != struct_def.fields.vec.end(); ++it) {
1350 const auto &field = **it;
1351 if (!field.deprecated) {
1352 code_.SetValue("PARAM_NAME", Name(field));
1353 code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a "));
1354 code_ += " pub {{PARAM_NAME}}: {{PARAM_TYPE}},";
1359 // Generate an impl of Default for the *Args type:
1360 code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1361 code_ += " #[inline]";
1362 code_ += " fn default() -> Self {";
1363 code_ += " {{STRUCT_NAME}}Args {";
1364 for (auto it = struct_def.fields.vec.begin();
1365 it != struct_def.fields.vec.end(); ++it) {
1366 const auto &field = **it;
1367 if (!field.deprecated) {
1368 code_.SetValue("PARAM_VALUE", TableBuilderArgsDefaultValue(field));
1369 code_.SetValue("REQ", field.required ? " // required field" : "");
1370 code_.SetValue("PARAM_NAME", Name(field));
1371 code_ += " {{PARAM_NAME}}: {{PARAM_VALUE}},{{REQ}}";
1378 // Generate a builder struct:
1379 code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
1380 code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1382 " 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]";
1413 " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
1414 "{{FIELD_TYPE}}) {";
1416 code_.SetValue("FIELD_DEFAULT_VALUE",
1417 TableBuilderAddFuncDefaultValue(field));
1419 " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
1420 "{{FIELD_DEFAULT_VALUE}});";
1422 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
1428 // Struct initializer (all fields required);
1429 code_ += " #[inline]";
1431 " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
1432 "{{STRUCT_NAME}}Builder<'a, 'b> {";
1433 code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
1434 code_ += " let start = _fbb.start_table();";
1435 code_ += " {{STRUCT_NAME}}Builder {";
1436 code_ += " fbb_: _fbb,";
1437 code_ += " start_: start,";
1441 // finish() function.
1442 code_ += " #[inline]";
1444 " pub fn finish(self) -> "
1445 "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
1446 code_ += " let o = self.fbb_.end_table(self.start_);";
1448 for (auto it = struct_def.fields.vec.begin();
1449 it != struct_def.fields.vec.end(); ++it) {
1450 const auto &field = **it;
1451 if (!field.deprecated && field.required) {
1452 code_.SetValue("FIELD_NAME", MakeSnakeCase(Name(field)));
1453 code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1455 " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
1456 "\"{{FIELD_NAME}}\");";
1459 code_ += " flatbuffers::WIPOffset::new(o.value())";
1465 // Generate functions to compare tables and structs by key. This function
1466 // must only be called if the field key is defined.
1467 void GenKeyFieldMethods(const FieldDef &field) {
1468 FLATBUFFERS_ASSERT(field.key);
1470 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
1472 code_ += " #[inline]";
1474 " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
1476 code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
1479 code_ += " #[inline]";
1481 " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
1482 " ::std::cmp::Ordering {";
1483 code_ += " let key = self.{{FIELD_NAME}}();";
1484 code_ += " key.cmp(&val)";
1488 // Generate functions for accessing the root table object. This function
1489 // must only be called if the root table is defined.
1490 void GenRootTableFuncs(const StructDef &struct_def) {
1491 FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
1492 auto name = Name(struct_def);
1494 code_.SetValue("STRUCT_NAME", name);
1495 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
1496 code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
1498 // The root datatype accessors:
1499 code_ += "#[inline]";
1501 "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
1502 " -> {{STRUCT_NAME}}<'a> {";
1503 code_ += " flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)";
1507 code_ += "#[inline]";
1509 "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
1510 "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
1512 " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
1517 if (parser_.file_identifier_.length()) {
1518 // Declare the identifier
1519 code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &'static str\\";
1520 code_ += " = \"" + parser_.file_identifier_ + "\";";
1523 // Check if a buffer has the identifier.
1524 code_ += "#[inline]";
1525 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
1526 code_ += "(buf: &[u8]) -> bool {";
1527 code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
1528 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false);";
1531 code_ += "#[inline]";
1532 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
1533 code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
1534 code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
1535 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true);";
1540 if (parser_.file_extension_.length()) {
1541 // Return the extension
1542 code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &'static str = \\";
1543 code_ += "\"" + parser_.file_extension_ + "\";";
1547 // Finish a buffer with a given root object:
1548 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1549 code_ += "#[inline]";
1550 code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
1551 code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1552 code_ += " root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1553 if (parser_.file_identifier_.length()) {
1554 code_ += " fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1556 code_ += " fbb.finish(root, None);";
1560 code_ += "#[inline]";
1562 "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
1564 "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
1565 "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1566 if (parser_.file_identifier_.length()) {
1568 " fbb.finish_size_prefixed(root, "
1569 "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1571 code_ += " fbb.finish_size_prefixed(root, None);";
1576 static void GenPadding(
1577 const FieldDef &field, std::string *code_ptr, int *id,
1578 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
1579 if (field.padding) {
1580 for (int i = 0; i < 4; i++) {
1581 if (static_cast<int>(field.padding) & (1 << i)) {
1582 f((1 << i) * 8, code_ptr, id);
1585 assert(!(field.padding & ~0xF));
1589 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
1591 " padding" + NumToString((*id)++) + "__: u" + NumToString(bits) + ",";
1594 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
1596 *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
1599 // Generate an accessor struct with constructor for a flatbuffers struct.
1600 void GenStruct(const StructDef &struct_def) {
1601 // Generates manual padding and alignment.
1602 // Variables are private because they contain little endian data on all
1604 GenComment(struct_def.doc_comment);
1605 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
1606 code_.SetValue("STRUCT_NAME", Name(struct_def));
1608 code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
1609 code_ += "#[repr(C, align({{ALIGN}}))]";
1611 // PartialEq is useful to derive because we can correctly compare structs
1612 // for equality by just comparing their underlying byte data. This doesn't
1613 // hold for PartialOrd/Ord.
1614 code_ += "#[derive(Clone, Copy, Debug, PartialEq)]";
1615 code_ += "pub struct {{STRUCT_NAME}} {";
1618 for (auto it = struct_def.fields.vec.begin();
1619 it != struct_def.fields.vec.end(); ++it) {
1620 const auto &field = **it;
1621 code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
1622 code_.SetValue("FIELD_NAME", Name(field));
1623 code_ += " {{FIELD_NAME}}_: {{FIELD_TYPE}},";
1625 if (field.padding) {
1626 std::string padding;
1627 GenPadding(field, &padding, &padding_id, PaddingDefinition);
1632 code_ += "} // pub struct {{STRUCT_NAME}}";
1634 // Generate impls for SafeSliceAccess (because all structs are endian-safe),
1635 // Follow for the value type, Follow for the reference type, Push for the
1636 // value type, and Push for the reference type.
1637 code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
1638 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
1639 code_ += " type Inner = &'a {{STRUCT_NAME}};";
1640 code_ += " #[inline]";
1641 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1642 code_ += " <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
1645 code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
1646 code_ += " type Inner = &'a {{STRUCT_NAME}};";
1647 code_ += " #[inline]";
1648 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1649 code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
1652 code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
1653 code_ += " type Output = {{STRUCT_NAME}};";
1654 code_ += " #[inline]";
1655 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1656 code_ += " let src = unsafe {";
1658 " ::std::slice::from_raw_parts("
1659 "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1661 code_ += " dst.copy_from_slice(src);";
1664 code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
1665 code_ += " type Output = {{STRUCT_NAME}};";
1667 code_ += " #[inline]";
1668 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1669 code_ += " let src = unsafe {";
1671 " ::std::slice::from_raw_parts("
1672 "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1674 code_ += " dst.copy_from_slice(src);";
1680 // Generate a constructor that takes all fields as arguments.
1681 code_ += "impl {{STRUCT_NAME}} {";
1682 std::string arg_list;
1683 std::string init_list;
1685 for (auto it = struct_def.fields.vec.begin();
1686 it != struct_def.fields.vec.end(); ++it) {
1687 const auto &field = **it;
1688 const auto member_name = Name(field) + "_";
1689 const auto reference =
1690 StructMemberAccessNeedsCopy(field.value.type) ? "" : "&'a ";
1691 const auto arg_name = "_" + Name(field);
1692 const auto arg_type = reference + GetTypeGet(field.value.type);
1694 if (it != struct_def.fields.vec.begin()) { arg_list += ", "; }
1695 arg_list += arg_name + ": ";
1696 arg_list += arg_type;
1697 init_list += " " + member_name;
1698 if (StructMemberAccessNeedsCopy(field.value.type)) {
1699 init_list += ": " + arg_name + ".to_little_endian(),\n";
1701 init_list += ": *" + arg_name + ",\n";
1705 code_.SetValue("ARG_LIST", arg_list);
1706 code_.SetValue("INIT_LIST", init_list);
1707 code_ += " pub fn new<'a>({{ARG_LIST}}) -> Self {";
1708 code_ += " {{STRUCT_NAME}} {";
1709 code_ += "{{INIT_LIST}}";
1711 for (auto it = struct_def.fields.vec.begin();
1712 it != struct_def.fields.vec.end(); ++it) {
1713 const auto &field = **it;
1714 if (field.padding) {
1715 std::string padding;
1716 GenPadding(field, &padding, &padding_id, PaddingInitializer);
1717 code_ += " " + padding;
1723 // Generate accessor methods for the struct.
1724 for (auto it = struct_def.fields.vec.begin();
1725 it != struct_def.fields.vec.end(); ++it) {
1726 const auto &field = **it;
1728 auto field_type = TableBuilderArgsAddFuncType(field, "'a");
1729 auto member = "self." + Name(field) + "_";
1730 auto value = StructMemberAccessNeedsCopy(field.value.type)
1731 ? member + ".from_little_endian()"
1734 code_.SetValue("FIELD_NAME", Name(field));
1735 code_.SetValue("FIELD_TYPE", field_type);
1736 code_.SetValue("FIELD_VALUE", value);
1737 code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
1739 GenComment(field.doc_comment, " ");
1740 code_ += " pub fn {{FIELD_NAME}}<'a>(&'a self) -> {{FIELD_TYPE}} {";
1741 code_ += " {{REF}}{{FIELD_VALUE}}";
1744 // Generate a comparison function for this field if it is a key.
1745 if (field.key) { GenKeyFieldMethods(field); }
1751 void GenNamespaceImports(const int white_spaces) {
1752 std::string indent = std::string(white_spaces, ' ');
1754 code_ += indent + "use std::mem;";
1755 code_ += indent + "use std::cmp::Ordering;";
1757 code_ += indent + "extern crate flatbuffers;";
1758 code_ += indent + "use self::flatbuffers::EndianScalar;";
1761 // Set up the correct namespace. This opens a namespace if the current
1762 // namespace is different from the target namespace. This function
1763 // closes and opens the namespaces only as necessary.
1765 // The file must start and end with an empty (or null) namespace so that
1766 // namespaces are properly opened and closed.
1767 void SetNameSpace(const Namespace *ns) {
1768 if (cur_name_space_ == ns) { return; }
1770 // Compute the size of the longest common namespace prefix.
1771 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
1772 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
1773 // and common_prefix_size = 2
1774 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
1775 size_t new_size = ns ? ns->components.size() : 0;
1777 size_t common_prefix_size = 0;
1778 while (common_prefix_size < old_size && common_prefix_size < new_size &&
1779 ns->components[common_prefix_size] ==
1780 cur_name_space_->components[common_prefix_size]) {
1781 common_prefix_size++;
1784 // Close cur_name_space in reverse order to reach the common prefix.
1785 // In the previous example, D then C are closed.
1786 for (size_t j = old_size; j > common_prefix_size; --j) {
1787 code_ += "} // pub mod " + cur_name_space_->components[j - 1];
1789 if (old_size != common_prefix_size) { code_ += ""; }
1791 // open namespace parts to reach the ns namespace
1792 // in the previous example, E, then F, then G are opened
1793 for (auto j = common_prefix_size; j != new_size; ++j) {
1794 code_ += "#[allow(unused_imports, dead_code)]";
1795 code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
1796 // Generate local namespace imports.
1797 GenNamespaceImports(2);
1799 if (new_size != common_prefix_size) { code_ += ""; }
1801 cur_name_space_ = ns;
1807 bool GenerateRust(const Parser &parser, const std::string &path,
1808 const std::string &file_name) {
1809 rust::RustGenerator generator(parser, path, file_name);
1810 return generator.generate();
1813 std::string RustMakeRule(const Parser &parser, const std::string &path,
1814 const std::string &file_name) {
1815 std::string filebase =
1816 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
1817 std::string make_rule = GeneratedFileName(path, filebase) + ": ";
1819 auto included_files = parser.GetIncludedFilesRecursive(file_name);
1820 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1821 make_rule += " " + *it;
1826 } // namespace flatbuffers
1828 // TODO(rw): Generated code should import other generated files.
1829 // TODO(rw): Generated code should refer to namespaces in included files in a
1830 // way that makes them referrable.
1831 // TODO(rw): Generated code should indent according to nesting level.
1832 // TODO(rw): Generated code should generate endian-safe Debug impls.
1833 // TODO(rw): Generated code could use a Rust-only enum type to access unions,
1834 // instead of making the user use _type() to manually switch.