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