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