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