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