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