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