blob: 936ac8369c468c20eb1fa0ba5b61583da810c58d [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
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
24namespace flatbuffers {
25
26static 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.
33std::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.
55std::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?
69enum 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).
96FullType 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<...>
170std::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()
179std::string AddUnwrapIfRequired(std::string s, bool required) {
180 if (required) {
181 return s + ".unwrap()";
182 } else {
183 return s;
184 }
185}
186
187namespace rust {
188
189class 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
1798bool 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
1804std::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.