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