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