• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // independent from idl_parser, since this code is not needed for most clients
18 
19 #include "flatbuffers/code_generators.h"
20 #include "flatbuffers/flatbuffers.h"
21 #include "flatbuffers/idl.h"
22 #include "flatbuffers/util.h"
23 
24 namespace flatbuffers {
25 
GeneratedFileName(const std::string & path,const std::string & file_name)26 static std::string GeneratedFileName(const std::string &path,
27                                      const std::string &file_name) {
28   return path + file_name + "_generated.rs";
29 }
30 
31 // Convert a camelCaseIdentifier or CamelCaseIdentifier to a
32 // snake_case_indentifier.
MakeSnakeCase(const std::string & in)33 std::string MakeSnakeCase(const std::string &in) {
34   std::string s;
35   for (size_t i = 0; i < in.length(); i++) {
36     if (i == 0) {
37       s += static_cast<char>(tolower(in[0]));
38     } else if (in[i] == '_') {
39       s += '_';
40     } else if (!islower(in[i])) {
41       // Prevent duplicate underscores for Upper_Snake_Case strings
42       // and UPPERCASE strings.
43       if (islower(in[i - 1])) {
44         s += '_';
45       }
46       s += static_cast<char>(tolower(in[i]));
47     } else {
48       s += in[i];
49     }
50   }
51   return s;
52 }
53 
54 // Convert a string to all uppercase.
MakeUpper(const std::string & in)55 std::string MakeUpper(const std::string &in) {
56   std::string s;
57   for (size_t i = 0; i < in.length(); i++) {
58     s += static_cast<char>(toupper(in[i]));
59   }
60   return s;
61 }
62 
63 // Encapsulate all logical field types in this enum. This allows us to write
64 // field logic based on type switches, instead of branches on the properties
65 // set on the Type.
66 // TODO(rw): for backwards compatibility, we can't use a strict `enum class`
67 //           declaration here. could we use the `-Wswitch-enum` warning to
68 //           achieve the same effect?
69 enum FullType {
70   ftInteger = 0,
71   ftFloat = 1,
72   ftBool = 2,
73 
74   ftStruct = 3,
75   ftTable = 4,
76 
77   ftEnumKey = 5,
78   ftUnionKey = 6,
79 
80   ftUnionValue = 7,
81 
82   // TODO(rw): bytestring?
83   ftString = 8,
84 
85   ftVectorOfInteger = 9,
86   ftVectorOfFloat = 10,
87   ftVectorOfBool = 11,
88   ftVectorOfEnumKey = 12,
89   ftVectorOfStruct = 13,
90   ftVectorOfTable = 14,
91   ftVectorOfString = 15,
92   ftVectorOfUnionValue = 16,
93 };
94 
95 // Convert a Type to a FullType (exhaustive).
GetFullType(const Type & type)96 FullType GetFullType(const Type &type) {
97   // N.B. The order of these conditionals matters for some types.
98 
99   if (type.base_type == BASE_TYPE_STRING) {
100     return ftString;
101   } else if (type.base_type == BASE_TYPE_STRUCT) {
102     if (type.struct_def->fixed) {
103       return ftStruct;
104     } else {
105       return ftTable;
106     }
107   } else if (type.base_type == BASE_TYPE_VECTOR) {
108     switch (GetFullType(type.VectorType())) {
109       case ftInteger: {
110         return ftVectorOfInteger;
111       }
112       case ftFloat: {
113         return ftVectorOfFloat;
114       }
115       case ftBool: {
116         return ftVectorOfBool;
117       }
118       case ftStruct: {
119         return ftVectorOfStruct;
120       }
121       case ftTable: {
122         return ftVectorOfTable;
123       }
124       case ftString: {
125         return ftVectorOfString;
126       }
127       case ftEnumKey: {
128         return ftVectorOfEnumKey;
129       }
130       case ftUnionKey:
131       case ftUnionValue: {
132         FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
133         break;
134       }
135       default: {
136         FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
137       }
138     }
139   } else if (type.enum_def != nullptr) {
140     if (type.enum_def->is_union) {
141       if (type.base_type == BASE_TYPE_UNION) {
142         return ftUnionValue;
143       } else if (IsInteger(type.base_type)) {
144         return ftUnionKey;
145       } else {
146         FLATBUFFERS_ASSERT(false && "unknown union field type");
147       }
148     } else {
149       return ftEnumKey;
150     }
151   } else if (IsScalar(type.base_type)) {
152     if (IsBool(type.base_type)) {
153       return ftBool;
154     } else if (IsInteger(type.base_type)) {
155       return ftInteger;
156     } else if (IsFloat(type.base_type)) {
157       return ftFloat;
158     } else {
159       FLATBUFFERS_ASSERT(false && "unknown number type");
160     }
161   }
162 
163   FLATBUFFERS_ASSERT(false && "completely unknown type");
164 
165   // this is only to satisfy the compiler's return analysis.
166   return ftBool;
167 }
168 
169 // If the second parameter is false then wrap the first with Option<...>
WrapInOptionIfNotRequired(std::string s,bool required)170 std::string WrapInOptionIfNotRequired(std::string s, bool required) {
171   if (required) {
172     return s;
173   } else {
174     return "Option<" + s + ">";
175   }
176 }
177 
178 // If the second parameter is false then add .unwrap()
AddUnwrapIfRequired(std::string s,bool required)179 std::string AddUnwrapIfRequired(std::string s, bool required) {
180   if (required) {
181     return s + ".unwrap()";
182   } else {
183     return s;
184   }
185 }
186 
187 namespace rust {
188 
189 class RustGenerator : public BaseGenerator {
190  public:
RustGenerator(const Parser & parser,const std::string & path,const std::string & file_name)191   RustGenerator(const Parser &parser, const std::string &path,
192                 const std::string &file_name)
193       : BaseGenerator(parser, path, file_name, "", "::"),
194         cur_name_space_(nullptr) {
195     const char *keywords[] = {
196       // list taken from:
197       // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
198       //
199       // we write keywords one per line so that we can easily compare them with
200       // changes to that webpage in the future.
201 
202       // currently-used keywords
203       "as",
204       "break",
205       "const",
206       "continue",
207       "crate",
208       "else",
209       "enum",
210       "extern",
211       "false",
212       "fn",
213       "for",
214       "if",
215       "impl",
216       "in",
217       "let",
218       "loop",
219       "match",
220       "mod",
221       "move",
222       "mut",
223       "pub",
224       "ref",
225       "return",
226       "Self",
227       "self",
228       "static",
229       "struct",
230       "super",
231       "trait",
232       "true",
233       "type",
234       "unsafe",
235       "use",
236       "where",
237       "while",
238 
239       // future possible keywords
240       "abstract",
241       "alignof",
242       "become",
243       "box",
244       "do",
245       "final",
246       "macro",
247       "offsetof",
248       "override",
249       "priv",
250       "proc",
251       "pure",
252       "sizeof",
253       "typeof",
254       "unsized",
255       "virtual",
256       "yield",
257 
258       // other rust terms we should not use
259       "std",
260       "usize",
261       "isize",
262       "u8",
263       "i8",
264       "u16",
265       "i16",
266       "u32",
267       "i32",
268       "u64",
269       "i64",
270       "u128",
271       "i128",
272       "f32",
273       "f64",
274 
275       // These are terms the code generator can implement on types.
276       //
277       // In Rust, the trait resolution rules (as described at
278       // https://github.com/rust-lang/rust/issues/26007) mean that, as long
279       // as we impl table accessors as inherent methods, we'll never create
280       // conflicts with these keywords. However, that's a fairly nuanced
281       // implementation detail, and how we implement methods could change in
282       // the future. as a result, we proactively block these out as reserved
283       // words.
284       "follow",
285       "push",
286       "size",
287       "alignment",
288       "to_little_endian",
289       "from_little_endian",
290       nullptr };
291     for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
292   }
293 
294   // Iterate through all definitions we haven't generated code for (enums,
295   // structs, and tables) and output them to a single file.
generate()296   bool generate() {
297     code_.Clear();
298     code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
299 
300     assert(!cur_name_space_);
301 
302     // Generate imports for the global scope in case no namespace is used
303     // in the schema file.
304     GenNamespaceImports(0);
305     code_ += "";
306 
307     // Generate all code in their namespaces, once, because Rust does not
308     // permit re-opening modules.
309     //
310     // TODO(rw): Use a set data structure to reduce namespace evaluations from
311     //           O(n**2) to O(n).
312     for (auto ns_it = parser_.namespaces_.begin();
313          ns_it != parser_.namespaces_.end();
314          ++ns_it) {
315       const auto &ns = *ns_it;
316 
317       // Generate code for all the enum declarations.
318       for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
319            ++it) {
320         const auto &enum_def = **it;
321         if (enum_def.defined_namespace != ns) { continue; }
322         if (!enum_def.generated) {
323           SetNameSpace(enum_def.defined_namespace);
324           GenEnum(enum_def);
325         }
326       }
327 
328       // Generate code for all structs.
329       for (auto it = parser_.structs_.vec.begin();
330            it != parser_.structs_.vec.end(); ++it) {
331         const auto &struct_def = **it;
332         if (struct_def.defined_namespace != ns) { continue; }
333         if (struct_def.fixed && !struct_def.generated) {
334           SetNameSpace(struct_def.defined_namespace);
335           GenStruct(struct_def);
336         }
337       }
338 
339       // Generate code for all tables.
340       for (auto it = parser_.structs_.vec.begin();
341            it != parser_.structs_.vec.end(); ++it) {
342         const auto &struct_def = **it;
343         if (struct_def.defined_namespace != ns) { continue; }
344         if (!struct_def.fixed && !struct_def.generated) {
345           SetNameSpace(struct_def.defined_namespace);
346           GenTable(struct_def);
347         }
348       }
349 
350       // Generate global helper functions.
351       if (parser_.root_struct_def_) {
352         auto &struct_def = *parser_.root_struct_def_;
353         if (struct_def.defined_namespace != ns) { continue; }
354         SetNameSpace(struct_def.defined_namespace);
355         GenRootTableFuncs(struct_def);
356       }
357     }
358     if (cur_name_space_) SetNameSpace(nullptr);
359 
360     const auto file_path = GeneratedFileName(path_, file_name_);
361     const auto final_code = code_.ToString();
362     return SaveFile(file_path.c_str(), final_code, false);
363   }
364 
365  private:
366   CodeWriter code_;
367 
368   std::set<std::string> keywords_;
369 
370   // This tracks the current namespace so we can insert namespace declarations.
371   const Namespace *cur_name_space_;
372 
CurrentNameSpace() const373   const Namespace *CurrentNameSpace() const { return cur_name_space_; }
374 
375   // Determine if a Type needs a lifetime template parameter when used in the
376   // Rust builder args.
TableBuilderTypeNeedsLifetime(const Type & type) const377   bool TableBuilderTypeNeedsLifetime(const Type &type) const {
378     switch (GetFullType(type)) {
379       case ftInteger:
380       case ftFloat:
381       case ftBool:
382       case ftEnumKey:
383       case ftUnionKey:
384       case ftUnionValue: { return false; }
385       default: { return true; }
386     }
387   }
388 
389   // Determine if a table args rust type needs a lifetime template parameter.
TableBuilderArgsNeedsLifetime(const StructDef & struct_def) const390   bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
391     FLATBUFFERS_ASSERT(!struct_def.fixed);
392 
393     for (auto it = struct_def.fields.vec.begin();
394          it != struct_def.fields.vec.end(); ++it) {
395       const auto &field = **it;
396       if (field.deprecated) {
397         continue;
398       }
399 
400       if (TableBuilderTypeNeedsLifetime(field.value.type)) {
401         return true;
402       }
403     }
404 
405     return false;
406   }
407 
408   // Determine if a Type needs to be copied (for endian safety) when used in a
409   // Struct.
StructMemberAccessNeedsCopy(const Type & type) const410   bool StructMemberAccessNeedsCopy(const Type &type) const {
411     switch (GetFullType(type)) {
412       case ftInteger:  // requires endian swap
413       case ftFloat: // requires endian swap
414       case ftBool: // no endian-swap, but do the copy for UX consistency
415       case ftEnumKey: { return true; } // requires endian swap
416       case ftStruct: { return false; } // no endian swap
417       default: {
418         // logic error: no other types can be struct members.
419         FLATBUFFERS_ASSERT(false && "invalid struct member type");
420         return false; // only to satisfy compiler's return analysis
421       }
422     }
423   }
424 
EscapeKeyword(const std::string & name) const425   std::string EscapeKeyword(const std::string &name) const {
426     return keywords_.find(name) == keywords_.end() ? name : name + "_";
427   }
428 
Name(const Definition & def) const429   std::string Name(const Definition &def) const {
430     return EscapeKeyword(def.name);
431   }
432 
Name(const EnumVal & ev) const433   std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
434 
WrapInNameSpace(const Definition & def) const435   std::string WrapInNameSpace(const Definition &def) const {
436     return WrapInNameSpace(def.defined_namespace, Name(def));
437   }
WrapInNameSpace(const Namespace * ns,const std::string & name) const438   std::string WrapInNameSpace(const Namespace *ns,
439                               const std::string &name) const {
440     if (CurrentNameSpace() == ns) return name;
441     std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
442     return prefix + name;
443   }
444 
445   // Determine the namespace traversal needed from the Rust crate root.
446   // This may be useful in the future for referring to included files, but is
447   // currently unused.
GetAbsoluteNamespaceTraversal(const Namespace * dst) const448   std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const {
449     std::stringstream stream;
450 
451     stream << "::";
452     for (auto d = dst->components.begin(); d != dst->components.end(); d++) {
453       stream << MakeSnakeCase(*d) + "::";
454     }
455     return stream.str();
456   }
457 
458   // Determine the relative namespace traversal needed to reference one
459   // namespace from another namespace. This is useful because it does not force
460   // the user to have a particular file layout. (If we output absolute
461   // namespace paths, that may require users to organize their Rust crates in a
462   // particular way.)
GetRelativeNamespaceTraversal(const Namespace * src,const Namespace * dst) const463   std::string GetRelativeNamespaceTraversal(const Namespace *src,
464                                             const Namespace *dst) const {
465     // calculate the path needed to reference dst from src.
466     // example: f(A::B::C, A::B::C) -> (none)
467     // example: f(A::B::C, A::B)    -> super::
468     // example: f(A::B::C, A::B::D) -> super::D
469     // example: f(A::B::C, A)       -> super::super::
470     // example: f(A::B::C, D)       -> super::super::super::D
471     // example: f(A::B::C, D::E)    -> super::super::super::D::E
472     // example: f(A, D::E)          -> super::D::E
473     // does not include leaf object (typically a struct type).
474 
475     size_t i = 0;
476     std::stringstream stream;
477 
478     auto s = src->components.begin();
479     auto d = dst->components.begin();
480     for(;;) {
481       if (s == src->components.end()) { break; }
482       if (d == dst->components.end()) { break; }
483       if (*s != *d) { break; }
484       s++;
485       d++;
486       i++;
487     }
488 
489     for (; s != src->components.end(); s++) {
490       stream << "super::";
491     }
492     for (; d != dst->components.end(); d++) {
493       stream << MakeSnakeCase(*d) + "::";
494     }
495     return stream.str();
496   }
497 
498   // Generate a comment from the schema.
GenComment(const std::vector<std::string> & dc,const char * prefix="")499   void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
500     std::string text;
501     ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
502     code_ += text + "\\";
503   }
504 
505   // Return a Rust type from the table in idl.h.
GetTypeBasic(const Type & type) const506   std::string GetTypeBasic(const Type &type) const {
507     switch (GetFullType(type)) {
508       case ftInteger:
509       case ftFloat:
510       case ftBool:
511       case ftEnumKey:
512       case ftUnionKey: { break; }
513       default: { FLATBUFFERS_ASSERT(false && "incorrect type given");}
514     }
515 
516     // clang-format off
517     static const char * const ctypename[] = {
518     #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
519                            RTYPE) \
520             #RTYPE,
521         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
522     #undef FLATBUFFERS_TD
523       // clang-format on
524     };
525 
526     if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
527     return ctypename[type.base_type];
528   }
529 
530   // Look up the native type for an enum. This will always be an integer like
531   // u8, i32, etc.
GetEnumTypeForDecl(const Type & type)532   std::string GetEnumTypeForDecl(const Type &type) {
533     const auto ft = GetFullType(type);
534     if (!(ft == ftEnumKey || ft == ftUnionKey)) {
535       FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
536     }
537 
538     static const char *ctypename[] = {
539     // clang-format off
540     #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
541                            RTYPE) \
542             #RTYPE,
543         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
544     #undef FLATBUFFERS_TD
545       // clang-format on
546     };
547 
548     // Enums can be bools, but their Rust representation must be a u8, as used
549     // in the repr attribute (#[repr(bool)] is an invalid attribute).
550     if (type.base_type == BASE_TYPE_BOOL) return "u8";
551     return ctypename[type.base_type];
552   }
553 
554   // Return a Rust type for any type (scalar, table, struct) specifically for
555   // using a FlatBuffer.
GetTypeGet(const Type & type) const556   std::string GetTypeGet(const Type &type) const {
557     switch (GetFullType(type)) {
558       case ftInteger:
559       case ftFloat:
560       case ftBool:
561       case ftEnumKey:
562       case ftUnionKey: {
563         return GetTypeBasic(type); }
564       case ftTable: {
565         return WrapInNameSpace(type.struct_def->defined_namespace,
566                                type.struct_def->name) + "<'a>"; }
567       default: {
568         return WrapInNameSpace(type.struct_def->defined_namespace,
569                                type.struct_def->name); }
570     }
571   }
572 
GetEnumValUse(const EnumDef & enum_def,const EnumVal & enum_val) const573   std::string GetEnumValUse(const EnumDef &enum_def,
574                             const EnumVal &enum_val) const {
575     return Name(enum_def) + "::" + Name(enum_val);
576   }
577 
578   // Generate an enum declaration,
579   // an enum string lookup table,
580   // an enum match function,
581   // and an enum array of values
GenEnum(const EnumDef & enum_def)582   void GenEnum(const EnumDef &enum_def) {
583     code_.SetValue("ENUM_NAME", Name(enum_def));
584     code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
585 
586     GenComment(enum_def.doc_comment);
587     code_ += "#[allow(non_camel_case_types)]";
588     code_ += "#[repr({{BASE_TYPE}})]";
589     code_ += "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]";
590     code_ += "pub enum " + Name(enum_def) + " {";
591 
592     int64_t anyv = 0;
593     const EnumVal *minv = nullptr, *maxv = nullptr;
594     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
595       const auto &ev = **it;
596 
597       GenComment(ev.doc_comment, "  ");
598       code_.SetValue("KEY", Name(ev));
599       code_.SetValue("VALUE", NumToString(ev.value));
600       code_ += "  {{KEY}} = {{VALUE}},";
601 
602       minv = !minv || minv->value > ev.value ? &ev : minv;
603       maxv = !maxv || maxv->value < ev.value ? &ev : maxv;
604       anyv |= ev.value;
605     }
606 
607     code_ += "";
608     code_ += "}";
609     code_ += "";
610 
611     code_.SetValue("ENUM_NAME", Name(enum_def));
612     code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
613     code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
614     code_.SetValue("ENUM_MIN_BASE_VALUE", NumToString(minv->value));
615     code_.SetValue("ENUM_MAX_BASE_VALUE", NumToString(maxv->value));
616 
617     // Generate enum constants, and impls for Follow, EndianScalar, and Push.
618     code_ += "const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
619     code_ += "{{ENUM_MIN_BASE_VALUE}};";
620     code_ += "const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
621     code_ += "{{ENUM_MAX_BASE_VALUE}};";
622     code_ += "";
623     code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
624     code_ += "  type Inner = Self;";
625     code_ += "  #[inline]";
626     code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
627     code_ += "    flatbuffers::read_scalar_at::<Self>(buf, loc)";
628     code_ += "  }";
629     code_ += "}";
630     code_ += "";
631     code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
632     code_ += "  #[inline]";
633     code_ += "  fn to_little_endian(self) -> Self {";
634     code_ += "    let n = {{BASE_TYPE}}::to_le(self as {{BASE_TYPE}});";
635     code_ += "    let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
636     code_ += "    unsafe { *p }";
637     code_ += "  }";
638     code_ += "  #[inline]";
639     code_ += "  fn from_little_endian(self) -> Self {";
640     code_ += "    let n = {{BASE_TYPE}}::from_le(self as {{BASE_TYPE}});";
641     code_ += "    let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
642     code_ += "    unsafe { *p }";
643     code_ += "  }";
644     code_ += "}";
645     code_ += "";
646     code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
647     code_ += "    type Output = {{ENUM_NAME}};";
648     code_ += "    #[inline]";
649     code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
650     code_ += "        flatbuffers::emplace_scalar::<{{ENUM_NAME}}>"
651              "(dst, *self);";
652     code_ += "    }";
653     code_ += "}";
654     code_ += "";
655 
656     // Generate an array of all enumeration values.
657     auto num_fields = NumToString(enum_def.size());
658     code_ += "#[allow(non_camel_case_types)]";
659     code_ += "const ENUM_VALUES_{{ENUM_NAME_CAPS}}:[{{ENUM_NAME}}; " +
660               num_fields + "] = [";
661     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
662       const auto &ev = **it;
663       auto value = GetEnumValUse(enum_def, ev);
664       auto suffix = *it != enum_def.Vals().back() ? "," : "";
665       code_ += "  " + value + suffix;
666     }
667     code_ += "];";
668     code_ += "";
669 
670     // Generate a string table for enum values.
671     // Problem is, if values are very sparse that could generate really big
672     // tables. Ideally in that case we generate a map lookup instead, but for
673     // the moment we simply don't output a table at all.
674     auto range =
675         enum_def.vals.vec.back()->value - enum_def.vals.vec.front()->value + 1;
676     // Average distance between values above which we consider a table
677     // "too sparse". Change at will.
678     static const int kMaxSparseness = 5;
679     if (range / static_cast<int64_t>(enum_def.vals.vec.size()) <
680         kMaxSparseness) {
681       code_ += "#[allow(non_camel_case_types)]";
682       code_ += "const ENUM_NAMES_{{ENUM_NAME_CAPS}}:[&'static str; " +
683                 NumToString(range) + "] = [";
684 
685       auto val = enum_def.Vals().front()->value;
686       for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
687            ++it) {
688         const auto &ev = **it;
689         while (val++ != ev.value) { code_ += "    \"\","; }
690         auto suffix = *it != enum_def.vals.vec.back() ? "," : "";
691         code_ += "    \"" + Name(ev) + "\"" + suffix;
692       }
693       code_ += "];";
694       code_ += "";
695 
696       code_ += "pub fn enum_name_{{ENUM_NAME_SNAKE}}(e: {{ENUM_NAME}}) -> "
697                "&'static str {";
698 
699       code_ += "  let index = e as {{BASE_TYPE}}\\";
700       if (enum_def.vals.vec.front()->value) {
701         auto vals = GetEnumValUse(enum_def, *enum_def.vals.vec.front());
702         code_ += " - " + vals + " as {{BASE_TYPE}}\\";
703       }
704       code_ += ";";
705 
706       code_ += "  ENUM_NAMES_{{ENUM_NAME_CAPS}}[index as usize]";
707       code_ += "}";
708       code_ += "";
709     }
710 
711     if (enum_def.is_union) {
712       // Generate tyoesafe offset(s) for unions
713       code_.SetValue("NAME", Name(enum_def));
714       code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
715       code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
716     }
717   }
718 
GetFieldOffsetName(const FieldDef & field)719   std::string GetFieldOffsetName(const FieldDef &field) {
720     return "VT_" + MakeUpper(Name(field));
721   }
722 
GetDefaultConstant(const FieldDef & field)723   std::string GetDefaultConstant(const FieldDef &field) {
724     return field.value.type.base_type == BASE_TYPE_FLOAT
725                ? field.value.constant + ""
726                : field.value.constant;
727   }
728 
GetDefaultScalarValue(const FieldDef & field)729   std::string GetDefaultScalarValue(const FieldDef &field) {
730     switch (GetFullType(field.value.type)) {
731       case ftInteger: { return GetDefaultConstant(field); }
732       case ftFloat: { return GetDefaultConstant(field); }
733       case ftBool: {
734         return field.value.constant == "0" ? "false" : "true";
735       }
736       case ftUnionKey:
737       case ftEnumKey: {
738         auto ev = field.value.type.enum_def->ReverseLookup(
739             StringToInt(field.value.constant.c_str()), false);
740         assert(ev);
741         return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
742                                GetEnumValUse(*field.value.type.enum_def, *ev));
743       }
744 
745       // All pointer-ish types have a default value of None, because they are
746       // wrapped in Option.
747       default: { return "None"; }
748     }
749   }
750 
751   // Create the return type for fields in the *BuilderArgs structs that are
752   // used to create Tables.
753   //
754   // Note: we could make all inputs to the BuilderArgs be an Option, as well
755   // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
756   // know if the value is default or not, because there are three ways to
757   // return a default value:
758   // 1) return a stored value that happens to be the default,
759   // 2) return a hardcoded value because the relevant vtable field is not in
760   //    the vtable, or
761   // 3) return a hardcoded value because the vtable field value is set to zero.
TableBuilderArgsDefnType(const FieldDef & field,const std::string lifetime)762   std::string TableBuilderArgsDefnType(const FieldDef &field,
763                                        const std::string lifetime) {
764     const Type& type = field.value.type;
765 
766     switch (GetFullType(type)) {
767       case ftInteger:
768       case ftFloat:
769       case ftBool: {
770         const auto typname = GetTypeBasic(type);
771         return typname;
772       }
773       case ftStruct: {
774         const auto typname = WrapInNameSpace(*type.struct_def);
775         return "Option<&" + lifetime + " " + typname + ">";
776       }
777       case ftTable: {
778         const auto typname = WrapInNameSpace(*type.struct_def);
779         return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime + \
780                ">>>";
781       }
782       case ftString: {
783         return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
784       }
785       case ftEnumKey:
786       case ftUnionKey: {
787         const auto typname = WrapInNameSpace(*type.enum_def);
788         return typname;
789       }
790       case ftUnionValue: {
791         const auto typname = WrapInNameSpace(*type.enum_def);
792         return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
793       }
794 
795       case ftVectorOfInteger:
796       case ftVectorOfFloat: {
797         const auto typname = GetTypeBasic(type.VectorType());
798         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
799                lifetime + ",  " + typname + ">>>";
800       }
801       case ftVectorOfBool: {
802         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
803                lifetime + ", bool>>>";
804       }
805       case ftVectorOfEnumKey: {
806         const auto typname = WrapInNameSpace(*type.enum_def);
807         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
808                lifetime + ", " + typname + ">>>";
809       }
810       case ftVectorOfStruct: {
811         const auto typname = WrapInNameSpace(*type.struct_def);
812         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
813                lifetime + ", " + typname + ">>>";
814       }
815       case ftVectorOfTable: {
816         const auto typname = WrapInNameSpace(*type.struct_def);
817         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
818                lifetime + ", flatbuffers::ForwardsUOffset<" + typname + \
819                "<" + lifetime + ">>>>>";
820       }
821       case ftVectorOfString: {
822         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
823                lifetime + ", flatbuffers::ForwardsUOffset<&" + lifetime + \
824                " str>>>>";
825       }
826       case ftVectorOfUnionValue: {
827         const auto typname = WrapInNameSpace(*type.enum_def) + \
828                              "UnionTableOffset";
829         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
830                lifetime + ", flatbuffers::ForwardsUOffset<"
831                "flatbuffers::Table<" + lifetime + ">>>>";
832       }
833     }
834     return "INVALID_CODE_GENERATION"; // for return analysis
835   }
836 
TableBuilderArgsDefaultValue(const FieldDef & field)837   std::string TableBuilderArgsDefaultValue(const FieldDef &field) {
838     return GetDefaultScalarValue(field);
839   }
TableBuilderAddFuncDefaultValue(const FieldDef & field)840   std::string TableBuilderAddFuncDefaultValue(const FieldDef &field) {
841     switch (GetFullType(field.value.type)) {
842       case ftUnionKey:
843       case ftEnumKey: {
844         const std::string basetype = GetTypeBasic(field.value.type);
845         return GetDefaultScalarValue(field);
846       }
847 
848       default: { return GetDefaultScalarValue(field); }
849     }
850   }
851 
TableBuilderArgsAddFuncType(const FieldDef & field,const std::string lifetime)852   std::string TableBuilderArgsAddFuncType(const FieldDef &field,
853                                           const std::string lifetime) {
854     const Type& type = field.value.type;
855 
856     switch (GetFullType(field.value.type)) {
857       case ftVectorOfStruct: {
858         const auto typname = WrapInNameSpace(*type.struct_def);
859         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
860                ", " + typname + ">>";
861       }
862       case ftVectorOfTable: {
863         const auto typname = WrapInNameSpace(*type.struct_def);
864         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
865                ", flatbuffers::ForwardsUOffset<" + typname + \
866                "<" + lifetime + ">>>>";
867       }
868       case ftVectorOfInteger:
869       case ftVectorOfFloat: {
870         const auto typname = GetTypeBasic(type.VectorType());
871         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
872                ", " + typname + ">>";
873       }
874       case ftVectorOfBool: {
875         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
876                ", bool>>";
877       }
878       case ftVectorOfString: {
879         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
880                ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
881       }
882       case ftVectorOfEnumKey: {
883         const auto typname = WrapInNameSpace(*type.enum_def);
884         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
885                ", " + typname + ">>";
886       }
887       case ftVectorOfUnionValue: {
888         const auto typname = WrapInNameSpace(*type.enum_def);
889         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
890                ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + \
891                lifetime + ">>>";
892       }
893       case ftEnumKey: {
894         const auto typname = WrapInNameSpace(*type.enum_def);
895         return typname;
896       }
897       case ftStruct: {
898         const auto typname = WrapInNameSpace(*type.struct_def);
899         return "&" + lifetime + " " + typname + "";
900       }
901       case ftTable: {
902         const auto typname = WrapInNameSpace(*type.struct_def);
903         return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
904       }
905       case ftInteger:
906       case ftFloat: {
907         const auto typname = GetTypeBasic(type);
908         return typname;
909       }
910       case ftBool: {
911         return "bool";
912       }
913       case ftString: {
914         return "flatbuffers::WIPOffset<&" + lifetime + " str>";
915       }
916       case ftUnionKey: {
917         const auto typname = WrapInNameSpace(*type.enum_def);
918         return typname;
919       }
920       case ftUnionValue: {
921         const auto typname = WrapInNameSpace(*type.enum_def);
922         return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
923       }
924     }
925 
926     return "INVALID_CODE_GENERATION"; // for return analysis
927   }
928 
TableBuilderArgsAddFuncBody(const FieldDef & field)929   std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
930     const Type& type = field.value.type;
931 
932     switch (GetFullType(field.value.type)) {
933       case ftInteger:
934       case ftFloat: {
935         const auto typname = GetTypeBasic(field.value.type);
936         return "self.fbb_.push_slot::<" + typname + ">";
937       }
938       case ftBool: {
939         return "self.fbb_.push_slot::<bool>";
940       }
941 
942       case ftEnumKey:
943       case ftUnionKey: {
944         const auto underlying_typname = GetTypeBasic(type);
945         return "self.fbb_.push_slot::<" + underlying_typname + ">";
946       }
947 
948       case ftStruct: {
949         const std::string typname = WrapInNameSpace(*type.struct_def);
950         return "self.fbb_.push_slot_always::<&" + typname + ">";
951       }
952       case ftTable: {
953         const auto typname = WrapInNameSpace(*type.struct_def);
954         return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" + \
955                typname +  ">>";
956       }
957 
958       case ftUnionValue:
959       case ftString:
960       case ftVectorOfInteger:
961       case ftVectorOfFloat:
962       case ftVectorOfBool:
963       case ftVectorOfEnumKey:
964       case ftVectorOfStruct:
965       case ftVectorOfTable:
966       case ftVectorOfString:
967       case ftVectorOfUnionValue: {
968         return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
969       }
970     }
971     return "INVALID_CODE_GENERATION"; // for return analysis
972   }
973 
GenTableAccessorFuncReturnType(const FieldDef & field,const std::string lifetime)974   std::string GenTableAccessorFuncReturnType(const FieldDef &field,
975                                              const std::string lifetime) {
976     const Type& type = field.value.type;
977 
978     switch (GetFullType(field.value.type)) {
979       case ftInteger:
980       case ftFloat: {
981         const auto typname = GetTypeBasic(type);
982         return typname;
983       }
984       case ftBool: {
985         return "bool";
986       }
987       case ftStruct: {
988         const auto typname = WrapInNameSpace(*type.struct_def);
989         return WrapInOptionIfNotRequired("&" + lifetime + " " + typname, field.required);
990       }
991       case ftTable: {
992         const auto typname = WrapInNameSpace(*type.struct_def);
993         return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">", field.required);
994       }
995       case ftEnumKey:
996       case ftUnionKey: {
997         const auto typname = WrapInNameSpace(*type.enum_def);
998         return typname;
999       }
1000 
1001       case ftUnionValue: {
1002         return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">", field.required);
1003       }
1004       case ftString: {
1005          return WrapInOptionIfNotRequired("&" + lifetime + " str", field.required);
1006       }
1007       case ftVectorOfInteger:
1008       case ftVectorOfFloat: {
1009         const auto typname = GetTypeBasic(type.VectorType());
1010         if (IsOneByte(type.VectorType().base_type)) {
1011           return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
1012         }
1013         return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
1014       }
1015       case ftVectorOfBool: {
1016         return WrapInOptionIfNotRequired("&" + lifetime + " [bool]", field.required);
1017       }
1018       case ftVectorOfEnumKey: {
1019         const auto typname = WrapInNameSpace(*type.enum_def);
1020         return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
1021       }
1022       case ftVectorOfStruct: {
1023         const auto typname = WrapInNameSpace(*type.struct_def);
1024         return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
1025       }
1026       case ftVectorOfTable: {
1027         const auto typname = WrapInNameSpace(*type.struct_def);
1028         return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<" + \
1029                typname + "<" + lifetime + ">>>", field.required);
1030       }
1031       case ftVectorOfString: {
1032         return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<&" + \
1033                lifetime + " str>>", field.required);
1034       }
1035       case ftVectorOfUnionValue: {
1036         FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1037         // TODO(rw): when we do support these, we should consider using the
1038         //           Into trait to convert tables to typesafe union values.
1039         return "INVALID_CODE_GENERATION"; // for return analysis
1040       }
1041     }
1042     return "INVALID_CODE_GENERATION"; // for return analysis
1043   }
1044 
GenTableAccessorFuncBody(const FieldDef & field,const std::string lifetime,const std::string offset_prefix)1045   std::string GenTableAccessorFuncBody(const FieldDef &field,
1046                                        const std::string lifetime,
1047                                        const std::string offset_prefix) {
1048     const std::string offset_name = offset_prefix + "::" + \
1049                                     GetFieldOffsetName(field);
1050     const Type& type = field.value.type;
1051 
1052     switch (GetFullType(field.value.type)) {
1053       case ftInteger:
1054       case ftFloat:
1055       case ftBool: {
1056         const auto typname = GetTypeBasic(type);
1057         const auto default_value = GetDefaultScalarValue(field);
1058         return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + \
1059                default_value + ")).unwrap()";
1060       }
1061       case ftStruct: {
1062         const auto typname = WrapInNameSpace(*type.struct_def);
1063         return AddUnwrapIfRequired("self._tab.get::<" + typname + ">(" + offset_name + ", None)", field.required);
1064       }
1065       case ftTable: {
1066         const auto typname = WrapInNameSpace(*type.struct_def);
1067         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + \
1068                typname + "<" + lifetime + ">>>(" + offset_name + ", None)", field.required);
1069       }
1070       case ftUnionValue: {
1071         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1072                "flatbuffers::Table<" + lifetime + ">>>(" + offset_name + \
1073                ", None)", field.required);
1074       }
1075       case ftUnionKey:
1076       case ftEnumKey: {
1077         const auto underlying_typname = GetTypeBasic(type);
1078         const auto typname = WrapInNameSpace(*type.enum_def);
1079         const auto default_value = GetDefaultScalarValue(field);
1080         return "self._tab.get::<" + typname + ">(" + offset_name + \
1081                ", Some(" + default_value + ")).unwrap()";
1082       }
1083       case ftString: {
1084         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" + \
1085                offset_name + ", None)", field.required);
1086       }
1087 
1088       case ftVectorOfInteger:
1089       case ftVectorOfFloat: {
1090         const auto typname = GetTypeBasic(type.VectorType());
1091         std::string s = "self._tab.get::<flatbuffers::ForwardsUOffset<"
1092                         "flatbuffers::Vector<" + lifetime + ", " + typname + \
1093                         ">>>(" + offset_name + ", None)";
1094         // single-byte values are safe to slice
1095         if (IsOneByte(type.VectorType().base_type)) {
1096           s += ".map(|v| v.safe_slice())";
1097         }
1098         return AddUnwrapIfRequired(s, field.required);
1099       }
1100       case ftVectorOfBool: {
1101         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1102                "flatbuffers::Vector<" + lifetime + ", bool>>>(" + \
1103                offset_name + ", None).map(|v| v.safe_slice())", field.required);
1104       }
1105       case ftVectorOfEnumKey: {
1106         const auto typname = WrapInNameSpace(*type.enum_def);
1107         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1108                "flatbuffers::Vector<" + lifetime + ", " + typname + ">>>(" + \
1109                offset_name + ", None)", field.required);
1110       }
1111       case ftVectorOfStruct: {
1112         const auto typname = WrapInNameSpace(*type.struct_def);
1113         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1114                "flatbuffers::Vector<" + typname + ">>>(" + \
1115                offset_name + ", None).map(|v| v.safe_slice() )", field.required);
1116       }
1117       case ftVectorOfTable: {
1118         const auto typname = WrapInNameSpace(*type.struct_def);
1119         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1120                "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + typname + \
1121                "<" + lifetime + ">>>>>(" + offset_name + ", None)", field.required);
1122       }
1123       case ftVectorOfString: {
1124         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1125                "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \
1126                lifetime + " str>>>>(" + offset_name + ", None)", field.required);
1127       }
1128       case ftVectorOfUnionValue: {
1129         FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1130         return "INVALID_CODE_GENERATION"; // for return analysis
1131       }
1132     }
1133     return "INVALID_CODE_GENERATION"; // for return analysis
1134   }
1135 
TableFieldReturnsOption(const Type & type)1136   bool TableFieldReturnsOption(const Type& type) {
1137     switch (GetFullType(type)) {
1138       case ftInteger:
1139       case ftFloat:
1140       case ftBool:
1141       case ftEnumKey:
1142       case ftUnionKey:
1143         return false;
1144       default: return true;
1145     }
1146   }
1147 
1148   // Generate an accessor struct, builder struct, and create function for a
1149   // table.
GenTable(const StructDef & struct_def)1150   void GenTable(const StructDef &struct_def) {
1151     code_.SetValue("STRUCT_NAME", Name(struct_def));
1152     code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1153     code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
1154 
1155     // Generate an offset type, the base type, the Follow impl, and the
1156     // init_from_table impl.
1157     code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
1158     code_ += "#[derive(Copy, Clone, Debug, PartialEq)]";
1159     code_ += "";
1160 
1161     GenComment(struct_def.doc_comment);
1162 
1163     code_ += "pub struct {{STRUCT_NAME}}<'a> {";
1164     code_ += "  pub _tab: flatbuffers::Table<'a>,";
1165     code_ += "}";
1166     code_ += "";
1167     code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
1168     code_ += "    type Inner = {{STRUCT_NAME}}<'a>;";
1169     code_ += "    #[inline]";
1170     code_ += "    fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1171     code_ += "        Self {";
1172     code_ += "            _tab: flatbuffers::Table { buf: buf, loc: loc },";
1173     code_ += "        }";
1174     code_ += "    }";
1175     code_ += "}";
1176     code_ += "";
1177     code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
1178     code_ += "    #[inline]";
1179     code_ += "    pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
1180              "Self {";
1181     code_ += "        {{STRUCT_NAME}} {";
1182     code_ += "            _tab: table,";
1183     code_ += "        }";
1184     code_ += "    }";
1185 
1186     // Generate a convenient create* function that uses the above builder
1187     // to create a table in one function call.
1188     code_.SetValue("MAYBE_US",
1189         struct_def.fields.vec.size() == 0 ? "_" : "");
1190     code_.SetValue("MAYBE_LT",
1191         TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
1192     code_ += "    #[allow(unused_mut)]";
1193     code_ += "    pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
1194     code_ += "        _fbb: "
1195              "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1196     code_ += "        {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
1197              " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
1198 
1199     code_ += "      let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
1200     for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1201          size; size /= 2) {
1202       for (auto it = struct_def.fields.vec.rbegin();
1203            it != struct_def.fields.vec.rend(); ++it) {
1204         const auto &field = **it;
1205         // TODO(rw): fully understand this sortbysize usage
1206         if (!field.deprecated && (!struct_def.sortbysize ||
1207                                   size == SizeOf(field.value.type.base_type))) {
1208           code_.SetValue("FIELD_NAME", Name(field));
1209           if (TableFieldReturnsOption(field.value.type)) {
1210             code_ += "      if let Some(x) = args.{{FIELD_NAME}} "
1211                      "{ builder.add_{{FIELD_NAME}}(x); }";
1212           } else {
1213             code_ += "      builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
1214           }
1215         }
1216       }
1217     }
1218     code_ += "      builder.finish()";
1219     code_ += "    }";
1220     code_ += "";
1221 
1222     // Generate field id constants.
1223     if (struct_def.fields.vec.size() > 0) {
1224       for (auto it = struct_def.fields.vec.begin();
1225            it != struct_def.fields.vec.end(); ++it) {
1226         const auto &field = **it;
1227         if (field.deprecated) {
1228           // Deprecated fields won't be accessible.
1229           continue;
1230         }
1231 
1232         code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1233         code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
1234         code_ += "    pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1235                  "{{OFFSET_VALUE}};";
1236       }
1237       code_ += "";
1238     }
1239 
1240     // Generate the accessors. Each has one of two forms:
1241     //
1242     // If a value can be None:
1243     //   pub fn name(&'a self) -> Option<user_facing_type> {
1244     //     self._tab.get::<internal_type>(offset, defaultval)
1245     //   }
1246     //
1247     // If a value is always Some:
1248     //   pub fn name(&'a self) -> user_facing_type {
1249     //     self._tab.get::<internal_type>(offset, defaultval).unwrap()
1250     //   }
1251     const auto offset_prefix = Name(struct_def);
1252     for (auto it = struct_def.fields.vec.begin();
1253          it != struct_def.fields.vec.end(); ++it) {
1254       const auto &field = **it;
1255       if (field.deprecated) {
1256         // Deprecated fields won't be accessible.
1257         continue;
1258       }
1259 
1260       code_.SetValue("FIELD_NAME", Name(field));
1261       code_.SetValue("RETURN_TYPE",
1262                      GenTableAccessorFuncReturnType(field, "'a"));
1263       code_.SetValue("FUNC_BODY",
1264                      GenTableAccessorFuncBody(field, "'a", offset_prefix));
1265 
1266       GenComment(field.doc_comment, "  ");
1267       code_ += "  #[inline]";
1268       code_ += "  pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
1269       code_ += "    {{FUNC_BODY}}";
1270       code_ += "  }";
1271 
1272       // Generate a comparison function for this field if it is a key.
1273       if (field.key) {
1274         GenKeyFieldMethods(field);
1275       }
1276 
1277       // Generate a nested flatbuffer field, if applicable.
1278       auto nested = field.attributes.Lookup("nested_flatbuffer");
1279       if (nested) {
1280         std::string qualified_name = nested->constant;
1281         auto nested_root = parser_.LookupStruct(nested->constant);
1282         if (nested_root == nullptr) {
1283           qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1284               nested->constant);
1285           nested_root = parser_.LookupStruct(qualified_name);
1286         }
1287         FLATBUFFERS_ASSERT(nested_root);  // Guaranteed to exist by parser.
1288         (void)nested_root;
1289 
1290         code_.SetValue("OFFSET_NAME",
1291                        offset_prefix + "::" + GetFieldOffsetName(field));
1292         code_ += "  pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> "
1293                  " Option<{{STRUCT_NAME}}<'a>> {";
1294         code_ += "     match self.{{FIELD_NAME}}() {";
1295         code_ += "         None => { None }";
1296         code_ += "         Some(data) => {";
1297         code_ += "             use self::flatbuffers::Follow;";
1298         code_ += "             Some(<flatbuffers::ForwardsUOffset"
1299                  "<{{STRUCT_NAME}}<'a>>>::follow(data, 0))";
1300         code_ += "         },";
1301         code_ += "     }";
1302         code_ += "  }";
1303       }
1304     }
1305 
1306     // Explicit specializations for union accessors
1307     for (auto it = struct_def.fields.vec.begin();
1308          it != struct_def.fields.vec.end(); ++it) {
1309       const auto &field = **it;
1310       if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
1311         continue;
1312       }
1313 
1314       auto u = field.value.type.enum_def;
1315 
1316       code_.SetValue("FIELD_NAME", Name(field));
1317 
1318       for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
1319         auto &ev = **u_it;
1320         if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1321 
1322         auto table_init_type = WrapInNameSpace(
1323           ev.union_type.struct_def->defined_namespace,
1324           ev.union_type.struct_def->name);
1325 
1326           code_.SetValue("U_ELEMENT_ENUM_TYPE",
1327               WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
1328         code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type);
1329         code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
1330 
1331         code_ += "  #[inline]";
1332         code_ += "  #[allow(non_snake_case)]";
1333         code_ += "  pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
1334                  "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
1335         code_ += "    if self.{{FIELD_NAME}}_type() == {{U_ELEMENT_ENUM_TYPE}} {";
1336         code_ += "      self.{{FIELD_NAME}}().map(|u| "
1337                  "{{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
1338         code_ += "    } else {";
1339         code_ += "      None";
1340         code_ += "    }";
1341         code_ += "  }";
1342         code_ += "";
1343       }
1344     }
1345 
1346     code_ += "}";  // End of table impl.
1347     code_ += "";
1348 
1349     // Generate an args struct:
1350     code_.SetValue("MAYBE_LT",
1351         TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
1352     code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1353     for (auto it = struct_def.fields.vec.begin();
1354          it != struct_def.fields.vec.end(); ++it) {
1355       const auto &field = **it;
1356       if (!field.deprecated) {
1357         code_.SetValue("PARAM_NAME", Name(field));
1358         code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a "));
1359         code_ += "    pub {{PARAM_NAME}}: {{PARAM_TYPE}},";
1360       }
1361     }
1362     code_ += "}";
1363 
1364     // Generate an impl of Default for the *Args type:
1365     code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1366     code_ += "    #[inline]";
1367     code_ += "    fn default() -> Self {";
1368     code_ += "        {{STRUCT_NAME}}Args {";
1369     for (auto it = struct_def.fields.vec.begin();
1370         it != struct_def.fields.vec.end(); ++it) {
1371       const auto &field = **it;
1372       if (!field.deprecated) {
1373         code_.SetValue("PARAM_VALUE", TableBuilderArgsDefaultValue(field));
1374         code_.SetValue("REQ", field.required ? " // required field" : "");
1375         code_.SetValue("PARAM_NAME", Name(field));
1376         code_ += "            {{PARAM_NAME}}: {{PARAM_VALUE}},{{REQ}}";
1377       }
1378     }
1379     code_ += "        }";
1380     code_ += "    }";
1381     code_ += "}";
1382 
1383     // Generate a builder struct:
1384     code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
1385     code_ += "  fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1386     code_ += "  start_: flatbuffers::WIPOffset<"
1387              "flatbuffers::TableUnfinishedWIPOffset>,";
1388     code_ += "}";
1389 
1390     // Generate builder functions:
1391     code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
1392     for (auto it = struct_def.fields.vec.begin();
1393          it != struct_def.fields.vec.end(); ++it) {
1394       const auto &field = **it;
1395       if (!field.deprecated) {
1396         const bool is_scalar = IsScalar(field.value.type.base_type);
1397 
1398         std::string offset = GetFieldOffsetName(field);
1399         std::string name = Name(field);
1400         std::string value = GetDefaultScalarValue(field);
1401 
1402         // Generate functions to add data, which take one of two forms.
1403         //
1404         // If a value has a default:
1405         //   fn add_x(x_: type) {
1406         //     fbb_.push_slot::<type>(offset, x_, Some(default));
1407         //   }
1408         //
1409         // If a value does not have a default:
1410         //   fn add_x(x_: type) {
1411         //     fbb_.push_slot_always::<type>(offset, x_);
1412         //   }
1413         code_.SetValue("FIELD_NAME", Name(field));
1414         code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
1415         code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
1416         code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
1417         code_ += "  #[inline]";
1418         code_ += "  pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
1419                  "{{FIELD_TYPE}}) {";
1420         if (is_scalar) {
1421           code_.SetValue("FIELD_DEFAULT_VALUE",
1422                          TableBuilderAddFuncDefaultValue(field));
1423           code_ += "    {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
1424                    "{{FIELD_DEFAULT_VALUE}});";
1425         } else {
1426           code_ += "    {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
1427         }
1428         code_ += "  }";
1429       }
1430     }
1431 
1432     // Struct initializer (all fields required);
1433     code_ += "  #[inline]";
1434     code_ +=
1435         "  pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
1436         "{{STRUCT_NAME}}Builder<'a, 'b> {";
1437     code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
1438     code_ += "    let start = _fbb.start_table();";
1439     code_ += "    {{STRUCT_NAME}}Builder {";
1440     code_ += "      fbb_: _fbb,";
1441     code_ += "      start_: start,";
1442     code_ += "    }";
1443     code_ += "  }";
1444 
1445     // finish() function.
1446     code_ += "  #[inline]";
1447     code_ += "  pub fn finish(self) -> "
1448              "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
1449     code_ += "    let o = self.fbb_.end_table(self.start_);";
1450 
1451     for (auto it = struct_def.fields.vec.begin();
1452          it != struct_def.fields.vec.end(); ++it) {
1453       const auto &field = **it;
1454       if (!field.deprecated && field.required) {
1455         code_.SetValue("FIELD_NAME", MakeSnakeCase(Name(field)));
1456         code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1457         code_ += "    self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
1458                  "\"{{FIELD_NAME}}\");";
1459       }
1460     }
1461     code_ += "    flatbuffers::WIPOffset::new(o.value())";
1462     code_ += "  }";
1463     code_ += "}";
1464     code_ += "";
1465   }
1466 
1467   // Generate functions to compare tables and structs by key. This function
1468   // must only be called if the field key is defined.
GenKeyFieldMethods(const FieldDef & field)1469   void GenKeyFieldMethods(const FieldDef &field) {
1470     FLATBUFFERS_ASSERT(field.key);
1471 
1472     code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
1473 
1474     code_ += "  #[inline]";
1475     code_ += "  pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
1476              " bool {";
1477     code_ += "    self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
1478     code_ += "  }";
1479     code_ += "";
1480     code_ += "  #[inline]";
1481     code_ += "  pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
1482              " ::std::cmp::Ordering {";
1483     code_ += "    let key = self.{{FIELD_NAME}}();";
1484     code_ += "    key.cmp(&val)";
1485     code_ += "  }";
1486   }
1487 
1488   // Generate functions for accessing the root table object. This function
1489   // must only be called if the root table is defined.
GenRootTableFuncs(const StructDef & struct_def)1490   void GenRootTableFuncs(const StructDef &struct_def) {
1491     FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
1492     auto name = Name(struct_def);
1493 
1494     code_.SetValue("STRUCT_NAME", name);
1495     code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
1496     code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
1497 
1498     // The root datatype accessors:
1499     code_ += "#[inline]";
1500     code_ +=
1501         "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
1502         " -> {{STRUCT_NAME}}<'a> {";
1503     code_ += "  flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)";
1504     code_ += "}";
1505     code_ += "";
1506 
1507     code_ += "#[inline]";
1508     code_ += "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
1509              "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
1510     code_ += "  flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
1511              "(buf)";
1512     code_ += "}";
1513     code_ += "";
1514 
1515     if (parser_.file_identifier_.length()) {
1516       // Declare the identifier
1517       code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &'static str\\";
1518       code_ += " = \"" + parser_.file_identifier_ + "\";";
1519       code_ += "";
1520 
1521       // Check if a buffer has the identifier.
1522       code_ += "#[inline]";
1523       code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
1524       code_ += "(buf: &[u8]) -> bool {";
1525       code_ += "  return flatbuffers::buffer_has_identifier(buf, \\";
1526       code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false);";
1527       code_ += "}";
1528       code_ += "";
1529       code_ += "#[inline]";
1530       code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
1531       code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
1532       code_ += "  return flatbuffers::buffer_has_identifier(buf, \\";
1533       code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true);";
1534       code_ += "}";
1535       code_ += "";
1536     }
1537 
1538     if (parser_.file_extension_.length()) {
1539       // Return the extension
1540       code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &'static str = \\";
1541       code_ += "\"" + parser_.file_extension_ + "\";";
1542       code_ += "";
1543     }
1544 
1545     // Finish a buffer with a given root object:
1546     code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1547     code_ += "#[inline]";
1548     code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
1549     code_ += "    fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1550     code_ += "    root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1551     if (parser_.file_identifier_.length()) {
1552       code_ += "  fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1553     } else {
1554       code_ += "  fbb.finish(root, None);";
1555     }
1556     code_ += "}";
1557     code_ += "";
1558     code_ += "#[inline]";
1559     code_ += "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
1560              "<'a, 'b>("
1561              "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
1562              "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1563     if (parser_.file_identifier_.length()) {
1564       code_ += "  fbb.finish_size_prefixed(root, "
1565                "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1566     } else {
1567       code_ += "  fbb.finish_size_prefixed(root, None);";
1568     }
1569     code_ += "}";
1570   }
1571 
GenPadding(const FieldDef & field,std::string * code_ptr,int * id,const std::function<void (int bits,std::string * code_ptr,int * id)> & f)1572   static void GenPadding(
1573       const FieldDef &field, std::string *code_ptr, int *id,
1574       const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
1575     if (field.padding) {
1576       for (int i = 0; i < 4; i++) {
1577         if (static_cast<int>(field.padding) & (1 << i)) {
1578           f((1 << i) * 8, code_ptr, id);
1579         }
1580       }
1581       assert(!(field.padding & ~0xF));
1582     }
1583   }
1584 
PaddingDefinition(int bits,std::string * code_ptr,int * id)1585   static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
1586     *code_ptr += "  padding" + NumToString((*id)++) + "__: u" + \
1587                  NumToString(bits) + ",";
1588   }
1589 
PaddingInitializer(int bits,std::string * code_ptr,int * id)1590   static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
1591     (void)bits;
1592     *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
1593   }
1594 
1595   // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def)1596   void GenStruct(const StructDef &struct_def) {
1597     // Generates manual padding and alignment.
1598     // Variables are private because they contain little endian data on all
1599     // platforms.
1600     GenComment(struct_def.doc_comment);
1601     code_.SetValue("ALIGN", NumToString(struct_def.minalign));
1602     code_.SetValue("STRUCT_NAME", Name(struct_def));
1603 
1604     code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
1605     code_ += "#[repr(C, align({{ALIGN}}))]";
1606 
1607     // PartialEq is useful to derive because we can correctly compare structs
1608     // for equality by just comparing their underlying byte data. This doesn't
1609     // hold for PartialOrd/Ord.
1610     code_ += "#[derive(Clone, Copy, Debug, PartialEq)]";
1611     code_ += "pub struct {{STRUCT_NAME}} {";
1612 
1613     int padding_id = 0;
1614     for (auto it = struct_def.fields.vec.begin();
1615          it != struct_def.fields.vec.end(); ++it) {
1616       const auto &field = **it;
1617       code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
1618       code_.SetValue("FIELD_NAME", Name(field));
1619       code_ += "  {{FIELD_NAME}}_: {{FIELD_TYPE}},";
1620 
1621       if (field.padding) {
1622         std::string padding;
1623         GenPadding(field, &padding, &padding_id, PaddingDefinition);
1624         code_ += padding;
1625       }
1626     }
1627 
1628     code_ += "} // pub struct {{STRUCT_NAME}}";
1629 
1630     // Generate impls for SafeSliceAccess (because all structs are endian-safe),
1631     // Follow for the value type, Follow for the reference type, Push for the
1632     // value type, and Push for the reference type.
1633     code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
1634     code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
1635     code_ += "  type Inner = &'a {{STRUCT_NAME}};";
1636     code_ += "  #[inline]";
1637     code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1638     code_ += "    <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
1639     code_ += "  }";
1640     code_ += "}";
1641     code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
1642     code_ += "  type Inner = &'a {{STRUCT_NAME}};";
1643     code_ += "  #[inline]";
1644     code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1645     code_ += "    flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
1646     code_ += "  }";
1647     code_ += "}";
1648     code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
1649     code_ += "    type Output = {{STRUCT_NAME}};";
1650     code_ += "    #[inline]";
1651     code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1652     code_ += "        let src = unsafe {";
1653     code_ += "            ::std::slice::from_raw_parts("
1654              "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1655     code_ += "        };";
1656     code_ += "        dst.copy_from_slice(src);";
1657     code_ += "    }";
1658     code_ += "}";
1659     code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
1660     code_ += "    type Output = {{STRUCT_NAME}};";
1661     code_ += "";
1662     code_ += "    #[inline]";
1663     code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1664     code_ += "        let src = unsafe {";
1665     code_ += "            ::std::slice::from_raw_parts("
1666              "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1667     code_ += "        };";
1668     code_ += "        dst.copy_from_slice(src);";
1669     code_ += "    }";
1670     code_ += "}";
1671     code_ += "";
1672     code_ += "";
1673 
1674     // Generate a constructor that takes all fields as arguments.
1675     code_ += "impl {{STRUCT_NAME}} {";
1676     std::string arg_list;
1677     std::string init_list;
1678     padding_id = 0;
1679     for (auto it = struct_def.fields.vec.begin();
1680          it != struct_def.fields.vec.end(); ++it) {
1681       const auto &field = **it;
1682       const auto member_name = Name(field) + "_";
1683       const auto reference = StructMemberAccessNeedsCopy(field.value.type)
1684                              ? "" : "&'a ";
1685       const auto arg_name = "_" + Name(field);
1686       const auto arg_type = reference + GetTypeGet(field.value.type);
1687 
1688       if (it != struct_def.fields.vec.begin()) {
1689         arg_list += ", ";
1690       }
1691       arg_list += arg_name + ": ";
1692       arg_list += arg_type;
1693       init_list += "      " + member_name;
1694       if (StructMemberAccessNeedsCopy(field.value.type)) {
1695         init_list += ": " + arg_name + ".to_little_endian(),\n";
1696       } else {
1697         init_list += ": *" + arg_name + ",\n";
1698       }
1699     }
1700 
1701     code_.SetValue("ARG_LIST", arg_list);
1702     code_.SetValue("INIT_LIST", init_list);
1703     code_ += "  pub fn new<'a>({{ARG_LIST}}) -> Self {";
1704     code_ += "    {{STRUCT_NAME}} {";
1705     code_ += "{{INIT_LIST}}";
1706     padding_id = 0;
1707     for (auto it = struct_def.fields.vec.begin();
1708          it != struct_def.fields.vec.end(); ++it) {
1709       const auto &field = **it;
1710       if (field.padding) {
1711         std::string padding;
1712         GenPadding(field, &padding, &padding_id, PaddingInitializer);
1713         code_ += "      " + padding;
1714       }
1715     }
1716     code_ += "    }";
1717     code_ += "  }";
1718 
1719     // Generate accessor methods for the struct.
1720     for (auto it = struct_def.fields.vec.begin();
1721          it != struct_def.fields.vec.end(); ++it) {
1722       const auto &field = **it;
1723 
1724       auto field_type = TableBuilderArgsAddFuncType(field, "'a");
1725       auto member = "self." + Name(field) + "_";
1726       auto value = StructMemberAccessNeedsCopy(field.value.type) ?
1727         member + ".from_little_endian()" : member;
1728 
1729       code_.SetValue("FIELD_NAME", Name(field));
1730       code_.SetValue("FIELD_TYPE", field_type);
1731       code_.SetValue("FIELD_VALUE", value);
1732       code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
1733 
1734       GenComment(field.doc_comment, "  ");
1735       code_ += "  pub fn {{FIELD_NAME}}<'a>(&'a self) -> {{FIELD_TYPE}} {";
1736       code_ += "    {{REF}}{{FIELD_VALUE}}";
1737       code_ += "  }";
1738 
1739       // Generate a comparison function for this field if it is a key.
1740       if (field.key) {
1741         GenKeyFieldMethods(field);
1742       }
1743     }
1744     code_ += "}";
1745     code_ += "";
1746   }
1747 
GenNamespaceImports(const int white_spaces)1748   void GenNamespaceImports(const int white_spaces) {
1749       std::string indent = std::string(white_spaces, ' ');
1750       code_ += "";
1751       code_ += indent + "use std::mem;";
1752       code_ += indent + "use std::cmp::Ordering;";
1753       code_ += "";
1754       code_ += indent + "extern crate flatbuffers;";
1755       code_ += indent + "use self::flatbuffers::EndianScalar;";
1756   }
1757 
1758   // Set up the correct namespace. This opens a namespace if the current
1759   // namespace is different from the target namespace. This function
1760   // closes and opens the namespaces only as necessary.
1761   //
1762   // The file must start and end with an empty (or null) namespace so that
1763   // namespaces are properly opened and closed.
SetNameSpace(const Namespace * ns)1764   void SetNameSpace(const Namespace *ns) {
1765     if (cur_name_space_ == ns) { return; }
1766 
1767     // Compute the size of the longest common namespace prefix.
1768     // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
1769     // the common prefix is A::B:: and we have old_size = 4, new_size = 5
1770     // and common_prefix_size = 2
1771     size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
1772     size_t new_size = ns ? ns->components.size() : 0;
1773 
1774     size_t common_prefix_size = 0;
1775     while (common_prefix_size < old_size && common_prefix_size < new_size &&
1776            ns->components[common_prefix_size] ==
1777                cur_name_space_->components[common_prefix_size]) {
1778       common_prefix_size++;
1779     }
1780 
1781     // Close cur_name_space in reverse order to reach the common prefix.
1782     // In the previous example, D then C are closed.
1783     for (size_t j = old_size; j > common_prefix_size; --j) {
1784       code_ += "}  // pub mod " + cur_name_space_->components[j - 1];
1785     }
1786     if (old_size != common_prefix_size) { code_ += ""; }
1787 
1788     // open namespace parts to reach the ns namespace
1789     // in the previous example, E, then F, then G are opened
1790     for (auto j = common_prefix_size; j != new_size; ++j) {
1791       code_ += "#[allow(unused_imports, dead_code)]";
1792       code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
1793       // Generate local namespace imports.
1794       GenNamespaceImports(2);
1795     }
1796     if (new_size != common_prefix_size) { code_ += ""; }
1797 
1798     cur_name_space_ = ns;
1799   }
1800 };
1801 
1802 }  // namespace rust
1803 
GenerateRust(const Parser & parser,const std::string & path,const std::string & file_name)1804 bool GenerateRust(const Parser &parser, const std::string &path,
1805                   const std::string &file_name) {
1806   rust::RustGenerator generator(parser, path, file_name);
1807   return generator.generate();
1808 }
1809 
RustMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)1810 std::string RustMakeRule(const Parser &parser, const std::string &path,
1811                          const std::string &file_name) {
1812   std::string filebase =
1813       flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
1814   std::string make_rule = GeneratedFileName(path, filebase) + ": ";
1815 
1816   auto included_files = parser.GetIncludedFilesRecursive(file_name);
1817   for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1818     make_rule += " " + *it;
1819   }
1820   return make_rule;
1821 }
1822 
1823 }  // namespace flatbuffers
1824 
1825 // TODO(rw): Generated code should import other generated files.
1826 // TODO(rw): Generated code should refer to namespaces in included files in a
1827 //           way that makes them referrable.
1828 // TODO(rw): Generated code should indent according to nesting level.
1829 // TODO(rw): Generated code should generate endian-safe Debug impls.
1830 // TODO(rw): Generated code could use a Rust-only enum type to access unions,
1831 //           instead of making the user use _type() to manually switch.
1832