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