• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google Inc. All rights reserved.
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 // independent from idl_parser, since this code is not needed for most clients
18 
19 #include "flatbuffers/code_generators.h"
20 #include "flatbuffers/flatbuffers.h"
21 #include "flatbuffers/idl.h"
22 #include "flatbuffers/util.h"
23 
24 namespace flatbuffers {
25 
26 // Convert a camelCaseIdentifier or CamelCaseIdentifier to a
27 // snake_case_identifier.
MakeSnakeCase(const std::string & in)28 std::string MakeSnakeCase(const std::string &in) {
29   std::string s;
30   for (size_t i = 0; i < in.length(); i++) {
31     if (i == 0) {
32       s += CharToLower(in[0]);
33     } else if (in[i] == '_') {
34       s += '_';
35     } else if (!islower(in[i])) {
36       // Prevent duplicate underscores for Upper_Snake_Case strings
37       // and UPPERCASE strings.
38       if (islower(in[i - 1])) { s += '_'; }
39       s += CharToLower(in[i]);
40     } else {
41       s += in[i];
42     }
43   }
44   return s;
45 }
46 
47 // Convert a string to all uppercase.
MakeUpper(const std::string & in)48 std::string MakeUpper(const std::string &in) {
49   std::string s;
50   for (size_t i = 0; i < in.length(); i++) { s += CharToUpper(in[i]); }
51   return s;
52 }
53 
54 // Encapsulate all logical field types in this enum. This allows us to write
55 // field logic based on type switches, instead of branches on the properties
56 // set on the Type.
57 // TODO(rw): for backwards compatibility, we can't use a strict `enum class`
58 //           declaration here. could we use the `-Wswitch-enum` warning to
59 //           achieve the same effect?
60 enum FullType {
61   ftInteger = 0,
62   ftFloat = 1,
63   ftBool = 2,
64 
65   ftStruct = 3,
66   ftTable = 4,
67 
68   ftEnumKey = 5,
69   ftUnionKey = 6,
70 
71   ftUnionValue = 7,
72 
73   // TODO(rw): bytestring?
74   ftString = 8,
75 
76   ftVectorOfInteger = 9,
77   ftVectorOfFloat = 10,
78   ftVectorOfBool = 11,
79   ftVectorOfEnumKey = 12,
80   ftVectorOfStruct = 13,
81   ftVectorOfTable = 14,
82   ftVectorOfString = 15,
83   ftVectorOfUnionValue = 16,
84 
85   ftArrayOfBuiltin = 17,
86   ftArrayOfEnum = 18,
87   ftArrayOfStruct = 19,
88 };
89 
90 // Convert a Type to a FullType (exhaustive).
GetFullType(const Type & type)91 FullType GetFullType(const Type &type) {
92   // N.B. The order of these conditionals matters for some types.
93 
94   if (IsString(type)) {
95     return ftString;
96   } else if (type.base_type == BASE_TYPE_STRUCT) {
97     if (type.struct_def->fixed) {
98       return ftStruct;
99     } else {
100       return ftTable;
101     }
102   } else if (IsVector(type)) {
103     switch (GetFullType(type.VectorType())) {
104       case ftInteger: {
105         return ftVectorOfInteger;
106       }
107       case ftFloat: {
108         return ftVectorOfFloat;
109       }
110       case ftBool: {
111         return ftVectorOfBool;
112       }
113       case ftStruct: {
114         return ftVectorOfStruct;
115       }
116       case ftTable: {
117         return ftVectorOfTable;
118       }
119       case ftString: {
120         return ftVectorOfString;
121       }
122       case ftEnumKey: {
123         return ftVectorOfEnumKey;
124       }
125       case ftUnionKey:
126       case ftUnionValue: {
127         FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
128         break;
129       }
130       default: {
131         FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
132       }
133     }
134   } else if (IsArray(type)) {
135     switch (GetFullType(type.VectorType())) {
136       case ftInteger:
137       case ftFloat:
138       case ftBool: {
139         return ftArrayOfBuiltin;
140       }
141       case ftStruct: {
142         return ftArrayOfStruct;
143       }
144       case ftEnumKey: {
145         return ftArrayOfEnum;
146       }
147       default: {
148         FLATBUFFERS_ASSERT(false && "Unsupported type for fixed array");
149       }
150     }
151   } else if (type.enum_def != nullptr) {
152     if (type.enum_def->is_union) {
153       if (type.base_type == BASE_TYPE_UNION) {
154         return ftUnionValue;
155       } else if (IsInteger(type.base_type)) {
156         return ftUnionKey;
157       } else {
158         FLATBUFFERS_ASSERT(false && "unknown union field type");
159       }
160     } else {
161       return ftEnumKey;
162     }
163   } else if (IsScalar(type.base_type)) {
164     if (IsBool(type.base_type)) {
165       return ftBool;
166     } else if (IsInteger(type.base_type)) {
167       return ftInteger;
168     } else if (IsFloat(type.base_type)) {
169       return ftFloat;
170     } else {
171       FLATBUFFERS_ASSERT(false && "unknown number type");
172     }
173   }
174 
175   FLATBUFFERS_ASSERT(false && "completely unknown type");
176 
177   // this is only to satisfy the compiler's return analysis.
178   return ftBool;
179 }
180 
181 // If the second parameter is false then wrap the first with Option<...>
WrapInOptionIfNotRequired(std::string s,bool required)182 std::string WrapInOptionIfNotRequired(std::string s, bool required) {
183   if (required) {
184     return s;
185   } else {
186     return "Option<" + s + ">";
187   }
188 }
189 
190 // If the second parameter is false then add .unwrap()
AddUnwrapIfRequired(std::string s,bool required)191 std::string AddUnwrapIfRequired(std::string s, bool required) {
192   if (required) {
193     return s + ".unwrap()";
194   } else {
195     return s;
196   }
197 }
198 
IsBitFlagsEnum(const EnumDef & enum_def)199 bool IsBitFlagsEnum(const EnumDef &enum_def) {
200   return enum_def.attributes.Lookup("bit_flags") != nullptr;
201 }
IsBitFlagsEnum(const FieldDef & field)202 bool IsBitFlagsEnum(const FieldDef &field) {
203   EnumDef *ed = field.value.type.enum_def;
204   return ed && IsBitFlagsEnum(*ed);
205 }
206 
207 // TableArgs make required non-scalars "Option<_>".
208 // TODO(cneo): Rework how we do defaults and stuff.
IsOptionalToBuilder(const FieldDef & field)209 bool IsOptionalToBuilder(const FieldDef &field) {
210   return field.IsOptional() || !IsScalar(field.value.type.base_type);
211 }
212 
213 namespace rust {
214 
215 class RustGenerator : public BaseGenerator {
216  public:
RustGenerator(const Parser & parser,const std::string & path,const std::string & file_name)217   RustGenerator(const Parser &parser, const std::string &path,
218                 const std::string &file_name)
219       : BaseGenerator(parser, path, file_name, "", "::", "rs"),
220         cur_name_space_(nullptr) {
221     const char *keywords[] = {
222       // clang-format off
223       // list taken from:
224       // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
225       //
226       // we write keywords one per line so that we can easily compare them with
227       // changes to that webpage in the future.
228 
229       // currently-used keywords
230       "as",
231       "break",
232       "const",
233       "continue",
234       "crate",
235       "else",
236       "enum",
237       "extern",
238       "false",
239       "fn",
240       "for",
241       "if",
242       "impl",
243       "in",
244       "let",
245       "loop",
246       "match",
247       "mod",
248       "move",
249       "mut",
250       "pub",
251       "ref",
252       "return",
253       "Self",
254       "self",
255       "static",
256       "struct",
257       "super",
258       "trait",
259       "true",
260       "type",
261       "unsafe",
262       "use",
263       "where",
264       "while",
265 
266       // future possible keywords
267       "abstract",
268       "alignof",
269       "become",
270       "box",
271       "do",
272       "final",
273       "macro",
274       "offsetof",
275       "override",
276       "priv",
277       "proc",
278       "pure",
279       "sizeof",
280       "typeof",
281       "unsized",
282       "virtual",
283       "yield",
284 
285       // other rust terms we should not use
286       "std",
287       "usize",
288       "isize",
289       "u8",
290       "i8",
291       "u16",
292       "i16",
293       "u32",
294       "i32",
295       "u64",
296       "i64",
297       "u128",
298       "i128",
299       "f32",
300       "f64",
301 
302       // These are terms the code generator can implement on types.
303       //
304       // In Rust, the trait resolution rules (as described at
305       // https://github.com/rust-lang/rust/issues/26007) mean that, as long
306       // as we impl table accessors as inherent methods, we'll never create
307       // conflicts with these keywords. However, that's a fairly nuanced
308       // implementation detail, and how we implement methods could change in
309       // the future. as a result, we proactively block these out as reserved
310       // words.
311       "follow",
312       "push",
313       "size",
314       "alignment",
315       "to_little_endian",
316       "from_little_endian",
317       nullptr,
318 
319       // used by Enum constants
320       "ENUM_MAX",
321       "ENUM_MIN",
322       "ENUM_VALUES",
323     };
324     for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
325   }
326 
327   // Iterate through all definitions we haven't generated code for (enums,
328   // structs, and tables) and output them to a single file.
generate()329   bool generate() {
330     code_.Clear();
331     code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
332 
333     assert(!cur_name_space_);
334 
335     // Generate imports for the global scope in case no namespace is used
336     // in the schema file.
337     GenNamespaceImports(0);
338     code_ += "";
339 
340     // Generate all code in their namespaces, once, because Rust does not
341     // permit re-opening modules.
342     //
343     // TODO(rw): Use a set data structure to reduce namespace evaluations from
344     //           O(n**2) to O(n).
345     for (auto ns_it = parser_.namespaces_.begin();
346          ns_it != parser_.namespaces_.end(); ++ns_it) {
347       const auto &ns = *ns_it;
348 
349       // Generate code for all the enum declarations.
350       for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
351            ++it) {
352         const auto &enum_def = **it;
353         if (enum_def.defined_namespace == ns && !enum_def.generated) {
354           SetNameSpace(enum_def.defined_namespace);
355           GenEnum(enum_def);
356         }
357       }
358 
359       // Generate code for all structs.
360       for (auto it = parser_.structs_.vec.begin();
361            it != parser_.structs_.vec.end(); ++it) {
362         const auto &struct_def = **it;
363         if (struct_def.defined_namespace == ns && struct_def.fixed &&
364             !struct_def.generated) {
365           SetNameSpace(struct_def.defined_namespace);
366           GenStruct(struct_def);
367         }
368       }
369 
370       // Generate code for all tables.
371       for (auto it = parser_.structs_.vec.begin();
372            it != parser_.structs_.vec.end(); ++it) {
373         const auto &struct_def = **it;
374         if (struct_def.defined_namespace == ns && !struct_def.fixed &&
375             !struct_def.generated) {
376           SetNameSpace(struct_def.defined_namespace);
377           GenTable(struct_def);
378           if (parser_.opts.generate_object_based_api) {
379             GenTableObject(struct_def);
380           }
381         }
382       }
383 
384       // Generate global helper functions.
385       if (parser_.root_struct_def_) {
386         auto &struct_def = *parser_.root_struct_def_;
387         if (struct_def.defined_namespace != ns) { continue; }
388         SetNameSpace(struct_def.defined_namespace);
389         GenRootTableFuncs(struct_def);
390       }
391     }
392     if (cur_name_space_) SetNameSpace(nullptr);
393 
394     const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts);
395     const auto final_code = code_.ToString();
396     return SaveFile(file_path.c_str(), final_code, false);
397   }
398 
399  private:
400   CodeWriter code_;
401 
402   std::set<std::string> keywords_;
403 
404   // This tracks the current namespace so we can insert namespace declarations.
405   const Namespace *cur_name_space_;
406 
CurrentNameSpace() const407   const Namespace *CurrentNameSpace() const { return cur_name_space_; }
408 
409   // Determine if a Type needs a lifetime template parameter when used in the
410   // Rust builder args.
TableBuilderTypeNeedsLifetime(const Type & type) const411   bool TableBuilderTypeNeedsLifetime(const Type &type) const {
412     switch (GetFullType(type)) {
413       case ftInteger:
414       case ftFloat:
415       case ftBool:
416       case ftEnumKey:
417       case ftUnionKey:
418       case ftUnionValue: {
419         return false;
420       }
421       default: {
422         return true;
423       }
424     }
425   }
426 
427   // Determine if a table args rust type needs a lifetime template parameter.
TableBuilderArgsNeedsLifetime(const StructDef & struct_def) const428   bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
429     FLATBUFFERS_ASSERT(!struct_def.fixed);
430 
431     for (auto it = struct_def.fields.vec.begin();
432          it != struct_def.fields.vec.end(); ++it) {
433       const auto &field = **it;
434       if (field.deprecated) { continue; }
435 
436       if (TableBuilderTypeNeedsLifetime(field.value.type)) { return true; }
437     }
438 
439     return false;
440   }
441 
EscapeKeyword(const std::string & name) const442   std::string EscapeKeyword(const std::string &name) const {
443     return keywords_.find(name) == keywords_.end() ? name : name + "_";
444   }
NamespacedNativeName(const Definition & def)445   std::string NamespacedNativeName(const Definition &def) {
446     return WrapInNameSpace(def.defined_namespace, NativeName(def));
447   }
448 
NativeName(const Definition & def)449   std::string NativeName(const Definition &def) {
450     return parser_.opts.object_prefix + Name(def) + parser_.opts.object_suffix;
451   }
452 
Name(const Definition & def) const453   std::string Name(const Definition &def) const {
454     return EscapeKeyword(def.name);
455   }
456 
Name(const EnumVal & ev) const457   std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
458 
WrapInNameSpace(const Definition & def) const459   std::string WrapInNameSpace(const Definition &def) const {
460     return WrapInNameSpace(def.defined_namespace, Name(def));
461   }
WrapInNameSpace(const Namespace * ns,const std::string & name) const462   std::string WrapInNameSpace(const Namespace *ns,
463                               const std::string &name) const {
464     if (CurrentNameSpace() == ns) return name;
465     std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
466     return prefix + name;
467   }
468 
469   // Determine the namespace traversal needed from the Rust crate root.
470   // This may be useful in the future for referring to included files, but is
471   // currently unused.
GetAbsoluteNamespaceTraversal(const Namespace * dst) const472   std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const {
473     std::stringstream stream;
474 
475     stream << "::";
476     for (auto d = dst->components.begin(); d != dst->components.end(); ++d) {
477       stream << MakeSnakeCase(*d) + "::";
478     }
479     return stream.str();
480   }
481 
482   // Determine the relative namespace traversal needed to reference one
483   // namespace from another namespace. This is useful because it does not force
484   // the user to have a particular file layout. (If we output absolute
485   // namespace paths, that may require users to organize their Rust crates in a
486   // particular way.)
GetRelativeNamespaceTraversal(const Namespace * src,const Namespace * dst) const487   std::string GetRelativeNamespaceTraversal(const Namespace *src,
488                                             const Namespace *dst) const {
489     // calculate the path needed to reference dst from src.
490     // example: f(A::B::C, A::B::C) -> (none)
491     // example: f(A::B::C, A::B)    -> super::
492     // example: f(A::B::C, A::B::D) -> super::D
493     // example: f(A::B::C, A)       -> super::super::
494     // example: f(A::B::C, D)       -> super::super::super::D
495     // example: f(A::B::C, D::E)    -> super::super::super::D::E
496     // example: f(A, D::E)          -> super::D::E
497     // does not include leaf object (typically a struct type).
498 
499     size_t i = 0;
500     std::stringstream stream;
501 
502     auto s = src->components.begin();
503     auto d = dst->components.begin();
504     for (;;) {
505       if (s == src->components.end()) { break; }
506       if (d == dst->components.end()) { break; }
507       if (*s != *d) { break; }
508       ++s;
509       ++d;
510       ++i;
511     }
512 
513     for (; s != src->components.end(); ++s) { stream << "super::"; }
514     for (; d != dst->components.end(); ++d) {
515       stream << MakeSnakeCase(*d) + "::";
516     }
517     return stream.str();
518   }
519 
520   // Generate a comment from the schema.
GenComment(const std::vector<std::string> & dc,const char * prefix="")521   void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
522     std::string text;
523     ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
524     code_ += text + "\\";
525   }
526 
527   // Return a Rust type from the table in idl.h.
GetTypeBasic(const Type & type) const528   std::string GetTypeBasic(const Type &type) const {
529     switch (GetFullType(type)) {
530       case ftInteger:
531       case ftFloat:
532       case ftBool:
533       case ftEnumKey:
534       case ftUnionKey: {
535         break;
536       }
537       default: {
538         FLATBUFFERS_ASSERT(false && "incorrect type given");
539       }
540     }
541 
542     // clang-format off
543     static const char * const ctypename[] = {
544     #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
545                            RTYPE, ...) \
546       #RTYPE,
547       FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
548     #undef FLATBUFFERS_TD
549     };
550     // clang-format on
551 
552     if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
553     return ctypename[type.base_type];
554   }
555 
556   // Look up the native type for an enum. This will always be an integer like
557   // u8, i32, etc.
GetEnumTypeForDecl(const Type & type)558   std::string GetEnumTypeForDecl(const Type &type) {
559     const auto ft = GetFullType(type);
560     if (!(ft == ftEnumKey || ft == ftUnionKey)) {
561       FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
562     }
563 
564     // clang-format off
565     static const char *ctypename[] = {
566     #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
567                            RTYPE, ...) \
568       #RTYPE,
569       FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
570     #undef FLATBUFFERS_TD
571     };
572     // clang-format on
573 
574     // Enums can be bools, but their Rust representation must be a u8, as used
575     // in the repr attribute (#[repr(bool)] is an invalid attribute).
576     if (type.base_type == BASE_TYPE_BOOL) return "u8";
577     return ctypename[type.base_type];
578   }
579 
580   // Return a Rust type for any type (scalar, table, struct) specifically for
581   // using a FlatBuffer.
GetTypeGet(const Type & type) const582   std::string GetTypeGet(const Type &type) const {
583     switch (GetFullType(type)) {
584       case ftInteger:
585       case ftFloat:
586       case ftBool:
587       case ftEnumKey:
588       case ftUnionKey: {
589         return GetTypeBasic(type);
590       }
591       case ftArrayOfBuiltin:
592       case ftArrayOfEnum:
593       case ftArrayOfStruct: {
594         return "[" + GetTypeGet(type.VectorType()) + "; " +
595                NumToString(type.fixed_length) + "]";
596       }
597       case ftTable: {
598         return WrapInNameSpace(type.struct_def->defined_namespace,
599                                type.struct_def->name) +
600                "<'a>";
601       }
602       default: {
603         return WrapInNameSpace(type.struct_def->defined_namespace,
604                                type.struct_def->name);
605       }
606     }
607   }
608 
GetEnumValue(const EnumDef & enum_def,const EnumVal & enum_val) const609   std::string GetEnumValue(const EnumDef &enum_def,
610                            const EnumVal &enum_val) const {
611     return Name(enum_def) + "::" + Name(enum_val);
612   }
613 
614   // 1 suffix since old C++ can't figure out the overload.
ForAllEnumValues1(const EnumDef & enum_def,std::function<void (const EnumVal &)> cb)615   void ForAllEnumValues1(const EnumDef &enum_def,
616                          std::function<void(const EnumVal &)> cb) {
617     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
618       const auto &ev = **it;
619       code_.SetValue("VARIANT", Name(ev));
620       code_.SetValue("VALUE", enum_def.ToString(ev));
621       cb(ev);
622     }
623   }
ForAllEnumValues(const EnumDef & enum_def,std::function<void ()> cb)624   void ForAllEnumValues(const EnumDef &enum_def, std::function<void()> cb) {
625     std::function<void(const EnumVal &)> wrapped = [&](const EnumVal &unused) {
626       (void)unused;
627       cb();
628     };
629     ForAllEnumValues1(enum_def, wrapped);
630   }
631   // Generate an enum declaration,
632   // an enum string lookup table,
633   // an enum match function,
634   // and an enum array of values
GenEnum(const EnumDef & enum_def)635   void GenEnum(const EnumDef &enum_def) {
636     code_.SetValue("ENUM_NAME", Name(enum_def));
637     code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
638     code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
639     code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
640     const EnumVal *minv = enum_def.MinValue();
641     const EnumVal *maxv = enum_def.MaxValue();
642     FLATBUFFERS_ASSERT(minv && maxv);
643     code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
644     code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
645 
646     if (IsBitFlagsEnum(enum_def)) {
647       // Defer to the convenient and canonical bitflags crate. We declare it in
648       // a module to #allow camel case constants in a smaller scope. This
649       // matches Flatbuffers c-modeled enums where variants are associated
650       // constants but in camel case.
651       code_ += "#[allow(non_upper_case_globals)]";
652       code_ += "mod bitflags_{{ENUM_NAME_SNAKE}} {";
653       code_ += "  flatbuffers::bitflags::bitflags! {";
654       GenComment(enum_def.doc_comment, "    ");
655       code_ += "    #[derive(Default)]";
656       code_ += "    pub struct {{ENUM_NAME}}: {{BASE_TYPE}} {";
657       ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
658         this->GenComment(ev.doc_comment, "      ");
659         code_ += "      const {{VARIANT}} = {{VALUE}};";
660       });
661       code_ += "    }";
662       code_ += "  }";
663       code_ += "}";
664       code_ += "pub use self::bitflags_{{ENUM_NAME_SNAKE}}::{{ENUM_NAME}};";
665       code_ += "";
666 
667       code_.SetValue("FROM_BASE", "unsafe { Self::from_bits_unchecked(b) }");
668       code_.SetValue("INTO_BASE", "self.bits()");
669     } else {
670       // Normal, c-modelled enums.
671       // Deprecated associated constants;
672       const std::string deprecation_warning =
673           "#[deprecated(since = \"2.0.0\", note = \"Use associated constants"
674           " instead. This will no longer be generated in 2021.\")]";
675       code_ += deprecation_warning;
676       code_ +=
677           "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
678           " = {{ENUM_MIN_BASE_VALUE}};";
679       code_ += deprecation_warning;
680       code_ +=
681           "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
682           " = {{ENUM_MAX_BASE_VALUE}};";
683       auto num_fields = NumToString(enum_def.size());
684       code_ += deprecation_warning;
685       code_ += "#[allow(non_camel_case_types)]";
686       code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " +
687                num_fields + "] = [";
688       ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
689         code_ += "  " + GetEnumValue(enum_def, ev) + ",";
690       });
691       code_ += "];";
692       code_ += "";
693 
694       GenComment(enum_def.doc_comment);
695       // Derive Default to be 0. flatc enforces this when the enum
696       // is put into a struct, though this isn't documented behavior, it is
697       // needed to derive defaults in struct objects.
698       code_ +=
699           "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, "
700           "Default)]";
701       code_ += "#[repr(transparent)]";
702       code_ += "pub struct {{ENUM_NAME}}(pub {{BASE_TYPE}});";
703       code_ += "#[allow(non_upper_case_globals)]";
704       code_ += "impl {{ENUM_NAME}} {";
705       ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
706         this->GenComment(ev.doc_comment, "  ");
707         code_ += "  pub const {{VARIANT}}: Self = Self({{VALUE}});";
708       });
709       code_ += "";
710       // Generate Associated constants
711       code_ += "  pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};";
712       code_ += "  pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};";
713       code_ += "  pub const ENUM_VALUES: &'static [Self] = &[";
714       ForAllEnumValues(enum_def, [&]() { code_ += "    Self::{{VARIANT}},"; });
715       code_ += "  ];";
716       code_ += "  /// Returns the variant's name or \"\" if unknown.";
717       code_ += "  pub fn variant_name(self) -> Option<&'static str> {";
718       code_ += "    match self {";
719       ForAllEnumValues(enum_def, [&]() {
720         code_ += "      Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),";
721       });
722       code_ += "      _ => None,";
723       code_ += "    }";
724       code_ += "  }";
725       code_ += "}";
726 
727       // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>".
728       code_ += "impl std::fmt::Debug for {{ENUM_NAME}} {";
729       code_ +=
730           "  fn fmt(&self, f: &mut std::fmt::Formatter) ->"
731           " std::fmt::Result {";
732       code_ += "    if let Some(name) = self.variant_name() {";
733       code_ += "      f.write_str(name)";
734       code_ += "    } else {";
735       code_ += "      f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))";
736       code_ += "    }";
737       code_ += "  }";
738       code_ += "}";
739 
740       code_.SetValue("FROM_BASE", "Self(b)");
741       code_.SetValue("INTO_BASE", "self.0");
742     }
743 
744     // Generate Follow and Push so we can serialize and stuff.
745     code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
746     code_ += "  type Inner = Self;";
747     code_ += "  #[inline]";
748     code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
749     code_ += "    let b = unsafe {";
750     code_ += "      flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc)";
751     code_ += "    };";
752     code_ += "    {{FROM_BASE}}";
753     code_ += "  }";
754     code_ += "}";
755     code_ += "";
756     code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
757     code_ += "    type Output = {{ENUM_NAME}};";
758     code_ += "    #[inline]";
759     code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
760     code_ +=
761         "        unsafe { flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
762         "(dst, {{INTO_BASE}}); }";
763     code_ += "    }";
764     code_ += "}";
765     code_ += "";
766     code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
767     code_ += "  #[inline]";
768     code_ += "  fn to_little_endian(self) -> Self {";
769     code_ += "    let b = {{BASE_TYPE}}::to_le({{INTO_BASE}});";
770     code_ += "    {{FROM_BASE}}";
771     code_ += "  }";
772     code_ += "  #[inline]";
773     code_ += "  #[allow(clippy::wrong_self_convention)]";
774     code_ += "  fn from_little_endian(self) -> Self {";
775     code_ += "    let b = {{BASE_TYPE}}::from_le({{INTO_BASE}});";
776     code_ += "    {{FROM_BASE}}";
777     code_ += "  }";
778     code_ += "}";
779     code_ += "";
780 
781     // Generate verifier - deferring to the base type.
782     code_ += "impl<'a> flatbuffers::Verifiable for {{ENUM_NAME}} {";
783     code_ += "  #[inline]";
784     code_ += "  fn run_verifier(";
785     code_ += "    v: &mut flatbuffers::Verifier, pos: usize";
786     code_ += "  ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
787     code_ += "    use self::flatbuffers::Verifiable;";
788     code_ += "    {{BASE_TYPE}}::run_verifier(v, pos)";
789     code_ += "  }";
790     code_ += "}";
791     code_ += "";
792     // Enums are basically integers.
793     code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{ENUM_NAME}} {}";
794 
795     if (enum_def.is_union) {
796       // Generate typesafe offset(s) for unions
797       code_.SetValue("NAME", Name(enum_def));
798       code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
799       code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
800       code_ += "";
801       if (parser_.opts.generate_object_based_api) { GenUnionObject(enum_def); }
802     }
803   }
804 
805   // CASPER: dedup Object versions from non object versions.
ForAllUnionObjectVariantsBesidesNone(const EnumDef & enum_def,std::function<void ()> cb)806   void ForAllUnionObjectVariantsBesidesNone(const EnumDef &enum_def,
807                                             std::function<void()> cb) {
808     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
809       auto &enum_val = **it;
810       if (enum_val.union_type.base_type == BASE_TYPE_NONE) continue;
811       code_.SetValue("VARIANT_NAME", Name(enum_val));
812       code_.SetValue("NATIVE_VARIANT", MakeCamel(Name(enum_val)));
813       code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(enum_val)));
814       code_.SetValue("U_ELEMENT_TABLE_TYPE",
815                      NamespacedNativeName(*enum_val.union_type.struct_def));
816       cb();
817     }
818   }
GenUnionObject(const EnumDef & enum_def)819   void GenUnionObject(const EnumDef &enum_def) {
820     code_.SetValue("ENUM_NAME", Name(enum_def));
821     code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
822     code_.SetValue("NATIVE_NAME", NativeName(enum_def));
823 
824     // Generate native union.
825     code_ += "#[non_exhaustive]";
826     code_ += "#[derive(Debug, Clone, PartialEq)]";
827     code_ += "pub enum {{NATIVE_NAME}} {";
828     code_ += "  NONE,";
829     ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
830       code_ += "  {{NATIVE_VARIANT}}(Box<{{U_ELEMENT_TABLE_TYPE}}>),";
831     });
832     code_ += "}";
833     // Generate Default (NONE).
834     code_ += "impl Default for {{NATIVE_NAME}} {";
835     code_ += "  fn default() -> Self {";
836     code_ += "    Self::NONE";
837     code_ += "  }";
838     code_ += "}";
839 
840     // Generate native union methods.
841     code_ += "impl {{NATIVE_NAME}} {";
842 
843     // Get flatbuffers union key.
844     // CASPER: add docstrings?
845     code_ += "  pub fn {{ENUM_NAME_SNAKE}}_type(&self) -> {{ENUM_NAME}} {";
846     code_ += "    match self {";
847     code_ += "      Self::NONE => {{ENUM_NAME}}::NONE,";
848     ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
849       code_ +=
850           "      Self::{{NATIVE_VARIANT}}(_) => {{ENUM_NAME}}::"
851           "{{VARIANT_NAME}},";
852     });
853     code_ += "    }";
854     code_ += "  }";
855     // Pack flatbuffers union value
856     code_ +=
857         "  pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder)"
858         " -> Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>"
859         " {";
860     code_ += "    match self {";
861     code_ += "      Self::NONE => None,";
862     ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
863       code_ +=
864           "      Self::{{NATIVE_VARIANT}}(v) => "
865           "Some(v.pack(fbb).as_union_value()),";
866     });
867     code_ += "    }";
868     code_ += "  }";
869 
870     // Generate some accessors;
871     ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
872       // Move accessor.
873       code_ +=
874           "  /// If the union variant matches, return the owned "
875           "{{U_ELEMENT_TABLE_TYPE}}, setting the union to NONE.";
876       code_ +=
877           "  pub fn take_{{U_ELEMENT_NAME}}(&mut self) -> "
878           "Option<Box<{{U_ELEMENT_TABLE_TYPE}}>> {";
879       code_ += "    if let Self::{{NATIVE_VARIANT}}(_) = self {";
880       code_ += "      let v = std::mem::replace(self, Self::NONE);";
881       code_ += "      if let Self::{{NATIVE_VARIANT}}(w) = v {";
882       code_ += "        Some(w)";
883       code_ += "      } else {";
884       code_ += "        unreachable!()";
885       code_ += "      }";
886       code_ += "    } else {";
887       code_ += "      None";
888       code_ += "    }";
889       code_ += "  }";
890       // Immutable reference accessor.
891       code_ +=
892           "  /// If the union variant matches, return a reference to the "
893           "{{U_ELEMENT_TABLE_TYPE}}.";
894       code_ +=
895           "  pub fn as_{{U_ELEMENT_NAME}}(&self) -> "
896           "Option<&{{U_ELEMENT_TABLE_TYPE}}> {";
897       code_ +=
898           "    if let Self::{{NATIVE_VARIANT}}(v) = self "
899           "{ Some(v.as_ref()) } else { None }";
900       code_ += "  }";
901       // Mutable reference accessor.
902       code_ +=
903           "  /// If the union variant matches, return a mutable reference"
904           " to the {{U_ELEMENT_TABLE_TYPE}}.";
905       code_ +=
906           "  pub fn as_{{U_ELEMENT_NAME}}_mut(&mut self) -> "
907           "Option<&mut {{U_ELEMENT_TABLE_TYPE}}> {";
908       code_ +=
909           "    if let Self::{{NATIVE_VARIANT}}(v) = self "
910           "{ Some(v.as_mut()) } else { None }";
911       code_ += "  }";
912     });
913     code_ += "}";  // End union methods impl.
914   }
915 
GetFieldOffsetName(const FieldDef & field)916   std::string GetFieldOffsetName(const FieldDef &field) {
917     return "VT_" + MakeUpper(Name(field));
918   }
919 
920   enum DefaultContext { kBuilder, kAccessor, kObject };
GetDefaultValue(const FieldDef & field,const DefaultContext context)921   std::string GetDefaultValue(const FieldDef &field,
922                               const DefaultContext context) {
923     if (context == kBuilder) {
924       // Builders and Args structs model nonscalars "optional" even if they're
925       // required or have defaults according to the schema. I guess its because
926       // WIPOffset is not nullable.
927       if (!IsScalar(field.value.type.base_type) || field.IsOptional()) {
928         return "None";
929       }
930     } else {
931       // This for defaults in objects.
932       // Unions have a NONE variant instead of using Rust's None.
933       if (field.IsOptional() && !IsUnion(field.value.type)) { return "None"; }
934     }
935     switch (GetFullType(field.value.type)) {
936       case ftInteger:
937       case ftFloat: {
938         return field.value.constant;
939       }
940       case ftBool: {
941         return field.value.constant == "0" ? "false" : "true";
942       }
943       case ftUnionKey:
944       case ftEnumKey: {
945         auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
946         if (!ev) return "Default::default()";  // Bitflags enum.
947         return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
948                                GetEnumValue(*field.value.type.enum_def, *ev));
949       }
950       case ftUnionValue: {
951         return ObjectFieldType(field, true) + "::NONE";
952       }
953       case ftString: {
954         // Required fields do not have defaults defined by the schema, but we
955         // need one for Rust's Default trait so we use empty string. The usual
956         // value of field.value.constant is `0`, which is non-sensical except
957         // maybe to c++ (nullptr == 0).
958         // TODO: Escape strings?
959         const std::string defval =
960             field.IsRequired() ? "\"\"" : "\"" + field.value.constant + "\"";
961         if (context == kObject) return defval + ".to_string()";
962         if (context == kAccessor) return "&" + defval;
963         FLATBUFFERS_ASSERT("Unreachable.");
964         return "INVALID_CODE_GENERATION";
965       }
966 
967       case ftArrayOfStruct:
968       case ftArrayOfEnum:
969       case ftArrayOfBuiltin:
970       case ftVectorOfBool:
971       case ftVectorOfFloat:
972       case ftVectorOfInteger:
973       case ftVectorOfString:
974       case ftVectorOfStruct:
975       case ftVectorOfTable:
976       case ftVectorOfEnumKey:
977       case ftVectorOfUnionValue:
978       case ftStruct:
979       case ftTable: {
980         // We only support empty vectors which matches the defaults for
981         // &[T] and Vec<T> anyway.
982         //
983         // For required structs and tables fields, we defer to their object API
984         // defaults. This works so long as there's nothing recursive happening,
985         // but `table Infinity { i: Infinity (required); }` does compile.
986         return "Default::default()";
987       }
988     }
989     FLATBUFFERS_ASSERT("Unreachable.");
990     return "INVALID_CODE_GENERATION";
991   }
992 
993   // Create the return type for fields in the *BuilderArgs structs that are
994   // used to create Tables.
995   //
996   // Note: we could make all inputs to the BuilderArgs be an Option, as well
997   // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
998   // know if the value is default or not, because there are three ways to
999   // return a default value:
1000   // 1) return a stored value that happens to be the default,
1001   // 2) return a hardcoded value because the relevant vtable field is not in
1002   //    the vtable, or
1003   // 3) return a hardcoded value because the vtable field value is set to zero.
TableBuilderArgsDefnType(const FieldDef & field,const std::string & lifetime)1004   std::string TableBuilderArgsDefnType(const FieldDef &field,
1005                                        const std::string &lifetime) {
1006     const Type &type = field.value.type;
1007     auto WrapOption = [&](std::string s) {
1008       return IsOptionalToBuilder(field) ? "Option<" + s + ">" : s;
1009     };
1010     auto WrapVector = [&](std::string ty) {
1011       return WrapOption("flatbuffers::WIPOffset<flatbuffers::Vector<" +
1012                         lifetime + ", " + ty + ">>");
1013     };
1014     auto WrapUOffsetsVector = [&](std::string ty) {
1015       return WrapVector("flatbuffers::ForwardsUOffset<" + ty + ">");
1016     };
1017 
1018     switch (GetFullType(type)) {
1019       case ftInteger:
1020       case ftFloat:
1021       case ftBool: {
1022         return WrapOption(GetTypeBasic(type));
1023       }
1024       case ftStruct: {
1025         const auto typname = WrapInNameSpace(*type.struct_def);
1026         return WrapOption("&" + lifetime + " " + typname);
1027       }
1028       case ftTable: {
1029         const auto typname = WrapInNameSpace(*type.struct_def);
1030         return WrapOption("flatbuffers::WIPOffset<" + typname + "<" + lifetime +
1031                           ">>");
1032       }
1033       case ftString: {
1034         return WrapOption("flatbuffers::WIPOffset<&" + lifetime + " str>");
1035       }
1036       case ftEnumKey:
1037       case ftUnionKey: {
1038         return WrapOption(WrapInNameSpace(*type.enum_def));
1039       }
1040       case ftUnionValue: {
1041         return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
1042       }
1043 
1044       case ftVectorOfInteger:
1045       case ftVectorOfBool:
1046       case ftVectorOfFloat: {
1047         const auto typname = GetTypeBasic(type.VectorType());
1048         return WrapVector(typname);
1049       }
1050       case ftVectorOfEnumKey: {
1051         const auto typname = WrapInNameSpace(*type.enum_def);
1052         return WrapVector(typname);
1053       }
1054       case ftVectorOfStruct: {
1055         const auto typname = WrapInNameSpace(*type.struct_def);
1056         return WrapVector(typname);
1057       }
1058       case ftVectorOfTable: {
1059         const auto typname = WrapInNameSpace(*type.struct_def);
1060         return WrapUOffsetsVector(typname + "<" + lifetime + ">");
1061       }
1062       case ftVectorOfString: {
1063         return WrapUOffsetsVector("&" + lifetime + " str");
1064       }
1065       case ftVectorOfUnionValue: {
1066         return WrapUOffsetsVector("flatbuffers::Table<" + lifetime + ">");
1067       }
1068       case ftArrayOfEnum:
1069       case ftArrayOfStruct:
1070       case ftArrayOfBuiltin: {
1071         FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1072         return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1073       }
1074     }
1075     return "INVALID_CODE_GENERATION";  // for return analysis
1076   }
1077 
ObjectFieldType(const FieldDef & field,bool in_a_table)1078   std::string ObjectFieldType(const FieldDef &field, bool in_a_table) {
1079     const Type &type = field.value.type;
1080     std::string ty;
1081     switch (GetFullType(type)) {
1082       case ftInteger:
1083       case ftBool:
1084       case ftFloat: {
1085         ty = GetTypeBasic(type);
1086         break;
1087       }
1088       case ftString: {
1089         ty = "String";
1090         break;
1091       }
1092       case ftStruct: {
1093         ty = NamespacedNativeName(*type.struct_def);
1094         break;
1095       }
1096       case ftTable: {
1097         // Since Tables can contain themselves, Box is required to avoid
1098         // infinite types.
1099         ty = "Box<" + NamespacedNativeName(*type.struct_def) + ">";
1100         break;
1101       }
1102       case ftUnionKey: {
1103         // There is no native "UnionKey", natively, unions are rust enums with
1104         // newtype-struct-variants.
1105         return "INVALID_CODE_GENERATION";
1106       }
1107       case ftUnionValue: {
1108         ty = NamespacedNativeName(*type.enum_def);
1109         break;
1110       }
1111       case ftEnumKey: {
1112         ty = WrapInNameSpace(*type.enum_def);
1113         break;
1114       }
1115       // Vectors are in tables and are optional
1116       case ftVectorOfEnumKey: {
1117         ty = "Vec<" + WrapInNameSpace(*type.VectorType().enum_def) + ">";
1118         break;
1119       }
1120       case ftVectorOfInteger:
1121       case ftVectorOfBool:
1122       case ftVectorOfFloat: {
1123         ty = "Vec<" + GetTypeBasic(type.VectorType()) + ">";
1124         break;
1125       }
1126       case ftVectorOfString: {
1127         ty = "Vec<String>";
1128         break;
1129       }
1130       case ftVectorOfTable:
1131       case ftVectorOfStruct: {
1132         ty = NamespacedNativeName(*type.VectorType().struct_def);
1133         ty = "Vec<" + ty + ">";
1134         break;
1135       }
1136       case ftVectorOfUnionValue: {
1137         FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1138         return "INVALID_CODE_GENERATION";  // OH NO!
1139       }
1140       case ftArrayOfEnum: {
1141         ty = "[" + WrapInNameSpace(*type.VectorType().enum_def) + "; " +
1142              NumToString(type.fixed_length) + "]";
1143         break;
1144       }
1145       case ftArrayOfStruct: {
1146         ty = "[" + NamespacedNativeName(*type.VectorType().struct_def) + "; " +
1147              NumToString(type.fixed_length) + "]";
1148         break;
1149       }
1150       case ftArrayOfBuiltin: {
1151         ty = "[" + GetTypeBasic(type.VectorType()) + "; " +
1152              NumToString(type.fixed_length) + "]";
1153         break;
1154       }
1155     }
1156     if (in_a_table && !IsUnion(type) && field.IsOptional()) {
1157       return "Option<" + ty + ">";
1158     } else {
1159       return ty;
1160     }
1161   }
1162 
TableBuilderArgsAddFuncType(const FieldDef & field,const std::string & lifetime)1163   std::string TableBuilderArgsAddFuncType(const FieldDef &field,
1164                                           const std::string &lifetime) {
1165     const Type &type = field.value.type;
1166 
1167     switch (GetFullType(field.value.type)) {
1168       case ftVectorOfStruct: {
1169         const auto typname = WrapInNameSpace(*type.struct_def);
1170         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1171                typname + ">>";
1172       }
1173       case ftVectorOfTable: {
1174         const auto typname = WrapInNameSpace(*type.struct_def);
1175         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1176                ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
1177                ">>>>";
1178       }
1179       case ftVectorOfInteger:
1180       case ftVectorOfBool:
1181       case ftVectorOfFloat: {
1182         const auto typname = GetTypeBasic(type.VectorType());
1183         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1184                typname + ">>";
1185       }
1186       case ftVectorOfString: {
1187         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1188                ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
1189       }
1190       case ftVectorOfEnumKey: {
1191         const auto typname = WrapInNameSpace(*type.enum_def);
1192         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1193                typname + ">>";
1194       }
1195       case ftVectorOfUnionValue: {
1196         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1197                ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + lifetime +
1198                ">>>";
1199       }
1200       case ftEnumKey:
1201       case ftUnionKey: {
1202         const auto typname = WrapInNameSpace(*type.enum_def);
1203         return typname;
1204       }
1205       case ftStruct: {
1206         const auto typname = WrapInNameSpace(*type.struct_def);
1207         return "&" + typname + "";
1208       }
1209       case ftTable: {
1210         const auto typname = WrapInNameSpace(*type.struct_def);
1211         return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
1212       }
1213       case ftInteger:
1214       case ftBool:
1215       case ftFloat: {
1216         return GetTypeBasic(type);
1217       }
1218       case ftString: {
1219         return "flatbuffers::WIPOffset<&" + lifetime + " str>";
1220       }
1221       case ftUnionValue: {
1222         return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
1223       }
1224       case ftArrayOfBuiltin: {
1225         const auto typname = GetTypeBasic(type.VectorType());
1226         return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1227                NumToString(type.fixed_length) + ">";
1228       }
1229       case ftArrayOfEnum: {
1230         const auto typname = WrapInNameSpace(*type.enum_def);
1231         return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1232                NumToString(type.fixed_length) + ">";
1233       }
1234       case ftArrayOfStruct: {
1235         const auto typname = WrapInNameSpace(*type.struct_def);
1236         return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1237                NumToString(type.fixed_length) + ">";
1238       }
1239     }
1240 
1241     return "INVALID_CODE_GENERATION";  // for return analysis
1242   }
1243 
TableBuilderArgsAddFuncBody(const FieldDef & field)1244   std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
1245     const Type &type = field.value.type;
1246 
1247     switch (GetFullType(field.value.type)) {
1248       case ftInteger:
1249       case ftBool:
1250       case ftFloat: {
1251         const auto typname = GetTypeBasic(field.value.type);
1252         return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
1253                                    : "self.fbb_.push_slot::<") +
1254                typname + ">";
1255       }
1256       case ftEnumKey:
1257       case ftUnionKey: {
1258         const auto underlying_typname = GetTypeBasic(type);
1259         return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
1260                                    : "self.fbb_.push_slot::<") +
1261                underlying_typname + ">";
1262       }
1263 
1264       case ftStruct: {
1265         const std::string typname = WrapInNameSpace(*type.struct_def);
1266         return "self.fbb_.push_slot_always::<&" + typname + ">";
1267       }
1268       case ftTable: {
1269         const auto typname = WrapInNameSpace(*type.struct_def);
1270         return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" +
1271                typname + ">>";
1272       }
1273 
1274       case ftUnionValue:
1275       case ftString:
1276       case ftVectorOfInteger:
1277       case ftVectorOfFloat:
1278       case ftVectorOfBool:
1279       case ftVectorOfEnumKey:
1280       case ftVectorOfStruct:
1281       case ftVectorOfTable:
1282       case ftVectorOfString:
1283       case ftVectorOfUnionValue: {
1284         return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
1285       }
1286       case ftArrayOfEnum:
1287       case ftArrayOfStruct:
1288       case ftArrayOfBuiltin: {
1289         FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1290         return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1291       }
1292     }
1293     return "INVALID_CODE_GENERATION";  // for return analysis
1294   }
1295 
GenTableAccessorFuncReturnType(const FieldDef & field,const std::string & lifetime)1296   std::string GenTableAccessorFuncReturnType(const FieldDef &field,
1297                                              const std::string &lifetime) {
1298     const Type &type = field.value.type;
1299     const auto WrapOption = [&](std::string s) {
1300       return field.IsOptional() ? "Option<" + s + ">" : s;
1301     };
1302 
1303     switch (GetFullType(field.value.type)) {
1304       case ftInteger:
1305       case ftFloat:
1306       case ftBool: {
1307         return WrapOption(GetTypeBasic(type));
1308       }
1309       case ftStruct: {
1310         const auto typname = WrapInNameSpace(*type.struct_def);
1311         return WrapOption("&" + lifetime + " " + typname);
1312       }
1313       case ftTable: {
1314         const auto typname = WrapInNameSpace(*type.struct_def);
1315         return WrapOption(typname + "<" + lifetime + ">");
1316       }
1317       case ftEnumKey:
1318       case ftUnionKey: {
1319         return WrapOption(WrapInNameSpace(*type.enum_def));
1320       }
1321 
1322       case ftUnionValue: {
1323         return WrapOption("flatbuffers::Table<" + lifetime + ">");
1324       }
1325       case ftString: {
1326         return WrapOption("&" + lifetime + " str");
1327       }
1328       case ftVectorOfInteger:
1329       case ftVectorOfBool:
1330       case ftVectorOfFloat: {
1331         const auto typname = GetTypeBasic(type.VectorType());
1332         const auto vector_type =
1333             IsOneByte(type.VectorType().base_type)
1334                 ? "&" + lifetime + " [" + typname + "]"
1335                 : "flatbuffers::Vector<" + lifetime + ", " + typname + ">";
1336         return WrapOption(vector_type);
1337       }
1338       case ftVectorOfEnumKey: {
1339         const auto typname = WrapInNameSpace(*type.enum_def);
1340         return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname +
1341                           ">");
1342       }
1343       case ftVectorOfStruct: {
1344         const auto typname = WrapInNameSpace(*type.struct_def);
1345         return WrapOption("&" + lifetime + " [" + typname + "]");
1346       }
1347       case ftVectorOfTable: {
1348         const auto typname = WrapInNameSpace(*type.struct_def);
1349         return WrapOption("flatbuffers::Vector<" + lifetime +
1350                           ", flatbuffers::ForwardsUOffset<" + typname + "<" +
1351                           lifetime + ">>>");
1352       }
1353       case ftVectorOfString: {
1354         return WrapOption("flatbuffers::Vector<" + lifetime +
1355                           ", flatbuffers::ForwardsUOffset<&" + lifetime +
1356                           " str>>");
1357       }
1358       case ftVectorOfUnionValue: {
1359         FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1360         // TODO(rw): when we do support these, we should consider using the
1361         //           Into trait to convert tables to typesafe union values.
1362         return "INVALID_CODE_GENERATION";  // for return analysis
1363       }
1364       case ftArrayOfEnum:
1365       case ftArrayOfStruct:
1366       case ftArrayOfBuiltin: {
1367         FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1368         return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1369       }
1370     }
1371     return "INVALID_CODE_GENERATION";  // for return analysis
1372   }
1373 
FollowType(const Type & type,const std::string & lifetime)1374   std::string FollowType(const Type &type, const std::string &lifetime) {
1375     // IsVector... This can be made iterative?
1376 
1377     const auto WrapForwardsUOffset = [](std::string ty) -> std::string {
1378       return "flatbuffers::ForwardsUOffset<" + ty + ">";
1379     };
1380     const auto WrapVector = [&](std::string ty) -> std::string {
1381       return "flatbuffers::Vector<" + lifetime + ", " + ty + ">";
1382     };
1383     const auto WrapArray = [&](std::string ty, uint16_t length) -> std::string {
1384       return "flatbuffers::Array<" + lifetime + ", " + ty + ", " +
1385              NumToString(length) + ">";
1386     };
1387     switch (GetFullType(type)) {
1388       case ftInteger:
1389       case ftFloat:
1390       case ftBool: {
1391         return GetTypeBasic(type);
1392       }
1393       case ftStruct: {
1394         return WrapInNameSpace(*type.struct_def);
1395       }
1396       case ftUnionKey:
1397       case ftEnumKey: {
1398         return WrapInNameSpace(*type.enum_def);
1399       }
1400       case ftTable: {
1401         const auto typname = WrapInNameSpace(*type.struct_def);
1402         return WrapForwardsUOffset(typname);
1403       }
1404       case ftUnionValue: {
1405         return WrapForwardsUOffset("flatbuffers::Table<" + lifetime + ">");
1406       }
1407       case ftString: {
1408         return WrapForwardsUOffset("&str");
1409       }
1410       case ftVectorOfInteger:
1411       case ftVectorOfBool:
1412       case ftVectorOfFloat: {
1413         const auto typname = GetTypeBasic(type.VectorType());
1414         return WrapForwardsUOffset(WrapVector(typname));
1415       }
1416       case ftVectorOfEnumKey: {
1417         const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
1418         return WrapForwardsUOffset(WrapVector(typname));
1419       }
1420       case ftVectorOfStruct: {
1421         const auto typname = WrapInNameSpace(*type.struct_def);
1422         return WrapForwardsUOffset(WrapVector(typname));
1423       }
1424       case ftVectorOfTable: {
1425         const auto typname = WrapInNameSpace(*type.struct_def);
1426         return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(typname)));
1427       }
1428       case ftVectorOfString: {
1429         return WrapForwardsUOffset(
1430             WrapVector(WrapForwardsUOffset("&" + lifetime + " str")));
1431       }
1432       case ftVectorOfUnionValue: {
1433         FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1434         return "INVALID_CODE_GENERATION";  // for return analysis
1435       }
1436       case ftArrayOfEnum: {
1437         const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
1438         return WrapArray(typname, type.fixed_length);
1439       }
1440       case ftArrayOfStruct: {
1441         const auto typname = WrapInNameSpace(*type.struct_def);
1442         return WrapArray(typname, type.fixed_length);
1443       }
1444       case ftArrayOfBuiltin: {
1445         const auto typname = GetTypeBasic(type.VectorType());
1446         return WrapArray(typname, type.fixed_length);
1447       }
1448     }
1449     return "INVALID_CODE_GENERATION";  // for return analysis
1450   }
1451 
GenTableAccessorFuncBody(const FieldDef & field,const std::string & lifetime)1452   std::string GenTableAccessorFuncBody(const FieldDef &field,
1453                                        const std::string &lifetime) {
1454     const std::string vt_offset = GetFieldOffsetName(field);
1455     const std::string typname = FollowType(field.value.type, lifetime);
1456     // Default-y fields (scalars so far) are neither optional nor required.
1457     const std::string default_value =
1458         !(field.IsOptional() || field.IsRequired())
1459             ? "Some(" + GetDefaultValue(field, kAccessor) + ")"
1460             : "None";
1461     const std::string unwrap = field.IsOptional() ? "" : ".unwrap()";
1462 
1463     const auto t = GetFullType(field.value.type);
1464 
1465     // TODO(caspern): Shouldn't 1byte VectorOfEnumKey be slice too?
1466     const std::string safe_slice =
1467         (t == ftVectorOfStruct ||
1468          ((t == ftVectorOfBool || t == ftVectorOfFloat ||
1469            t == ftVectorOfInteger) &&
1470           IsOneByte(field.value.type.VectorType().base_type)))
1471             ? ".map(|v| v.safe_slice())"
1472             : "";
1473 
1474     return "self._tab.get::<" + typname + ">({{STRUCT_NAME}}::" + vt_offset +
1475            ", " + default_value + ")" + safe_slice + unwrap;
1476   }
1477 
1478   // Generates a fully-qualified name getter for use with --gen-name-strings
GenFullyQualifiedNameGetter(const StructDef & struct_def,const std::string & name)1479   void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1480                                    const std::string &name) {
1481     code_ += "    pub const fn get_fully_qualified_name() -> &'static str {";
1482     code_ += "        \"" +
1483              struct_def.defined_namespace->GetFullyQualifiedName(name) + "\"";
1484     code_ += "    }";
1485     code_ += "";
1486   }
1487 
ForAllUnionVariantsBesidesNone(const EnumDef & def,std::function<void (const EnumVal & ev)> cb)1488   void ForAllUnionVariantsBesidesNone(
1489       const EnumDef &def, std::function<void(const EnumVal &ev)> cb) {
1490     FLATBUFFERS_ASSERT(def.is_union);
1491 
1492     for (auto it = def.Vals().begin(); it != def.Vals().end(); ++it) {
1493       const EnumVal &ev = **it;
1494       // TODO(cneo): Can variants be deprecated, should we skip them?
1495       if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1496       code_.SetValue(
1497           "U_ELEMENT_ENUM_TYPE",
1498           WrapInNameSpace(def.defined_namespace, GetEnumValue(def, ev)));
1499       code_.SetValue(
1500           "U_ELEMENT_TABLE_TYPE",
1501           WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
1502                           ev.union_type.struct_def->name));
1503       code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
1504       cb(ev);
1505     }
1506   }
1507 
ForAllTableFields(const StructDef & struct_def,std::function<void (const FieldDef &)> cb,bool reversed=false)1508   void ForAllTableFields(const StructDef &struct_def,
1509                          std::function<void(const FieldDef &)> cb,
1510                          bool reversed = false) {
1511     // TODO(cneo): Remove `reversed` overload. It's only here to minimize the
1512     // diff when refactoring to the `ForAllX` helper functions.
1513     auto go = [&](const FieldDef &field) {
1514       if (field.deprecated) return;
1515       code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1516       code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
1517       code_.SetValue("FIELD_NAME", Name(field));
1518       code_.SetValue("BLDR_DEF_VAL", GetDefaultValue(field, kBuilder));
1519       cb(field);
1520     };
1521     const auto &fields = struct_def.fields.vec;
1522     if (reversed) {
1523       for (auto it = fields.rbegin(); it != fields.rend(); ++it) go(**it);
1524     } else {
1525       for (auto it = fields.begin(); it != fields.end(); ++it) go(**it);
1526     }
1527   }
1528   // Generate an accessor struct, builder struct, and create function for a
1529   // table.
GenTable(const StructDef & struct_def)1530   void GenTable(const StructDef &struct_def) {
1531     code_.SetValue("STRUCT_NAME", Name(struct_def));
1532     code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1533     code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
1534 
1535     // Generate an offset type, the base type, the Follow impl, and the
1536     // init_from_table impl.
1537     code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
1538     code_ += "#[derive(Copy, Clone, PartialEq)]";
1539     code_ += "";
1540 
1541     GenComment(struct_def.doc_comment);
1542 
1543     code_ += "pub struct {{STRUCT_NAME}}<'a> {";
1544     code_ += "  pub _tab: flatbuffers::Table<'a>,";
1545     code_ += "}";
1546     code_ += "";
1547     code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
1548     code_ += "    type Inner = {{STRUCT_NAME}}<'a>;";
1549     code_ += "    #[inline]";
1550     code_ += "    fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1551     code_ += "        Self { _tab: flatbuffers::Table { buf, loc } }";
1552     code_ += "    }";
1553     code_ += "}";
1554     code_ += "";
1555     code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
1556 
1557     if (parser_.opts.generate_name_strings) {
1558       GenFullyQualifiedNameGetter(struct_def, struct_def.name);
1559     }
1560 
1561     code_ += "    #[inline]";
1562     code_ +=
1563         "    pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
1564         "Self {";
1565     code_ += "        {{STRUCT_NAME}} { _tab: table }";
1566     code_ += "    }";
1567 
1568     // Generate a convenient create* function that uses the above builder
1569     // to create a table in one function call.
1570     code_.SetValue("MAYBE_US", struct_def.fields.vec.size() == 0 ? "_" : "");
1571     code_.SetValue("MAYBE_LT",
1572                    TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
1573     code_ += "    #[allow(unused_mut)]";
1574     code_ += "    pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
1575     code_ +=
1576         "        _fbb: "
1577         "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1578     code_ +=
1579         "        {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
1580         " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
1581 
1582     code_ += "      let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
1583     for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1584          size; size /= 2) {
1585       ForAllTableFields(
1586           struct_def,
1587           [&](const FieldDef &field) {
1588             if (struct_def.sortbysize &&
1589                 size != SizeOf(field.value.type.base_type))
1590               return;
1591             if (IsOptionalToBuilder(field)) {
1592               code_ +=
1593                   "      if let Some(x) = args.{{FIELD_NAME}} "
1594                   "{ builder.add_{{FIELD_NAME}}(x); }";
1595             } else {
1596               code_ += "      builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
1597             }
1598           },
1599           /*reverse=*/true);
1600     }
1601     code_ += "      builder.finish()";
1602     code_ += "    }";
1603     code_ += "";
1604     // Generate Object API Packer function.
1605     if (parser_.opts.generate_object_based_api) {
1606       // TODO(cneo): Replace more for loops with ForAllX stuff.
1607       // TODO(cneo): Manage indentation with IncrementIdentLevel?
1608       code_.SetValue("OBJECT_NAME", NativeName(struct_def));
1609       code_ += "    pub fn unpack(&self) -> {{OBJECT_NAME}} {";
1610       ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
1611         const Type &type = field.value.type;
1612         switch (GetFullType(type)) {
1613           case ftInteger:
1614           case ftBool:
1615           case ftFloat:
1616           case ftEnumKey: {
1617             code_ += "      let {{FIELD_NAME}} = self.{{FIELD_NAME}}();";
1618             return;
1619           }
1620           case ftUnionKey: return;
1621           case ftUnionValue: {
1622             const auto &enum_def = *type.enum_def;
1623             code_.SetValue("ENUM_NAME", WrapInNameSpace(enum_def));
1624             code_.SetValue("NATIVE_ENUM_NAME", NamespacedNativeName(enum_def));
1625             code_ +=
1626                 "      let {{FIELD_NAME}} = match "
1627                 "self.{{FIELD_NAME}}_type() {";
1628             code_ +=
1629                 "        {{ENUM_NAME}}::NONE =>"
1630                 " {{NATIVE_ENUM_NAME}}::NONE,";
1631             ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
1632               code_ +=
1633                   "        {{ENUM_NAME}}::{{VARIANT_NAME}} => "
1634                   "{{NATIVE_ENUM_NAME}}::{{NATIVE_VARIANT}}(Box::new(";
1635               code_ +=
1636                   "          self.{{FIELD_NAME}}_as_"
1637                   "{{U_ELEMENT_NAME}}()";
1638               code_ +=
1639                   "              .expect(\"Invalid union table, "
1640                   "expected `{{ENUM_NAME}}::{{VARIANT_NAME}}`.\")";
1641               code_ += "              .unpack()";
1642               code_ += "        )),";
1643             });
1644             // Maybe we shouldn't throw away unknown discriminants?
1645             code_ += "        _ => {{NATIVE_ENUM_NAME}}::NONE,";
1646             code_ += "      };";
1647             return;
1648           }
1649           // The rest of the types need special handling based on if the field
1650           // is optional or not.
1651           case ftString: {
1652             code_.SetValue("EXPR", "x.to_string()");
1653             break;
1654           }
1655           case ftStruct: {
1656             code_.SetValue("EXPR", "x.unpack()");
1657             break;
1658           }
1659           case ftTable: {
1660             code_.SetValue("EXPR", "Box::new(x.unpack())");
1661             break;
1662           }
1663           case ftVectorOfInteger:
1664           case ftVectorOfBool: {
1665             if (IsOneByte(type.VectorType().base_type)) {
1666               // 1 byte stuff is viewed w/ slice instead of flatbuffer::Vector
1667               // and thus needs to be cloned out of the slice.
1668               code_.SetValue("EXPR", "x.to_vec()");
1669               break;
1670             }
1671             code_.SetValue("EXPR", "x.into_iter().collect()");
1672             break;
1673           }
1674           case ftVectorOfFloat:
1675           case ftVectorOfEnumKey: {
1676             code_.SetValue("EXPR", "x.into_iter().collect()");
1677             break;
1678           }
1679           case ftVectorOfString: {
1680             code_.SetValue("EXPR", "x.iter().map(|s| s.to_string()).collect()");
1681             break;
1682           }
1683           case ftVectorOfStruct:
1684           case ftVectorOfTable: {
1685             code_.SetValue("EXPR", "x.iter().map(|t| t.unpack()).collect()");
1686             break;
1687           }
1688           case ftVectorOfUnionValue: {
1689             FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
1690             return;
1691           }
1692           case ftArrayOfEnum:
1693           case ftArrayOfStruct:
1694           case ftArrayOfBuiltin: {
1695             FLATBUFFERS_ASSERT(false &&
1696                                "arrays are not supported within tables");
1697             return;
1698           }
1699         }
1700         if (field.IsOptional()) {
1701           code_ += "      let {{FIELD_NAME}} = self.{{FIELD_NAME}}().map(|x| {";
1702           code_ += "        {{EXPR}}";
1703           code_ += "      });";
1704         } else {
1705           code_ += "      let {{FIELD_NAME}} = {";
1706           code_ += "        let x = self.{{FIELD_NAME}}();";
1707           code_ += "        {{EXPR}}";
1708           code_ += "      };";
1709         }
1710       });
1711       code_ += "      {{OBJECT_NAME}} {";
1712       ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
1713         if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
1714         code_ += "        {{FIELD_NAME}},";
1715       });
1716       code_ += "      }";
1717       code_ += "    }";
1718     }
1719 
1720     // Generate field id constants.
1721     ForAllTableFields(struct_def, [&](const FieldDef &unused) {
1722       (void)unused;
1723       code_ +=
1724           "    pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1725           "{{OFFSET_VALUE}};";
1726     });
1727     if (struct_def.fields.vec.size() > 0) code_ += "";
1728 
1729     // Generate the accessors. Each has one of two forms:
1730     //
1731     // If a value can be None:
1732     //   pub fn name(&'a self) -> Option<user_facing_type> {
1733     //     self._tab.get::<internal_type>(offset, defaultval)
1734     //   }
1735     //
1736     // If a value is always Some:
1737     //   pub fn name(&'a self) -> user_facing_type {
1738     //     self._tab.get::<internal_type>(offset, defaultval).unwrap()
1739     //   }
1740     ForAllTableFields(struct_def, [&](const FieldDef &field) {
1741       code_.SetValue("RETURN_TYPE",
1742                      GenTableAccessorFuncReturnType(field, "'a"));
1743 
1744       this->GenComment(field.doc_comment, "  ");
1745       code_ += "  #[inline]";
1746       code_ += "  pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
1747       code_ += "    " + GenTableAccessorFuncBody(field, "'a");
1748       code_ += "  }";
1749 
1750       // Generate a comparison function for this field if it is a key.
1751       if (field.key) { GenKeyFieldMethods(field); }
1752 
1753       // Generate a nested flatbuffer field, if applicable.
1754       auto nested = field.attributes.Lookup("nested_flatbuffer");
1755       if (nested) {
1756         std::string qualified_name = nested->constant;
1757         auto nested_root = parser_.LookupStruct(nested->constant);
1758         if (nested_root == nullptr) {
1759           qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1760               nested->constant);
1761           nested_root = parser_.LookupStruct(qualified_name);
1762         }
1763         FLATBUFFERS_ASSERT(nested_root);  // Guaranteed to exist by parser.
1764 
1765         code_.SetValue("NESTED", WrapInNameSpace(*nested_root));
1766         code_ += "  pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> \\";
1767         if (field.IsRequired()) {
1768           code_ += "{{NESTED}}<'a> {";
1769           code_ += "    let data = self.{{FIELD_NAME}}();";
1770           code_ += "    use flatbuffers::Follow;";
1771           code_ +=
1772               "    <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1773               "::follow(data, 0)";
1774         } else {
1775           code_ += "Option<{{NESTED}}<'a>> {";
1776           code_ += "    self.{{FIELD_NAME}}().map(|data| {";
1777           code_ += "      use flatbuffers::Follow;";
1778           code_ +=
1779               "      <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1780               "::follow(data, 0)";
1781           code_ += "    })";
1782         }
1783         code_ += "  }";
1784       }
1785     });
1786 
1787     // Explicit specializations for union accessors
1788     ForAllTableFields(struct_def, [&](const FieldDef &field) {
1789       if (field.value.type.base_type != BASE_TYPE_UNION) return;
1790       code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
1791       ForAllUnionVariantsBesidesNone(
1792           *field.value.type.enum_def, [&](const EnumVal &unused) {
1793             (void)unused;
1794             code_ += "  #[inline]";
1795             code_ += "  #[allow(non_snake_case)]";
1796             code_ +=
1797                 "  pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
1798                 "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
1799             // If the user defined schemas name a field that clashes with a
1800             // language reserved word, flatc will try to escape the field name
1801             // by appending an underscore. This works well for most cases,
1802             // except one. When generating union accessors (and referring to
1803             // them internally within the code generated here), an extra
1804             // underscore will be appended to the name, causing build failures.
1805             //
1806             // This only happens when unions have members that overlap with
1807             // language reserved words.
1808             //
1809             // To avoid this problem the type field name is used unescaped here:
1810             code_ +=
1811                 "    if self.{{FIELD_TYPE_FIELD_NAME}}_type() == "
1812                 "{{U_ELEMENT_ENUM_TYPE}} {";
1813 
1814             // The following logic is not tested in the integration test,
1815             // as of April 10, 2020
1816             if (field.IsRequired()) {
1817               code_ += "      let u = self.{{FIELD_NAME}}();";
1818               code_ +=
1819                   "      Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
1820             } else {
1821               code_ +=
1822                   "      self.{{FIELD_NAME}}().map("
1823                   "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)";
1824             }
1825             code_ += "    } else {";
1826             code_ += "      None";
1827             code_ += "    }";
1828             code_ += "  }";
1829             code_ += "";
1830           });
1831     });
1832     code_ += "}";  // End of table impl.
1833     code_ += "";
1834 
1835     // Generate Verifier;
1836     code_ += "impl flatbuffers::Verifiable for {{STRUCT_NAME}}<'_> {";
1837     code_ += "  #[inline]";
1838     code_ += "  fn run_verifier(";
1839     code_ += "    v: &mut flatbuffers::Verifier, pos: usize";
1840     code_ += "  ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
1841     code_ += "    use self::flatbuffers::Verifiable;";
1842     code_ += "    v.visit_table(pos)?\\";
1843     // Escape newline and insert it onthe next line so we can end the builder
1844     // with a nice semicolon.
1845     ForAllTableFields(struct_def, [&](const FieldDef &field) {
1846       if (GetFullType(field.value.type) == ftUnionKey) return;
1847 
1848       code_.SetValue("IS_REQ", field.IsRequired() ? "true" : "false");
1849       if (GetFullType(field.value.type) != ftUnionValue) {
1850         // All types besides unions.
1851         code_.SetValue("TY", FollowType(field.value.type, "'_"));
1852         code_ +=
1853             "\n     .visit_field::<{{TY}}>(&\"{{FIELD_NAME}}\", "
1854             "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\";
1855         return;
1856       }
1857       // Unions.
1858       EnumDef &union_def = *field.value.type.enum_def;
1859       code_.SetValue("UNION_TYPE", WrapInNameSpace(union_def));
1860       code_ +=
1861           "\n     .visit_union::<{{UNION_TYPE}}, _>("
1862           "&\"{{FIELD_NAME}}_type\", Self::{{OFFSET_NAME}}_TYPE, "
1863           "&\"{{FIELD_NAME}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, "
1864           "|key, v, pos| {";
1865       code_ += "        match key {";
1866       ForAllUnionVariantsBesidesNone(union_def, [&](const EnumVal &unused) {
1867         (void)unused;
1868         code_ +=
1869             "          {{U_ELEMENT_ENUM_TYPE}} => v.verify_union_variant::"
1870             "<flatbuffers::ForwardsUOffset<{{U_ELEMENT_TABLE_TYPE}}>>("
1871             "\"{{U_ELEMENT_ENUM_TYPE}}\", pos),";
1872       });
1873       code_ += "          _ => Ok(()),";
1874       code_ += "        }";
1875       code_ += "     })?\\";
1876     });
1877     code_ += "\n     .finish();";
1878     code_ += "    Ok(())";
1879     code_ += "  }";
1880     code_ += "}";
1881 
1882     // Generate an args struct:
1883     code_.SetValue("MAYBE_LT",
1884                    TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
1885     code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1886     ForAllTableFields(struct_def, [&](const FieldDef &field) {
1887       code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
1888       code_ += "    pub {{FIELD_NAME}}: {{PARAM_TYPE}},";
1889     });
1890     code_ += "}";
1891 
1892     // Generate an impl of Default for the *Args type:
1893     code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1894     code_ += "    #[inline]";
1895     code_ += "    fn default() -> Self {";
1896     code_ += "        {{STRUCT_NAME}}Args {";
1897     ForAllTableFields(struct_def, [&](const FieldDef &field) {
1898       code_ += "            {{FIELD_NAME}}: {{BLDR_DEF_VAL}},\\";
1899       code_ += field.IsRequired() ? " // required field" : "";
1900     });
1901     code_ += "        }";
1902     code_ += "    }";
1903     code_ += "}";
1904 
1905     // Generate a builder struct:
1906     code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
1907     code_ += "  fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1908     code_ +=
1909         "  start_: flatbuffers::WIPOffset<"
1910         "flatbuffers::TableUnfinishedWIPOffset>,";
1911     code_ += "}";
1912 
1913     // Generate builder functions:
1914     code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
1915     ForAllTableFields(struct_def, [&](const FieldDef &field) {
1916       const bool is_scalar = IsScalar(field.value.type.base_type);
1917       std::string offset = GetFieldOffsetName(field);
1918       // Generate functions to add data, which take one of two forms.
1919       //
1920       // If a value has a default:
1921       //   fn add_x(x_: type) {
1922       //     fbb_.push_slot::<type>(offset, x_, Some(default));
1923       //   }
1924       //
1925       // If a value does not have a default:
1926       //   fn add_x(x_: type) {
1927       //     fbb_.push_slot_always::<type>(offset, x_);
1928       //   }
1929       code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
1930       code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
1931       code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
1932       code_ += "  #[inline]";
1933       code_ +=
1934           "  pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
1935           "{{FIELD_TYPE}}) {";
1936       if (is_scalar && !field.IsOptional()) {
1937         code_ +=
1938             "    {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
1939             "{{BLDR_DEF_VAL}});";
1940       } else {
1941         code_ += "    {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
1942       }
1943       code_ += "  }";
1944     });
1945 
1946     // Struct initializer (all fields required);
1947     code_ += "  #[inline]";
1948     code_ +=
1949         "  pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
1950         "{{STRUCT_NAME}}Builder<'a, 'b> {";
1951     code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
1952     code_ += "    let start = _fbb.start_table();";
1953     code_ += "    {{STRUCT_NAME}}Builder {";
1954     code_ += "      fbb_: _fbb,";
1955     code_ += "      start_: start,";
1956     code_ += "    }";
1957     code_ += "  }";
1958 
1959     // finish() function.
1960     code_ += "  #[inline]";
1961     code_ +=
1962         "  pub fn finish(self) -> "
1963         "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
1964     code_ += "    let o = self.fbb_.end_table(self.start_);";
1965 
1966     ForAllTableFields(struct_def, [&](const FieldDef &field) {
1967       if (!field.IsRequired()) return;
1968       code_ +=
1969           "    self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
1970           "\"{{FIELD_NAME}}\");";
1971     });
1972     code_ += "    flatbuffers::WIPOffset::new(o.value())";
1973     code_ += "  }";
1974     code_ += "}";
1975     code_ += "";
1976 
1977     code_ += "impl std::fmt::Debug for {{STRUCT_NAME}}<'_> {";
1978     code_ +=
1979         "  fn fmt(&self, f: &mut std::fmt::Formatter<'_>"
1980         ") -> std::fmt::Result {";
1981     code_ += "    let mut ds = f.debug_struct(\"{{STRUCT_NAME}}\");";
1982     ForAllTableFields(struct_def, [&](const FieldDef &field) {
1983       if (GetFullType(field.value.type) == ftUnionValue) {
1984         // Generate a match statement to handle unions properly.
1985         code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
1986         code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
1987         code_.SetValue("UNION_ERR",
1988                        "&\"InvalidFlatbuffer: Union discriminant"
1989                        " does not match value.\"");
1990 
1991         code_ += "      match self.{{FIELD_NAME}}_type() {";
1992         ForAllUnionVariantsBesidesNone(
1993             *field.value.type.enum_def, [&](const EnumVal &unused) {
1994               (void)unused;
1995               code_ += "        {{U_ELEMENT_ENUM_TYPE}} => {";
1996               code_ +=
1997                   "          if let Some(x) = "
1998                   "self.{{FIELD_TYPE_FIELD_NAME}}_as_"
1999                   "{{U_ELEMENT_NAME}}() {";
2000               code_ += "            ds.field(\"{{FIELD_NAME}}\", &x)";
2001               code_ += "          } else {";
2002               code_ +=
2003                   "            ds.field(\"{{FIELD_NAME}}\", {{UNION_ERR}})";
2004               code_ += "          }";
2005               code_ += "        },";
2006             });
2007         code_ += "        _ => {";
2008         code_ += "          let x: Option<()> = None;";
2009         code_ += "          ds.field(\"{{FIELD_NAME}}\", &x)";
2010         code_ += "        },";
2011         code_ += "      };";
2012       } else {
2013         // Most fields.
2014         code_ += "      ds.field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}());";
2015       }
2016     });
2017     code_ += "      ds.finish()";
2018     code_ += "  }";
2019     code_ += "}";
2020   }
2021 
GenTableObject(const StructDef & table)2022   void GenTableObject(const StructDef &table) {
2023     code_.SetValue("OBJECT_NAME", NativeName(table));
2024     code_.SetValue("STRUCT_NAME", Name(table));
2025 
2026     // Generate the native object.
2027     code_ += "#[non_exhaustive]";
2028     code_ += "#[derive(Debug, Clone, PartialEq)]";
2029     code_ += "pub struct {{OBJECT_NAME}} {";
2030     ForAllObjectTableFields(table, [&](const FieldDef &field) {
2031       // Union objects combine both the union discriminant and value, so we
2032       // skip making a field for the discriminant.
2033       if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
2034       code_ += "  pub {{FIELD_NAME}}: {{FIELD_OBJECT_TYPE}},";
2035     });
2036     code_ += "}";
2037 
2038     code_ += "impl Default for {{OBJECT_NAME}} {";
2039     code_ += "  fn default() -> Self {";
2040     code_ += "    Self {";
2041     ForAllObjectTableFields(table, [&](const FieldDef &field) {
2042       if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
2043       std::string default_value = GetDefaultValue(field, kObject);
2044       code_ += "      {{FIELD_NAME}}: " + default_value + ",";
2045     });
2046     code_ += "    }";
2047     code_ += "  }";
2048     code_ += "}";
2049 
2050     // TODO(cneo): Generate defaults for Native tables. However, since structs
2051     // may be required, they, and therefore enums need defaults.
2052 
2053     // Generate pack function.
2054     code_ += "impl {{OBJECT_NAME}} {";
2055     code_ += "  pub fn pack<'b>(";
2056     code_ += "    &self,";
2057     code_ += "    _fbb: &mut flatbuffers::FlatBufferBuilder<'b>";
2058     code_ += "  ) -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'b>> {";
2059     // First we generate variables for each field and then later assemble them
2060     // using "StructArgs" to more easily manage ownership of the builder.
2061     ForAllObjectTableFields(table, [&](const FieldDef &field) {
2062       const Type &type = field.value.type;
2063       switch (GetFullType(type)) {
2064         case ftInteger:
2065         case ftBool:
2066         case ftFloat:
2067         case ftEnumKey: {
2068           code_ += "    let {{FIELD_NAME}} = self.{{FIELD_NAME}};";
2069           return;
2070         }
2071         case ftUnionKey: return;  // Generate union type with union value.
2072         case ftUnionValue: {
2073           code_.SetValue("SNAKE_CASE_ENUM_NAME",
2074                          MakeSnakeCase(Name(*field.value.type.enum_def)));
2075           code_ +=
2076               "    let {{FIELD_NAME}}_type = "
2077               "self.{{FIELD_NAME}}.{{SNAKE_CASE_ENUM_NAME}}_type();";
2078           code_ += "    let {{FIELD_NAME}} = self.{{FIELD_NAME}}.pack(_fbb);";
2079           return;
2080         }
2081         // The rest of the types require special casing around optionalness
2082         // due to "required" annotation.
2083         case ftString: {
2084           MapNativeTableField(field, "_fbb.create_string(x)");
2085           return;
2086         }
2087         case ftStruct: {
2088           // Hold the struct in a variable so we can reference it.
2089           if (field.IsRequired()) {
2090             code_ +=
2091                 "    let {{FIELD_NAME}}_tmp = "
2092                 "Some(self.{{FIELD_NAME}}.pack());";
2093           } else {
2094             code_ +=
2095                 "    let {{FIELD_NAME}}_tmp = self.{{FIELD_NAME}}"
2096                 ".as_ref().map(|x| x.pack());";
2097           }
2098           code_ += "    let {{FIELD_NAME}} = {{FIELD_NAME}}_tmp.as_ref();";
2099 
2100           return;
2101         }
2102         case ftTable: {
2103           MapNativeTableField(field, "x.pack(_fbb)");
2104           return;
2105         }
2106         case ftVectorOfEnumKey:
2107         case ftVectorOfInteger:
2108         case ftVectorOfBool:
2109         case ftVectorOfFloat: {
2110           MapNativeTableField(field, "_fbb.create_vector(x)");
2111           return;
2112         }
2113         case ftVectorOfStruct: {
2114           MapNativeTableField(
2115               field,
2116               "let w: Vec<_> = x.iter().map(|t| t.pack()).collect();"
2117               "_fbb.create_vector(&w)");
2118           return;
2119         }
2120         case ftVectorOfString: {
2121           // TODO(cneo): create_vector* should be more generic to avoid
2122           // allocations.
2123 
2124           MapNativeTableField(
2125               field,
2126               "let w: Vec<_> = x.iter().map(|s| s.as_ref()).collect();"
2127               "_fbb.create_vector_of_strings(&w)");
2128           return;
2129         }
2130         case ftVectorOfTable: {
2131           MapNativeTableField(
2132               field,
2133               "let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();"
2134               "_fbb.create_vector(&w)");
2135           return;
2136         }
2137         case ftVectorOfUnionValue: {
2138           FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
2139           return;
2140         }
2141         case ftArrayOfEnum:
2142         case ftArrayOfStruct:
2143         case ftArrayOfBuiltin: {
2144           FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
2145           return;
2146         }
2147       }
2148     });
2149     code_ += "    {{STRUCT_NAME}}::create(_fbb, &{{STRUCT_NAME}}Args{";
2150     ForAllObjectTableFields(table, [&](const FieldDef &field) {
2151       (void)field;  // Unused.
2152       code_ += "      {{FIELD_NAME}},";
2153     });
2154     code_ += "    })";
2155     code_ += "  }";
2156     code_ += "}";
2157   }
ForAllObjectTableFields(const StructDef & table,std::function<void (const FieldDef &)> cb)2158   void ForAllObjectTableFields(const StructDef &table,
2159                                std::function<void(const FieldDef &)> cb) {
2160     const std::vector<FieldDef *> &v = table.fields.vec;
2161     for (auto it = v.begin(); it != v.end(); it++) {
2162       const FieldDef &field = **it;
2163       if (field.deprecated) continue;
2164       code_.SetValue("FIELD_NAME", Name(field));
2165       code_.SetValue("FIELD_OBJECT_TYPE", ObjectFieldType(field, true));
2166       cb(field);
2167     }
2168   }
MapNativeTableField(const FieldDef & field,const std::string & expr)2169   void MapNativeTableField(const FieldDef &field, const std::string &expr) {
2170     if (field.IsOptional()) {
2171       code_ += "    let {{FIELD_NAME}} = self.{{FIELD_NAME}}.as_ref().map(|x|{";
2172       code_ += "      " + expr;
2173       code_ += "    });";
2174     } else {
2175       // For some reason Args has optional types for required fields.
2176       // TODO(cneo): Fix this... but its a breaking change?
2177       code_ += "    let {{FIELD_NAME}} = Some({";
2178       code_ += "      let x = &self.{{FIELD_NAME}};";
2179       code_ += "      " + expr;
2180       code_ += "    });";
2181     }
2182   }
2183 
2184   // Generate functions to compare tables and structs by key. This function
2185   // must only be called if the field key is defined.
GenKeyFieldMethods(const FieldDef & field)2186   void GenKeyFieldMethods(const FieldDef &field) {
2187     FLATBUFFERS_ASSERT(field.key);
2188 
2189     code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
2190 
2191     code_ += "  #[inline]";
2192     code_ +=
2193         "  pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
2194         " bool {";
2195     code_ += "    self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
2196     code_ += "  }";
2197     code_ += "";
2198     code_ += "  #[inline]";
2199     code_ +=
2200         "  pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
2201         " ::std::cmp::Ordering {";
2202     code_ += "    let key = self.{{FIELD_NAME}}();";
2203     code_ += "    key.cmp(&val)";
2204     code_ += "  }";
2205   }
2206 
2207   // Generate functions for accessing the root table object. This function
2208   // must only be called if the root table is defined.
GenRootTableFuncs(const StructDef & struct_def)2209   void GenRootTableFuncs(const StructDef &struct_def) {
2210     FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
2211     auto name = Name(struct_def);
2212 
2213     code_.SetValue("STRUCT_NAME", name);
2214     code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
2215     code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
2216 
2217     // The root datatype accessors:
2218     code_ += "#[inline]";
2219     code_ +=
2220         "#[deprecated(since=\"2.0.0\", "
2221         "note=\"Deprecated in favor of `root_as...` methods.\")]";
2222     code_ +=
2223         "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
2224         " -> {{STRUCT_NAME}}<'a> {";
2225     code_ +=
2226         "  unsafe { flatbuffers::root_unchecked::<{{STRUCT_NAME}}"
2227         "<'a>>(buf) }";
2228     code_ += "}";
2229     code_ += "";
2230 
2231     code_ += "#[inline]";
2232     code_ +=
2233         "#[deprecated(since=\"2.0.0\", "
2234         "note=\"Deprecated in favor of `root_as...` methods.\")]";
2235     code_ +=
2236         "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
2237         "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
2238     code_ +=
2239         "  unsafe { flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}"
2240         "<'a>>(buf) }";
2241     code_ += "}";
2242     code_ += "";
2243     // Default verifier root fns.
2244     code_ += "#[inline]";
2245     code_ += "/// Verifies that a buffer of bytes contains a `{{STRUCT_NAME}}`";
2246     code_ += "/// and returns it.";
2247     code_ += "/// Note that verification is still experimental and may not";
2248     code_ += "/// catch every error, or be maximally performant. For the";
2249     code_ += "/// previous, unchecked, behavior use";
2250     code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
2251     code_ +=
2252         "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}(buf: &[u8]) "
2253         "-> Result<{{STRUCT_NAME}}, flatbuffers::InvalidFlatbuffer> {";
2254     code_ += "  flatbuffers::root::<{{STRUCT_NAME}}>(buf)";
2255     code_ += "}";
2256     code_ += "#[inline]";
2257     code_ += "/// Verifies that a buffer of bytes contains a size prefixed";
2258     code_ += "/// `{{STRUCT_NAME}}` and returns it.";
2259     code_ += "/// Note that verification is still experimental and may not";
2260     code_ += "/// catch every error, or be maximally performant. For the";
2261     code_ += "/// previous, unchecked, behavior use";
2262     code_ += "/// `size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
2263     code_ +=
2264         "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
2265         "(buf: &[u8]) -> Result<{{STRUCT_NAME}}, "
2266         "flatbuffers::InvalidFlatbuffer> {";
2267     code_ += "  flatbuffers::size_prefixed_root::<{{STRUCT_NAME}}>(buf)";
2268     code_ += "}";
2269     // Verifier with options root fns.
2270     code_ += "#[inline]";
2271     code_ += "/// Verifies, with the given options, that a buffer of bytes";
2272     code_ += "/// contains a `{{STRUCT_NAME}}` and returns it.";
2273     code_ += "/// Note that verification is still experimental and may not";
2274     code_ += "/// catch every error, or be maximally performant. For the";
2275     code_ += "/// previous, unchecked, behavior use";
2276     code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
2277     code_ += "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts<'b, 'o>(";
2278     code_ += "  opts: &'o flatbuffers::VerifierOptions,";
2279     code_ += "  buf: &'b [u8],";
2280     code_ +=
2281         ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>"
2282         " {";
2283     code_ += "  flatbuffers::root_with_opts::<{{STRUCT_NAME}}<'b>>(opts, buf)";
2284     code_ += "}";
2285     code_ += "#[inline]";
2286     code_ += "/// Verifies, with the given verifier options, that a buffer of";
2287     code_ += "/// bytes contains a size prefixed `{{STRUCT_NAME}}` and returns";
2288     code_ += "/// it. Note that verification is still experimental and may not";
2289     code_ += "/// catch every error, or be maximally performant. For the";
2290     code_ += "/// previous, unchecked, behavior use";
2291     code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
2292     code_ +=
2293         "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts"
2294         "<'b, 'o>(";
2295     code_ += "  opts: &'o flatbuffers::VerifierOptions,";
2296     code_ += "  buf: &'b [u8],";
2297     code_ +=
2298         ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>"
2299         " {";
2300     code_ +=
2301         "  flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_NAME}}"
2302         "<'b>>(opts, buf)";
2303     code_ += "}";
2304     // Unchecked root fns.
2305     code_ += "#[inline]";
2306     code_ +=
2307         "/// Assumes, without verification, that a buffer of bytes "
2308         "contains a {{STRUCT_NAME}} and returns it.";
2309     code_ += "/// # Safety";
2310     code_ +=
2311         "/// Callers must trust the given bytes do indeed contain a valid"
2312         " `{{STRUCT_NAME}}`.";
2313     code_ +=
2314         "pub unsafe fn root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked"
2315         "(buf: &[u8]) -> {{STRUCT_NAME}} {";
2316     code_ += "  flatbuffers::root_unchecked::<{{STRUCT_NAME}}>(buf)";
2317     code_ += "}";
2318     code_ += "#[inline]";
2319     code_ +=
2320         "/// Assumes, without verification, that a buffer of bytes "
2321         "contains a size prefixed {{STRUCT_NAME}} and returns it.";
2322     code_ += "/// # Safety";
2323     code_ +=
2324         "/// Callers must trust the given bytes do indeed contain a valid"
2325         " size prefixed `{{STRUCT_NAME}}`.";
2326     code_ +=
2327         "pub unsafe fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
2328         "_unchecked(buf: &[u8]) -> {{STRUCT_NAME}} {";
2329     code_ +=
2330         "  flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}>"
2331         "(buf)";
2332     code_ += "}";
2333 
2334     if (parser_.file_identifier_.length()) {
2335       // Declare the identifier
2336       // (no lifetime needed as constants have static lifetimes by default)
2337       code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &str\\";
2338       code_ += " = \"" + parser_.file_identifier_ + "\";";
2339       code_ += "";
2340 
2341       // Check if a buffer has the identifier.
2342       code_ += "#[inline]";
2343       code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
2344       code_ += "(buf: &[u8]) -> bool {";
2345       code_ += "  flatbuffers::buffer_has_identifier(buf, \\";
2346       code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false)";
2347       code_ += "}";
2348       code_ += "";
2349       code_ += "#[inline]";
2350       code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
2351       code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
2352       code_ += "  flatbuffers::buffer_has_identifier(buf, \\";
2353       code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true)";
2354       code_ += "}";
2355       code_ += "";
2356     }
2357 
2358     if (parser_.file_extension_.length()) {
2359       // Return the extension
2360       code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &str = \\";
2361       code_ += "\"" + parser_.file_extension_ + "\";";
2362       code_ += "";
2363     }
2364 
2365     // Finish a buffer with a given root object:
2366     code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
2367     code_ += "#[inline]";
2368     code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
2369     code_ += "    fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
2370     code_ += "    root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
2371     if (parser_.file_identifier_.length()) {
2372       code_ += "  fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
2373     } else {
2374       code_ += "  fbb.finish(root, None);";
2375     }
2376     code_ += "}";
2377     code_ += "";
2378     code_ += "#[inline]";
2379     code_ +=
2380         "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
2381         "<'a, 'b>("
2382         "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
2383         "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
2384     if (parser_.file_identifier_.length()) {
2385       code_ +=
2386           "  fbb.finish_size_prefixed(root, "
2387           "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
2388     } else {
2389       code_ += "  fbb.finish_size_prefixed(root, None);";
2390     }
2391     code_ += "}";
2392   }
2393 
GenPadding(const FieldDef & field,std::string * code_ptr,int * id,const std::function<void (int bits,std::string * code_ptr,int * id)> & f)2394   static void GenPadding(
2395       const FieldDef &field, std::string *code_ptr, int *id,
2396       const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
2397     if (field.padding) {
2398       for (int i = 0; i < 4; i++) {
2399         if (static_cast<int>(field.padding) & (1 << i)) {
2400           f((1 << i) * 8, code_ptr, id);
2401         }
2402       }
2403       assert(!(field.padding & ~0xF));
2404     }
2405   }
2406 
PaddingDefinition(int bits,std::string * code_ptr,int * id)2407   static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
2408     *code_ptr +=
2409         "  padding" + NumToString((*id)++) + "__: u" + NumToString(bits) + ",";
2410   }
2411 
PaddingInitializer(int bits,std::string * code_ptr,int * id)2412   static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
2413     (void)bits;
2414     *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
2415   }
2416 
ForAllStructFields(const StructDef & struct_def,std::function<void (const FieldDef & field)> cb)2417   void ForAllStructFields(const StructDef &struct_def,
2418                           std::function<void(const FieldDef &field)> cb) {
2419     size_t offset_to_field = 0;
2420     for (auto it = struct_def.fields.vec.begin();
2421          it != struct_def.fields.vec.end(); ++it) {
2422       const auto &field = **it;
2423       code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
2424       code_.SetValue("FIELD_OBJECT_TYPE", ObjectFieldType(field, false));
2425       code_.SetValue("FIELD_NAME", Name(field));
2426       code_.SetValue("FIELD_OFFSET", NumToString(offset_to_field));
2427       code_.SetValue(
2428           "REF",
2429           IsStruct(field.value.type) || IsArray(field.value.type) ? "&" : "");
2430       cb(field);
2431       const size_t size = InlineSize(field.value.type);
2432       offset_to_field += size + field.padding;
2433     }
2434   }
2435   // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def)2436   void GenStruct(const StructDef &struct_def) {
2437     // Generates manual padding and alignment.
2438     // Variables are private because they contain little endian data on all
2439     // platforms.
2440     GenComment(struct_def.doc_comment);
2441     code_.SetValue("ALIGN", NumToString(struct_def.minalign));
2442     code_.SetValue("STRUCT_NAME", Name(struct_def));
2443     code_.SetValue("STRUCT_SIZE", NumToString(struct_def.bytesize));
2444 
2445     // We represent Flatbuffers-structs in Rust-u8-arrays since the data may be
2446     // of the wrong endianness and alignment 1.
2447     //
2448     // PartialEq is useful to derive because we can correctly compare structs
2449     // for equality by just comparing their underlying byte data. This doesn't
2450     // hold for PartialOrd/Ord.
2451     code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
2452     code_ += "#[repr(transparent)]";
2453     code_ += "#[derive(Clone, Copy, PartialEq)]";
2454     code_ += "pub struct {{STRUCT_NAME}}(pub [u8; {{STRUCT_SIZE}}]);";
2455     code_ += "impl Default for {{STRUCT_NAME}} { ";
2456     code_ += "  fn default() -> Self { ";
2457     code_ += "    Self([0; {{STRUCT_SIZE}}])";
2458     code_ += "  }";
2459     code_ += "}";
2460 
2461     // Debug for structs.
2462     code_ += "impl std::fmt::Debug for {{STRUCT_NAME}} {";
2463     code_ +=
2464         "  fn fmt(&self, f: &mut std::fmt::Formatter"
2465         ") -> std::fmt::Result {";
2466     code_ += "    f.debug_struct(\"{{STRUCT_NAME}}\")";
2467     ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2468       (void)unused;
2469       code_ += "      .field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}())";
2470     });
2471     code_ += "      .finish()";
2472     code_ += "  }";
2473     code_ += "}";
2474     code_ += "";
2475 
2476     // Generate impls for SafeSliceAccess (because all structs are endian-safe),
2477     // Follow for the value type, Follow for the reference type, Push for the
2478     // value type, and Push for the reference type.
2479     code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{STRUCT_NAME}} {}";
2480     code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
2481     code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
2482     code_ += "  type Inner = &'a {{STRUCT_NAME}};";
2483     code_ += "  #[inline]";
2484     code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
2485     code_ += "    <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
2486     code_ += "  }";
2487     code_ += "}";
2488     code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
2489     code_ += "  type Inner = &'a {{STRUCT_NAME}};";
2490     code_ += "  #[inline]";
2491     code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
2492     code_ += "    flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
2493     code_ += "  }";
2494     code_ += "}";
2495     code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
2496     code_ += "    type Output = {{STRUCT_NAME}};";
2497     code_ += "    #[inline]";
2498     code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
2499     code_ += "        let src = unsafe {";
2500     code_ +=
2501         "            ::std::slice::from_raw_parts("
2502         "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
2503     code_ += "        };";
2504     code_ += "        dst.copy_from_slice(src);";
2505     code_ += "    }";
2506     code_ += "}";
2507     code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
2508     code_ += "    type Output = {{STRUCT_NAME}};";
2509     code_ += "";
2510     code_ += "    #[inline]";
2511     code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
2512     code_ += "        let src = unsafe {";
2513     code_ +=
2514         "            ::std::slice::from_raw_parts("
2515         "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
2516     code_ += "        };";
2517     code_ += "        dst.copy_from_slice(src);";
2518     code_ += "    }";
2519     code_ += "}";
2520     code_ += "";
2521 
2522     // Generate verifier: Structs are simple so presence and alignment are
2523     // all that need to be checked.
2524     code_ += "impl<'a> flatbuffers::Verifiable for {{STRUCT_NAME}} {";
2525     code_ += "  #[inline]";
2526     code_ += "  fn run_verifier(";
2527     code_ += "    v: &mut flatbuffers::Verifier, pos: usize";
2528     code_ += "  ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
2529     code_ += "    use self::flatbuffers::Verifiable;";
2530     code_ += "    v.in_buffer::<Self>(pos)";
2531     code_ += "  }";
2532     code_ += "}";
2533 
2534     // Generate a constructor that takes all fields as arguments.
2535     code_ += "impl<'a> {{STRUCT_NAME}} {";
2536     code_ += "  #[allow(clippy::too_many_arguments)]";
2537     code_ += "  pub fn new(";
2538     ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2539       (void)unused;
2540       code_ += "    {{FIELD_NAME}}: {{REF}}{{FIELD_TYPE}},";
2541     });
2542     code_ += "  ) -> Self {";
2543     code_ += "    let mut s = Self([0; {{STRUCT_SIZE}}]);";
2544     ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2545       (void)unused;
2546       code_ += "    s.set_{{FIELD_NAME}}({{REF}}{{FIELD_NAME}});";
2547     });
2548     code_ += "    s";
2549     code_ += "  }";
2550     code_ += "";
2551 
2552     if (parser_.opts.generate_name_strings) {
2553       GenFullyQualifiedNameGetter(struct_def, struct_def.name);
2554     }
2555 
2556     // Generate accessor methods for the struct.
2557     ForAllStructFields(struct_def, [&](const FieldDef &field) {
2558       this->GenComment(field.doc_comment, "  ");
2559       // Getter.
2560       if (IsStruct(field.value.type)) {
2561         code_ += "  pub fn {{FIELD_NAME}}(&self) -> &{{FIELD_TYPE}} {";
2562         code_ +=
2563             "    unsafe {"
2564             " &*(self.0[{{FIELD_OFFSET}}..].as_ptr() as *const"
2565             " {{FIELD_TYPE}}) }";
2566       } else if (IsArray(field.value.type)) {
2567         code_.SetValue("ARRAY_SIZE",
2568                        NumToString(field.value.type.fixed_length));
2569         code_.SetValue("ARRAY_ITEM", GetTypeGet(field.value.type.VectorType()));
2570         code_ +=
2571             "  pub fn {{FIELD_NAME}}(&'a self) -> "
2572             "flatbuffers::Array<'a, {{ARRAY_ITEM}}, {{ARRAY_SIZE}}> {";
2573         code_ += "    flatbuffers::Array::follow(&self.0, {{FIELD_OFFSET}})";
2574       } else {
2575         code_ += "  pub fn {{FIELD_NAME}}(&self) -> {{FIELD_TYPE}} {";
2576         code_ +=
2577             "    let mut mem = core::mem::MaybeUninit::"
2578             "<{{FIELD_TYPE}}>::uninit();";
2579         code_ += "    unsafe {";
2580         code_ += "      core::ptr::copy_nonoverlapping(";
2581         code_ += "        self.0[{{FIELD_OFFSET}}..].as_ptr(),";
2582         code_ += "        mem.as_mut_ptr() as *mut u8,";
2583         code_ += "        core::mem::size_of::<{{FIELD_TYPE}}>(),";
2584         code_ += "      );";
2585         code_ += "      mem.assume_init()";
2586         code_ += "    }.from_little_endian()";
2587       }
2588       code_ += "  }\n";
2589       // Setter.
2590       if (IsStruct(field.value.type)) {
2591         code_.SetValue("FIELD_SIZE", NumToString(InlineSize(field.value.type)));
2592         code_ += "  pub fn set_{{FIELD_NAME}}(&mut self, x: &{{FIELD_TYPE}}) {";
2593         code_ +=
2594             "    self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}}+{{FIELD_SIZE}}]"
2595             ".copy_from_slice(&x.0)";
2596       } else if (IsArray(field.value.type)) {
2597         if (GetFullType(field.value.type) == ftArrayOfBuiltin) {
2598           code_.SetValue("ARRAY_ITEM",
2599                          GetTypeGet(field.value.type.VectorType()));
2600           code_.SetValue(
2601               "ARRAY_ITEM_SIZE",
2602               NumToString(InlineSize(field.value.type.VectorType())));
2603           code_ +=
2604               "  pub fn set_{{FIELD_NAME}}(&mut self, items: &{{FIELD_TYPE}}) "
2605               "{";
2606           code_ +=
2607               "    flatbuffers::emplace_scalar_array(&mut self.0, "
2608               "{{FIELD_OFFSET}}, items);";
2609         } else {
2610           code_.SetValue("FIELD_SIZE",
2611                          NumToString(InlineSize(field.value.type)));
2612           code_ +=
2613               "  pub fn set_{{FIELD_NAME}}(&mut self, x: &{{FIELD_TYPE}}) {";
2614           code_ += "    unsafe {";
2615           code_ += "      std::ptr::copy(";
2616           code_ += "        x.as_ptr() as *const u8,";
2617           code_ += "        self.0.as_mut_ptr().add({{FIELD_OFFSET}}),";
2618           code_ += "        {{FIELD_SIZE}},";
2619           code_ += "      );";
2620           code_ += "    }";
2621         }
2622       } else {
2623         code_ += "  pub fn set_{{FIELD_NAME}}(&mut self, x: {{FIELD_TYPE}}) {";
2624         code_ += "    let x_le = x.to_little_endian();";
2625         code_ += "    unsafe {";
2626         code_ += "      core::ptr::copy_nonoverlapping(";
2627         code_ += "        &x_le as *const {{FIELD_TYPE}} as *const u8,";
2628         code_ += "        self.0[{{FIELD_OFFSET}}..].as_mut_ptr(),";
2629         code_ += "        core::mem::size_of::<{{FIELD_TYPE}}>(),";
2630         code_ += "      );";
2631         code_ += "    }";
2632       }
2633       code_ += "  }\n";
2634 
2635       // Generate a comparison function for this field if it is a key.
2636       if (field.key) { GenKeyFieldMethods(field); }
2637     });
2638 
2639     // Generate Object API unpack method.
2640     if (parser_.opts.generate_object_based_api) {
2641       code_.SetValue("NATIVE_STRUCT_NAME", NativeName(struct_def));
2642       code_ += "  pub fn unpack(&self) -> {{NATIVE_STRUCT_NAME}} {";
2643       code_ += "    {{NATIVE_STRUCT_NAME}} {";
2644       ForAllStructFields(struct_def, [&](const FieldDef &field) {
2645         if (IsArray(field.value.type)) {
2646           if (GetFullType(field.value.type) == ftArrayOfStruct) {
2647             code_ +=
2648                 "      {{FIELD_NAME}}: { let {{FIELD_NAME}} = "
2649                 "self.{{FIELD_NAME}}(); flatbuffers::array_init(|i| "
2650                 "{{FIELD_NAME}}.get(i).unpack()) },";
2651           } else {
2652             code_ += "      {{FIELD_NAME}}: self.{{FIELD_NAME}}().into(),";
2653           }
2654         } else {
2655           std::string unpack = IsStruct(field.value.type) ? ".unpack()" : "";
2656           code_ += "      {{FIELD_NAME}}: self.{{FIELD_NAME}}()" + unpack + ",";
2657         }
2658       });
2659       code_ += "    }";
2660       code_ += "  }";
2661     }
2662 
2663     code_ += "}";  // End impl Struct methods.
2664     code_ += "";
2665 
2666     // Generate Struct Object.
2667     if (parser_.opts.generate_object_based_api) {
2668       // Struct declaration
2669       code_ += "#[derive(Debug, Clone, PartialEq, Default)]";
2670       code_ += "pub struct {{NATIVE_STRUCT_NAME}} {";
2671       ForAllStructFields(struct_def, [&](const FieldDef &field) {
2672         (void)field;  // unused.
2673         code_ += "  pub {{FIELD_NAME}}: {{FIELD_OBJECT_TYPE}},";
2674       });
2675       code_ += "}";
2676       // The `pack` method that turns the native struct into its Flatbuffers
2677       // counterpart.
2678       code_ += "impl {{NATIVE_STRUCT_NAME}} {";
2679       code_ += "  pub fn pack(&self) -> {{STRUCT_NAME}} {";
2680       code_ += "    {{STRUCT_NAME}}::new(";
2681       ForAllStructFields(struct_def, [&](const FieldDef &field) {
2682         if (IsStruct(field.value.type)) {
2683           code_ += "      &self.{{FIELD_NAME}}.pack(),";
2684         } else if (IsArray(field.value.type)) {
2685           if (GetFullType(field.value.type) == ftArrayOfStruct) {
2686             code_ +=
2687                 "      &flatbuffers::array_init(|i| "
2688                 "self.{{FIELD_NAME}}[i].pack()),";
2689           } else {
2690             code_ += "      &self.{{FIELD_NAME}},";
2691           }
2692         } else {
2693           code_ += "      self.{{FIELD_NAME}},";
2694         }
2695       });
2696       code_ += "    )";
2697       code_ += "  }";
2698       code_ += "}";
2699       code_ += "";
2700     }
2701   }
2702 
GenNamespaceImports(const int white_spaces)2703   void GenNamespaceImports(const int white_spaces) {
2704     // DO not use global attributes (i.e. #![...]) since it interferes
2705     // with users who include! generated files.
2706     // See: https://github.com/google/flatbuffers/issues/6261
2707     std::string indent = std::string(white_spaces, ' ');
2708     code_ += "";
2709     if (!parser_.opts.generate_all) {
2710       for (auto it = parser_.included_files_.begin();
2711            it != parser_.included_files_.end(); ++it) {
2712         if (it->second.empty()) continue;
2713         auto noext = flatbuffers::StripExtension(it->second);
2714         auto basename = flatbuffers::StripPath(noext);
2715 
2716         if (parser_.opts.include_prefix.empty()) {
2717           code_ += indent + "use crate::" + basename +
2718                    parser_.opts.filename_suffix + "::*;";
2719         } else {
2720           auto prefix = parser_.opts.include_prefix;
2721           prefix.pop_back();
2722 
2723           code_ += indent + "use crate::" + prefix + "::" + basename +
2724                    parser_.opts.filename_suffix + "::*;";
2725         }
2726       }
2727     }
2728     code_ += indent + "use std::mem;";
2729     code_ += indent + "use std::cmp::Ordering;";
2730     code_ += "";
2731     code_ += indent + "extern crate flatbuffers;";
2732     code_ += indent + "use self::flatbuffers::{EndianScalar, Follow};";
2733   }
2734 
2735   // Set up the correct namespace. This opens a namespace if the current
2736   // namespace is different from the target namespace. This function
2737   // closes and opens the namespaces only as necessary.
2738   //
2739   // The file must start and end with an empty (or null) namespace so that
2740   // namespaces are properly opened and closed.
SetNameSpace(const Namespace * ns)2741   void SetNameSpace(const Namespace *ns) {
2742     if (cur_name_space_ == ns) { return; }
2743 
2744     // Compute the size of the longest common namespace prefix.
2745     // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
2746     // the common prefix is A::B:: and we have old_size = 4, new_size = 5
2747     // and common_prefix_size = 2
2748     size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
2749     size_t new_size = ns ? ns->components.size() : 0;
2750 
2751     size_t common_prefix_size = 0;
2752     while (common_prefix_size < old_size && common_prefix_size < new_size &&
2753            ns->components[common_prefix_size] ==
2754                cur_name_space_->components[common_prefix_size]) {
2755       common_prefix_size++;
2756     }
2757 
2758     // Close cur_name_space in reverse order to reach the common prefix.
2759     // In the previous example, D then C are closed.
2760     for (size_t j = old_size; j > common_prefix_size; --j) {
2761       code_ += "}  // pub mod " + cur_name_space_->components[j - 1];
2762     }
2763     if (old_size != common_prefix_size) { code_ += ""; }
2764 
2765     // open namespace parts to reach the ns namespace
2766     // in the previous example, E, then F, then G are opened
2767     for (auto j = common_prefix_size; j != new_size; ++j) {
2768       code_ += "#[allow(unused_imports, dead_code)]";
2769       code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
2770       // Generate local namespace imports.
2771       GenNamespaceImports(2);
2772     }
2773     if (new_size != common_prefix_size) { code_ += ""; }
2774 
2775     cur_name_space_ = ns;
2776   }
2777 };
2778 
2779 }  // namespace rust
2780 
GenerateRust(const Parser & parser,const std::string & path,const std::string & file_name)2781 bool GenerateRust(const Parser &parser, const std::string &path,
2782                   const std::string &file_name) {
2783   rust::RustGenerator generator(parser, path, file_name);
2784   return generator.generate();
2785 }
2786 
RustMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)2787 std::string RustMakeRule(const Parser &parser, const std::string &path,
2788                          const std::string &file_name) {
2789   std::string filebase =
2790       flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
2791   rust::RustGenerator generator(parser, path, file_name);
2792   std::string make_rule =
2793       generator.GeneratedFileName(path, filebase, parser.opts) + ": ";
2794 
2795   auto included_files = parser.GetIncludedFilesRecursive(file_name);
2796   for (auto it = included_files.begin(); it != included_files.end(); ++it) {
2797     make_rule += " " + *it;
2798   }
2799   return make_rule;
2800 }
2801 
2802 }  // namespace flatbuffers
2803 
2804 // TODO(rw): Generated code should import other generated files.
2805 // TODO(rw): Generated code should refer to namespaces in included files in a
2806 //           way that makes them referrable.
2807 // TODO(rw): Generated code should indent according to nesting level.
2808 // TODO(rw): Generated code should generate endian-safe Debug impls.
2809 // TODO(rw): Generated code could use a Rust-only enum type to access unions,
2810 //           instead of making the user use _type() to manually switch.
2811 // TODO(maxburke): There should be test schemas added that use language
2812 //           keywords as fields of structs, tables, unions, enums, to make sure
2813 //           that internal code generated references escaped names correctly.
2814 // TODO(maxburke): We should see if there is a more flexible way of resolving
2815 //           module paths for use declarations. Right now if schemas refer to
2816 //           other flatbuffer files, the include paths in emitted Rust bindings
2817 //           are crate-relative which may undesirable.
2818