• 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, 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.vec.begin(); it != enum_def.vals.vec.end();
595          ++it) {
596       const auto &ev = **it;
597 
598       GenComment(ev.doc_comment, "  ");
599       code_.SetValue("KEY", Name(ev));
600       code_.SetValue("VALUE", NumToString(ev.value));
601       code_ += "  {{KEY}} = {{VALUE}},";
602 
603       minv = !minv || minv->value > ev.value ? &ev : minv;
604       maxv = !maxv || maxv->value < ev.value ? &ev : maxv;
605       anyv |= ev.value;
606     }
607 
608     code_ += "";
609     code_ += "}";
610     code_ += "";
611 
612     code_.SetValue("ENUM_NAME", Name(enum_def));
613     code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
614     code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
615     code_.SetValue("ENUM_MIN_BASE_VALUE", NumToString(minv->value));
616     code_.SetValue("ENUM_MAX_BASE_VALUE", NumToString(maxv->value));
617 
618     // Generate enum constants, and impls for Follow, EndianScalar, and Push.
619     code_ += "const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
620     code_ += "{{ENUM_MIN_BASE_VALUE}};";
621     code_ += "const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
622     code_ += "{{ENUM_MAX_BASE_VALUE}};";
623     code_ += "";
624     code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
625     code_ += "  type Inner = Self;";
626     code_ += "  #[inline]";
627     code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
628     code_ += "    flatbuffers::read_scalar_at::<Self>(buf, loc)";
629     code_ += "  }";
630     code_ += "}";
631     code_ += "";
632     code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
633     code_ += "  #[inline]";
634     code_ += "  fn to_little_endian(self) -> Self {";
635     code_ += "    let n = {{BASE_TYPE}}::to_le(self as {{BASE_TYPE}});";
636     code_ += "    let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
637     code_ += "    unsafe { *p }";
638     code_ += "  }";
639     code_ += "  #[inline]";
640     code_ += "  fn from_little_endian(self) -> Self {";
641     code_ += "    let n = {{BASE_TYPE}}::from_le(self as {{BASE_TYPE}});";
642     code_ += "    let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
643     code_ += "    unsafe { *p }";
644     code_ += "  }";
645     code_ += "}";
646     code_ += "";
647     code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
648     code_ += "    type Output = {{ENUM_NAME}};";
649     code_ += "    #[inline]";
650     code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
651     code_ += "        flatbuffers::emplace_scalar::<{{ENUM_NAME}}>"
652              "(dst, *self);";
653     code_ += "    }";
654     code_ += "}";
655     code_ += "";
656 
657     // Generate an array of all enumeration values.
658     auto num_fields = NumToString(enum_def.vals.vec.size());
659     code_ += "#[allow(non_camel_case_types)]";
660     code_ += "const ENUM_VALUES_{{ENUM_NAME_CAPS}}:[{{ENUM_NAME}}; " +
661               num_fields + "] = [";
662     for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
663          ++it) {
664       const auto &ev = **it;
665       auto value = GetEnumValUse(enum_def, ev);
666       auto suffix = *it != enum_def.vals.vec.back() ? "," : "";
667       code_ += "  " + value + suffix;
668     }
669     code_ += "];";
670     code_ += "";
671 
672     // Generate a string table for enum values.
673     // Problem is, if values are very sparse that could generate really big
674     // tables. Ideally in that case we generate a map lookup instead, but for
675     // the moment we simply don't output a table at all.
676     auto range =
677         enum_def.vals.vec.back()->value - enum_def.vals.vec.front()->value + 1;
678     // Average distance between values above which we consider a table
679     // "too sparse". Change at will.
680     static const int kMaxSparseness = 5;
681     if (range / static_cast<int64_t>(enum_def.vals.vec.size()) <
682         kMaxSparseness) {
683       code_ += "#[allow(non_camel_case_types)]";
684       code_ += "const ENUM_NAMES_{{ENUM_NAME_CAPS}}:[&'static str; " +
685                 NumToString(range) + "] = [";
686 
687       auto val = enum_def.vals.vec.front()->value;
688       for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
689            ++it) {
690         const auto &ev = **it;
691         while (val++ != ev.value) { code_ += "    \"\","; }
692         auto suffix = *it != enum_def.vals.vec.back() ? "," : "";
693         code_ += "    \"" + Name(ev) + "\"" + suffix;
694       }
695       code_ += "];";
696       code_ += "";
697 
698       code_ += "pub fn enum_name_{{ENUM_NAME_SNAKE}}(e: {{ENUM_NAME}}) -> "
699                "&'static str {";
700 
701       code_ += "  let index: usize = e as usize\\";
702       if (enum_def.vals.vec.front()->value) {
703         auto vals = GetEnumValUse(enum_def, *enum_def.vals.vec.front());
704         code_ += " - " + vals + " as usize\\";
705       }
706       code_ += ";";
707 
708       code_ += "  ENUM_NAMES_{{ENUM_NAME_CAPS}}[index]";
709       code_ += "}";
710       code_ += "";
711     }
712 
713     if (enum_def.is_union) {
714       // Generate tyoesafe offset(s) for unions
715       code_.SetValue("NAME", Name(enum_def));
716       code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
717       code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
718     }
719   }
720 
GetFieldOffsetName(const FieldDef & field)721   std::string GetFieldOffsetName(const FieldDef &field) {
722     return "VT_" + MakeUpper(Name(field));
723   }
724 
GetDefaultConstant(const FieldDef & field)725   std::string GetDefaultConstant(const FieldDef &field) {
726     return field.value.type.base_type == BASE_TYPE_FLOAT
727                ? field.value.constant + ""
728                : field.value.constant;
729   }
730 
GetDefaultScalarValue(const FieldDef & field)731   std::string GetDefaultScalarValue(const FieldDef &field) {
732     switch (GetFullType(field.value.type)) {
733       case ftInteger: { return GetDefaultConstant(field); }
734       case ftFloat: { return GetDefaultConstant(field); }
735       case ftBool: {
736         return field.value.constant == "0" ? "false" : "true";
737       }
738       case ftUnionKey:
739       case ftEnumKey: {
740         auto ev = field.value.type.enum_def->ReverseLookup(
741             StringToInt(field.value.constant.c_str()), false);
742         assert(ev);
743         return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
744                                GetEnumValUse(*field.value.type.enum_def, *ev));
745       }
746 
747       // All pointer-ish types have a default value of None, because they are
748       // wrapped in Option.
749       default: { return "None"; }
750     }
751   }
752 
753   // Create the return type for fields in the *BuilderArgs structs that are
754   // used to create Tables.
755   //
756   // Note: we could make all inputs to the BuilderArgs be an Option, as well
757   // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
758   // know if the value is default or not, because there are three ways to
759   // return a default value:
760   // 1) return a stored value that happens to be the default,
761   // 2) return a hardcoded value because the relevant vtable field is not in
762   //    the vtable, or
763   // 3) return a hardcoded value because the vtable field value is set to zero.
TableBuilderArgsDefnType(const FieldDef & field,const std::string lifetime)764   std::string TableBuilderArgsDefnType(const FieldDef &field,
765                                        const std::string lifetime) {
766     const Type& type = field.value.type;
767 
768     switch (GetFullType(type)) {
769       case ftInteger:
770       case ftFloat:
771       case ftBool: {
772         const auto typname = GetTypeBasic(type);
773         return typname;
774       }
775       case ftStruct: {
776         const auto typname = WrapInNameSpace(*type.struct_def);
777         return "Option<&" + lifetime + " " + typname + ">";
778       }
779       case ftTable: {
780         const auto typname = WrapInNameSpace(*type.struct_def);
781         return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime + \
782                ">>>";
783       }
784       case ftString: {
785         return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
786       }
787       case ftEnumKey:
788       case ftUnionKey: {
789         const auto typname = WrapInNameSpace(*type.enum_def);
790         return typname;
791       }
792       case ftUnionValue: {
793         const auto typname = WrapInNameSpace(*type.enum_def);
794         return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
795       }
796 
797       case ftVectorOfInteger:
798       case ftVectorOfFloat: {
799         const auto typname = GetTypeBasic(type.VectorType());
800         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
801                lifetime + ",  " + typname + ">>>";
802       }
803       case ftVectorOfBool: {
804         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
805                lifetime + ", bool>>>";
806       }
807       case ftVectorOfEnumKey: {
808         const auto typname = WrapInNameSpace(*type.enum_def);
809         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
810                lifetime + ", " + typname + ">>>";
811       }
812       case ftVectorOfStruct: {
813         const auto typname = WrapInNameSpace(*type.struct_def);
814         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
815                lifetime + ", " + typname + ">>>";
816       }
817       case ftVectorOfTable: {
818         const auto typname = WrapInNameSpace(*type.struct_def);
819         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
820                lifetime + ", flatbuffers::ForwardsUOffset<" + typname + \
821                "<" + lifetime + ">>>>>";
822       }
823       case ftVectorOfString: {
824         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
825                lifetime + ", flatbuffers::ForwardsUOffset<&" + lifetime + \
826                " str>>>>";
827       }
828       case ftVectorOfUnionValue: {
829         const auto typname = WrapInNameSpace(*type.enum_def) + \
830                              "UnionTableOffset";
831         return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
832                lifetime + ", flatbuffers::ForwardsUOffset<"
833                "flatbuffers::Table<" + lifetime + ">>>>";
834       }
835     }
836     return "INVALID_CODE_GENERATION"; // for return analysis
837   }
838 
TableBuilderArgsDefaultValue(const FieldDef & field)839   std::string TableBuilderArgsDefaultValue(const FieldDef &field) {
840     return GetDefaultScalarValue(field);
841   }
TableBuilderAddFuncDefaultValue(const FieldDef & field)842   std::string TableBuilderAddFuncDefaultValue(const FieldDef &field) {
843     switch (GetFullType(field.value.type)) {
844       case ftUnionKey:
845       case ftEnumKey: {
846         const std::string basetype = GetTypeBasic(field.value.type);
847         return GetDefaultScalarValue(field);
848       }
849 
850       default: { return GetDefaultScalarValue(field); }
851     }
852   }
853 
TableBuilderArgsAddFuncType(const FieldDef & field,const std::string lifetime)854   std::string TableBuilderArgsAddFuncType(const FieldDef &field,
855                                           const std::string lifetime) {
856     const Type& type = field.value.type;
857 
858     switch (GetFullType(field.value.type)) {
859       case ftVectorOfStruct: {
860         const auto typname = WrapInNameSpace(*type.struct_def);
861         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
862                ", " + typname + ">>";
863       }
864       case ftVectorOfTable: {
865         const auto typname = WrapInNameSpace(*type.struct_def);
866         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
867                ", flatbuffers::ForwardsUOffset<" + typname + \
868                "<" + lifetime + ">>>>";
869       }
870       case ftVectorOfInteger:
871       case ftVectorOfFloat: {
872         const auto typname = GetTypeBasic(type.VectorType());
873         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
874                ", " + typname + ">>";
875       }
876       case ftVectorOfBool: {
877         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
878                ", bool>>";
879       }
880       case ftVectorOfString: {
881         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
882                ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
883       }
884       case ftVectorOfEnumKey: {
885         const auto typname = WrapInNameSpace(*type.enum_def);
886         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
887                ", " + typname + ">>";
888       }
889       case ftVectorOfUnionValue: {
890         const auto typname = WrapInNameSpace(*type.enum_def);
891         return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
892                ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + \
893                lifetime + ">>>";
894       }
895       case ftEnumKey: {
896         const auto typname = WrapInNameSpace(*type.enum_def);
897         return typname;
898       }
899       case ftStruct: {
900         const auto typname = WrapInNameSpace(*type.struct_def);
901         return "&" + lifetime + " " + typname + "";
902       }
903       case ftTable: {
904         const auto typname = WrapInNameSpace(*type.struct_def);
905         return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
906       }
907       case ftInteger:
908       case ftFloat: {
909         const auto typname = GetTypeBasic(type);
910         return typname;
911       }
912       case ftBool: {
913         return "bool";
914       }
915       case ftString: {
916         return "flatbuffers::WIPOffset<&" + lifetime + " str>";
917       }
918       case ftUnionKey: {
919         const auto typname = WrapInNameSpace(*type.enum_def);
920         return typname;
921       }
922       case ftUnionValue: {
923         const auto typname = WrapInNameSpace(*type.enum_def);
924         return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
925       }
926     }
927 
928     return "INVALID_CODE_GENERATION"; // for return analysis
929   }
930 
TableBuilderArgsAddFuncBody(const FieldDef & field)931   std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
932     const Type& type = field.value.type;
933 
934     switch (GetFullType(field.value.type)) {
935       case ftInteger:
936       case ftFloat: {
937         const auto typname = GetTypeBasic(field.value.type);
938         return "self.fbb_.push_slot::<" + typname + ">";
939       }
940       case ftBool: {
941         return "self.fbb_.push_slot::<bool>";
942       }
943 
944       case ftEnumKey:
945       case ftUnionKey: {
946         const auto underlying_typname = GetTypeBasic(type);
947         return "self.fbb_.push_slot::<" + underlying_typname + ">";
948       }
949 
950       case ftStruct: {
951         const std::string typname = WrapInNameSpace(*type.struct_def);
952         return "self.fbb_.push_slot_always::<&" + typname + ">";
953       }
954       case ftTable: {
955         const auto typname = WrapInNameSpace(*type.struct_def);
956         return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" + \
957                typname +  ">>";
958       }
959 
960       case ftUnionValue:
961       case ftString:
962       case ftVectorOfInteger:
963       case ftVectorOfFloat:
964       case ftVectorOfBool:
965       case ftVectorOfEnumKey:
966       case ftVectorOfStruct:
967       case ftVectorOfTable:
968       case ftVectorOfString:
969       case ftVectorOfUnionValue: {
970         return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
971       }
972     }
973     return "INVALID_CODE_GENERATION"; // for return analysis
974   }
975 
GenTableAccessorFuncReturnType(const FieldDef & field,const std::string lifetime)976   std::string GenTableAccessorFuncReturnType(const FieldDef &field,
977                                              const std::string lifetime) {
978     const Type& type = field.value.type;
979 
980     switch (GetFullType(field.value.type)) {
981       case ftInteger:
982       case ftFloat: {
983         const auto typname = GetTypeBasic(type);
984         return typname;
985       }
986       case ftBool: {
987         return "bool";
988       }
989       case ftStruct: {
990         const auto typname = WrapInNameSpace(*type.struct_def);
991         return WrapInOptionIfNotRequired("&" + lifetime + " " + typname, field.required);
992       }
993       case ftTable: {
994         const auto typname = WrapInNameSpace(*type.struct_def);
995         return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">", field.required);
996       }
997       case ftEnumKey:
998       case ftUnionKey: {
999         const auto typname = WrapInNameSpace(*type.enum_def);
1000         return typname;
1001       }
1002 
1003       case ftUnionValue: {
1004         return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">", field.required);
1005       }
1006       case ftString: {
1007          return WrapInOptionIfNotRequired("&" + lifetime + " str", field.required);
1008       }
1009       case ftVectorOfInteger:
1010       case ftVectorOfFloat: {
1011         const auto typname = GetTypeBasic(type.VectorType());
1012         if (IsOneByte(type.VectorType().base_type)) {
1013           return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
1014         }
1015         return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
1016       }
1017       case ftVectorOfBool: {
1018         return WrapInOptionIfNotRequired("&" + lifetime + " [bool]", field.required);
1019       }
1020       case ftVectorOfEnumKey: {
1021         const auto typname = WrapInNameSpace(*type.enum_def);
1022         return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
1023       }
1024       case ftVectorOfStruct: {
1025         const auto typname = WrapInNameSpace(*type.struct_def);
1026         return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
1027       }
1028       case ftVectorOfTable: {
1029         const auto typname = WrapInNameSpace(*type.struct_def);
1030         return WrapInOptionIfNotRequired("flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + \
1031                typname + "<" + lifetime + ">>>", field.required);
1032       }
1033       case ftVectorOfString: {
1034         return WrapInOptionIfNotRequired("flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \
1035                lifetime + " str>>", field.required);
1036       }
1037       case ftVectorOfUnionValue: {
1038         FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1039         // TODO(rw): when we do support these, we should consider using the
1040         //           Into trait to convert tables to typesafe union values.
1041         return "INVALID_CODE_GENERATION"; // for return analysis
1042       }
1043     }
1044     return "INVALID_CODE_GENERATION"; // for return analysis
1045   }
1046 
GenTableAccessorFuncBody(const FieldDef & field,const std::string lifetime,const std::string offset_prefix)1047   std::string GenTableAccessorFuncBody(const FieldDef &field,
1048                                        const std::string lifetime,
1049                                        const std::string offset_prefix) {
1050     const std::string offset_name = offset_prefix + "::" + \
1051                                     GetFieldOffsetName(field);
1052     const Type& type = field.value.type;
1053 
1054     switch (GetFullType(field.value.type)) {
1055       case ftInteger:
1056       case ftFloat:
1057       case ftBool: {
1058         const auto typname = GetTypeBasic(type);
1059         const auto default_value = GetDefaultScalarValue(field);
1060         return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + \
1061                default_value + ")).unwrap()";
1062       }
1063       case ftStruct: {
1064         const auto typname = WrapInNameSpace(*type.struct_def);
1065         return AddUnwrapIfRequired("self._tab.get::<" + typname + ">(" + offset_name + ", None)", field.required);
1066       }
1067       case ftTable: {
1068         const auto typname = WrapInNameSpace(*type.struct_def);
1069         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + \
1070                typname + "<" + lifetime + ">>>(" + offset_name + ", None)", field.required);
1071       }
1072       case ftUnionValue: {
1073         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1074                "flatbuffers::Table<" + lifetime + ">>>(" + offset_name + \
1075                ", None)", field.required);
1076       }
1077       case ftUnionKey:
1078       case ftEnumKey: {
1079         const auto underlying_typname = GetTypeBasic(type);
1080         const auto typname = WrapInNameSpace(*type.enum_def);
1081         const auto default_value = GetDefaultScalarValue(field);
1082         return "self._tab.get::<" + typname + ">(" + offset_name + \
1083                ", Some(" + default_value + ")).unwrap()";
1084       }
1085       case ftString: {
1086         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" + \
1087                offset_name + ", None)", field.required);
1088       }
1089 
1090       case ftVectorOfInteger:
1091       case ftVectorOfFloat: {
1092         const auto typname = GetTypeBasic(type.VectorType());
1093         std::string s = "self._tab.get::<flatbuffers::ForwardsUOffset<"
1094                         "flatbuffers::Vector<" + lifetime + ", " + typname + \
1095                         ">>>(" + offset_name + ", None)";
1096         // single-byte values are safe to slice
1097         if (IsOneByte(type.VectorType().base_type)) {
1098           s += ".map(|v| v.safe_slice())";
1099         }
1100         return AddUnwrapIfRequired(s, field.required);
1101       }
1102       case ftVectorOfBool: {
1103         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1104                "flatbuffers::Vector<" + lifetime + ", bool>>>(" + \
1105                offset_name + ", None).map(|v| v.safe_slice())", field.required);
1106       }
1107       case ftVectorOfEnumKey: {
1108         const auto typname = WrapInNameSpace(*type.enum_def);
1109         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1110                "flatbuffers::Vector<" + lifetime + ", " + typname + ">>>(" + \
1111                offset_name + ", None)", field.required);
1112       }
1113       case ftVectorOfStruct: {
1114         const auto typname = WrapInNameSpace(*type.struct_def);
1115         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1116                "flatbuffers::Vector<" + typname + ">>>(" + \
1117                offset_name + ", None).map(|v| v.safe_slice() )", field.required);
1118       }
1119       case ftVectorOfTable: {
1120         const auto typname = WrapInNameSpace(*type.struct_def);
1121         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1122                "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + typname + \
1123                "<" + lifetime + ">>>>>(" + offset_name + ", None)", field.required);
1124       }
1125       case ftVectorOfString: {
1126         return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1127                "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \
1128                lifetime + " str>>>>(" + offset_name + ", None)", field.required);
1129       }
1130       case ftVectorOfUnionValue: {
1131         FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1132         return "INVALID_CODE_GENERATION"; // for return analysis
1133       }
1134     }
1135     return "INVALID_CODE_GENERATION"; // for return analysis
1136   }
1137 
TableFieldReturnsOption(const Type & type)1138   bool TableFieldReturnsOption(const Type& type) {
1139     switch (GetFullType(type)) {
1140       case ftInteger:
1141       case ftFloat:
1142       case ftBool:
1143       case ftEnumKey:
1144       case ftUnionKey:
1145         return false;
1146       default: return true;
1147     }
1148   }
1149 
1150   // Generate an accessor struct, builder struct, and create function for a
1151   // table.
GenTable(const StructDef & struct_def)1152   void GenTable(const StructDef &struct_def) {
1153     GenComment(struct_def.doc_comment);
1154 
1155     code_.SetValue("STRUCT_NAME", Name(struct_def));
1156     code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1157     code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
1158 
1159     // Generate an offset type, the base type, the Follow impl, and the
1160     // init_from_table impl.
1161     code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
1162     code_ += "#[derive(Copy, Clone, Debug, PartialEq)]";
1163     code_ += "";
1164     code_ += "pub struct {{STRUCT_NAME}}<'a> {";
1165     code_ += "  pub _tab: flatbuffers::Table<'a>,";
1166     code_ += "}";
1167     code_ += "";
1168     code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
1169     code_ += "    type Inner = {{STRUCT_NAME}}<'a>;";
1170     code_ += "    #[inline]";
1171     code_ += "    fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1172     code_ += "        Self {";
1173     code_ += "            _tab: flatbuffers::Table { buf: buf, loc: loc },";
1174     code_ += "        }";
1175     code_ += "    }";
1176     code_ += "}";
1177     code_ += "";
1178     code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
1179     code_ += "    #[inline]";
1180     code_ += "    pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
1181              "Self {";
1182     code_ += "        {{STRUCT_NAME}} {";
1183     code_ += "            _tab: table,";
1184     code_ += "        }";
1185     code_ += "    }";
1186 
1187     // Generate a convenient create* function that uses the above builder
1188     // to create a table in one function call.
1189     code_.SetValue("MAYBE_US",
1190         struct_def.fields.vec.size() == 0 ? "_" : "");
1191     code_.SetValue("MAYBE_LT",
1192         TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
1193     code_ += "    #[allow(unused_mut)]";
1194     code_ += "    pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
1195     code_ += "        _fbb: "
1196              "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1197     code_ += "        {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
1198              " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
1199 
1200     code_ += "      let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
1201     for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1202          size; size /= 2) {
1203       for (auto it = struct_def.fields.vec.rbegin();
1204            it != struct_def.fields.vec.rend(); ++it) {
1205         const auto &field = **it;
1206         // TODO(rw): fully understand this sortbysize usage
1207         if (!field.deprecated && (!struct_def.sortbysize ||
1208                                   size == SizeOf(field.value.type.base_type))) {
1209           code_.SetValue("FIELD_NAME", Name(field));
1210           if (TableFieldReturnsOption(field.value.type)) {
1211             code_ += "      if let Some(x) = args.{{FIELD_NAME}} "
1212                      "{ builder.add_{{FIELD_NAME}}(x); }";
1213           } else {
1214             code_ += "      builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
1215           }
1216         }
1217       }
1218     }
1219     code_ += "      builder.finish()";
1220     code_ += "    }";
1221     code_ += "";
1222 
1223     // Generate field id constants.
1224     if (struct_def.fields.vec.size() > 0) {
1225       for (auto it = struct_def.fields.vec.begin();
1226            it != struct_def.fields.vec.end(); ++it) {
1227         const auto &field = **it;
1228         if (field.deprecated) {
1229           // Deprecated fields won't be accessible.
1230           continue;
1231         }
1232 
1233         code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1234         code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
1235         code_ += "    pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1236                  "{{OFFSET_VALUE}};";
1237       }
1238       code_ += "";
1239     }
1240 
1241     // Generate the accessors. Each has one of two forms:
1242     //
1243     // If a value can be None:
1244     //   pub fn name(&'a self) -> Option<user_facing_type> {
1245     //     self._tab.get::<internal_type>(offset, defaultval)
1246     //   }
1247     //
1248     // If a value is always Some:
1249     //   pub fn name(&'a self) -> user_facing_type {
1250     //     self._tab.get::<internal_type>(offset, defaultval).unwrap()
1251     //   }
1252     const auto offset_prefix = Name(struct_def);
1253     for (auto it = struct_def.fields.vec.begin();
1254          it != struct_def.fields.vec.end(); ++it) {
1255       const auto &field = **it;
1256       if (field.deprecated) {
1257         // Deprecated fields won't be accessible.
1258         continue;
1259       }
1260 
1261       code_.SetValue("FIELD_NAME", Name(field));
1262       code_.SetValue("RETURN_TYPE",
1263                      GenTableAccessorFuncReturnType(field, "'a"));
1264       code_.SetValue("FUNC_BODY",
1265                      GenTableAccessorFuncBody(field, "'a", offset_prefix));
1266 
1267       GenComment(field.doc_comment, "  ");
1268       code_ += "  #[inline]";
1269       code_ += "  pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
1270       code_ += "    {{FUNC_BODY}}";
1271       code_ += "  }";
1272 
1273       // Generate a comparison function for this field if it is a key.
1274       if (field.key) {
1275         GenKeyFieldMethods(field);
1276       }
1277 
1278       // Generate a nested flatbuffer field, if applicable.
1279       auto nested = field.attributes.Lookup("nested_flatbuffer");
1280       if (nested) {
1281         std::string qualified_name = nested->constant;
1282         auto nested_root = parser_.LookupStruct(nested->constant);
1283         if (nested_root == nullptr) {
1284           qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1285               nested->constant);
1286           nested_root = parser_.LookupStruct(qualified_name);
1287         }
1288         FLATBUFFERS_ASSERT(nested_root);  // Guaranteed to exist by parser.
1289         (void)nested_root;
1290 
1291         code_.SetValue("OFFSET_NAME",
1292                        offset_prefix + "::" + GetFieldOffsetName(field));
1293         code_ += "  pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> "
1294                  " Option<{{STRUCT_NAME}}<'a>> {";
1295         code_ += "     match self.{{FIELD_NAME}}() {";
1296         code_ += "         None => { None }";
1297         code_ += "         Some(data) => {";
1298         code_ += "             use self::flatbuffers::Follow;";
1299         code_ += "             Some(<flatbuffers::ForwardsUOffset"
1300                  "<{{STRUCT_NAME}}<'a>>>::follow(data, 0))";
1301         code_ += "         },";
1302         code_ += "     }";
1303         code_ += "  }";
1304       }
1305     }
1306 
1307     // Explicit specializations for union accessors
1308     for (auto it = struct_def.fields.vec.begin();
1309          it != struct_def.fields.vec.end(); ++it) {
1310       const auto &field = **it;
1311       if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
1312         continue;
1313       }
1314 
1315       auto u = field.value.type.enum_def;
1316 
1317       code_.SetValue("FIELD_NAME", Name(field));
1318 
1319       for (auto u_it = u->vals.vec.begin(); u_it != u->vals.vec.end(); ++u_it) {
1320         auto &ev = **u_it;
1321         if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1322 
1323         auto table_init_type = WrapInNameSpace(
1324           ev.union_type.struct_def->defined_namespace,
1325           ev.union_type.struct_def->name);
1326 
1327           code_.SetValue("U_ELEMENT_ENUM_TYPE",
1328               WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
1329         code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type);
1330         code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
1331 
1332         code_ += "  #[inline]";
1333         code_ += "  #[allow(non_snake_case)]";
1334         code_ += "  pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
1335                  "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
1336         code_ += "    if self.{{FIELD_NAME}}_type() == {{U_ELEMENT_ENUM_TYPE}} {";
1337         code_ += "      self.{{FIELD_NAME}}().map(|u| "
1338                  "{{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
1339         code_ += "    } else {";
1340         code_ += "      None";
1341         code_ += "    }";
1342         code_ += "  }";
1343         code_ += "";
1344       }
1345     }
1346 
1347     code_ += "}";  // End of table impl.
1348     code_ += "";
1349 
1350     // Generate an args struct:
1351     code_.SetValue("MAYBE_LT",
1352         TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
1353     code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1354     for (auto it = struct_def.fields.vec.begin();
1355          it != struct_def.fields.vec.end(); ++it) {
1356       const auto &field = **it;
1357       if (!field.deprecated) {
1358         code_.SetValue("PARAM_NAME", Name(field));
1359         code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a "));
1360         code_ += "    pub {{PARAM_NAME}}: {{PARAM_TYPE}},";
1361       }
1362     }
1363     code_ += "}";
1364 
1365     // Generate an impl of Default for the *Args type:
1366     code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1367     code_ += "    #[inline]";
1368     code_ += "    fn default() -> Self {";
1369     code_ += "        {{STRUCT_NAME}}Args {";
1370     for (auto it = struct_def.fields.vec.begin();
1371         it != struct_def.fields.vec.end(); ++it) {
1372       const auto &field = **it;
1373       if (!field.deprecated) {
1374         code_.SetValue("PARAM_VALUE", TableBuilderArgsDefaultValue(field));
1375         code_.SetValue("REQ", field.required ? " // required field" : "");
1376         code_.SetValue("PARAM_NAME", Name(field));
1377         code_ += "            {{PARAM_NAME}}: {{PARAM_VALUE}},{{REQ}}";
1378       }
1379     }
1380     code_ += "        }";
1381     code_ += "    }";
1382     code_ += "}";
1383 
1384     // Generate a builder struct:
1385     code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
1386     code_ += "  fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1387     code_ += "  start_: flatbuffers::WIPOffset<"
1388              "flatbuffers::TableUnfinishedWIPOffset>,";
1389     code_ += "}";
1390 
1391     // Generate builder functions:
1392     code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
1393     for (auto it = struct_def.fields.vec.begin();
1394          it != struct_def.fields.vec.end(); ++it) {
1395       const auto &field = **it;
1396       if (!field.deprecated) {
1397         const bool is_scalar = IsScalar(field.value.type.base_type);
1398 
1399         std::string offset = GetFieldOffsetName(field);
1400         std::string name = Name(field);
1401         std::string value = GetDefaultScalarValue(field);
1402 
1403         // Generate functions to add data, which take one of two forms.
1404         //
1405         // If a value has a default:
1406         //   fn add_x(x_: type) {
1407         //     fbb_.push_slot::<type>(offset, x_, Some(default));
1408         //   }
1409         //
1410         // If a value does not have a default:
1411         //   fn add_x(x_: type) {
1412         //     fbb_.push_slot_always::<type>(offset, x_);
1413         //   }
1414         code_.SetValue("FIELD_NAME", Name(field));
1415         code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
1416         code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
1417         code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
1418         code_ += "  #[inline]";
1419         code_ += "  pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
1420                  "{{FIELD_TYPE}}) {";
1421         if (is_scalar) {
1422           code_.SetValue("FIELD_DEFAULT_VALUE",
1423                          TableBuilderAddFuncDefaultValue(field));
1424           code_ += "    {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
1425                    "{{FIELD_DEFAULT_VALUE}});";
1426         } else {
1427           code_ += "    {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
1428         }
1429         code_ += "  }";
1430       }
1431     }
1432 
1433     // Struct initializer (all fields required);
1434     code_ += "  #[inline]";
1435     code_ +=
1436         "  pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
1437         "{{STRUCT_NAME}}Builder<'a, 'b> {";
1438     code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
1439     code_ += "    let start = _fbb.start_table();";
1440     code_ += "    {{STRUCT_NAME}}Builder {";
1441     code_ += "      fbb_: _fbb,";
1442     code_ += "      start_: start,";
1443     code_ += "    }";
1444     code_ += "  }";
1445 
1446     // finish() function.
1447     code_ += "  #[inline]";
1448     code_ += "  pub fn finish(self) -> "
1449              "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
1450     code_ += "    let o = self.fbb_.end_table(self.start_);";
1451 
1452     for (auto it = struct_def.fields.vec.begin();
1453          it != struct_def.fields.vec.end(); ++it) {
1454       const auto &field = **it;
1455       if (!field.deprecated && field.required) {
1456         code_.SetValue("FIELD_NAME", MakeSnakeCase(Name(field)));
1457         code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1458         code_ += "    self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
1459                  "\"{{FIELD_NAME}}\");";
1460       }
1461     }
1462     code_ += "    flatbuffers::WIPOffset::new(o.value())";
1463     code_ += "  }";
1464     code_ += "}";
1465     code_ += "";
1466   }
1467 
1468   // Generate functions to compare tables and structs by key. This function
1469   // must only be called if the field key is defined.
GenKeyFieldMethods(const FieldDef & field)1470   void GenKeyFieldMethods(const FieldDef &field) {
1471     FLATBUFFERS_ASSERT(field.key);
1472 
1473     code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
1474 
1475     code_ += "  #[inline]";
1476     code_ += "  pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
1477              " bool {";
1478     code_ += "    self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
1479     code_ += "  }";
1480     code_ += "";
1481     code_ += "  #[inline]";
1482     code_ += "  pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
1483              " ::std::cmp::Ordering {";
1484     code_ += "    let key = self.{{FIELD_NAME}}();";
1485     code_ += "    key.cmp(&val)";
1486     code_ += "  }";
1487   }
1488 
1489   // Generate functions for accessing the root table object. This function
1490   // must only be called if the root table is defined.
GenRootTableFuncs(const StructDef & struct_def)1491   void GenRootTableFuncs(const StructDef &struct_def) {
1492     FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
1493     auto name = Name(struct_def);
1494 
1495     code_.SetValue("STRUCT_NAME", name);
1496     code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
1497     code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
1498 
1499     // The root datatype accessors:
1500     code_ += "#[inline]";
1501     code_ +=
1502         "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
1503         " -> {{STRUCT_NAME}}<'a> {";
1504     code_ += "  flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)";
1505     code_ += "}";
1506     code_ += "";
1507 
1508     code_ += "#[inline]";
1509     code_ += "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
1510              "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
1511     code_ += "  flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
1512              "(buf)";
1513     code_ += "}";
1514     code_ += "";
1515 
1516     if (parser_.file_identifier_.length()) {
1517       // Declare the identifier
1518       code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &'static str\\";
1519       code_ += " = \"" + parser_.file_identifier_ + "\";";
1520       code_ += "";
1521 
1522       // Check if a buffer has the identifier.
1523       code_ += "#[inline]";
1524       code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
1525       code_ += "(buf: &[u8]) -> bool {";
1526       code_ += "  return flatbuffers::buffer_has_identifier(buf, \\";
1527       code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false);";
1528       code_ += "}";
1529       code_ += "";
1530       code_ += "#[inline]";
1531       code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
1532       code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
1533       code_ += "  return flatbuffers::buffer_has_identifier(buf, \\";
1534       code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true);";
1535       code_ += "}";
1536       code_ += "";
1537     }
1538 
1539     if (parser_.file_extension_.length()) {
1540       // Return the extension
1541       code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &'static str = \\";
1542       code_ += "\"" + parser_.file_extension_ + "\";";
1543       code_ += "";
1544     }
1545 
1546     // Finish a buffer with a given root object:
1547     code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1548     code_ += "#[inline]";
1549     code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
1550     code_ += "    fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1551     code_ += "    root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1552     if (parser_.file_identifier_.length()) {
1553       code_ += "  fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1554     } else {
1555       code_ += "  fbb.finish(root, None);";
1556     }
1557     code_ += "}";
1558     code_ += "";
1559     code_ += "#[inline]";
1560     code_ += "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
1561              "<'a, 'b>("
1562              "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
1563              "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1564     if (parser_.file_identifier_.length()) {
1565       code_ += "  fbb.finish_size_prefixed(root, "
1566                "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1567     } else {
1568       code_ += "  fbb.finish_size_prefixed(root, None);";
1569     }
1570     code_ += "}";
1571   }
1572 
GenPadding(const FieldDef & field,std::string * code_ptr,int * id,const std::function<void (int bits,std::string * code_ptr,int * id)> & f)1573   static void GenPadding(
1574       const FieldDef &field, std::string *code_ptr, int *id,
1575       const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
1576     if (field.padding) {
1577       for (int i = 0; i < 4; i++) {
1578         if (static_cast<int>(field.padding) & (1 << i)) {
1579           f((1 << i) * 8, code_ptr, id);
1580         }
1581       }
1582       assert(!(field.padding & ~0xF));
1583     }
1584   }
1585 
PaddingDefinition(int bits,std::string * code_ptr,int * id)1586   static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
1587     *code_ptr += "  padding" + NumToString((*id)++) + "__: u" + \
1588                  NumToString(bits) + ",";
1589   }
1590 
PaddingInitializer(int bits,std::string * code_ptr,int * id)1591   static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
1592     (void)bits;
1593     *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
1594   }
1595 
1596   // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def)1597   void GenStruct(const StructDef &struct_def) {
1598     // Generates manual padding and alignment.
1599     // Variables are private because they contain little endian data on all
1600     // platforms.
1601     GenComment(struct_def.doc_comment);
1602     code_.SetValue("ALIGN", NumToString(struct_def.minalign));
1603     code_.SetValue("STRUCT_NAME", Name(struct_def));
1604 
1605     code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
1606     code_ += "#[repr(C, align({{ALIGN}}))]";
1607 
1608     // PartialEq is useful to derive because we can correctly compare structs
1609     // for equality by just comparing their underlying byte data. This doesn't
1610     // hold for PartialOrd/Ord.
1611     code_ += "#[derive(Clone, Copy, Debug, PartialEq)]";
1612     code_ += "pub struct {{STRUCT_NAME}} {";
1613 
1614     int padding_id = 0;
1615     for (auto it = struct_def.fields.vec.begin();
1616          it != struct_def.fields.vec.end(); ++it) {
1617       const auto &field = **it;
1618       code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
1619       code_.SetValue("FIELD_NAME", Name(field));
1620       code_ += "  {{FIELD_NAME}}_: {{FIELD_TYPE}},";
1621 
1622       if (field.padding) {
1623         std::string padding;
1624         GenPadding(field, &padding, &padding_id, PaddingDefinition);
1625         code_ += padding;
1626       }
1627     }
1628 
1629     code_ += "} // pub struct {{STRUCT_NAME}}";
1630 
1631     // Generate impls for SafeSliceAccess (because all structs are endian-safe),
1632     // Follow for the value type, Follow for the reference type, Push for the
1633     // value type, and Push for the reference type.
1634     code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
1635     code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
1636     code_ += "  type Inner = &'a {{STRUCT_NAME}};";
1637     code_ += "  #[inline]";
1638     code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1639     code_ += "    <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
1640     code_ += "  }";
1641     code_ += "}";
1642     code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
1643     code_ += "  type Inner = &'a {{STRUCT_NAME}};";
1644     code_ += "  #[inline]";
1645     code_ += "  fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1646     code_ += "    flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
1647     code_ += "  }";
1648     code_ += "}";
1649     code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
1650     code_ += "    type Output = {{STRUCT_NAME}};";
1651     code_ += "    #[inline]";
1652     code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1653     code_ += "        let src = unsafe {";
1654     code_ += "            ::std::slice::from_raw_parts("
1655              "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1656     code_ += "        };";
1657     code_ += "        dst.copy_from_slice(src);";
1658     code_ += "    }";
1659     code_ += "}";
1660     code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
1661     code_ += "    type Output = {{STRUCT_NAME}};";
1662     code_ += "";
1663     code_ += "    #[inline]";
1664     code_ += "    fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1665     code_ += "        let src = unsafe {";
1666     code_ += "            ::std::slice::from_raw_parts("
1667              "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1668     code_ += "        };";
1669     code_ += "        dst.copy_from_slice(src);";
1670     code_ += "    }";
1671     code_ += "}";
1672     code_ += "";
1673     code_ += "";
1674 
1675     // Generate a constructor that takes all fields as arguments.
1676     code_ += "impl {{STRUCT_NAME}} {";
1677     std::string arg_list;
1678     std::string init_list;
1679     padding_id = 0;
1680     for (auto it = struct_def.fields.vec.begin();
1681          it != struct_def.fields.vec.end(); ++it) {
1682       const auto &field = **it;
1683       const auto member_name = Name(field) + "_";
1684       const auto reference = StructMemberAccessNeedsCopy(field.value.type)
1685                              ? "" : "&'a ";
1686       const auto arg_name = "_" + Name(field);
1687       const auto arg_type = reference + GetTypeGet(field.value.type);
1688 
1689       if (it != struct_def.fields.vec.begin()) {
1690         arg_list += ", ";
1691       }
1692       arg_list += arg_name + ": ";
1693       arg_list += arg_type;
1694       init_list += "      " + member_name;
1695       if (StructMemberAccessNeedsCopy(field.value.type)) {
1696         init_list += ": " + arg_name + ".to_little_endian(),\n";
1697       } else {
1698         init_list += ": *" + arg_name + ",\n";
1699       }
1700     }
1701 
1702     code_.SetValue("ARG_LIST", arg_list);
1703     code_.SetValue("INIT_LIST", init_list);
1704     code_ += "  pub fn new<'a>({{ARG_LIST}}) -> Self {";
1705     code_ += "    {{STRUCT_NAME}} {";
1706     code_ += "{{INIT_LIST}}";
1707     padding_id = 0;
1708     for (auto it = struct_def.fields.vec.begin();
1709          it != struct_def.fields.vec.end(); ++it) {
1710       const auto &field = **it;
1711       if (field.padding) {
1712         std::string padding;
1713         GenPadding(field, &padding, &padding_id, PaddingInitializer);
1714         code_ += "      " + padding;
1715       }
1716     }
1717     code_ += "    }";
1718     code_ += "  }";
1719 
1720     // Generate accessor methods for the struct.
1721     for (auto it = struct_def.fields.vec.begin();
1722          it != struct_def.fields.vec.end(); ++it) {
1723       const auto &field = **it;
1724 
1725       auto field_type = TableBuilderArgsAddFuncType(field, "'a");
1726       auto member = "self." + Name(field) + "_";
1727       auto value = StructMemberAccessNeedsCopy(field.value.type) ?
1728         member + ".from_little_endian()" : member;
1729 
1730       code_.SetValue("FIELD_NAME", Name(field));
1731       code_.SetValue("FIELD_TYPE", field_type);
1732       code_.SetValue("FIELD_VALUE", value);
1733       code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
1734 
1735       GenComment(field.doc_comment, "  ");
1736       code_ += "  pub fn {{FIELD_NAME}}<'a>(&'a self) -> {{FIELD_TYPE}} {";
1737       code_ += "    {{REF}}{{FIELD_VALUE}}";
1738       code_ += "  }";
1739 
1740       // Generate a comparison function for this field if it is a key.
1741       if (field.key) {
1742         GenKeyFieldMethods(field);
1743       }
1744     }
1745     code_ += "}";
1746     code_ += "";
1747   }
1748 
GenNamespaceImports(const int white_spaces)1749   void GenNamespaceImports(const int white_spaces) {
1750       std::string indent = std::string(white_spaces, ' ');
1751       code_ += indent + "#![allow(dead_code)]";
1752       code_ += indent + "#![allow(unused_imports)]";
1753       code_ += "";
1754       code_ += indent + "use std::mem;";
1755       code_ += indent + "use std::cmp::Ordering;";
1756       code_ += "";
1757       code_ += indent + "extern crate flatbuffers;";
1758       code_ += indent + "use self::flatbuffers::EndianScalar;";
1759   }
1760 
1761   // Set up the correct namespace. This opens a namespace if the current
1762   // namespace is different from the target namespace. This function
1763   // closes and opens the namespaces only as necessary.
1764   //
1765   // The file must start and end with an empty (or null) namespace so that
1766   // namespaces are properly opened and closed.
SetNameSpace(const Namespace * ns)1767   void SetNameSpace(const Namespace *ns) {
1768     if (cur_name_space_ == ns) { return; }
1769 
1770     // Compute the size of the longest common namespace prefix.
1771     // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
1772     // the common prefix is A::B:: and we have old_size = 4, new_size = 5
1773     // and common_prefix_size = 2
1774     size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
1775     size_t new_size = ns ? ns->components.size() : 0;
1776 
1777     size_t common_prefix_size = 0;
1778     while (common_prefix_size < old_size && common_prefix_size < new_size &&
1779            ns->components[common_prefix_size] ==
1780                cur_name_space_->components[common_prefix_size]) {
1781       common_prefix_size++;
1782     }
1783 
1784     // Close cur_name_space in reverse order to reach the common prefix.
1785     // In the previous example, D then C are closed.
1786     for (size_t j = old_size; j > common_prefix_size; --j) {
1787       code_ += "}  // pub mod " + cur_name_space_->components[j - 1];
1788     }
1789     if (old_size != common_prefix_size) { code_ += ""; }
1790 
1791     // open namespace parts to reach the ns namespace
1792     // in the previous example, E, then F, then G are opened
1793     for (auto j = common_prefix_size; j != new_size; ++j) {
1794       code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
1795       // Generate local namespace imports.
1796       GenNamespaceImports(2);
1797     }
1798     if (new_size != common_prefix_size) { code_ += ""; }
1799 
1800     cur_name_space_ = ns;
1801   }
1802 };
1803 
1804 }  // namespace rust
1805 
GenerateRust(const Parser & parser,const std::string & path,const std::string & file_name)1806 bool GenerateRust(const Parser &parser, const std::string &path,
1807                   const std::string &file_name) {
1808   rust::RustGenerator generator(parser, path, file_name);
1809   return generator.generate();
1810 }
1811 
RustMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)1812 std::string RustMakeRule(const Parser &parser, const std::string &path,
1813                          const std::string &file_name) {
1814   std::string filebase =
1815       flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
1816   std::string make_rule = GeneratedFileName(path, filebase) + ": ";
1817 
1818   auto included_files = parser.GetIncludedFilesRecursive(file_name);
1819   for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1820     make_rule += " " + *it;
1821   }
1822   return make_rule;
1823 }
1824 
1825 }  // namespace flatbuffers
1826 
1827 // TODO(rw): Generated code should import other generated files.
1828 // TODO(rw): Generated code should refer to namespaces in included files in a
1829 //           way that makes them referrable.
1830 // TODO(rw): Generated code should indent according to nesting level.
1831 // TODO(rw): Generated code should generate endian-safe Debug impls.
1832 // TODO(rw): Generated code could use a Rust-only enum type to access unions,
1833 //           instead of making the user use _type() to manually switch.
1834