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