1 /*
2 * Copyright 2018 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // independent from idl_parser, since this code is not needed for most clients
18
19 #include "flatbuffers/code_generators.h"
20 #include "flatbuffers/flatbuffers.h"
21 #include "flatbuffers/idl.h"
22 #include "flatbuffers/util.h"
23
24 namespace flatbuffers {
25
26 // Convert a camelCaseIdentifier or CamelCaseIdentifier to a
27 // snake_case_identifier.
MakeSnakeCase(const std::string & in)28 std::string MakeSnakeCase(const std::string &in) {
29 std::string s;
30 for (size_t i = 0; i < in.length(); i++) {
31 if (i == 0) {
32 s += CharToLower(in[0]);
33 } else if (in[i] == '_') {
34 s += '_';
35 } else if (!islower(in[i])) {
36 // Prevent duplicate underscores for Upper_Snake_Case strings
37 // and UPPERCASE strings.
38 if (islower(in[i - 1])) { s += '_'; }
39 s += CharToLower(in[i]);
40 } else {
41 s += in[i];
42 }
43 }
44 return s;
45 }
46
47 // Convert a string to all uppercase.
MakeUpper(const std::string & in)48 std::string MakeUpper(const std::string &in) {
49 std::string s;
50 for (size_t i = 0; i < in.length(); i++) { s += CharToUpper(in[i]); }
51 return s;
52 }
53
54 // Encapsulate all logical field types in this enum. This allows us to write
55 // field logic based on type switches, instead of branches on the properties
56 // set on the Type.
57 // TODO(rw): for backwards compatibility, we can't use a strict `enum class`
58 // declaration here. could we use the `-Wswitch-enum` warning to
59 // achieve the same effect?
60 enum FullType {
61 ftInteger = 0,
62 ftFloat = 1,
63 ftBool = 2,
64
65 ftStruct = 3,
66 ftTable = 4,
67
68 ftEnumKey = 5,
69 ftUnionKey = 6,
70
71 ftUnionValue = 7,
72
73 // TODO(rw): bytestring?
74 ftString = 8,
75
76 ftVectorOfInteger = 9,
77 ftVectorOfFloat = 10,
78 ftVectorOfBool = 11,
79 ftVectorOfEnumKey = 12,
80 ftVectorOfStruct = 13,
81 ftVectorOfTable = 14,
82 ftVectorOfString = 15,
83 ftVectorOfUnionValue = 16,
84
85 ftArrayOfBuiltin = 17,
86 ftArrayOfEnum = 18,
87 ftArrayOfStruct = 19,
88 };
89
90 // Convert a Type to a FullType (exhaustive).
GetFullType(const Type & type)91 FullType GetFullType(const Type &type) {
92 // N.B. The order of these conditionals matters for some types.
93
94 if (IsString(type)) {
95 return ftString;
96 } else if (type.base_type == BASE_TYPE_STRUCT) {
97 if (type.struct_def->fixed) {
98 return ftStruct;
99 } else {
100 return ftTable;
101 }
102 } else if (IsVector(type)) {
103 switch (GetFullType(type.VectorType())) {
104 case ftInteger: {
105 return ftVectorOfInteger;
106 }
107 case ftFloat: {
108 return ftVectorOfFloat;
109 }
110 case ftBool: {
111 return ftVectorOfBool;
112 }
113 case ftStruct: {
114 return ftVectorOfStruct;
115 }
116 case ftTable: {
117 return ftVectorOfTable;
118 }
119 case ftString: {
120 return ftVectorOfString;
121 }
122 case ftEnumKey: {
123 return ftVectorOfEnumKey;
124 }
125 case ftUnionKey:
126 case ftUnionValue: {
127 FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
128 break;
129 }
130 default: {
131 FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
132 }
133 }
134 } else if (IsArray(type)) {
135 switch (GetFullType(type.VectorType())) {
136 case ftInteger:
137 case ftFloat:
138 case ftBool: {
139 return ftArrayOfBuiltin;
140 }
141 case ftStruct: {
142 return ftArrayOfStruct;
143 }
144 case ftEnumKey: {
145 return ftArrayOfEnum;
146 }
147 default: {
148 FLATBUFFERS_ASSERT(false && "Unsupported type for fixed array");
149 }
150 }
151 } else if (type.enum_def != nullptr) {
152 if (type.enum_def->is_union) {
153 if (type.base_type == BASE_TYPE_UNION) {
154 return ftUnionValue;
155 } else if (IsInteger(type.base_type)) {
156 return ftUnionKey;
157 } else {
158 FLATBUFFERS_ASSERT(false && "unknown union field type");
159 }
160 } else {
161 return ftEnumKey;
162 }
163 } else if (IsScalar(type.base_type)) {
164 if (IsBool(type.base_type)) {
165 return ftBool;
166 } else if (IsInteger(type.base_type)) {
167 return ftInteger;
168 } else if (IsFloat(type.base_type)) {
169 return ftFloat;
170 } else {
171 FLATBUFFERS_ASSERT(false && "unknown number type");
172 }
173 }
174
175 FLATBUFFERS_ASSERT(false && "completely unknown type");
176
177 // this is only to satisfy the compiler's return analysis.
178 return ftBool;
179 }
180
181 // If the second parameter is false then wrap the first with Option<...>
WrapInOptionIfNotRequired(std::string s,bool required)182 std::string WrapInOptionIfNotRequired(std::string s, bool required) {
183 if (required) {
184 return s;
185 } else {
186 return "Option<" + s + ">";
187 }
188 }
189
190 // If the second parameter is false then add .unwrap()
AddUnwrapIfRequired(std::string s,bool required)191 std::string AddUnwrapIfRequired(std::string s, bool required) {
192 if (required) {
193 return s + ".unwrap()";
194 } else {
195 return s;
196 }
197 }
198
IsBitFlagsEnum(const EnumDef & enum_def)199 bool IsBitFlagsEnum(const EnumDef &enum_def) {
200 return enum_def.attributes.Lookup("bit_flags") != nullptr;
201 }
IsBitFlagsEnum(const FieldDef & field)202 bool IsBitFlagsEnum(const FieldDef &field) {
203 EnumDef *ed = field.value.type.enum_def;
204 return ed && IsBitFlagsEnum(*ed);
205 }
206
207 // TableArgs make required non-scalars "Option<_>".
208 // TODO(cneo): Rework how we do defaults and stuff.
IsOptionalToBuilder(const FieldDef & field)209 bool IsOptionalToBuilder(const FieldDef &field) {
210 return field.IsOptional() || !IsScalar(field.value.type.base_type);
211 }
212
213 namespace rust {
214
215 class RustGenerator : public BaseGenerator {
216 public:
RustGenerator(const Parser & parser,const std::string & path,const std::string & file_name)217 RustGenerator(const Parser &parser, const std::string &path,
218 const std::string &file_name)
219 : BaseGenerator(parser, path, file_name, "", "::", "rs"),
220 cur_name_space_(nullptr) {
221 const char *keywords[] = {
222 // clang-format off
223 // list taken from:
224 // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
225 //
226 // we write keywords one per line so that we can easily compare them with
227 // changes to that webpage in the future.
228
229 // currently-used keywords
230 "as",
231 "break",
232 "const",
233 "continue",
234 "crate",
235 "else",
236 "enum",
237 "extern",
238 "false",
239 "fn",
240 "for",
241 "if",
242 "impl",
243 "in",
244 "let",
245 "loop",
246 "match",
247 "mod",
248 "move",
249 "mut",
250 "pub",
251 "ref",
252 "return",
253 "Self",
254 "self",
255 "static",
256 "struct",
257 "super",
258 "trait",
259 "true",
260 "type",
261 "unsafe",
262 "use",
263 "where",
264 "while",
265
266 // future possible keywords
267 "abstract",
268 "alignof",
269 "become",
270 "box",
271 "do",
272 "final",
273 "macro",
274 "offsetof",
275 "override",
276 "priv",
277 "proc",
278 "pure",
279 "sizeof",
280 "typeof",
281 "unsized",
282 "virtual",
283 "yield",
284
285 // other rust terms we should not use
286 "std",
287 "usize",
288 "isize",
289 "u8",
290 "i8",
291 "u16",
292 "i16",
293 "u32",
294 "i32",
295 "u64",
296 "i64",
297 "u128",
298 "i128",
299 "f32",
300 "f64",
301
302 // These are terms the code generator can implement on types.
303 //
304 // In Rust, the trait resolution rules (as described at
305 // https://github.com/rust-lang/rust/issues/26007) mean that, as long
306 // as we impl table accessors as inherent methods, we'll never create
307 // conflicts with these keywords. However, that's a fairly nuanced
308 // implementation detail, and how we implement methods could change in
309 // the future. as a result, we proactively block these out as reserved
310 // words.
311 "follow",
312 "push",
313 "size",
314 "alignment",
315 "to_little_endian",
316 "from_little_endian",
317 nullptr,
318
319 // used by Enum constants
320 "ENUM_MAX",
321 "ENUM_MIN",
322 "ENUM_VALUES",
323 };
324 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
325 }
326
327 // Iterate through all definitions we haven't generated code for (enums,
328 // structs, and tables) and output them to a single file.
generate()329 bool generate() {
330 code_.Clear();
331 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
332
333 assert(!cur_name_space_);
334
335 // Generate imports for the global scope in case no namespace is used
336 // in the schema file.
337 GenNamespaceImports(0);
338 code_ += "";
339
340 // Generate all code in their namespaces, once, because Rust does not
341 // permit re-opening modules.
342 //
343 // TODO(rw): Use a set data structure to reduce namespace evaluations from
344 // O(n**2) to O(n).
345 for (auto ns_it = parser_.namespaces_.begin();
346 ns_it != parser_.namespaces_.end(); ++ns_it) {
347 const auto &ns = *ns_it;
348
349 // Generate code for all the enum declarations.
350 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
351 ++it) {
352 const auto &enum_def = **it;
353 if (enum_def.defined_namespace == ns && !enum_def.generated) {
354 SetNameSpace(enum_def.defined_namespace);
355 GenEnum(enum_def);
356 }
357 }
358
359 // Generate code for all structs.
360 for (auto it = parser_.structs_.vec.begin();
361 it != parser_.structs_.vec.end(); ++it) {
362 const auto &struct_def = **it;
363 if (struct_def.defined_namespace == ns && struct_def.fixed &&
364 !struct_def.generated) {
365 SetNameSpace(struct_def.defined_namespace);
366 GenStruct(struct_def);
367 }
368 }
369
370 // Generate code for all tables.
371 for (auto it = parser_.structs_.vec.begin();
372 it != parser_.structs_.vec.end(); ++it) {
373 const auto &struct_def = **it;
374 if (struct_def.defined_namespace == ns && !struct_def.fixed &&
375 !struct_def.generated) {
376 SetNameSpace(struct_def.defined_namespace);
377 GenTable(struct_def);
378 if (parser_.opts.generate_object_based_api) {
379 GenTableObject(struct_def);
380 }
381 }
382 }
383
384 // Generate global helper functions.
385 if (parser_.root_struct_def_) {
386 auto &struct_def = *parser_.root_struct_def_;
387 if (struct_def.defined_namespace != ns) { continue; }
388 SetNameSpace(struct_def.defined_namespace);
389 GenRootTableFuncs(struct_def);
390 }
391 }
392 if (cur_name_space_) SetNameSpace(nullptr);
393
394 const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts);
395 const auto final_code = code_.ToString();
396 return SaveFile(file_path.c_str(), final_code, false);
397 }
398
399 private:
400 CodeWriter code_;
401
402 std::set<std::string> keywords_;
403
404 // This tracks the current namespace so we can insert namespace declarations.
405 const Namespace *cur_name_space_;
406
CurrentNameSpace() const407 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
408
409 // Determine if a Type needs a lifetime template parameter when used in the
410 // Rust builder args.
TableBuilderTypeNeedsLifetime(const Type & type) const411 bool TableBuilderTypeNeedsLifetime(const Type &type) const {
412 switch (GetFullType(type)) {
413 case ftInteger:
414 case ftFloat:
415 case ftBool:
416 case ftEnumKey:
417 case ftUnionKey:
418 case ftUnionValue: {
419 return false;
420 }
421 default: {
422 return true;
423 }
424 }
425 }
426
427 // Determine if a table args rust type needs a lifetime template parameter.
TableBuilderArgsNeedsLifetime(const StructDef & struct_def) const428 bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
429 FLATBUFFERS_ASSERT(!struct_def.fixed);
430
431 for (auto it = struct_def.fields.vec.begin();
432 it != struct_def.fields.vec.end(); ++it) {
433 const auto &field = **it;
434 if (field.deprecated) { continue; }
435
436 if (TableBuilderTypeNeedsLifetime(field.value.type)) { return true; }
437 }
438
439 return false;
440 }
441
EscapeKeyword(const std::string & name) const442 std::string EscapeKeyword(const std::string &name) const {
443 return keywords_.find(name) == keywords_.end() ? name : name + "_";
444 }
NamespacedNativeName(const Definition & def)445 std::string NamespacedNativeName(const Definition &def) {
446 return WrapInNameSpace(def.defined_namespace, NativeName(def));
447 }
448
NativeName(const Definition & def)449 std::string NativeName(const Definition &def) {
450 return parser_.opts.object_prefix + Name(def) + parser_.opts.object_suffix;
451 }
452
Name(const Definition & def) const453 std::string Name(const Definition &def) const {
454 return EscapeKeyword(def.name);
455 }
456
Name(const EnumVal & ev) const457 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
458
WrapInNameSpace(const Definition & def) const459 std::string WrapInNameSpace(const Definition &def) const {
460 return WrapInNameSpace(def.defined_namespace, Name(def));
461 }
WrapInNameSpace(const Namespace * ns,const std::string & name) const462 std::string WrapInNameSpace(const Namespace *ns,
463 const std::string &name) const {
464 if (CurrentNameSpace() == ns) return name;
465 std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
466 return prefix + name;
467 }
468
469 // Determine the namespace traversal needed from the Rust crate root.
470 // This may be useful in the future for referring to included files, but is
471 // currently unused.
GetAbsoluteNamespaceTraversal(const Namespace * dst) const472 std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const {
473 std::stringstream stream;
474
475 stream << "::";
476 for (auto d = dst->components.begin(); d != dst->components.end(); ++d) {
477 stream << MakeSnakeCase(*d) + "::";
478 }
479 return stream.str();
480 }
481
482 // Determine the relative namespace traversal needed to reference one
483 // namespace from another namespace. This is useful because it does not force
484 // the user to have a particular file layout. (If we output absolute
485 // namespace paths, that may require users to organize their Rust crates in a
486 // particular way.)
GetRelativeNamespaceTraversal(const Namespace * src,const Namespace * dst) const487 std::string GetRelativeNamespaceTraversal(const Namespace *src,
488 const Namespace *dst) const {
489 // calculate the path needed to reference dst from src.
490 // example: f(A::B::C, A::B::C) -> (none)
491 // example: f(A::B::C, A::B) -> super::
492 // example: f(A::B::C, A::B::D) -> super::D
493 // example: f(A::B::C, A) -> super::super::
494 // example: f(A::B::C, D) -> super::super::super::D
495 // example: f(A::B::C, D::E) -> super::super::super::D::E
496 // example: f(A, D::E) -> super::D::E
497 // does not include leaf object (typically a struct type).
498
499 size_t i = 0;
500 std::stringstream stream;
501
502 auto s = src->components.begin();
503 auto d = dst->components.begin();
504 for (;;) {
505 if (s == src->components.end()) { break; }
506 if (d == dst->components.end()) { break; }
507 if (*s != *d) { break; }
508 ++s;
509 ++d;
510 ++i;
511 }
512
513 for (; s != src->components.end(); ++s) { stream << "super::"; }
514 for (; d != dst->components.end(); ++d) {
515 stream << MakeSnakeCase(*d) + "::";
516 }
517 return stream.str();
518 }
519
520 // Generate a comment from the schema.
GenComment(const std::vector<std::string> & dc,const char * prefix="")521 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
522 std::string text;
523 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
524 code_ += text + "\\";
525 }
526
527 // Return a Rust type from the table in idl.h.
GetTypeBasic(const Type & type) const528 std::string GetTypeBasic(const Type &type) const {
529 switch (GetFullType(type)) {
530 case ftInteger:
531 case ftFloat:
532 case ftBool:
533 case ftEnumKey:
534 case ftUnionKey: {
535 break;
536 }
537 default: {
538 FLATBUFFERS_ASSERT(false && "incorrect type given");
539 }
540 }
541
542 // clang-format off
543 static const char * const ctypename[] = {
544 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
545 RTYPE, ...) \
546 #RTYPE,
547 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
548 #undef FLATBUFFERS_TD
549 };
550 // clang-format on
551
552 if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
553 return ctypename[type.base_type];
554 }
555
556 // Look up the native type for an enum. This will always be an integer like
557 // u8, i32, etc.
GetEnumTypeForDecl(const Type & type)558 std::string GetEnumTypeForDecl(const Type &type) {
559 const auto ft = GetFullType(type);
560 if (!(ft == ftEnumKey || ft == ftUnionKey)) {
561 FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
562 }
563
564 // clang-format off
565 static const char *ctypename[] = {
566 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
567 RTYPE, ...) \
568 #RTYPE,
569 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
570 #undef FLATBUFFERS_TD
571 };
572 // clang-format on
573
574 // Enums can be bools, but their Rust representation must be a u8, as used
575 // in the repr attribute (#[repr(bool)] is an invalid attribute).
576 if (type.base_type == BASE_TYPE_BOOL) return "u8";
577 return ctypename[type.base_type];
578 }
579
580 // Return a Rust type for any type (scalar, table, struct) specifically for
581 // using a FlatBuffer.
GetTypeGet(const Type & type) const582 std::string GetTypeGet(const Type &type) const {
583 switch (GetFullType(type)) {
584 case ftInteger:
585 case ftFloat:
586 case ftBool:
587 case ftEnumKey:
588 case ftUnionKey: {
589 return GetTypeBasic(type);
590 }
591 case ftArrayOfBuiltin:
592 case ftArrayOfEnum:
593 case ftArrayOfStruct: {
594 return "[" + GetTypeGet(type.VectorType()) + "; " +
595 NumToString(type.fixed_length) + "]";
596 }
597 case ftTable: {
598 return WrapInNameSpace(type.struct_def->defined_namespace,
599 type.struct_def->name) +
600 "<'a>";
601 }
602 default: {
603 return WrapInNameSpace(type.struct_def->defined_namespace,
604 type.struct_def->name);
605 }
606 }
607 }
608
GetEnumValue(const EnumDef & enum_def,const EnumVal & enum_val) const609 std::string GetEnumValue(const EnumDef &enum_def,
610 const EnumVal &enum_val) const {
611 return Name(enum_def) + "::" + Name(enum_val);
612 }
613
614 // 1 suffix since old C++ can't figure out the overload.
ForAllEnumValues1(const EnumDef & enum_def,std::function<void (const EnumVal &)> cb)615 void ForAllEnumValues1(const EnumDef &enum_def,
616 std::function<void(const EnumVal &)> cb) {
617 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
618 const auto &ev = **it;
619 code_.SetValue("VARIANT", Name(ev));
620 code_.SetValue("VALUE", enum_def.ToString(ev));
621 cb(ev);
622 }
623 }
ForAllEnumValues(const EnumDef & enum_def,std::function<void ()> cb)624 void ForAllEnumValues(const EnumDef &enum_def, std::function<void()> cb) {
625 std::function<void(const EnumVal &)> wrapped = [&](const EnumVal &unused) {
626 (void)unused;
627 cb();
628 };
629 ForAllEnumValues1(enum_def, wrapped);
630 }
631 // Generate an enum declaration,
632 // an enum string lookup table,
633 // an enum match function,
634 // and an enum array of values
GenEnum(const EnumDef & enum_def)635 void GenEnum(const EnumDef &enum_def) {
636 code_.SetValue("ENUM_NAME", Name(enum_def));
637 code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
638 code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
639 code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
640 const EnumVal *minv = enum_def.MinValue();
641 const EnumVal *maxv = enum_def.MaxValue();
642 FLATBUFFERS_ASSERT(minv && maxv);
643 code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
644 code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
645
646 if (IsBitFlagsEnum(enum_def)) {
647 // Defer to the convenient and canonical bitflags crate. We declare it in
648 // a module to #allow camel case constants in a smaller scope. This
649 // matches Flatbuffers c-modeled enums where variants are associated
650 // constants but in camel case.
651 code_ += "#[allow(non_upper_case_globals)]";
652 code_ += "mod bitflags_{{ENUM_NAME_SNAKE}} {";
653 code_ += " flatbuffers::bitflags::bitflags! {";
654 GenComment(enum_def.doc_comment, " ");
655 code_ += " #[derive(Default)]";
656 code_ += " pub struct {{ENUM_NAME}}: {{BASE_TYPE}} {";
657 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
658 this->GenComment(ev.doc_comment, " ");
659 code_ += " const {{VARIANT}} = {{VALUE}};";
660 });
661 code_ += " }";
662 code_ += " }";
663 code_ += "}";
664 code_ += "pub use self::bitflags_{{ENUM_NAME_SNAKE}}::{{ENUM_NAME}};";
665 code_ += "";
666
667 code_.SetValue("FROM_BASE", "unsafe { Self::from_bits_unchecked(b) }");
668 code_.SetValue("INTO_BASE", "self.bits()");
669 } else {
670 // Normal, c-modelled enums.
671 // Deprecated associated constants;
672 const std::string deprecation_warning =
673 "#[deprecated(since = \"2.0.0\", note = \"Use associated constants"
674 " instead. This will no longer be generated in 2021.\")]";
675 code_ += deprecation_warning;
676 code_ +=
677 "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
678 " = {{ENUM_MIN_BASE_VALUE}};";
679 code_ += deprecation_warning;
680 code_ +=
681 "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
682 " = {{ENUM_MAX_BASE_VALUE}};";
683 auto num_fields = NumToString(enum_def.size());
684 code_ += deprecation_warning;
685 code_ += "#[allow(non_camel_case_types)]";
686 code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " +
687 num_fields + "] = [";
688 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
689 code_ += " " + GetEnumValue(enum_def, ev) + ",";
690 });
691 code_ += "];";
692 code_ += "";
693
694 GenComment(enum_def.doc_comment);
695 // Derive Default to be 0. flatc enforces this when the enum
696 // is put into a struct, though this isn't documented behavior, it is
697 // needed to derive defaults in struct objects.
698 code_ +=
699 "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, "
700 "Default)]";
701 code_ += "#[repr(transparent)]";
702 code_ += "pub struct {{ENUM_NAME}}(pub {{BASE_TYPE}});";
703 code_ += "#[allow(non_upper_case_globals)]";
704 code_ += "impl {{ENUM_NAME}} {";
705 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
706 this->GenComment(ev.doc_comment, " ");
707 code_ += " pub const {{VARIANT}}: Self = Self({{VALUE}});";
708 });
709 code_ += "";
710 // Generate Associated constants
711 code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};";
712 code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};";
713 code_ += " pub const ENUM_VALUES: &'static [Self] = &[";
714 ForAllEnumValues(enum_def, [&]() { code_ += " Self::{{VARIANT}},"; });
715 code_ += " ];";
716 code_ += " /// Returns the variant's name or \"\" if unknown.";
717 code_ += " pub fn variant_name(self) -> Option<&'static str> {";
718 code_ += " match self {";
719 ForAllEnumValues(enum_def, [&]() {
720 code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),";
721 });
722 code_ += " _ => None,";
723 code_ += " }";
724 code_ += " }";
725 code_ += "}";
726
727 // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>".
728 code_ += "impl std::fmt::Debug for {{ENUM_NAME}} {";
729 code_ +=
730 " fn fmt(&self, f: &mut std::fmt::Formatter) ->"
731 " std::fmt::Result {";
732 code_ += " if let Some(name) = self.variant_name() {";
733 code_ += " f.write_str(name)";
734 code_ += " } else {";
735 code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))";
736 code_ += " }";
737 code_ += " }";
738 code_ += "}";
739
740 code_.SetValue("FROM_BASE", "Self(b)");
741 code_.SetValue("INTO_BASE", "self.0");
742 }
743
744 // Generate Follow and Push so we can serialize and stuff.
745 code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
746 code_ += " type Inner = Self;";
747 code_ += " #[inline]";
748 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
749 code_ += " let b = unsafe {";
750 code_ += " flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc)";
751 code_ += " };";
752 code_ += " {{FROM_BASE}}";
753 code_ += " }";
754 code_ += "}";
755 code_ += "";
756 code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
757 code_ += " type Output = {{ENUM_NAME}};";
758 code_ += " #[inline]";
759 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
760 code_ +=
761 " unsafe { flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
762 "(dst, {{INTO_BASE}}); }";
763 code_ += " }";
764 code_ += "}";
765 code_ += "";
766 code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
767 code_ += " #[inline]";
768 code_ += " fn to_little_endian(self) -> Self {";
769 code_ += " let b = {{BASE_TYPE}}::to_le({{INTO_BASE}});";
770 code_ += " {{FROM_BASE}}";
771 code_ += " }";
772 code_ += " #[inline]";
773 code_ += " #[allow(clippy::wrong_self_convention)]";
774 code_ += " fn from_little_endian(self) -> Self {";
775 code_ += " let b = {{BASE_TYPE}}::from_le({{INTO_BASE}});";
776 code_ += " {{FROM_BASE}}";
777 code_ += " }";
778 code_ += "}";
779 code_ += "";
780
781 // Generate verifier - deferring to the base type.
782 code_ += "impl<'a> flatbuffers::Verifiable for {{ENUM_NAME}} {";
783 code_ += " #[inline]";
784 code_ += " fn run_verifier(";
785 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
786 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
787 code_ += " use self::flatbuffers::Verifiable;";
788 code_ += " {{BASE_TYPE}}::run_verifier(v, pos)";
789 code_ += " }";
790 code_ += "}";
791 code_ += "";
792 // Enums are basically integers.
793 code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{ENUM_NAME}} {}";
794
795 if (enum_def.is_union) {
796 // Generate typesafe offset(s) for unions
797 code_.SetValue("NAME", Name(enum_def));
798 code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
799 code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
800 code_ += "";
801 if (parser_.opts.generate_object_based_api) { GenUnionObject(enum_def); }
802 }
803 }
804
805 // CASPER: dedup Object versions from non object versions.
ForAllUnionObjectVariantsBesidesNone(const EnumDef & enum_def,std::function<void ()> cb)806 void ForAllUnionObjectVariantsBesidesNone(const EnumDef &enum_def,
807 std::function<void()> cb) {
808 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
809 auto &enum_val = **it;
810 if (enum_val.union_type.base_type == BASE_TYPE_NONE) continue;
811 code_.SetValue("VARIANT_NAME", Name(enum_val));
812 code_.SetValue("NATIVE_VARIANT", MakeCamel(Name(enum_val)));
813 code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(enum_val)));
814 code_.SetValue("U_ELEMENT_TABLE_TYPE",
815 NamespacedNativeName(*enum_val.union_type.struct_def));
816 cb();
817 }
818 }
GenUnionObject(const EnumDef & enum_def)819 void GenUnionObject(const EnumDef &enum_def) {
820 code_.SetValue("ENUM_NAME", Name(enum_def));
821 code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
822 code_.SetValue("NATIVE_NAME", NativeName(enum_def));
823
824 // Generate native union.
825 code_ += "#[non_exhaustive]";
826 code_ += "#[derive(Debug, Clone, PartialEq)]";
827 code_ += "pub enum {{NATIVE_NAME}} {";
828 code_ += " NONE,";
829 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
830 code_ += " {{NATIVE_VARIANT}}(Box<{{U_ELEMENT_TABLE_TYPE}}>),";
831 });
832 code_ += "}";
833 // Generate Default (NONE).
834 code_ += "impl Default for {{NATIVE_NAME}} {";
835 code_ += " fn default() -> Self {";
836 code_ += " Self::NONE";
837 code_ += " }";
838 code_ += "}";
839
840 // Generate native union methods.
841 code_ += "impl {{NATIVE_NAME}} {";
842
843 // Get flatbuffers union key.
844 // CASPER: add docstrings?
845 code_ += " pub fn {{ENUM_NAME_SNAKE}}_type(&self) -> {{ENUM_NAME}} {";
846 code_ += " match self {";
847 code_ += " Self::NONE => {{ENUM_NAME}}::NONE,";
848 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
849 code_ +=
850 " Self::{{NATIVE_VARIANT}}(_) => {{ENUM_NAME}}::"
851 "{{VARIANT_NAME}},";
852 });
853 code_ += " }";
854 code_ += " }";
855 // Pack flatbuffers union value
856 code_ +=
857 " pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder)"
858 " -> Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>"
859 " {";
860 code_ += " match self {";
861 code_ += " Self::NONE => None,";
862 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
863 code_ +=
864 " Self::{{NATIVE_VARIANT}}(v) => "
865 "Some(v.pack(fbb).as_union_value()),";
866 });
867 code_ += " }";
868 code_ += " }";
869
870 // Generate some accessors;
871 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
872 // Move accessor.
873 code_ +=
874 " /// If the union variant matches, return the owned "
875 "{{U_ELEMENT_TABLE_TYPE}}, setting the union to NONE.";
876 code_ +=
877 " pub fn take_{{U_ELEMENT_NAME}}(&mut self) -> "
878 "Option<Box<{{U_ELEMENT_TABLE_TYPE}}>> {";
879 code_ += " if let Self::{{NATIVE_VARIANT}}(_) = self {";
880 code_ += " let v = std::mem::replace(self, Self::NONE);";
881 code_ += " if let Self::{{NATIVE_VARIANT}}(w) = v {";
882 code_ += " Some(w)";
883 code_ += " } else {";
884 code_ += " unreachable!()";
885 code_ += " }";
886 code_ += " } else {";
887 code_ += " None";
888 code_ += " }";
889 code_ += " }";
890 // Immutable reference accessor.
891 code_ +=
892 " /// If the union variant matches, return a reference to the "
893 "{{U_ELEMENT_TABLE_TYPE}}.";
894 code_ +=
895 " pub fn as_{{U_ELEMENT_NAME}}(&self) -> "
896 "Option<&{{U_ELEMENT_TABLE_TYPE}}> {";
897 code_ +=
898 " if let Self::{{NATIVE_VARIANT}}(v) = self "
899 "{ Some(v.as_ref()) } else { None }";
900 code_ += " }";
901 // Mutable reference accessor.
902 code_ +=
903 " /// If the union variant matches, return a mutable reference"
904 " to the {{U_ELEMENT_TABLE_TYPE}}.";
905 code_ +=
906 " pub fn as_{{U_ELEMENT_NAME}}_mut(&mut self) -> "
907 "Option<&mut {{U_ELEMENT_TABLE_TYPE}}> {";
908 code_ +=
909 " if let Self::{{NATIVE_VARIANT}}(v) = self "
910 "{ Some(v.as_mut()) } else { None }";
911 code_ += " }";
912 });
913 code_ += "}"; // End union methods impl.
914 }
915
GetFieldOffsetName(const FieldDef & field)916 std::string GetFieldOffsetName(const FieldDef &field) {
917 return "VT_" + MakeUpper(Name(field));
918 }
919
920 enum DefaultContext { kBuilder, kAccessor, kObject };
GetDefaultValue(const FieldDef & field,const DefaultContext context)921 std::string GetDefaultValue(const FieldDef &field,
922 const DefaultContext context) {
923 if (context == kBuilder) {
924 // Builders and Args structs model nonscalars "optional" even if they're
925 // required or have defaults according to the schema. I guess its because
926 // WIPOffset is not nullable.
927 if (!IsScalar(field.value.type.base_type) || field.IsOptional()) {
928 return "None";
929 }
930 } else {
931 // This for defaults in objects.
932 // Unions have a NONE variant instead of using Rust's None.
933 if (field.IsOptional() && !IsUnion(field.value.type)) { return "None"; }
934 }
935 switch (GetFullType(field.value.type)) {
936 case ftInteger:
937 case ftFloat: {
938 return field.value.constant;
939 }
940 case ftBool: {
941 return field.value.constant == "0" ? "false" : "true";
942 }
943 case ftUnionKey:
944 case ftEnumKey: {
945 auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
946 if (!ev) return "Default::default()"; // Bitflags enum.
947 return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
948 GetEnumValue(*field.value.type.enum_def, *ev));
949 }
950 case ftUnionValue: {
951 return ObjectFieldType(field, true) + "::NONE";
952 }
953 case ftString: {
954 // Required fields do not have defaults defined by the schema, but we
955 // need one for Rust's Default trait so we use empty string. The usual
956 // value of field.value.constant is `0`, which is non-sensical except
957 // maybe to c++ (nullptr == 0).
958 // TODO: Escape strings?
959 const std::string defval =
960 field.IsRequired() ? "\"\"" : "\"" + field.value.constant + "\"";
961 if (context == kObject) return defval + ".to_string()";
962 if (context == kAccessor) return "&" + defval;
963 FLATBUFFERS_ASSERT("Unreachable.");
964 return "INVALID_CODE_GENERATION";
965 }
966
967 case ftArrayOfStruct:
968 case ftArrayOfEnum:
969 case ftArrayOfBuiltin:
970 case ftVectorOfBool:
971 case ftVectorOfFloat:
972 case ftVectorOfInteger:
973 case ftVectorOfString:
974 case ftVectorOfStruct:
975 case ftVectorOfTable:
976 case ftVectorOfEnumKey:
977 case ftVectorOfUnionValue:
978 case ftStruct:
979 case ftTable: {
980 // We only support empty vectors which matches the defaults for
981 // &[T] and Vec<T> anyway.
982 //
983 // For required structs and tables fields, we defer to their object API
984 // defaults. This works so long as there's nothing recursive happening,
985 // but `table Infinity { i: Infinity (required); }` does compile.
986 return "Default::default()";
987 }
988 }
989 FLATBUFFERS_ASSERT("Unreachable.");
990 return "INVALID_CODE_GENERATION";
991 }
992
993 // Create the return type for fields in the *BuilderArgs structs that are
994 // used to create Tables.
995 //
996 // Note: we could make all inputs to the BuilderArgs be an Option, as well
997 // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
998 // know if the value is default or not, because there are three ways to
999 // return a default value:
1000 // 1) return a stored value that happens to be the default,
1001 // 2) return a hardcoded value because the relevant vtable field is not in
1002 // the vtable, or
1003 // 3) return a hardcoded value because the vtable field value is set to zero.
TableBuilderArgsDefnType(const FieldDef & field,const std::string & lifetime)1004 std::string TableBuilderArgsDefnType(const FieldDef &field,
1005 const std::string &lifetime) {
1006 const Type &type = field.value.type;
1007 auto WrapOption = [&](std::string s) {
1008 return IsOptionalToBuilder(field) ? "Option<" + s + ">" : s;
1009 };
1010 auto WrapVector = [&](std::string ty) {
1011 return WrapOption("flatbuffers::WIPOffset<flatbuffers::Vector<" +
1012 lifetime + ", " + ty + ">>");
1013 };
1014 auto WrapUOffsetsVector = [&](std::string ty) {
1015 return WrapVector("flatbuffers::ForwardsUOffset<" + ty + ">");
1016 };
1017
1018 switch (GetFullType(type)) {
1019 case ftInteger:
1020 case ftFloat:
1021 case ftBool: {
1022 return WrapOption(GetTypeBasic(type));
1023 }
1024 case ftStruct: {
1025 const auto typname = WrapInNameSpace(*type.struct_def);
1026 return WrapOption("&" + lifetime + " " + typname);
1027 }
1028 case ftTable: {
1029 const auto typname = WrapInNameSpace(*type.struct_def);
1030 return WrapOption("flatbuffers::WIPOffset<" + typname + "<" + lifetime +
1031 ">>");
1032 }
1033 case ftString: {
1034 return WrapOption("flatbuffers::WIPOffset<&" + lifetime + " str>");
1035 }
1036 case ftEnumKey:
1037 case ftUnionKey: {
1038 return WrapOption(WrapInNameSpace(*type.enum_def));
1039 }
1040 case ftUnionValue: {
1041 return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
1042 }
1043
1044 case ftVectorOfInteger:
1045 case ftVectorOfBool:
1046 case ftVectorOfFloat: {
1047 const auto typname = GetTypeBasic(type.VectorType());
1048 return WrapVector(typname);
1049 }
1050 case ftVectorOfEnumKey: {
1051 const auto typname = WrapInNameSpace(*type.enum_def);
1052 return WrapVector(typname);
1053 }
1054 case ftVectorOfStruct: {
1055 const auto typname = WrapInNameSpace(*type.struct_def);
1056 return WrapVector(typname);
1057 }
1058 case ftVectorOfTable: {
1059 const auto typname = WrapInNameSpace(*type.struct_def);
1060 return WrapUOffsetsVector(typname + "<" + lifetime + ">");
1061 }
1062 case ftVectorOfString: {
1063 return WrapUOffsetsVector("&" + lifetime + " str");
1064 }
1065 case ftVectorOfUnionValue: {
1066 return WrapUOffsetsVector("flatbuffers::Table<" + lifetime + ">");
1067 }
1068 case ftArrayOfEnum:
1069 case ftArrayOfStruct:
1070 case ftArrayOfBuiltin: {
1071 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1072 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1073 }
1074 }
1075 return "INVALID_CODE_GENERATION"; // for return analysis
1076 }
1077
ObjectFieldType(const FieldDef & field,bool in_a_table)1078 std::string ObjectFieldType(const FieldDef &field, bool in_a_table) {
1079 const Type &type = field.value.type;
1080 std::string ty;
1081 switch (GetFullType(type)) {
1082 case ftInteger:
1083 case ftBool:
1084 case ftFloat: {
1085 ty = GetTypeBasic(type);
1086 break;
1087 }
1088 case ftString: {
1089 ty = "String";
1090 break;
1091 }
1092 case ftStruct: {
1093 ty = NamespacedNativeName(*type.struct_def);
1094 break;
1095 }
1096 case ftTable: {
1097 // Since Tables can contain themselves, Box is required to avoid
1098 // infinite types.
1099 ty = "Box<" + NamespacedNativeName(*type.struct_def) + ">";
1100 break;
1101 }
1102 case ftUnionKey: {
1103 // There is no native "UnionKey", natively, unions are rust enums with
1104 // newtype-struct-variants.
1105 return "INVALID_CODE_GENERATION";
1106 }
1107 case ftUnionValue: {
1108 ty = NamespacedNativeName(*type.enum_def);
1109 break;
1110 }
1111 case ftEnumKey: {
1112 ty = WrapInNameSpace(*type.enum_def);
1113 break;
1114 }
1115 // Vectors are in tables and are optional
1116 case ftVectorOfEnumKey: {
1117 ty = "Vec<" + WrapInNameSpace(*type.VectorType().enum_def) + ">";
1118 break;
1119 }
1120 case ftVectorOfInteger:
1121 case ftVectorOfBool:
1122 case ftVectorOfFloat: {
1123 ty = "Vec<" + GetTypeBasic(type.VectorType()) + ">";
1124 break;
1125 }
1126 case ftVectorOfString: {
1127 ty = "Vec<String>";
1128 break;
1129 }
1130 case ftVectorOfTable:
1131 case ftVectorOfStruct: {
1132 ty = NamespacedNativeName(*type.VectorType().struct_def);
1133 ty = "Vec<" + ty + ">";
1134 break;
1135 }
1136 case ftVectorOfUnionValue: {
1137 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1138 return "INVALID_CODE_GENERATION"; // OH NO!
1139 }
1140 case ftArrayOfEnum: {
1141 ty = "[" + WrapInNameSpace(*type.VectorType().enum_def) + "; " +
1142 NumToString(type.fixed_length) + "]";
1143 break;
1144 }
1145 case ftArrayOfStruct: {
1146 ty = "[" + NamespacedNativeName(*type.VectorType().struct_def) + "; " +
1147 NumToString(type.fixed_length) + "]";
1148 break;
1149 }
1150 case ftArrayOfBuiltin: {
1151 ty = "[" + GetTypeBasic(type.VectorType()) + "; " +
1152 NumToString(type.fixed_length) + "]";
1153 break;
1154 }
1155 }
1156 if (in_a_table && !IsUnion(type) && field.IsOptional()) {
1157 return "Option<" + ty + ">";
1158 } else {
1159 return ty;
1160 }
1161 }
1162
TableBuilderArgsAddFuncType(const FieldDef & field,const std::string & lifetime)1163 std::string TableBuilderArgsAddFuncType(const FieldDef &field,
1164 const std::string &lifetime) {
1165 const Type &type = field.value.type;
1166
1167 switch (GetFullType(field.value.type)) {
1168 case ftVectorOfStruct: {
1169 const auto typname = WrapInNameSpace(*type.struct_def);
1170 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1171 typname + ">>";
1172 }
1173 case ftVectorOfTable: {
1174 const auto typname = WrapInNameSpace(*type.struct_def);
1175 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1176 ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
1177 ">>>>";
1178 }
1179 case ftVectorOfInteger:
1180 case ftVectorOfBool:
1181 case ftVectorOfFloat: {
1182 const auto typname = GetTypeBasic(type.VectorType());
1183 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1184 typname + ">>";
1185 }
1186 case ftVectorOfString: {
1187 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1188 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
1189 }
1190 case ftVectorOfEnumKey: {
1191 const auto typname = WrapInNameSpace(*type.enum_def);
1192 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1193 typname + ">>";
1194 }
1195 case ftVectorOfUnionValue: {
1196 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1197 ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + lifetime +
1198 ">>>";
1199 }
1200 case ftEnumKey:
1201 case ftUnionKey: {
1202 const auto typname = WrapInNameSpace(*type.enum_def);
1203 return typname;
1204 }
1205 case ftStruct: {
1206 const auto typname = WrapInNameSpace(*type.struct_def);
1207 return "&" + typname + "";
1208 }
1209 case ftTable: {
1210 const auto typname = WrapInNameSpace(*type.struct_def);
1211 return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
1212 }
1213 case ftInteger:
1214 case ftBool:
1215 case ftFloat: {
1216 return GetTypeBasic(type);
1217 }
1218 case ftString: {
1219 return "flatbuffers::WIPOffset<&" + lifetime + " str>";
1220 }
1221 case ftUnionValue: {
1222 return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
1223 }
1224 case ftArrayOfBuiltin: {
1225 const auto typname = GetTypeBasic(type.VectorType());
1226 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1227 NumToString(type.fixed_length) + ">";
1228 }
1229 case ftArrayOfEnum: {
1230 const auto typname = WrapInNameSpace(*type.enum_def);
1231 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1232 NumToString(type.fixed_length) + ">";
1233 }
1234 case ftArrayOfStruct: {
1235 const auto typname = WrapInNameSpace(*type.struct_def);
1236 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1237 NumToString(type.fixed_length) + ">";
1238 }
1239 }
1240
1241 return "INVALID_CODE_GENERATION"; // for return analysis
1242 }
1243
TableBuilderArgsAddFuncBody(const FieldDef & field)1244 std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
1245 const Type &type = field.value.type;
1246
1247 switch (GetFullType(field.value.type)) {
1248 case ftInteger:
1249 case ftBool:
1250 case ftFloat: {
1251 const auto typname = GetTypeBasic(field.value.type);
1252 return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
1253 : "self.fbb_.push_slot::<") +
1254 typname + ">";
1255 }
1256 case ftEnumKey:
1257 case ftUnionKey: {
1258 const auto underlying_typname = GetTypeBasic(type);
1259 return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
1260 : "self.fbb_.push_slot::<") +
1261 underlying_typname + ">";
1262 }
1263
1264 case ftStruct: {
1265 const std::string typname = WrapInNameSpace(*type.struct_def);
1266 return "self.fbb_.push_slot_always::<&" + typname + ">";
1267 }
1268 case ftTable: {
1269 const auto typname = WrapInNameSpace(*type.struct_def);
1270 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" +
1271 typname + ">>";
1272 }
1273
1274 case ftUnionValue:
1275 case ftString:
1276 case ftVectorOfInteger:
1277 case ftVectorOfFloat:
1278 case ftVectorOfBool:
1279 case ftVectorOfEnumKey:
1280 case ftVectorOfStruct:
1281 case ftVectorOfTable:
1282 case ftVectorOfString:
1283 case ftVectorOfUnionValue: {
1284 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
1285 }
1286 case ftArrayOfEnum:
1287 case ftArrayOfStruct:
1288 case ftArrayOfBuiltin: {
1289 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1290 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1291 }
1292 }
1293 return "INVALID_CODE_GENERATION"; // for return analysis
1294 }
1295
GenTableAccessorFuncReturnType(const FieldDef & field,const std::string & lifetime)1296 std::string GenTableAccessorFuncReturnType(const FieldDef &field,
1297 const std::string &lifetime) {
1298 const Type &type = field.value.type;
1299 const auto WrapOption = [&](std::string s) {
1300 return field.IsOptional() ? "Option<" + s + ">" : s;
1301 };
1302
1303 switch (GetFullType(field.value.type)) {
1304 case ftInteger:
1305 case ftFloat:
1306 case ftBool: {
1307 return WrapOption(GetTypeBasic(type));
1308 }
1309 case ftStruct: {
1310 const auto typname = WrapInNameSpace(*type.struct_def);
1311 return WrapOption("&" + lifetime + " " + typname);
1312 }
1313 case ftTable: {
1314 const auto typname = WrapInNameSpace(*type.struct_def);
1315 return WrapOption(typname + "<" + lifetime + ">");
1316 }
1317 case ftEnumKey:
1318 case ftUnionKey: {
1319 return WrapOption(WrapInNameSpace(*type.enum_def));
1320 }
1321
1322 case ftUnionValue: {
1323 return WrapOption("flatbuffers::Table<" + lifetime + ">");
1324 }
1325 case ftString: {
1326 return WrapOption("&" + lifetime + " str");
1327 }
1328 case ftVectorOfInteger:
1329 case ftVectorOfBool:
1330 case ftVectorOfFloat: {
1331 const auto typname = GetTypeBasic(type.VectorType());
1332 const auto vector_type =
1333 IsOneByte(type.VectorType().base_type)
1334 ? "&" + lifetime + " [" + typname + "]"
1335 : "flatbuffers::Vector<" + lifetime + ", " + typname + ">";
1336 return WrapOption(vector_type);
1337 }
1338 case ftVectorOfEnumKey: {
1339 const auto typname = WrapInNameSpace(*type.enum_def);
1340 return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname +
1341 ">");
1342 }
1343 case ftVectorOfStruct: {
1344 const auto typname = WrapInNameSpace(*type.struct_def);
1345 return WrapOption("&" + lifetime + " [" + typname + "]");
1346 }
1347 case ftVectorOfTable: {
1348 const auto typname = WrapInNameSpace(*type.struct_def);
1349 return WrapOption("flatbuffers::Vector<" + lifetime +
1350 ", flatbuffers::ForwardsUOffset<" + typname + "<" +
1351 lifetime + ">>>");
1352 }
1353 case ftVectorOfString: {
1354 return WrapOption("flatbuffers::Vector<" + lifetime +
1355 ", flatbuffers::ForwardsUOffset<&" + lifetime +
1356 " str>>");
1357 }
1358 case ftVectorOfUnionValue: {
1359 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1360 // TODO(rw): when we do support these, we should consider using the
1361 // Into trait to convert tables to typesafe union values.
1362 return "INVALID_CODE_GENERATION"; // for return analysis
1363 }
1364 case ftArrayOfEnum:
1365 case ftArrayOfStruct:
1366 case ftArrayOfBuiltin: {
1367 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1368 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1369 }
1370 }
1371 return "INVALID_CODE_GENERATION"; // for return analysis
1372 }
1373
FollowType(const Type & type,const std::string & lifetime)1374 std::string FollowType(const Type &type, const std::string &lifetime) {
1375 // IsVector... This can be made iterative?
1376
1377 const auto WrapForwardsUOffset = [](std::string ty) -> std::string {
1378 return "flatbuffers::ForwardsUOffset<" + ty + ">";
1379 };
1380 const auto WrapVector = [&](std::string ty) -> std::string {
1381 return "flatbuffers::Vector<" + lifetime + ", " + ty + ">";
1382 };
1383 const auto WrapArray = [&](std::string ty, uint16_t length) -> std::string {
1384 return "flatbuffers::Array<" + lifetime + ", " + ty + ", " +
1385 NumToString(length) + ">";
1386 };
1387 switch (GetFullType(type)) {
1388 case ftInteger:
1389 case ftFloat:
1390 case ftBool: {
1391 return GetTypeBasic(type);
1392 }
1393 case ftStruct: {
1394 return WrapInNameSpace(*type.struct_def);
1395 }
1396 case ftUnionKey:
1397 case ftEnumKey: {
1398 return WrapInNameSpace(*type.enum_def);
1399 }
1400 case ftTable: {
1401 const auto typname = WrapInNameSpace(*type.struct_def);
1402 return WrapForwardsUOffset(typname);
1403 }
1404 case ftUnionValue: {
1405 return WrapForwardsUOffset("flatbuffers::Table<" + lifetime + ">");
1406 }
1407 case ftString: {
1408 return WrapForwardsUOffset("&str");
1409 }
1410 case ftVectorOfInteger:
1411 case ftVectorOfBool:
1412 case ftVectorOfFloat: {
1413 const auto typname = GetTypeBasic(type.VectorType());
1414 return WrapForwardsUOffset(WrapVector(typname));
1415 }
1416 case ftVectorOfEnumKey: {
1417 const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
1418 return WrapForwardsUOffset(WrapVector(typname));
1419 }
1420 case ftVectorOfStruct: {
1421 const auto typname = WrapInNameSpace(*type.struct_def);
1422 return WrapForwardsUOffset(WrapVector(typname));
1423 }
1424 case ftVectorOfTable: {
1425 const auto typname = WrapInNameSpace(*type.struct_def);
1426 return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(typname)));
1427 }
1428 case ftVectorOfString: {
1429 return WrapForwardsUOffset(
1430 WrapVector(WrapForwardsUOffset("&" + lifetime + " str")));
1431 }
1432 case ftVectorOfUnionValue: {
1433 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1434 return "INVALID_CODE_GENERATION"; // for return analysis
1435 }
1436 case ftArrayOfEnum: {
1437 const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
1438 return WrapArray(typname, type.fixed_length);
1439 }
1440 case ftArrayOfStruct: {
1441 const auto typname = WrapInNameSpace(*type.struct_def);
1442 return WrapArray(typname, type.fixed_length);
1443 }
1444 case ftArrayOfBuiltin: {
1445 const auto typname = GetTypeBasic(type.VectorType());
1446 return WrapArray(typname, type.fixed_length);
1447 }
1448 }
1449 return "INVALID_CODE_GENERATION"; // for return analysis
1450 }
1451
GenTableAccessorFuncBody(const FieldDef & field,const std::string & lifetime)1452 std::string GenTableAccessorFuncBody(const FieldDef &field,
1453 const std::string &lifetime) {
1454 const std::string vt_offset = GetFieldOffsetName(field);
1455 const std::string typname = FollowType(field.value.type, lifetime);
1456 // Default-y fields (scalars so far) are neither optional nor required.
1457 const std::string default_value =
1458 !(field.IsOptional() || field.IsRequired())
1459 ? "Some(" + GetDefaultValue(field, kAccessor) + ")"
1460 : "None";
1461 const std::string unwrap = field.IsOptional() ? "" : ".unwrap()";
1462
1463 const auto t = GetFullType(field.value.type);
1464
1465 // TODO(caspern): Shouldn't 1byte VectorOfEnumKey be slice too?
1466 const std::string safe_slice =
1467 (t == ftVectorOfStruct ||
1468 ((t == ftVectorOfBool || t == ftVectorOfFloat ||
1469 t == ftVectorOfInteger) &&
1470 IsOneByte(field.value.type.VectorType().base_type)))
1471 ? ".map(|v| v.safe_slice())"
1472 : "";
1473
1474 return "self._tab.get::<" + typname + ">({{STRUCT_NAME}}::" + vt_offset +
1475 ", " + default_value + ")" + safe_slice + unwrap;
1476 }
1477
1478 // Generates a fully-qualified name getter for use with --gen-name-strings
GenFullyQualifiedNameGetter(const StructDef & struct_def,const std::string & name)1479 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1480 const std::string &name) {
1481 code_ += " pub const fn get_fully_qualified_name() -> &'static str {";
1482 code_ += " \"" +
1483 struct_def.defined_namespace->GetFullyQualifiedName(name) + "\"";
1484 code_ += " }";
1485 code_ += "";
1486 }
1487
ForAllUnionVariantsBesidesNone(const EnumDef & def,std::function<void (const EnumVal & ev)> cb)1488 void ForAllUnionVariantsBesidesNone(
1489 const EnumDef &def, std::function<void(const EnumVal &ev)> cb) {
1490 FLATBUFFERS_ASSERT(def.is_union);
1491
1492 for (auto it = def.Vals().begin(); it != def.Vals().end(); ++it) {
1493 const EnumVal &ev = **it;
1494 // TODO(cneo): Can variants be deprecated, should we skip them?
1495 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1496 code_.SetValue(
1497 "U_ELEMENT_ENUM_TYPE",
1498 WrapInNameSpace(def.defined_namespace, GetEnumValue(def, ev)));
1499 code_.SetValue(
1500 "U_ELEMENT_TABLE_TYPE",
1501 WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
1502 ev.union_type.struct_def->name));
1503 code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
1504 cb(ev);
1505 }
1506 }
1507
ForAllTableFields(const StructDef & struct_def,std::function<void (const FieldDef &)> cb,bool reversed=false)1508 void ForAllTableFields(const StructDef &struct_def,
1509 std::function<void(const FieldDef &)> cb,
1510 bool reversed = false) {
1511 // TODO(cneo): Remove `reversed` overload. It's only here to minimize the
1512 // diff when refactoring to the `ForAllX` helper functions.
1513 auto go = [&](const FieldDef &field) {
1514 if (field.deprecated) return;
1515 code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1516 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
1517 code_.SetValue("FIELD_NAME", Name(field));
1518 code_.SetValue("BLDR_DEF_VAL", GetDefaultValue(field, kBuilder));
1519 cb(field);
1520 };
1521 const auto &fields = struct_def.fields.vec;
1522 if (reversed) {
1523 for (auto it = fields.rbegin(); it != fields.rend(); ++it) go(**it);
1524 } else {
1525 for (auto it = fields.begin(); it != fields.end(); ++it) go(**it);
1526 }
1527 }
1528 // Generate an accessor struct, builder struct, and create function for a
1529 // table.
GenTable(const StructDef & struct_def)1530 void GenTable(const StructDef &struct_def) {
1531 code_.SetValue("STRUCT_NAME", Name(struct_def));
1532 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1533 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
1534
1535 // Generate an offset type, the base type, the Follow impl, and the
1536 // init_from_table impl.
1537 code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
1538 code_ += "#[derive(Copy, Clone, PartialEq)]";
1539 code_ += "";
1540
1541 GenComment(struct_def.doc_comment);
1542
1543 code_ += "pub struct {{STRUCT_NAME}}<'a> {";
1544 code_ += " pub _tab: flatbuffers::Table<'a>,";
1545 code_ += "}";
1546 code_ += "";
1547 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
1548 code_ += " type Inner = {{STRUCT_NAME}}<'a>;";
1549 code_ += " #[inline]";
1550 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1551 code_ += " Self { _tab: flatbuffers::Table { buf, loc } }";
1552 code_ += " }";
1553 code_ += "}";
1554 code_ += "";
1555 code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
1556
1557 if (parser_.opts.generate_name_strings) {
1558 GenFullyQualifiedNameGetter(struct_def, struct_def.name);
1559 }
1560
1561 code_ += " #[inline]";
1562 code_ +=
1563 " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
1564 "Self {";
1565 code_ += " {{STRUCT_NAME}} { _tab: table }";
1566 code_ += " }";
1567
1568 // Generate a convenient create* function that uses the above builder
1569 // to create a table in one function call.
1570 code_.SetValue("MAYBE_US", struct_def.fields.vec.size() == 0 ? "_" : "");
1571 code_.SetValue("MAYBE_LT",
1572 TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
1573 code_ += " #[allow(unused_mut)]";
1574 code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
1575 code_ +=
1576 " _fbb: "
1577 "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1578 code_ +=
1579 " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
1580 " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
1581
1582 code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
1583 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1584 size; size /= 2) {
1585 ForAllTableFields(
1586 struct_def,
1587 [&](const FieldDef &field) {
1588 if (struct_def.sortbysize &&
1589 size != SizeOf(field.value.type.base_type))
1590 return;
1591 if (IsOptionalToBuilder(field)) {
1592 code_ +=
1593 " if let Some(x) = args.{{FIELD_NAME}} "
1594 "{ builder.add_{{FIELD_NAME}}(x); }";
1595 } else {
1596 code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
1597 }
1598 },
1599 /*reverse=*/true);
1600 }
1601 code_ += " builder.finish()";
1602 code_ += " }";
1603 code_ += "";
1604 // Generate Object API Packer function.
1605 if (parser_.opts.generate_object_based_api) {
1606 // TODO(cneo): Replace more for loops with ForAllX stuff.
1607 // TODO(cneo): Manage indentation with IncrementIdentLevel?
1608 code_.SetValue("OBJECT_NAME", NativeName(struct_def));
1609 code_ += " pub fn unpack(&self) -> {{OBJECT_NAME}} {";
1610 ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
1611 const Type &type = field.value.type;
1612 switch (GetFullType(type)) {
1613 case ftInteger:
1614 case ftBool:
1615 case ftFloat:
1616 case ftEnumKey: {
1617 code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}();";
1618 return;
1619 }
1620 case ftUnionKey: return;
1621 case ftUnionValue: {
1622 const auto &enum_def = *type.enum_def;
1623 code_.SetValue("ENUM_NAME", WrapInNameSpace(enum_def));
1624 code_.SetValue("NATIVE_ENUM_NAME", NamespacedNativeName(enum_def));
1625 code_ +=
1626 " let {{FIELD_NAME}} = match "
1627 "self.{{FIELD_NAME}}_type() {";
1628 code_ +=
1629 " {{ENUM_NAME}}::NONE =>"
1630 " {{NATIVE_ENUM_NAME}}::NONE,";
1631 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
1632 code_ +=
1633 " {{ENUM_NAME}}::{{VARIANT_NAME}} => "
1634 "{{NATIVE_ENUM_NAME}}::{{NATIVE_VARIANT}}(Box::new(";
1635 code_ +=
1636 " self.{{FIELD_NAME}}_as_"
1637 "{{U_ELEMENT_NAME}}()";
1638 code_ +=
1639 " .expect(\"Invalid union table, "
1640 "expected `{{ENUM_NAME}}::{{VARIANT_NAME}}`.\")";
1641 code_ += " .unpack()";
1642 code_ += " )),";
1643 });
1644 // Maybe we shouldn't throw away unknown discriminants?
1645 code_ += " _ => {{NATIVE_ENUM_NAME}}::NONE,";
1646 code_ += " };";
1647 return;
1648 }
1649 // The rest of the types need special handling based on if the field
1650 // is optional or not.
1651 case ftString: {
1652 code_.SetValue("EXPR", "x.to_string()");
1653 break;
1654 }
1655 case ftStruct: {
1656 code_.SetValue("EXPR", "x.unpack()");
1657 break;
1658 }
1659 case ftTable: {
1660 code_.SetValue("EXPR", "Box::new(x.unpack())");
1661 break;
1662 }
1663 case ftVectorOfInteger:
1664 case ftVectorOfBool: {
1665 if (IsOneByte(type.VectorType().base_type)) {
1666 // 1 byte stuff is viewed w/ slice instead of flatbuffer::Vector
1667 // and thus needs to be cloned out of the slice.
1668 code_.SetValue("EXPR", "x.to_vec()");
1669 break;
1670 }
1671 code_.SetValue("EXPR", "x.into_iter().collect()");
1672 break;
1673 }
1674 case ftVectorOfFloat:
1675 case ftVectorOfEnumKey: {
1676 code_.SetValue("EXPR", "x.into_iter().collect()");
1677 break;
1678 }
1679 case ftVectorOfString: {
1680 code_.SetValue("EXPR", "x.iter().map(|s| s.to_string()).collect()");
1681 break;
1682 }
1683 case ftVectorOfStruct:
1684 case ftVectorOfTable: {
1685 code_.SetValue("EXPR", "x.iter().map(|t| t.unpack()).collect()");
1686 break;
1687 }
1688 case ftVectorOfUnionValue: {
1689 FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
1690 return;
1691 }
1692 case ftArrayOfEnum:
1693 case ftArrayOfStruct:
1694 case ftArrayOfBuiltin: {
1695 FLATBUFFERS_ASSERT(false &&
1696 "arrays are not supported within tables");
1697 return;
1698 }
1699 }
1700 if (field.IsOptional()) {
1701 code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}().map(|x| {";
1702 code_ += " {{EXPR}}";
1703 code_ += " });";
1704 } else {
1705 code_ += " let {{FIELD_NAME}} = {";
1706 code_ += " let x = self.{{FIELD_NAME}}();";
1707 code_ += " {{EXPR}}";
1708 code_ += " };";
1709 }
1710 });
1711 code_ += " {{OBJECT_NAME}} {";
1712 ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
1713 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
1714 code_ += " {{FIELD_NAME}},";
1715 });
1716 code_ += " }";
1717 code_ += " }";
1718 }
1719
1720 // Generate field id constants.
1721 ForAllTableFields(struct_def, [&](const FieldDef &unused) {
1722 (void)unused;
1723 code_ +=
1724 " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1725 "{{OFFSET_VALUE}};";
1726 });
1727 if (struct_def.fields.vec.size() > 0) code_ += "";
1728
1729 // Generate the accessors. Each has one of two forms:
1730 //
1731 // If a value can be None:
1732 // pub fn name(&'a self) -> Option<user_facing_type> {
1733 // self._tab.get::<internal_type>(offset, defaultval)
1734 // }
1735 //
1736 // If a value is always Some:
1737 // pub fn name(&'a self) -> user_facing_type {
1738 // self._tab.get::<internal_type>(offset, defaultval).unwrap()
1739 // }
1740 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1741 code_.SetValue("RETURN_TYPE",
1742 GenTableAccessorFuncReturnType(field, "'a"));
1743
1744 this->GenComment(field.doc_comment, " ");
1745 code_ += " #[inline]";
1746 code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
1747 code_ += " " + GenTableAccessorFuncBody(field, "'a");
1748 code_ += " }";
1749
1750 // Generate a comparison function for this field if it is a key.
1751 if (field.key) { GenKeyFieldMethods(field); }
1752
1753 // Generate a nested flatbuffer field, if applicable.
1754 auto nested = field.attributes.Lookup("nested_flatbuffer");
1755 if (nested) {
1756 std::string qualified_name = nested->constant;
1757 auto nested_root = parser_.LookupStruct(nested->constant);
1758 if (nested_root == nullptr) {
1759 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1760 nested->constant);
1761 nested_root = parser_.LookupStruct(qualified_name);
1762 }
1763 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
1764
1765 code_.SetValue("NESTED", WrapInNameSpace(*nested_root));
1766 code_ += " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> \\";
1767 if (field.IsRequired()) {
1768 code_ += "{{NESTED}}<'a> {";
1769 code_ += " let data = self.{{FIELD_NAME}}();";
1770 code_ += " use flatbuffers::Follow;";
1771 code_ +=
1772 " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1773 "::follow(data, 0)";
1774 } else {
1775 code_ += "Option<{{NESTED}}<'a>> {";
1776 code_ += " self.{{FIELD_NAME}}().map(|data| {";
1777 code_ += " use flatbuffers::Follow;";
1778 code_ +=
1779 " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1780 "::follow(data, 0)";
1781 code_ += " })";
1782 }
1783 code_ += " }";
1784 }
1785 });
1786
1787 // Explicit specializations for union accessors
1788 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1789 if (field.value.type.base_type != BASE_TYPE_UNION) return;
1790 code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
1791 ForAllUnionVariantsBesidesNone(
1792 *field.value.type.enum_def, [&](const EnumVal &unused) {
1793 (void)unused;
1794 code_ += " #[inline]";
1795 code_ += " #[allow(non_snake_case)]";
1796 code_ +=
1797 " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
1798 "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
1799 // If the user defined schemas name a field that clashes with a
1800 // language reserved word, flatc will try to escape the field name
1801 // by appending an underscore. This works well for most cases,
1802 // except one. When generating union accessors (and referring to
1803 // them internally within the code generated here), an extra
1804 // underscore will be appended to the name, causing build failures.
1805 //
1806 // This only happens when unions have members that overlap with
1807 // language reserved words.
1808 //
1809 // To avoid this problem the type field name is used unescaped here:
1810 code_ +=
1811 " if self.{{FIELD_TYPE_FIELD_NAME}}_type() == "
1812 "{{U_ELEMENT_ENUM_TYPE}} {";
1813
1814 // The following logic is not tested in the integration test,
1815 // as of April 10, 2020
1816 if (field.IsRequired()) {
1817 code_ += " let u = self.{{FIELD_NAME}}();";
1818 code_ +=
1819 " Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
1820 } else {
1821 code_ +=
1822 " self.{{FIELD_NAME}}().map("
1823 "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)";
1824 }
1825 code_ += " } else {";
1826 code_ += " None";
1827 code_ += " }";
1828 code_ += " }";
1829 code_ += "";
1830 });
1831 });
1832 code_ += "}"; // End of table impl.
1833 code_ += "";
1834
1835 // Generate Verifier;
1836 code_ += "impl flatbuffers::Verifiable for {{STRUCT_NAME}}<'_> {";
1837 code_ += " #[inline]";
1838 code_ += " fn run_verifier(";
1839 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
1840 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
1841 code_ += " use self::flatbuffers::Verifiable;";
1842 code_ += " v.visit_table(pos)?\\";
1843 // Escape newline and insert it onthe next line so we can end the builder
1844 // with a nice semicolon.
1845 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1846 if (GetFullType(field.value.type) == ftUnionKey) return;
1847
1848 code_.SetValue("IS_REQ", field.IsRequired() ? "true" : "false");
1849 if (GetFullType(field.value.type) != ftUnionValue) {
1850 // All types besides unions.
1851 code_.SetValue("TY", FollowType(field.value.type, "'_"));
1852 code_ +=
1853 "\n .visit_field::<{{TY}}>(&\"{{FIELD_NAME}}\", "
1854 "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\";
1855 return;
1856 }
1857 // Unions.
1858 EnumDef &union_def = *field.value.type.enum_def;
1859 code_.SetValue("UNION_TYPE", WrapInNameSpace(union_def));
1860 code_ +=
1861 "\n .visit_union::<{{UNION_TYPE}}, _>("
1862 "&\"{{FIELD_NAME}}_type\", Self::{{OFFSET_NAME}}_TYPE, "
1863 "&\"{{FIELD_NAME}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, "
1864 "|key, v, pos| {";
1865 code_ += " match key {";
1866 ForAllUnionVariantsBesidesNone(union_def, [&](const EnumVal &unused) {
1867 (void)unused;
1868 code_ +=
1869 " {{U_ELEMENT_ENUM_TYPE}} => v.verify_union_variant::"
1870 "<flatbuffers::ForwardsUOffset<{{U_ELEMENT_TABLE_TYPE}}>>("
1871 "\"{{U_ELEMENT_ENUM_TYPE}}\", pos),";
1872 });
1873 code_ += " _ => Ok(()),";
1874 code_ += " }";
1875 code_ += " })?\\";
1876 });
1877 code_ += "\n .finish();";
1878 code_ += " Ok(())";
1879 code_ += " }";
1880 code_ += "}";
1881
1882 // Generate an args struct:
1883 code_.SetValue("MAYBE_LT",
1884 TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
1885 code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1886 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1887 code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
1888 code_ += " pub {{FIELD_NAME}}: {{PARAM_TYPE}},";
1889 });
1890 code_ += "}";
1891
1892 // Generate an impl of Default for the *Args type:
1893 code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1894 code_ += " #[inline]";
1895 code_ += " fn default() -> Self {";
1896 code_ += " {{STRUCT_NAME}}Args {";
1897 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1898 code_ += " {{FIELD_NAME}}: {{BLDR_DEF_VAL}},\\";
1899 code_ += field.IsRequired() ? " // required field" : "";
1900 });
1901 code_ += " }";
1902 code_ += " }";
1903 code_ += "}";
1904
1905 // Generate a builder struct:
1906 code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
1907 code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1908 code_ +=
1909 " start_: flatbuffers::WIPOffset<"
1910 "flatbuffers::TableUnfinishedWIPOffset>,";
1911 code_ += "}";
1912
1913 // Generate builder functions:
1914 code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
1915 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1916 const bool is_scalar = IsScalar(field.value.type.base_type);
1917 std::string offset = GetFieldOffsetName(field);
1918 // Generate functions to add data, which take one of two forms.
1919 //
1920 // If a value has a default:
1921 // fn add_x(x_: type) {
1922 // fbb_.push_slot::<type>(offset, x_, Some(default));
1923 // }
1924 //
1925 // If a value does not have a default:
1926 // fn add_x(x_: type) {
1927 // fbb_.push_slot_always::<type>(offset, x_);
1928 // }
1929 code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
1930 code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
1931 code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
1932 code_ += " #[inline]";
1933 code_ +=
1934 " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
1935 "{{FIELD_TYPE}}) {";
1936 if (is_scalar && !field.IsOptional()) {
1937 code_ +=
1938 " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
1939 "{{BLDR_DEF_VAL}});";
1940 } else {
1941 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
1942 }
1943 code_ += " }";
1944 });
1945
1946 // Struct initializer (all fields required);
1947 code_ += " #[inline]";
1948 code_ +=
1949 " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
1950 "{{STRUCT_NAME}}Builder<'a, 'b> {";
1951 code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
1952 code_ += " let start = _fbb.start_table();";
1953 code_ += " {{STRUCT_NAME}}Builder {";
1954 code_ += " fbb_: _fbb,";
1955 code_ += " start_: start,";
1956 code_ += " }";
1957 code_ += " }";
1958
1959 // finish() function.
1960 code_ += " #[inline]";
1961 code_ +=
1962 " pub fn finish(self) -> "
1963 "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
1964 code_ += " let o = self.fbb_.end_table(self.start_);";
1965
1966 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1967 if (!field.IsRequired()) return;
1968 code_ +=
1969 " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
1970 "\"{{FIELD_NAME}}\");";
1971 });
1972 code_ += " flatbuffers::WIPOffset::new(o.value())";
1973 code_ += " }";
1974 code_ += "}";
1975 code_ += "";
1976
1977 code_ += "impl std::fmt::Debug for {{STRUCT_NAME}}<'_> {";
1978 code_ +=
1979 " fn fmt(&self, f: &mut std::fmt::Formatter<'_>"
1980 ") -> std::fmt::Result {";
1981 code_ += " let mut ds = f.debug_struct(\"{{STRUCT_NAME}}\");";
1982 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1983 if (GetFullType(field.value.type) == ftUnionValue) {
1984 // Generate a match statement to handle unions properly.
1985 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
1986 code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
1987 code_.SetValue("UNION_ERR",
1988 "&\"InvalidFlatbuffer: Union discriminant"
1989 " does not match value.\"");
1990
1991 code_ += " match self.{{FIELD_NAME}}_type() {";
1992 ForAllUnionVariantsBesidesNone(
1993 *field.value.type.enum_def, [&](const EnumVal &unused) {
1994 (void)unused;
1995 code_ += " {{U_ELEMENT_ENUM_TYPE}} => {";
1996 code_ +=
1997 " if let Some(x) = "
1998 "self.{{FIELD_TYPE_FIELD_NAME}}_as_"
1999 "{{U_ELEMENT_NAME}}() {";
2000 code_ += " ds.field(\"{{FIELD_NAME}}\", &x)";
2001 code_ += " } else {";
2002 code_ +=
2003 " ds.field(\"{{FIELD_NAME}}\", {{UNION_ERR}})";
2004 code_ += " }";
2005 code_ += " },";
2006 });
2007 code_ += " _ => {";
2008 code_ += " let x: Option<()> = None;";
2009 code_ += " ds.field(\"{{FIELD_NAME}}\", &x)";
2010 code_ += " },";
2011 code_ += " };";
2012 } else {
2013 // Most fields.
2014 code_ += " ds.field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}());";
2015 }
2016 });
2017 code_ += " ds.finish()";
2018 code_ += " }";
2019 code_ += "}";
2020 }
2021
GenTableObject(const StructDef & table)2022 void GenTableObject(const StructDef &table) {
2023 code_.SetValue("OBJECT_NAME", NativeName(table));
2024 code_.SetValue("STRUCT_NAME", Name(table));
2025
2026 // Generate the native object.
2027 code_ += "#[non_exhaustive]";
2028 code_ += "#[derive(Debug, Clone, PartialEq)]";
2029 code_ += "pub struct {{OBJECT_NAME}} {";
2030 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2031 // Union objects combine both the union discriminant and value, so we
2032 // skip making a field for the discriminant.
2033 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
2034 code_ += " pub {{FIELD_NAME}}: {{FIELD_OBJECT_TYPE}},";
2035 });
2036 code_ += "}";
2037
2038 code_ += "impl Default for {{OBJECT_NAME}} {";
2039 code_ += " fn default() -> Self {";
2040 code_ += " Self {";
2041 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2042 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
2043 std::string default_value = GetDefaultValue(field, kObject);
2044 code_ += " {{FIELD_NAME}}: " + default_value + ",";
2045 });
2046 code_ += " }";
2047 code_ += " }";
2048 code_ += "}";
2049
2050 // TODO(cneo): Generate defaults for Native tables. However, since structs
2051 // may be required, they, and therefore enums need defaults.
2052
2053 // Generate pack function.
2054 code_ += "impl {{OBJECT_NAME}} {";
2055 code_ += " pub fn pack<'b>(";
2056 code_ += " &self,";
2057 code_ += " _fbb: &mut flatbuffers::FlatBufferBuilder<'b>";
2058 code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'b>> {";
2059 // First we generate variables for each field and then later assemble them
2060 // using "StructArgs" to more easily manage ownership of the builder.
2061 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2062 const Type &type = field.value.type;
2063 switch (GetFullType(type)) {
2064 case ftInteger:
2065 case ftBool:
2066 case ftFloat:
2067 case ftEnumKey: {
2068 code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}};";
2069 return;
2070 }
2071 case ftUnionKey: return; // Generate union type with union value.
2072 case ftUnionValue: {
2073 code_.SetValue("SNAKE_CASE_ENUM_NAME",
2074 MakeSnakeCase(Name(*field.value.type.enum_def)));
2075 code_ +=
2076 " let {{FIELD_NAME}}_type = "
2077 "self.{{FIELD_NAME}}.{{SNAKE_CASE_ENUM_NAME}}_type();";
2078 code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}.pack(_fbb);";
2079 return;
2080 }
2081 // The rest of the types require special casing around optionalness
2082 // due to "required" annotation.
2083 case ftString: {
2084 MapNativeTableField(field, "_fbb.create_string(x)");
2085 return;
2086 }
2087 case ftStruct: {
2088 // Hold the struct in a variable so we can reference it.
2089 if (field.IsRequired()) {
2090 code_ +=
2091 " let {{FIELD_NAME}}_tmp = "
2092 "Some(self.{{FIELD_NAME}}.pack());";
2093 } else {
2094 code_ +=
2095 " let {{FIELD_NAME}}_tmp = self.{{FIELD_NAME}}"
2096 ".as_ref().map(|x| x.pack());";
2097 }
2098 code_ += " let {{FIELD_NAME}} = {{FIELD_NAME}}_tmp.as_ref();";
2099
2100 return;
2101 }
2102 case ftTable: {
2103 MapNativeTableField(field, "x.pack(_fbb)");
2104 return;
2105 }
2106 case ftVectorOfEnumKey:
2107 case ftVectorOfInteger:
2108 case ftVectorOfBool:
2109 case ftVectorOfFloat: {
2110 MapNativeTableField(field, "_fbb.create_vector(x)");
2111 return;
2112 }
2113 case ftVectorOfStruct: {
2114 MapNativeTableField(
2115 field,
2116 "let w: Vec<_> = x.iter().map(|t| t.pack()).collect();"
2117 "_fbb.create_vector(&w)");
2118 return;
2119 }
2120 case ftVectorOfString: {
2121 // TODO(cneo): create_vector* should be more generic to avoid
2122 // allocations.
2123
2124 MapNativeTableField(
2125 field,
2126 "let w: Vec<_> = x.iter().map(|s| s.as_ref()).collect();"
2127 "_fbb.create_vector_of_strings(&w)");
2128 return;
2129 }
2130 case ftVectorOfTable: {
2131 MapNativeTableField(
2132 field,
2133 "let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();"
2134 "_fbb.create_vector(&w)");
2135 return;
2136 }
2137 case ftVectorOfUnionValue: {
2138 FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
2139 return;
2140 }
2141 case ftArrayOfEnum:
2142 case ftArrayOfStruct:
2143 case ftArrayOfBuiltin: {
2144 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
2145 return;
2146 }
2147 }
2148 });
2149 code_ += " {{STRUCT_NAME}}::create(_fbb, &{{STRUCT_NAME}}Args{";
2150 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2151 (void)field; // Unused.
2152 code_ += " {{FIELD_NAME}},";
2153 });
2154 code_ += " })";
2155 code_ += " }";
2156 code_ += "}";
2157 }
ForAllObjectTableFields(const StructDef & table,std::function<void (const FieldDef &)> cb)2158 void ForAllObjectTableFields(const StructDef &table,
2159 std::function<void(const FieldDef &)> cb) {
2160 const std::vector<FieldDef *> &v = table.fields.vec;
2161 for (auto it = v.begin(); it != v.end(); it++) {
2162 const FieldDef &field = **it;
2163 if (field.deprecated) continue;
2164 code_.SetValue("FIELD_NAME", Name(field));
2165 code_.SetValue("FIELD_OBJECT_TYPE", ObjectFieldType(field, true));
2166 cb(field);
2167 }
2168 }
MapNativeTableField(const FieldDef & field,const std::string & expr)2169 void MapNativeTableField(const FieldDef &field, const std::string &expr) {
2170 if (field.IsOptional()) {
2171 code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}.as_ref().map(|x|{";
2172 code_ += " " + expr;
2173 code_ += " });";
2174 } else {
2175 // For some reason Args has optional types for required fields.
2176 // TODO(cneo): Fix this... but its a breaking change?
2177 code_ += " let {{FIELD_NAME}} = Some({";
2178 code_ += " let x = &self.{{FIELD_NAME}};";
2179 code_ += " " + expr;
2180 code_ += " });";
2181 }
2182 }
2183
2184 // Generate functions to compare tables and structs by key. This function
2185 // must only be called if the field key is defined.
GenKeyFieldMethods(const FieldDef & field)2186 void GenKeyFieldMethods(const FieldDef &field) {
2187 FLATBUFFERS_ASSERT(field.key);
2188
2189 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
2190
2191 code_ += " #[inline]";
2192 code_ +=
2193 " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
2194 " bool {";
2195 code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
2196 code_ += " }";
2197 code_ += "";
2198 code_ += " #[inline]";
2199 code_ +=
2200 " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
2201 " ::std::cmp::Ordering {";
2202 code_ += " let key = self.{{FIELD_NAME}}();";
2203 code_ += " key.cmp(&val)";
2204 code_ += " }";
2205 }
2206
2207 // Generate functions for accessing the root table object. This function
2208 // must only be called if the root table is defined.
GenRootTableFuncs(const StructDef & struct_def)2209 void GenRootTableFuncs(const StructDef &struct_def) {
2210 FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
2211 auto name = Name(struct_def);
2212
2213 code_.SetValue("STRUCT_NAME", name);
2214 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
2215 code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
2216
2217 // The root datatype accessors:
2218 code_ += "#[inline]";
2219 code_ +=
2220 "#[deprecated(since=\"2.0.0\", "
2221 "note=\"Deprecated in favor of `root_as...` methods.\")]";
2222 code_ +=
2223 "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
2224 " -> {{STRUCT_NAME}}<'a> {";
2225 code_ +=
2226 " unsafe { flatbuffers::root_unchecked::<{{STRUCT_NAME}}"
2227 "<'a>>(buf) }";
2228 code_ += "}";
2229 code_ += "";
2230
2231 code_ += "#[inline]";
2232 code_ +=
2233 "#[deprecated(since=\"2.0.0\", "
2234 "note=\"Deprecated in favor of `root_as...` methods.\")]";
2235 code_ +=
2236 "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
2237 "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
2238 code_ +=
2239 " unsafe { flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}"
2240 "<'a>>(buf) }";
2241 code_ += "}";
2242 code_ += "";
2243 // Default verifier root fns.
2244 code_ += "#[inline]";
2245 code_ += "/// Verifies that a buffer of bytes contains a `{{STRUCT_NAME}}`";
2246 code_ += "/// and returns it.";
2247 code_ += "/// Note that verification is still experimental and may not";
2248 code_ += "/// catch every error, or be maximally performant. For the";
2249 code_ += "/// previous, unchecked, behavior use";
2250 code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
2251 code_ +=
2252 "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}(buf: &[u8]) "
2253 "-> Result<{{STRUCT_NAME}}, flatbuffers::InvalidFlatbuffer> {";
2254 code_ += " flatbuffers::root::<{{STRUCT_NAME}}>(buf)";
2255 code_ += "}";
2256 code_ += "#[inline]";
2257 code_ += "/// Verifies that a buffer of bytes contains a size prefixed";
2258 code_ += "/// `{{STRUCT_NAME}}` and returns it.";
2259 code_ += "/// Note that verification is still experimental and may not";
2260 code_ += "/// catch every error, or be maximally performant. For the";
2261 code_ += "/// previous, unchecked, behavior use";
2262 code_ += "/// `size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
2263 code_ +=
2264 "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
2265 "(buf: &[u8]) -> Result<{{STRUCT_NAME}}, "
2266 "flatbuffers::InvalidFlatbuffer> {";
2267 code_ += " flatbuffers::size_prefixed_root::<{{STRUCT_NAME}}>(buf)";
2268 code_ += "}";
2269 // Verifier with options root fns.
2270 code_ += "#[inline]";
2271 code_ += "/// Verifies, with the given options, that a buffer of bytes";
2272 code_ += "/// contains a `{{STRUCT_NAME}}` and returns it.";
2273 code_ += "/// Note that verification is still experimental and may not";
2274 code_ += "/// catch every error, or be maximally performant. For the";
2275 code_ += "/// previous, unchecked, behavior use";
2276 code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
2277 code_ += "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts<'b, 'o>(";
2278 code_ += " opts: &'o flatbuffers::VerifierOptions,";
2279 code_ += " buf: &'b [u8],";
2280 code_ +=
2281 ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>"
2282 " {";
2283 code_ += " flatbuffers::root_with_opts::<{{STRUCT_NAME}}<'b>>(opts, buf)";
2284 code_ += "}";
2285 code_ += "#[inline]";
2286 code_ += "/// Verifies, with the given verifier options, that a buffer of";
2287 code_ += "/// bytes contains a size prefixed `{{STRUCT_NAME}}` and returns";
2288 code_ += "/// it. Note that verification is still experimental and may not";
2289 code_ += "/// catch every error, or be maximally performant. For the";
2290 code_ += "/// previous, unchecked, behavior use";
2291 code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
2292 code_ +=
2293 "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts"
2294 "<'b, 'o>(";
2295 code_ += " opts: &'o flatbuffers::VerifierOptions,";
2296 code_ += " buf: &'b [u8],";
2297 code_ +=
2298 ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>"
2299 " {";
2300 code_ +=
2301 " flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_NAME}}"
2302 "<'b>>(opts, buf)";
2303 code_ += "}";
2304 // Unchecked root fns.
2305 code_ += "#[inline]";
2306 code_ +=
2307 "/// Assumes, without verification, that a buffer of bytes "
2308 "contains a {{STRUCT_NAME}} and returns it.";
2309 code_ += "/// # Safety";
2310 code_ +=
2311 "/// Callers must trust the given bytes do indeed contain a valid"
2312 " `{{STRUCT_NAME}}`.";
2313 code_ +=
2314 "pub unsafe fn root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked"
2315 "(buf: &[u8]) -> {{STRUCT_NAME}} {";
2316 code_ += " flatbuffers::root_unchecked::<{{STRUCT_NAME}}>(buf)";
2317 code_ += "}";
2318 code_ += "#[inline]";
2319 code_ +=
2320 "/// Assumes, without verification, that a buffer of bytes "
2321 "contains a size prefixed {{STRUCT_NAME}} and returns it.";
2322 code_ += "/// # Safety";
2323 code_ +=
2324 "/// Callers must trust the given bytes do indeed contain a valid"
2325 " size prefixed `{{STRUCT_NAME}}`.";
2326 code_ +=
2327 "pub unsafe fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
2328 "_unchecked(buf: &[u8]) -> {{STRUCT_NAME}} {";
2329 code_ +=
2330 " flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}>"
2331 "(buf)";
2332 code_ += "}";
2333
2334 if (parser_.file_identifier_.length()) {
2335 // Declare the identifier
2336 // (no lifetime needed as constants have static lifetimes by default)
2337 code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &str\\";
2338 code_ += " = \"" + parser_.file_identifier_ + "\";";
2339 code_ += "";
2340
2341 // Check if a buffer has the identifier.
2342 code_ += "#[inline]";
2343 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
2344 code_ += "(buf: &[u8]) -> bool {";
2345 code_ += " flatbuffers::buffer_has_identifier(buf, \\";
2346 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false)";
2347 code_ += "}";
2348 code_ += "";
2349 code_ += "#[inline]";
2350 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
2351 code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
2352 code_ += " flatbuffers::buffer_has_identifier(buf, \\";
2353 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true)";
2354 code_ += "}";
2355 code_ += "";
2356 }
2357
2358 if (parser_.file_extension_.length()) {
2359 // Return the extension
2360 code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &str = \\";
2361 code_ += "\"" + parser_.file_extension_ + "\";";
2362 code_ += "";
2363 }
2364
2365 // Finish a buffer with a given root object:
2366 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
2367 code_ += "#[inline]";
2368 code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
2369 code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
2370 code_ += " root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
2371 if (parser_.file_identifier_.length()) {
2372 code_ += " fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
2373 } else {
2374 code_ += " fbb.finish(root, None);";
2375 }
2376 code_ += "}";
2377 code_ += "";
2378 code_ += "#[inline]";
2379 code_ +=
2380 "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
2381 "<'a, 'b>("
2382 "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
2383 "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
2384 if (parser_.file_identifier_.length()) {
2385 code_ +=
2386 " fbb.finish_size_prefixed(root, "
2387 "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
2388 } else {
2389 code_ += " fbb.finish_size_prefixed(root, None);";
2390 }
2391 code_ += "}";
2392 }
2393
GenPadding(const FieldDef & field,std::string * code_ptr,int * id,const std::function<void (int bits,std::string * code_ptr,int * id)> & f)2394 static void GenPadding(
2395 const FieldDef &field, std::string *code_ptr, int *id,
2396 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
2397 if (field.padding) {
2398 for (int i = 0; i < 4; i++) {
2399 if (static_cast<int>(field.padding) & (1 << i)) {
2400 f((1 << i) * 8, code_ptr, id);
2401 }
2402 }
2403 assert(!(field.padding & ~0xF));
2404 }
2405 }
2406
PaddingDefinition(int bits,std::string * code_ptr,int * id)2407 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
2408 *code_ptr +=
2409 " padding" + NumToString((*id)++) + "__: u" + NumToString(bits) + ",";
2410 }
2411
PaddingInitializer(int bits,std::string * code_ptr,int * id)2412 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
2413 (void)bits;
2414 *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
2415 }
2416
ForAllStructFields(const StructDef & struct_def,std::function<void (const FieldDef & field)> cb)2417 void ForAllStructFields(const StructDef &struct_def,
2418 std::function<void(const FieldDef &field)> cb) {
2419 size_t offset_to_field = 0;
2420 for (auto it = struct_def.fields.vec.begin();
2421 it != struct_def.fields.vec.end(); ++it) {
2422 const auto &field = **it;
2423 code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
2424 code_.SetValue("FIELD_OBJECT_TYPE", ObjectFieldType(field, false));
2425 code_.SetValue("FIELD_NAME", Name(field));
2426 code_.SetValue("FIELD_OFFSET", NumToString(offset_to_field));
2427 code_.SetValue(
2428 "REF",
2429 IsStruct(field.value.type) || IsArray(field.value.type) ? "&" : "");
2430 cb(field);
2431 const size_t size = InlineSize(field.value.type);
2432 offset_to_field += size + field.padding;
2433 }
2434 }
2435 // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def)2436 void GenStruct(const StructDef &struct_def) {
2437 // Generates manual padding and alignment.
2438 // Variables are private because they contain little endian data on all
2439 // platforms.
2440 GenComment(struct_def.doc_comment);
2441 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
2442 code_.SetValue("STRUCT_NAME", Name(struct_def));
2443 code_.SetValue("STRUCT_SIZE", NumToString(struct_def.bytesize));
2444
2445 // We represent Flatbuffers-structs in Rust-u8-arrays since the data may be
2446 // of the wrong endianness and alignment 1.
2447 //
2448 // PartialEq is useful to derive because we can correctly compare structs
2449 // for equality by just comparing their underlying byte data. This doesn't
2450 // hold for PartialOrd/Ord.
2451 code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
2452 code_ += "#[repr(transparent)]";
2453 code_ += "#[derive(Clone, Copy, PartialEq)]";
2454 code_ += "pub struct {{STRUCT_NAME}}(pub [u8; {{STRUCT_SIZE}}]);";
2455 code_ += "impl Default for {{STRUCT_NAME}} { ";
2456 code_ += " fn default() -> Self { ";
2457 code_ += " Self([0; {{STRUCT_SIZE}}])";
2458 code_ += " }";
2459 code_ += "}";
2460
2461 // Debug for structs.
2462 code_ += "impl std::fmt::Debug for {{STRUCT_NAME}} {";
2463 code_ +=
2464 " fn fmt(&self, f: &mut std::fmt::Formatter"
2465 ") -> std::fmt::Result {";
2466 code_ += " f.debug_struct(\"{{STRUCT_NAME}}\")";
2467 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2468 (void)unused;
2469 code_ += " .field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}())";
2470 });
2471 code_ += " .finish()";
2472 code_ += " }";
2473 code_ += "}";
2474 code_ += "";
2475
2476 // Generate impls for SafeSliceAccess (because all structs are endian-safe),
2477 // Follow for the value type, Follow for the reference type, Push for the
2478 // value type, and Push for the reference type.
2479 code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{STRUCT_NAME}} {}";
2480 code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
2481 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
2482 code_ += " type Inner = &'a {{STRUCT_NAME}};";
2483 code_ += " #[inline]";
2484 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
2485 code_ += " <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
2486 code_ += " }";
2487 code_ += "}";
2488 code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
2489 code_ += " type Inner = &'a {{STRUCT_NAME}};";
2490 code_ += " #[inline]";
2491 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
2492 code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
2493 code_ += " }";
2494 code_ += "}";
2495 code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
2496 code_ += " type Output = {{STRUCT_NAME}};";
2497 code_ += " #[inline]";
2498 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
2499 code_ += " let src = unsafe {";
2500 code_ +=
2501 " ::std::slice::from_raw_parts("
2502 "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
2503 code_ += " };";
2504 code_ += " dst.copy_from_slice(src);";
2505 code_ += " }";
2506 code_ += "}";
2507 code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
2508 code_ += " type Output = {{STRUCT_NAME}};";
2509 code_ += "";
2510 code_ += " #[inline]";
2511 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
2512 code_ += " let src = unsafe {";
2513 code_ +=
2514 " ::std::slice::from_raw_parts("
2515 "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
2516 code_ += " };";
2517 code_ += " dst.copy_from_slice(src);";
2518 code_ += " }";
2519 code_ += "}";
2520 code_ += "";
2521
2522 // Generate verifier: Structs are simple so presence and alignment are
2523 // all that need to be checked.
2524 code_ += "impl<'a> flatbuffers::Verifiable for {{STRUCT_NAME}} {";
2525 code_ += " #[inline]";
2526 code_ += " fn run_verifier(";
2527 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
2528 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
2529 code_ += " use self::flatbuffers::Verifiable;";
2530 code_ += " v.in_buffer::<Self>(pos)";
2531 code_ += " }";
2532 code_ += "}";
2533
2534 // Generate a constructor that takes all fields as arguments.
2535 code_ += "impl<'a> {{STRUCT_NAME}} {";
2536 code_ += " #[allow(clippy::too_many_arguments)]";
2537 code_ += " pub fn new(";
2538 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2539 (void)unused;
2540 code_ += " {{FIELD_NAME}}: {{REF}}{{FIELD_TYPE}},";
2541 });
2542 code_ += " ) -> Self {";
2543 code_ += " let mut s = Self([0; {{STRUCT_SIZE}}]);";
2544 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2545 (void)unused;
2546 code_ += " s.set_{{FIELD_NAME}}({{REF}}{{FIELD_NAME}});";
2547 });
2548 code_ += " s";
2549 code_ += " }";
2550 code_ += "";
2551
2552 if (parser_.opts.generate_name_strings) {
2553 GenFullyQualifiedNameGetter(struct_def, struct_def.name);
2554 }
2555
2556 // Generate accessor methods for the struct.
2557 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2558 this->GenComment(field.doc_comment, " ");
2559 // Getter.
2560 if (IsStruct(field.value.type)) {
2561 code_ += " pub fn {{FIELD_NAME}}(&self) -> &{{FIELD_TYPE}} {";
2562 code_ +=
2563 " unsafe {"
2564 " &*(self.0[{{FIELD_OFFSET}}..].as_ptr() as *const"
2565 " {{FIELD_TYPE}}) }";
2566 } else if (IsArray(field.value.type)) {
2567 code_.SetValue("ARRAY_SIZE",
2568 NumToString(field.value.type.fixed_length));
2569 code_.SetValue("ARRAY_ITEM", GetTypeGet(field.value.type.VectorType()));
2570 code_ +=
2571 " pub fn {{FIELD_NAME}}(&'a self) -> "
2572 "flatbuffers::Array<'a, {{ARRAY_ITEM}}, {{ARRAY_SIZE}}> {";
2573 code_ += " flatbuffers::Array::follow(&self.0, {{FIELD_OFFSET}})";
2574 } else {
2575 code_ += " pub fn {{FIELD_NAME}}(&self) -> {{FIELD_TYPE}} {";
2576 code_ +=
2577 " let mut mem = core::mem::MaybeUninit::"
2578 "<{{FIELD_TYPE}}>::uninit();";
2579 code_ += " unsafe {";
2580 code_ += " core::ptr::copy_nonoverlapping(";
2581 code_ += " self.0[{{FIELD_OFFSET}}..].as_ptr(),";
2582 code_ += " mem.as_mut_ptr() as *mut u8,";
2583 code_ += " core::mem::size_of::<{{FIELD_TYPE}}>(),";
2584 code_ += " );";
2585 code_ += " mem.assume_init()";
2586 code_ += " }.from_little_endian()";
2587 }
2588 code_ += " }\n";
2589 // Setter.
2590 if (IsStruct(field.value.type)) {
2591 code_.SetValue("FIELD_SIZE", NumToString(InlineSize(field.value.type)));
2592 code_ += " pub fn set_{{FIELD_NAME}}(&mut self, x: &{{FIELD_TYPE}}) {";
2593 code_ +=
2594 " self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}}+{{FIELD_SIZE}}]"
2595 ".copy_from_slice(&x.0)";
2596 } else if (IsArray(field.value.type)) {
2597 if (GetFullType(field.value.type) == ftArrayOfBuiltin) {
2598 code_.SetValue("ARRAY_ITEM",
2599 GetTypeGet(field.value.type.VectorType()));
2600 code_.SetValue(
2601 "ARRAY_ITEM_SIZE",
2602 NumToString(InlineSize(field.value.type.VectorType())));
2603 code_ +=
2604 " pub fn set_{{FIELD_NAME}}(&mut self, items: &{{FIELD_TYPE}}) "
2605 "{";
2606 code_ +=
2607 " flatbuffers::emplace_scalar_array(&mut self.0, "
2608 "{{FIELD_OFFSET}}, items);";
2609 } else {
2610 code_.SetValue("FIELD_SIZE",
2611 NumToString(InlineSize(field.value.type)));
2612 code_ +=
2613 " pub fn set_{{FIELD_NAME}}(&mut self, x: &{{FIELD_TYPE}}) {";
2614 code_ += " unsafe {";
2615 code_ += " std::ptr::copy(";
2616 code_ += " x.as_ptr() as *const u8,";
2617 code_ += " self.0.as_mut_ptr().add({{FIELD_OFFSET}}),";
2618 code_ += " {{FIELD_SIZE}},";
2619 code_ += " );";
2620 code_ += " }";
2621 }
2622 } else {
2623 code_ += " pub fn set_{{FIELD_NAME}}(&mut self, x: {{FIELD_TYPE}}) {";
2624 code_ += " let x_le = x.to_little_endian();";
2625 code_ += " unsafe {";
2626 code_ += " core::ptr::copy_nonoverlapping(";
2627 code_ += " &x_le as *const {{FIELD_TYPE}} as *const u8,";
2628 code_ += " self.0[{{FIELD_OFFSET}}..].as_mut_ptr(),";
2629 code_ += " core::mem::size_of::<{{FIELD_TYPE}}>(),";
2630 code_ += " );";
2631 code_ += " }";
2632 }
2633 code_ += " }\n";
2634
2635 // Generate a comparison function for this field if it is a key.
2636 if (field.key) { GenKeyFieldMethods(field); }
2637 });
2638
2639 // Generate Object API unpack method.
2640 if (parser_.opts.generate_object_based_api) {
2641 code_.SetValue("NATIVE_STRUCT_NAME", NativeName(struct_def));
2642 code_ += " pub fn unpack(&self) -> {{NATIVE_STRUCT_NAME}} {";
2643 code_ += " {{NATIVE_STRUCT_NAME}} {";
2644 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2645 if (IsArray(field.value.type)) {
2646 if (GetFullType(field.value.type) == ftArrayOfStruct) {
2647 code_ +=
2648 " {{FIELD_NAME}}: { let {{FIELD_NAME}} = "
2649 "self.{{FIELD_NAME}}(); flatbuffers::array_init(|i| "
2650 "{{FIELD_NAME}}.get(i).unpack()) },";
2651 } else {
2652 code_ += " {{FIELD_NAME}}: self.{{FIELD_NAME}}().into(),";
2653 }
2654 } else {
2655 std::string unpack = IsStruct(field.value.type) ? ".unpack()" : "";
2656 code_ += " {{FIELD_NAME}}: self.{{FIELD_NAME}}()" + unpack + ",";
2657 }
2658 });
2659 code_ += " }";
2660 code_ += " }";
2661 }
2662
2663 code_ += "}"; // End impl Struct methods.
2664 code_ += "";
2665
2666 // Generate Struct Object.
2667 if (parser_.opts.generate_object_based_api) {
2668 // Struct declaration
2669 code_ += "#[derive(Debug, Clone, PartialEq, Default)]";
2670 code_ += "pub struct {{NATIVE_STRUCT_NAME}} {";
2671 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2672 (void)field; // unused.
2673 code_ += " pub {{FIELD_NAME}}: {{FIELD_OBJECT_TYPE}},";
2674 });
2675 code_ += "}";
2676 // The `pack` method that turns the native struct into its Flatbuffers
2677 // counterpart.
2678 code_ += "impl {{NATIVE_STRUCT_NAME}} {";
2679 code_ += " pub fn pack(&self) -> {{STRUCT_NAME}} {";
2680 code_ += " {{STRUCT_NAME}}::new(";
2681 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2682 if (IsStruct(field.value.type)) {
2683 code_ += " &self.{{FIELD_NAME}}.pack(),";
2684 } else if (IsArray(field.value.type)) {
2685 if (GetFullType(field.value.type) == ftArrayOfStruct) {
2686 code_ +=
2687 " &flatbuffers::array_init(|i| "
2688 "self.{{FIELD_NAME}}[i].pack()),";
2689 } else {
2690 code_ += " &self.{{FIELD_NAME}},";
2691 }
2692 } else {
2693 code_ += " self.{{FIELD_NAME}},";
2694 }
2695 });
2696 code_ += " )";
2697 code_ += " }";
2698 code_ += "}";
2699 code_ += "";
2700 }
2701 }
2702
GenNamespaceImports(const int white_spaces)2703 void GenNamespaceImports(const int white_spaces) {
2704 // DO not use global attributes (i.e. #![...]) since it interferes
2705 // with users who include! generated files.
2706 // See: https://github.com/google/flatbuffers/issues/6261
2707 std::string indent = std::string(white_spaces, ' ');
2708 code_ += "";
2709 if (!parser_.opts.generate_all) {
2710 for (auto it = parser_.included_files_.begin();
2711 it != parser_.included_files_.end(); ++it) {
2712 if (it->second.empty()) continue;
2713 auto noext = flatbuffers::StripExtension(it->second);
2714 auto basename = flatbuffers::StripPath(noext);
2715
2716 if (parser_.opts.include_prefix.empty()) {
2717 code_ += indent + "use crate::" + basename +
2718 parser_.opts.filename_suffix + "::*;";
2719 } else {
2720 auto prefix = parser_.opts.include_prefix;
2721 prefix.pop_back();
2722
2723 code_ += indent + "use crate::" + prefix + "::" + basename +
2724 parser_.opts.filename_suffix + "::*;";
2725 }
2726 }
2727 }
2728 code_ += indent + "use std::mem;";
2729 code_ += indent + "use std::cmp::Ordering;";
2730 code_ += "";
2731 code_ += indent + "extern crate flatbuffers;";
2732 code_ += indent + "use self::flatbuffers::{EndianScalar, Follow};";
2733 }
2734
2735 // Set up the correct namespace. This opens a namespace if the current
2736 // namespace is different from the target namespace. This function
2737 // closes and opens the namespaces only as necessary.
2738 //
2739 // The file must start and end with an empty (or null) namespace so that
2740 // namespaces are properly opened and closed.
SetNameSpace(const Namespace * ns)2741 void SetNameSpace(const Namespace *ns) {
2742 if (cur_name_space_ == ns) { return; }
2743
2744 // Compute the size of the longest common namespace prefix.
2745 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
2746 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
2747 // and common_prefix_size = 2
2748 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
2749 size_t new_size = ns ? ns->components.size() : 0;
2750
2751 size_t common_prefix_size = 0;
2752 while (common_prefix_size < old_size && common_prefix_size < new_size &&
2753 ns->components[common_prefix_size] ==
2754 cur_name_space_->components[common_prefix_size]) {
2755 common_prefix_size++;
2756 }
2757
2758 // Close cur_name_space in reverse order to reach the common prefix.
2759 // In the previous example, D then C are closed.
2760 for (size_t j = old_size; j > common_prefix_size; --j) {
2761 code_ += "} // pub mod " + cur_name_space_->components[j - 1];
2762 }
2763 if (old_size != common_prefix_size) { code_ += ""; }
2764
2765 // open namespace parts to reach the ns namespace
2766 // in the previous example, E, then F, then G are opened
2767 for (auto j = common_prefix_size; j != new_size; ++j) {
2768 code_ += "#[allow(unused_imports, dead_code)]";
2769 code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
2770 // Generate local namespace imports.
2771 GenNamespaceImports(2);
2772 }
2773 if (new_size != common_prefix_size) { code_ += ""; }
2774
2775 cur_name_space_ = ns;
2776 }
2777 };
2778
2779 } // namespace rust
2780
GenerateRust(const Parser & parser,const std::string & path,const std::string & file_name)2781 bool GenerateRust(const Parser &parser, const std::string &path,
2782 const std::string &file_name) {
2783 rust::RustGenerator generator(parser, path, file_name);
2784 return generator.generate();
2785 }
2786
RustMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)2787 std::string RustMakeRule(const Parser &parser, const std::string &path,
2788 const std::string &file_name) {
2789 std::string filebase =
2790 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
2791 rust::RustGenerator generator(parser, path, file_name);
2792 std::string make_rule =
2793 generator.GeneratedFileName(path, filebase, parser.opts) + ": ";
2794
2795 auto included_files = parser.GetIncludedFilesRecursive(file_name);
2796 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
2797 make_rule += " " + *it;
2798 }
2799 return make_rule;
2800 }
2801
2802 } // namespace flatbuffers
2803
2804 // TODO(rw): Generated code should import other generated files.
2805 // TODO(rw): Generated code should refer to namespaces in included files in a
2806 // way that makes them referrable.
2807 // TODO(rw): Generated code should indent according to nesting level.
2808 // TODO(rw): Generated code should generate endian-safe Debug impls.
2809 // TODO(rw): Generated code could use a Rust-only enum type to access unions,
2810 // instead of making the user use _type() to manually switch.
2811 // TODO(maxburke): There should be test schemas added that use language
2812 // keywords as fields of structs, tables, unions, enums, to make sure
2813 // that internal code generated references escaped names correctly.
2814 // TODO(maxburke): We should see if there is a more flexible way of resolving
2815 // module paths for use declarations. Right now if schemas refer to
2816 // other flatbuffer files, the include paths in emitted Rust bindings
2817 // are crate-relative which may undesirable.
2818