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