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
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) \
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) \
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 int64_t anyv = 0;
593 const EnumVal *minv = nullptr, *maxv = nullptr;
594 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
595 const auto &ev = **it;
596
597 GenComment(ev.doc_comment, " ");
598 code_.SetValue("KEY", Name(ev));
599 code_.SetValue("VALUE", NumToString(ev.value));
600 code_ += " {{KEY}} = {{VALUE}},";
601
602 minv = !minv || minv->value > ev.value ? &ev : minv;
603 maxv = !maxv || maxv->value < ev.value ? &ev : maxv;
604 anyv |= ev.value;
605 }
606
607 code_ += "";
608 code_ += "}";
609 code_ += "";
610
611 code_.SetValue("ENUM_NAME", Name(enum_def));
612 code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
613 code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
614 code_.SetValue("ENUM_MIN_BASE_VALUE", NumToString(minv->value));
615 code_.SetValue("ENUM_MAX_BASE_VALUE", NumToString(maxv->value));
616
617 // Generate enum constants, and impls for Follow, EndianScalar, and Push.
618 code_ += "const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
619 code_ += "{{ENUM_MIN_BASE_VALUE}};";
620 code_ += "const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
621 code_ += "{{ENUM_MAX_BASE_VALUE}};";
622 code_ += "";
623 code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
624 code_ += " type Inner = Self;";
625 code_ += " #[inline]";
626 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
627 code_ += " flatbuffers::read_scalar_at::<Self>(buf, loc)";
628 code_ += " }";
629 code_ += "}";
630 code_ += "";
631 code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
632 code_ += " #[inline]";
633 code_ += " fn to_little_endian(self) -> Self {";
634 code_ += " let n = {{BASE_TYPE}}::to_le(self as {{BASE_TYPE}});";
635 code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
636 code_ += " unsafe { *p }";
637 code_ += " }";
638 code_ += " #[inline]";
639 code_ += " fn from_little_endian(self) -> Self {";
640 code_ += " let n = {{BASE_TYPE}}::from_le(self as {{BASE_TYPE}});";
641 code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
642 code_ += " unsafe { *p }";
643 code_ += " }";
644 code_ += "}";
645 code_ += "";
646 code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
647 code_ += " type Output = {{ENUM_NAME}};";
648 code_ += " #[inline]";
649 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
650 code_ += " flatbuffers::emplace_scalar::<{{ENUM_NAME}}>"
651 "(dst, *self);";
652 code_ += " }";
653 code_ += "}";
654 code_ += "";
655
656 // Generate an array of all enumeration values.
657 auto num_fields = NumToString(enum_def.size());
658 code_ += "#[allow(non_camel_case_types)]";
659 code_ += "const ENUM_VALUES_{{ENUM_NAME_CAPS}}:[{{ENUM_NAME}}; " +
660 num_fields + "] = [";
661 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
662 const auto &ev = **it;
663 auto value = GetEnumValUse(enum_def, ev);
664 auto suffix = *it != enum_def.Vals().back() ? "," : "";
665 code_ += " " + value + suffix;
666 }
667 code_ += "];";
668 code_ += "";
669
670 // Generate a string table for enum values.
671 // Problem is, if values are very sparse that could generate really big
672 // tables. Ideally in that case we generate a map lookup instead, but for
673 // the moment we simply don't output a table at all.
674 auto range =
675 enum_def.vals.vec.back()->value - enum_def.vals.vec.front()->value + 1;
676 // Average distance between values above which we consider a table
677 // "too sparse". Change at will.
678 static const int kMaxSparseness = 5;
679 if (range / static_cast<int64_t>(enum_def.vals.vec.size()) <
680 kMaxSparseness) {
681 code_ += "#[allow(non_camel_case_types)]";
682 code_ += "const ENUM_NAMES_{{ENUM_NAME_CAPS}}:[&'static str; " +
683 NumToString(range) + "] = [";
684
685 auto val = enum_def.Vals().front()->value;
686 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
687 ++it) {
688 const auto &ev = **it;
689 while (val++ != ev.value) { code_ += " \"\","; }
690 auto suffix = *it != enum_def.vals.vec.back() ? "," : "";
691 code_ += " \"" + Name(ev) + "\"" + suffix;
692 }
693 code_ += "];";
694 code_ += "";
695
696 code_ += "pub fn enum_name_{{ENUM_NAME_SNAKE}}(e: {{ENUM_NAME}}) -> "
697 "&'static str {";
698
699 code_ += " let index = e as {{BASE_TYPE}}\\";
700 if (enum_def.vals.vec.front()->value) {
701 auto vals = GetEnumValUse(enum_def, *enum_def.vals.vec.front());
702 code_ += " - " + vals + " as {{BASE_TYPE}}\\";
703 }
704 code_ += ";";
705
706 code_ += " ENUM_NAMES_{{ENUM_NAME_CAPS}}[index as usize]";
707 code_ += "}";
708 code_ += "";
709 }
710
711 if (enum_def.is_union) {
712 // Generate tyoesafe offset(s) for unions
713 code_.SetValue("NAME", Name(enum_def));
714 code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
715 code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
716 }
717 }
718
719 std::string GetFieldOffsetName(const FieldDef &field) {
720 return "VT_" + MakeUpper(Name(field));
721 }
722
723 std::string GetDefaultConstant(const FieldDef &field) {
724 return field.value.type.base_type == BASE_TYPE_FLOAT
725 ? field.value.constant + ""
726 : field.value.constant;
727 }
728
729 std::string GetDefaultScalarValue(const FieldDef &field) {
730 switch (GetFullType(field.value.type)) {
731 case ftInteger: { return GetDefaultConstant(field); }
732 case ftFloat: { return GetDefaultConstant(field); }
733 case ftBool: {
734 return field.value.constant == "0" ? "false" : "true";
735 }
736 case ftUnionKey:
737 case ftEnumKey: {
738 auto ev = field.value.type.enum_def->ReverseLookup(
739 StringToInt(field.value.constant.c_str()), false);
740 assert(ev);
741 return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
742 GetEnumValUse(*field.value.type.enum_def, *ev));
743 }
744
745 // All pointer-ish types have a default value of None, because they are
746 // wrapped in Option.
747 default: { return "None"; }
748 }
749 }
750
751 // Create the return type for fields in the *BuilderArgs structs that are
752 // used to create Tables.
753 //
754 // Note: we could make all inputs to the BuilderArgs be an Option, as well
755 // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
756 // know if the value is default or not, because there are three ways to
757 // return a default value:
758 // 1) return a stored value that happens to be the default,
759 // 2) return a hardcoded value because the relevant vtable field is not in
760 // the vtable, or
761 // 3) return a hardcoded value because the vtable field value is set to zero.
762 std::string TableBuilderArgsDefnType(const FieldDef &field,
763 const std::string lifetime) {
764 const Type& type = field.value.type;
765
766 switch (GetFullType(type)) {
767 case ftInteger:
768 case ftFloat:
769 case ftBool: {
770 const auto typname = GetTypeBasic(type);
771 return typname;
772 }
773 case ftStruct: {
774 const auto typname = WrapInNameSpace(*type.struct_def);
775 return "Option<&" + lifetime + " " + typname + ">";
776 }
777 case ftTable: {
778 const auto typname = WrapInNameSpace(*type.struct_def);
779 return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime + \
780 ">>>";
781 }
782 case ftString: {
783 return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
784 }
785 case ftEnumKey:
786 case ftUnionKey: {
787 const auto typname = WrapInNameSpace(*type.enum_def);
788 return typname;
789 }
790 case ftUnionValue: {
791 const auto typname = WrapInNameSpace(*type.enum_def);
792 return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
793 }
794
795 case ftVectorOfInteger:
796 case ftVectorOfFloat: {
797 const auto typname = GetTypeBasic(type.VectorType());
798 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
799 lifetime + ", " + typname + ">>>";
800 }
801 case ftVectorOfBool: {
802 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
803 lifetime + ", bool>>>";
804 }
805 case ftVectorOfEnumKey: {
806 const auto typname = WrapInNameSpace(*type.enum_def);
807 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
808 lifetime + ", " + typname + ">>>";
809 }
810 case ftVectorOfStruct: {
811 const auto typname = WrapInNameSpace(*type.struct_def);
812 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
813 lifetime + ", " + typname + ">>>";
814 }
815 case ftVectorOfTable: {
816 const auto typname = WrapInNameSpace(*type.struct_def);
817 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
818 lifetime + ", flatbuffers::ForwardsUOffset<" + typname + \
819 "<" + lifetime + ">>>>>";
820 }
821 case ftVectorOfString: {
822 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
823 lifetime + ", flatbuffers::ForwardsUOffset<&" + lifetime + \
824 " str>>>>";
825 }
826 case ftVectorOfUnionValue: {
827 const auto typname = WrapInNameSpace(*type.enum_def) + \
828 "UnionTableOffset";
829 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
830 lifetime + ", flatbuffers::ForwardsUOffset<"
831 "flatbuffers::Table<" + lifetime + ">>>>";
832 }
833 }
834 return "INVALID_CODE_GENERATION"; // for return analysis
835 }
836
837 std::string TableBuilderArgsDefaultValue(const FieldDef &field) {
838 return GetDefaultScalarValue(field);
839 }
840 std::string TableBuilderAddFuncDefaultValue(const FieldDef &field) {
841 switch (GetFullType(field.value.type)) {
842 case ftUnionKey:
843 case ftEnumKey: {
844 const std::string basetype = GetTypeBasic(field.value.type);
845 return GetDefaultScalarValue(field);
846 }
847
848 default: { return GetDefaultScalarValue(field); }
849 }
850 }
851
852 std::string TableBuilderArgsAddFuncType(const FieldDef &field,
853 const std::string lifetime) {
854 const Type& type = field.value.type;
855
856 switch (GetFullType(field.value.type)) {
857 case ftVectorOfStruct: {
858 const auto typname = WrapInNameSpace(*type.struct_def);
859 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
860 ", " + typname + ">>";
861 }
862 case ftVectorOfTable: {
863 const auto typname = WrapInNameSpace(*type.struct_def);
864 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
865 ", flatbuffers::ForwardsUOffset<" + typname + \
866 "<" + lifetime + ">>>>";
867 }
868 case ftVectorOfInteger:
869 case ftVectorOfFloat: {
870 const auto typname = GetTypeBasic(type.VectorType());
871 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
872 ", " + typname + ">>";
873 }
874 case ftVectorOfBool: {
875 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
876 ", bool>>";
877 }
878 case ftVectorOfString: {
879 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
880 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
881 }
882 case ftVectorOfEnumKey: {
883 const auto typname = WrapInNameSpace(*type.enum_def);
884 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
885 ", " + typname + ">>";
886 }
887 case ftVectorOfUnionValue: {
888 const auto typname = WrapInNameSpace(*type.enum_def);
889 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
890 ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + \
891 lifetime + ">>>";
892 }
893 case ftEnumKey: {
894 const auto typname = WrapInNameSpace(*type.enum_def);
895 return typname;
896 }
897 case ftStruct: {
898 const auto typname = WrapInNameSpace(*type.struct_def);
899 return "&" + lifetime + " " + typname + "";
900 }
901 case ftTable: {
902 const auto typname = WrapInNameSpace(*type.struct_def);
903 return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
904 }
905 case ftInteger:
906 case ftFloat: {
907 const auto typname = GetTypeBasic(type);
908 return typname;
909 }
910 case ftBool: {
911 return "bool";
912 }
913 case ftString: {
914 return "flatbuffers::WIPOffset<&" + lifetime + " str>";
915 }
916 case ftUnionKey: {
917 const auto typname = WrapInNameSpace(*type.enum_def);
918 return typname;
919 }
920 case ftUnionValue: {
921 const auto typname = WrapInNameSpace(*type.enum_def);
922 return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
923 }
924 }
925
926 return "INVALID_CODE_GENERATION"; // for return analysis
927 }
928
929 std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
930 const Type& type = field.value.type;
931
932 switch (GetFullType(field.value.type)) {
933 case ftInteger:
934 case ftFloat: {
935 const auto typname = GetTypeBasic(field.value.type);
936 return "self.fbb_.push_slot::<" + typname + ">";
937 }
938 case ftBool: {
939 return "self.fbb_.push_slot::<bool>";
940 }
941
942 case ftEnumKey:
943 case ftUnionKey: {
944 const auto underlying_typname = GetTypeBasic(type);
945 return "self.fbb_.push_slot::<" + underlying_typname + ">";
946 }
947
948 case ftStruct: {
949 const std::string typname = WrapInNameSpace(*type.struct_def);
950 return "self.fbb_.push_slot_always::<&" + typname + ">";
951 }
952 case ftTable: {
953 const auto typname = WrapInNameSpace(*type.struct_def);
954 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" + \
955 typname + ">>";
956 }
957
958 case ftUnionValue:
959 case ftString:
960 case ftVectorOfInteger:
961 case ftVectorOfFloat:
962 case ftVectorOfBool:
963 case ftVectorOfEnumKey:
964 case ftVectorOfStruct:
965 case ftVectorOfTable:
966 case ftVectorOfString:
967 case ftVectorOfUnionValue: {
968 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
969 }
970 }
971 return "INVALID_CODE_GENERATION"; // for return analysis
972 }
973
974 std::string GenTableAccessorFuncReturnType(const FieldDef &field,
975 const std::string lifetime) {
976 const Type& type = field.value.type;
977
978 switch (GetFullType(field.value.type)) {
979 case ftInteger:
980 case ftFloat: {
981 const auto typname = GetTypeBasic(type);
982 return typname;
983 }
984 case ftBool: {
985 return "bool";
986 }
987 case ftStruct: {
988 const auto typname = WrapInNameSpace(*type.struct_def);
989 return WrapInOptionIfNotRequired("&" + lifetime + " " + typname, field.required);
990 }
991 case ftTable: {
992 const auto typname = WrapInNameSpace(*type.struct_def);
993 return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">", field.required);
994 }
995 case ftEnumKey:
996 case ftUnionKey: {
997 const auto typname = WrapInNameSpace(*type.enum_def);
998 return typname;
999 }
1000
1001 case ftUnionValue: {
1002 return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">", field.required);
1003 }
1004 case ftString: {
1005 return WrapInOptionIfNotRequired("&" + lifetime + " str", field.required);
1006 }
1007 case ftVectorOfInteger:
1008 case ftVectorOfFloat: {
1009 const auto typname = GetTypeBasic(type.VectorType());
1010 if (IsOneByte(type.VectorType().base_type)) {
1011 return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
1012 }
1013 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
1014 }
1015 case ftVectorOfBool: {
1016 return WrapInOptionIfNotRequired("&" + lifetime + " [bool]", field.required);
1017 }
1018 case ftVectorOfEnumKey: {
1019 const auto typname = WrapInNameSpace(*type.enum_def);
1020 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
1021 }
1022 case ftVectorOfStruct: {
1023 const auto typname = WrapInNameSpace(*type.struct_def);
1024 return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
1025 }
1026 case ftVectorOfTable: {
1027 const auto typname = WrapInNameSpace(*type.struct_def);
1028 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<" + \
1029 typname + "<" + lifetime + ">>>", field.required);
1030 }
1031 case ftVectorOfString: {
1032 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<&" + \
1033 lifetime + " str>>", field.required);
1034 }
1035 case ftVectorOfUnionValue: {
1036 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1037 // TODO(rw): when we do support these, we should consider using the
1038 // Into trait to convert tables to typesafe union values.
1039 return "INVALID_CODE_GENERATION"; // for return analysis
1040 }
1041 }
1042 return "INVALID_CODE_GENERATION"; // for return analysis
1043 }
1044
1045 std::string GenTableAccessorFuncBody(const FieldDef &field,
1046 const std::string lifetime,
1047 const std::string offset_prefix) {
1048 const std::string offset_name = offset_prefix + "::" + \
1049 GetFieldOffsetName(field);
1050 const Type& type = field.value.type;
1051
1052 switch (GetFullType(field.value.type)) {
1053 case ftInteger:
1054 case ftFloat:
1055 case ftBool: {
1056 const auto typname = GetTypeBasic(type);
1057 const auto default_value = GetDefaultScalarValue(field);
1058 return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + \
1059 default_value + ")).unwrap()";
1060 }
1061 case ftStruct: {
1062 const auto typname = WrapInNameSpace(*type.struct_def);
1063 return AddUnwrapIfRequired("self._tab.get::<" + typname + ">(" + offset_name + ", None)", field.required);
1064 }
1065 case ftTable: {
1066 const auto typname = WrapInNameSpace(*type.struct_def);
1067 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + \
1068 typname + "<" + lifetime + ">>>(" + offset_name + ", None)", field.required);
1069 }
1070 case ftUnionValue: {
1071 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1072 "flatbuffers::Table<" + lifetime + ">>>(" + offset_name + \
1073 ", None)", field.required);
1074 }
1075 case ftUnionKey:
1076 case ftEnumKey: {
1077 const auto underlying_typname = GetTypeBasic(type);
1078 const auto typname = WrapInNameSpace(*type.enum_def);
1079 const auto default_value = GetDefaultScalarValue(field);
1080 return "self._tab.get::<" + typname + ">(" + offset_name + \
1081 ", Some(" + default_value + ")).unwrap()";
1082 }
1083 case ftString: {
1084 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" + \
1085 offset_name + ", None)", field.required);
1086 }
1087
1088 case ftVectorOfInteger:
1089 case ftVectorOfFloat: {
1090 const auto typname = GetTypeBasic(type.VectorType());
1091 std::string s = "self._tab.get::<flatbuffers::ForwardsUOffset<"
1092 "flatbuffers::Vector<" + lifetime + ", " + typname + \
1093 ">>>(" + offset_name + ", None)";
1094 // single-byte values are safe to slice
1095 if (IsOneByte(type.VectorType().base_type)) {
1096 s += ".map(|v| v.safe_slice())";
1097 }
1098 return AddUnwrapIfRequired(s, field.required);
1099 }
1100 case ftVectorOfBool: {
1101 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1102 "flatbuffers::Vector<" + lifetime + ", bool>>>(" + \
1103 offset_name + ", None).map(|v| v.safe_slice())", field.required);
1104 }
1105 case ftVectorOfEnumKey: {
1106 const auto typname = WrapInNameSpace(*type.enum_def);
1107 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1108 "flatbuffers::Vector<" + lifetime + ", " + typname + ">>>(" + \
1109 offset_name + ", None)", field.required);
1110 }
1111 case ftVectorOfStruct: {
1112 const auto typname = WrapInNameSpace(*type.struct_def);
1113 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1114 "flatbuffers::Vector<" + typname + ">>>(" + \
1115 offset_name + ", None).map(|v| v.safe_slice() )", field.required);
1116 }
1117 case ftVectorOfTable: {
1118 const auto typname = WrapInNameSpace(*type.struct_def);
1119 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1120 "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + typname + \
1121 "<" + lifetime + ">>>>>(" + offset_name + ", None)", field.required);
1122 }
1123 case ftVectorOfString: {
1124 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1125 "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \
1126 lifetime + " str>>>>(" + offset_name + ", None)", field.required);
1127 }
1128 case ftVectorOfUnionValue: {
1129 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1130 return "INVALID_CODE_GENERATION"; // for return analysis
1131 }
1132 }
1133 return "INVALID_CODE_GENERATION"; // for return analysis
1134 }
1135
1136 bool TableFieldReturnsOption(const Type& type) {
1137 switch (GetFullType(type)) {
1138 case ftInteger:
1139 case ftFloat:
1140 case ftBool:
1141 case ftEnumKey:
1142 case ftUnionKey:
1143 return false;
1144 default: return true;
1145 }
1146 }
1147
1148 // Generate an accessor struct, builder struct, and create function for a
1149 // table.
1150 void GenTable(const StructDef &struct_def) {
1151 code_.SetValue("STRUCT_NAME", Name(struct_def));
1152 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1153 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
1154
1155 // Generate an offset type, the base type, the Follow impl, and the
1156 // init_from_table impl.
1157 code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
1158 code_ += "#[derive(Copy, Clone, Debug, PartialEq)]";
1159 code_ += "";
1160
1161 GenComment(struct_def.doc_comment);
1162
1163 code_ += "pub struct {{STRUCT_NAME}}<'a> {";
1164 code_ += " pub _tab: flatbuffers::Table<'a>,";
1165 code_ += "}";
1166 code_ += "";
1167 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
1168 code_ += " type Inner = {{STRUCT_NAME}}<'a>;";
1169 code_ += " #[inline]";
1170 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1171 code_ += " Self {";
1172 code_ += " _tab: flatbuffers::Table { buf: buf, loc: loc },";
1173 code_ += " }";
1174 code_ += " }";
1175 code_ += "}";
1176 code_ += "";
1177 code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
1178 code_ += " #[inline]";
1179 code_ += " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
1180 "Self {";
1181 code_ += " {{STRUCT_NAME}} {";
1182 code_ += " _tab: table,";
1183 code_ += " }";
1184 code_ += " }";
1185
1186 // Generate a convenient create* function that uses the above builder
1187 // to create a table in one function call.
1188 code_.SetValue("MAYBE_US",
1189 struct_def.fields.vec.size() == 0 ? "_" : "");
1190 code_.SetValue("MAYBE_LT",
1191 TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
1192 code_ += " #[allow(unused_mut)]";
1193 code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
1194 code_ += " _fbb: "
1195 "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1196 code_ += " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
1197 " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
1198
1199 code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
1200 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1201 size; size /= 2) {
1202 for (auto it = struct_def.fields.vec.rbegin();
1203 it != struct_def.fields.vec.rend(); ++it) {
1204 const auto &field = **it;
1205 // TODO(rw): fully understand this sortbysize usage
1206 if (!field.deprecated && (!struct_def.sortbysize ||
1207 size == SizeOf(field.value.type.base_type))) {
1208 code_.SetValue("FIELD_NAME", Name(field));
1209 if (TableFieldReturnsOption(field.value.type)) {
1210 code_ += " 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_ += " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1235 "{{OFFSET_VALUE}};";
1236 }
1237 code_ += "";
1238 }
1239
1240 // Generate the accessors. Each has one of two forms:
1241 //
1242 // If a value can be None:
1243 // pub fn name(&'a self) -> Option<user_facing_type> {
1244 // self._tab.get::<internal_type>(offset, defaultval)
1245 // }
1246 //
1247 // If a value is always Some:
1248 // pub fn name(&'a self) -> user_facing_type {
1249 // self._tab.get::<internal_type>(offset, defaultval).unwrap()
1250 // }
1251 const auto offset_prefix = Name(struct_def);
1252 for (auto it = struct_def.fields.vec.begin();
1253 it != struct_def.fields.vec.end(); ++it) {
1254 const auto &field = **it;
1255 if (field.deprecated) {
1256 // Deprecated fields won't be accessible.
1257 continue;
1258 }
1259
1260 code_.SetValue("FIELD_NAME", Name(field));
1261 code_.SetValue("RETURN_TYPE",
1262 GenTableAccessorFuncReturnType(field, "'a"));
1263 code_.SetValue("FUNC_BODY",
1264 GenTableAccessorFuncBody(field, "'a", offset_prefix));
1265
1266 GenComment(field.doc_comment, " ");
1267 code_ += " #[inline]";
1268 code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
1269 code_ += " {{FUNC_BODY}}";
1270 code_ += " }";
1271
1272 // Generate a comparison function for this field if it is a key.
1273 if (field.key) {
1274 GenKeyFieldMethods(field);
1275 }
1276
1277 // Generate a nested flatbuffer field, if applicable.
1278 auto nested = field.attributes.Lookup("nested_flatbuffer");
1279 if (nested) {
1280 std::string qualified_name = nested->constant;
1281 auto nested_root = parser_.LookupStruct(nested->constant);
1282 if (nested_root == nullptr) {
1283 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1284 nested->constant);
1285 nested_root = parser_.LookupStruct(qualified_name);
1286 }
1287 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
1288 (void)nested_root;
1289
1290 code_.SetValue("OFFSET_NAME",
1291 offset_prefix + "::" + GetFieldOffsetName(field));
1292 code_ += " 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_ += " Some(<flatbuffers::ForwardsUOffset"
1299 "<{{STRUCT_NAME}}<'a>>>::follow(data, 0))";
1300 code_ += " },";
1301 code_ += " }";
1302 code_ += " }";
1303 }
1304 }
1305
1306 // Explicit specializations for union accessors
1307 for (auto it = struct_def.fields.vec.begin();
1308 it != struct_def.fields.vec.end(); ++it) {
1309 const auto &field = **it;
1310 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
1311 continue;
1312 }
1313
1314 auto u = field.value.type.enum_def;
1315
1316 code_.SetValue("FIELD_NAME", Name(field));
1317
1318 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
1319 auto &ev = **u_it;
1320 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1321
1322 auto table_init_type = WrapInNameSpace(
1323 ev.union_type.struct_def->defined_namespace,
1324 ev.union_type.struct_def->name);
1325
1326 code_.SetValue("U_ELEMENT_ENUM_TYPE",
1327 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
1328 code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type);
1329 code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
1330
1331 code_ += " #[inline]";
1332 code_ += " #[allow(non_snake_case)]";
1333 code_ += " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
1334 "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
1335 code_ += " if self.{{FIELD_NAME}}_type() == {{U_ELEMENT_ENUM_TYPE}} {";
1336 code_ += " self.{{FIELD_NAME}}().map(|u| "
1337 "{{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
1338 code_ += " } else {";
1339 code_ += " None";
1340 code_ += " }";
1341 code_ += " }";
1342 code_ += "";
1343 }
1344 }
1345
1346 code_ += "}"; // End of table impl.
1347 code_ += "";
1348
1349 // Generate an args struct:
1350 code_.SetValue("MAYBE_LT",
1351 TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
1352 code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1353 for (auto it = struct_def.fields.vec.begin();
1354 it != struct_def.fields.vec.end(); ++it) {
1355 const auto &field = **it;
1356 if (!field.deprecated) {
1357 code_.SetValue("PARAM_NAME", Name(field));
1358 code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a "));
1359 code_ += " pub {{PARAM_NAME}}: {{PARAM_TYPE}},";
1360 }
1361 }
1362 code_ += "}";
1363
1364 // Generate an impl of Default for the *Args type:
1365 code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1366 code_ += " #[inline]";
1367 code_ += " fn default() -> Self {";
1368 code_ += " {{STRUCT_NAME}}Args {";
1369 for (auto it = struct_def.fields.vec.begin();
1370 it != struct_def.fields.vec.end(); ++it) {
1371 const auto &field = **it;
1372 if (!field.deprecated) {
1373 code_.SetValue("PARAM_VALUE", TableBuilderArgsDefaultValue(field));
1374 code_.SetValue("REQ", field.required ? " // required field" : "");
1375 code_.SetValue("PARAM_NAME", Name(field));
1376 code_ += " {{PARAM_NAME}}: {{PARAM_VALUE}},{{REQ}}";
1377 }
1378 }
1379 code_ += " }";
1380 code_ += " }";
1381 code_ += "}";
1382
1383 // Generate a builder struct:
1384 code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
1385 code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1386 code_ += " start_: flatbuffers::WIPOffset<"
1387 "flatbuffers::TableUnfinishedWIPOffset>,";
1388 code_ += "}";
1389
1390 // Generate builder functions:
1391 code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
1392 for (auto it = struct_def.fields.vec.begin();
1393 it != struct_def.fields.vec.end(); ++it) {
1394 const auto &field = **it;
1395 if (!field.deprecated) {
1396 const bool is_scalar = IsScalar(field.value.type.base_type);
1397
1398 std::string offset = GetFieldOffsetName(field);
1399 std::string name = Name(field);
1400 std::string value = GetDefaultScalarValue(field);
1401
1402 // Generate functions to add data, which take one of two forms.
1403 //
1404 // If a value has a default:
1405 // fn add_x(x_: type) {
1406 // fbb_.push_slot::<type>(offset, x_, Some(default));
1407 // }
1408 //
1409 // If a value does not have a default:
1410 // fn add_x(x_: type) {
1411 // fbb_.push_slot_always::<type>(offset, x_);
1412 // }
1413 code_.SetValue("FIELD_NAME", Name(field));
1414 code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
1415 code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
1416 code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
1417 code_ += " #[inline]";
1418 code_ += " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
1419 "{{FIELD_TYPE}}) {";
1420 if (is_scalar) {
1421 code_.SetValue("FIELD_DEFAULT_VALUE",
1422 TableBuilderAddFuncDefaultValue(field));
1423 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
1424 "{{FIELD_DEFAULT_VALUE}});";
1425 } else {
1426 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
1427 }
1428 code_ += " }";
1429 }
1430 }
1431
1432 // Struct initializer (all fields required);
1433 code_ += " #[inline]";
1434 code_ +=
1435 " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
1436 "{{STRUCT_NAME}}Builder<'a, 'b> {";
1437 code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
1438 code_ += " let start = _fbb.start_table();";
1439 code_ += " {{STRUCT_NAME}}Builder {";
1440 code_ += " fbb_: _fbb,";
1441 code_ += " start_: start,";
1442 code_ += " }";
1443 code_ += " }";
1444
1445 // finish() function.
1446 code_ += " #[inline]";
1447 code_ += " pub fn finish(self) -> "
1448 "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
1449 code_ += " let o = self.fbb_.end_table(self.start_);";
1450
1451 for (auto it = struct_def.fields.vec.begin();
1452 it != struct_def.fields.vec.end(); ++it) {
1453 const auto &field = **it;
1454 if (!field.deprecated && field.required) {
1455 code_.SetValue("FIELD_NAME", MakeSnakeCase(Name(field)));
1456 code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1457 code_ += " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
1458 "\"{{FIELD_NAME}}\");";
1459 }
1460 }
1461 code_ += " flatbuffers::WIPOffset::new(o.value())";
1462 code_ += " }";
1463 code_ += "}";
1464 code_ += "";
1465 }
1466
1467 // Generate functions to compare tables and structs by key. This function
1468 // must only be called if the field key is defined.
1469 void GenKeyFieldMethods(const FieldDef &field) {
1470 FLATBUFFERS_ASSERT(field.key);
1471
1472 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
1473
1474 code_ += " #[inline]";
1475 code_ += " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
1476 " bool {";
1477 code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
1478 code_ += " }";
1479 code_ += "";
1480 code_ += " #[inline]";
1481 code_ += " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
1482 " ::std::cmp::Ordering {";
1483 code_ += " let key = self.{{FIELD_NAME}}();";
1484 code_ += " key.cmp(&val)";
1485 code_ += " }";
1486 }
1487
1488 // Generate functions for accessing the root table object. This function
1489 // must only be called if the root table is defined.
1490 void GenRootTableFuncs(const StructDef &struct_def) {
1491 FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
1492 auto name = Name(struct_def);
1493
1494 code_.SetValue("STRUCT_NAME", name);
1495 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
1496 code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
1497
1498 // The root datatype accessors:
1499 code_ += "#[inline]";
1500 code_ +=
1501 "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
1502 " -> {{STRUCT_NAME}}<'a> {";
1503 code_ += " flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)";
1504 code_ += "}";
1505 code_ += "";
1506
1507 code_ += "#[inline]";
1508 code_ += "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
1509 "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
1510 code_ += " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
1511 "(buf)";
1512 code_ += "}";
1513 code_ += "";
1514
1515 if (parser_.file_identifier_.length()) {
1516 // Declare the identifier
1517 code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &'static str\\";
1518 code_ += " = \"" + parser_.file_identifier_ + "\";";
1519 code_ += "";
1520
1521 // Check if a buffer has the identifier.
1522 code_ += "#[inline]";
1523 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
1524 code_ += "(buf: &[u8]) -> bool {";
1525 code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
1526 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false);";
1527 code_ += "}";
1528 code_ += "";
1529 code_ += "#[inline]";
1530 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
1531 code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
1532 code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
1533 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true);";
1534 code_ += "}";
1535 code_ += "";
1536 }
1537
1538 if (parser_.file_extension_.length()) {
1539 // Return the extension
1540 code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &'static str = \\";
1541 code_ += "\"" + parser_.file_extension_ + "\";";
1542 code_ += "";
1543 }
1544
1545 // Finish a buffer with a given root object:
1546 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1547 code_ += "#[inline]";
1548 code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
1549 code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1550 code_ += " root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1551 if (parser_.file_identifier_.length()) {
1552 code_ += " fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1553 } else {
1554 code_ += " fbb.finish(root, None);";
1555 }
1556 code_ += "}";
1557 code_ += "";
1558 code_ += "#[inline]";
1559 code_ += "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
1560 "<'a, 'b>("
1561 "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
1562 "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1563 if (parser_.file_identifier_.length()) {
1564 code_ += " fbb.finish_size_prefixed(root, "
1565 "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1566 } else {
1567 code_ += " fbb.finish_size_prefixed(root, None);";
1568 }
1569 code_ += "}";
1570 }
1571
1572 static void GenPadding(
1573 const FieldDef &field, std::string *code_ptr, int *id,
1574 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
1575 if (field.padding) {
1576 for (int i = 0; i < 4; i++) {
1577 if (static_cast<int>(field.padding) & (1 << i)) {
1578 f((1 << i) * 8, code_ptr, id);
1579 }
1580 }
1581 assert(!(field.padding & ~0xF));
1582 }
1583 }
1584
1585 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
1586 *code_ptr += " padding" + NumToString((*id)++) + "__: u" + \
1587 NumToString(bits) + ",";
1588 }
1589
1590 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
1591 (void)bits;
1592 *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
1593 }
1594
1595 // Generate an accessor struct with constructor for a flatbuffers struct.
1596 void GenStruct(const StructDef &struct_def) {
1597 // Generates manual padding and alignment.
1598 // Variables are private because they contain little endian data on all
1599 // platforms.
1600 GenComment(struct_def.doc_comment);
1601 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
1602 code_.SetValue("STRUCT_NAME", Name(struct_def));
1603
1604 code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
1605 code_ += "#[repr(C, align({{ALIGN}}))]";
1606
1607 // PartialEq is useful to derive because we can correctly compare structs
1608 // for equality by just comparing their underlying byte data. This doesn't
1609 // hold for PartialOrd/Ord.
1610 code_ += "#[derive(Clone, Copy, Debug, PartialEq)]";
1611 code_ += "pub struct {{STRUCT_NAME}} {";
1612
1613 int padding_id = 0;
1614 for (auto it = struct_def.fields.vec.begin();
1615 it != struct_def.fields.vec.end(); ++it) {
1616 const auto &field = **it;
1617 code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
1618 code_.SetValue("FIELD_NAME", Name(field));
1619 code_ += " {{FIELD_NAME}}_: {{FIELD_TYPE}},";
1620
1621 if (field.padding) {
1622 std::string padding;
1623 GenPadding(field, &padding, &padding_id, PaddingDefinition);
1624 code_ += padding;
1625 }
1626 }
1627
1628 code_ += "} // pub struct {{STRUCT_NAME}}";
1629
1630 // Generate impls for SafeSliceAccess (because all structs are endian-safe),
1631 // Follow for the value type, Follow for the reference type, Push for the
1632 // value type, and Push for the reference type.
1633 code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
1634 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
1635 code_ += " type Inner = &'a {{STRUCT_NAME}};";
1636 code_ += " #[inline]";
1637 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1638 code_ += " <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
1639 code_ += " }";
1640 code_ += "}";
1641 code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
1642 code_ += " type Inner = &'a {{STRUCT_NAME}};";
1643 code_ += " #[inline]";
1644 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1645 code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
1646 code_ += " }";
1647 code_ += "}";
1648 code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
1649 code_ += " type Output = {{STRUCT_NAME}};";
1650 code_ += " #[inline]";
1651 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1652 code_ += " let src = unsafe {";
1653 code_ += " ::std::slice::from_raw_parts("
1654 "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1655 code_ += " };";
1656 code_ += " dst.copy_from_slice(src);";
1657 code_ += " }";
1658 code_ += "}";
1659 code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
1660 code_ += " type Output = {{STRUCT_NAME}};";
1661 code_ += "";
1662 code_ += " #[inline]";
1663 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1664 code_ += " let src = unsafe {";
1665 code_ += " ::std::slice::from_raw_parts("
1666 "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1667 code_ += " };";
1668 code_ += " dst.copy_from_slice(src);";
1669 code_ += " }";
1670 code_ += "}";
1671 code_ += "";
1672 code_ += "";
1673
1674 // Generate a constructor that takes all fields as arguments.
1675 code_ += "impl {{STRUCT_NAME}} {";
1676 std::string arg_list;
1677 std::string init_list;
1678 padding_id = 0;
1679 for (auto it = struct_def.fields.vec.begin();
1680 it != struct_def.fields.vec.end(); ++it) {
1681 const auto &field = **it;
1682 const auto member_name = Name(field) + "_";
1683 const auto reference = StructMemberAccessNeedsCopy(field.value.type)
1684 ? "" : "&'a ";
1685 const auto arg_name = "_" + Name(field);
1686 const auto arg_type = reference + GetTypeGet(field.value.type);
1687
1688 if (it != struct_def.fields.vec.begin()) {
1689 arg_list += ", ";
1690 }
1691 arg_list += arg_name + ": ";
1692 arg_list += arg_type;
1693 init_list += " " + member_name;
1694 if (StructMemberAccessNeedsCopy(field.value.type)) {
1695 init_list += ": " + arg_name + ".to_little_endian(),\n";
1696 } else {
1697 init_list += ": *" + arg_name + ",\n";
1698 }
1699 }
1700
1701 code_.SetValue("ARG_LIST", arg_list);
1702 code_.SetValue("INIT_LIST", init_list);
1703 code_ += " pub fn new<'a>({{ARG_LIST}}) -> Self {";
1704 code_ += " {{STRUCT_NAME}} {";
1705 code_ += "{{INIT_LIST}}";
1706 padding_id = 0;
1707 for (auto it = struct_def.fields.vec.begin();
1708 it != struct_def.fields.vec.end(); ++it) {
1709 const auto &field = **it;
1710 if (field.padding) {
1711 std::string padding;
1712 GenPadding(field, &padding, &padding_id, PaddingInitializer);
1713 code_ += " " + padding;
1714 }
1715 }
1716 code_ += " }";
1717 code_ += " }";
1718
1719 // Generate accessor methods for the struct.
1720 for (auto it = struct_def.fields.vec.begin();
1721 it != struct_def.fields.vec.end(); ++it) {
1722 const auto &field = **it;
1723
1724 auto field_type = TableBuilderArgsAddFuncType(field, "'a");
1725 auto member = "self." + Name(field) + "_";
1726 auto value = StructMemberAccessNeedsCopy(field.value.type) ?
1727 member + ".from_little_endian()" : member;
1728
1729 code_.SetValue("FIELD_NAME", Name(field));
1730 code_.SetValue("FIELD_TYPE", field_type);
1731 code_.SetValue("FIELD_VALUE", value);
1732 code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
1733
1734 GenComment(field.doc_comment, " ");
1735 code_ += " pub fn {{FIELD_NAME}}<'a>(&'a self) -> {{FIELD_TYPE}} {";
1736 code_ += " {{REF}}{{FIELD_VALUE}}";
1737 code_ += " }";
1738
1739 // Generate a comparison function for this field if it is a key.
1740 if (field.key) {
1741 GenKeyFieldMethods(field);
1742 }
1743 }
1744 code_ += "}";
1745 code_ += "";
1746 }
1747
1748 void GenNamespaceImports(const int white_spaces) {
1749 std::string indent = std::string(white_spaces, ' ');
1750 code_ += "";
1751 code_ += indent + "use std::mem;";
1752 code_ += indent + "use std::cmp::Ordering;";
1753 code_ += "";
1754 code_ += indent + "extern crate flatbuffers;";
1755 code_ += indent + "use self::flatbuffers::EndianScalar;";
1756 }
1757
1758 // Set up the correct namespace. This opens a namespace if the current
1759 // namespace is different from the target namespace. This function
1760 // closes and opens the namespaces only as necessary.
1761 //
1762 // The file must start and end with an empty (or null) namespace so that
1763 // namespaces are properly opened and closed.
1764 void SetNameSpace(const Namespace *ns) {
1765 if (cur_name_space_ == ns) { return; }
1766
1767 // Compute the size of the longest common namespace prefix.
1768 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
1769 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
1770 // and common_prefix_size = 2
1771 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
1772 size_t new_size = ns ? ns->components.size() : 0;
1773
1774 size_t common_prefix_size = 0;
1775 while (common_prefix_size < old_size && common_prefix_size < new_size &&
1776 ns->components[common_prefix_size] ==
1777 cur_name_space_->components[common_prefix_size]) {
1778 common_prefix_size++;
1779 }
1780
1781 // Close cur_name_space in reverse order to reach the common prefix.
1782 // In the previous example, D then C are closed.
1783 for (size_t j = old_size; j > common_prefix_size; --j) {
1784 code_ += "} // pub mod " + cur_name_space_->components[j - 1];
1785 }
1786 if (old_size != common_prefix_size) { code_ += ""; }
1787
1788 // open namespace parts to reach the ns namespace
1789 // in the previous example, E, then F, then G are opened
1790 for (auto j = common_prefix_size; j != new_size; ++j) {
1791 code_ += "#[allow(unused_imports, dead_code)]";
1792 code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
1793 // Generate local namespace imports.
1794 GenNamespaceImports(2);
1795 }
1796 if (new_size != common_prefix_size) { code_ += ""; }
1797
1798 cur_name_space_ = ns;
1799 }
1800};
1801
1802} // namespace rust
1803
1804bool GenerateRust(const Parser &parser, const std::string &path,
1805 const std::string &file_name) {
1806 rust::RustGenerator generator(parser, path, file_name);
1807 return generator.generate();
1808}
1809
1810std::string RustMakeRule(const Parser &parser, const std::string &path,
1811 const std::string &file_name) {
1812 std::string filebase =
1813 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
1814 std::string make_rule = GeneratedFileName(path, filebase) + ": ";
1815
1816 auto included_files = parser.GetIncludedFilesRecursive(file_name);
1817 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1818 make_rule += " " + *it;
1819 }
1820 return make_rule;
1821}
1822
1823} // namespace flatbuffers
1824
1825// TODO(rw): Generated code should import other generated files.
1826// TODO(rw): Generated code should refer to namespaces in included files in a
1827// way that makes them referrable.
1828// TODO(rw): Generated code should indent according to nesting level.
1829// TODO(rw): Generated code should generate endian-safe Debug impls.
1830// TODO(rw): Generated code could use a Rust-only enum type to access unions,
1831// instead of making the user use _type() to manually switch.
1832