blob: 17853a09dc63ccb6ad005b51a24f93bada2947ab [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
2 * Copyright 2018 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// independent from idl_parser, since this code is not needed for most clients
18
19#include "flatbuffers/code_generators.h"
20#include "flatbuffers/flatbuffers.h"
21#include "flatbuffers/idl.h"
22#include "flatbuffers/util.h"
James Kuszmaul8e62b022022-03-22 09:33:25 -070023#include "namer.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070024
25namespace flatbuffers {
26
James Kuszmaul8e62b022022-03-22 09:33:25 -070027Namer::Config RustDefaultConfig() {
28 // Historical note: We've been using "keep" casing since the original
29 // implementation, presumably because Flatbuffers schema style and Rust style
30 // roughly align. We are not going to enforce proper casing since its an
31 // unnecessary breaking change.
32 return { /*types=*/Case::kKeep,
33 /*constants=*/Case::kScreamingSnake,
34 /*methods=*/Case::kSnake,
35 /*functions=*/Case::kSnake,
36 /*fields=*/Case::kKeep,
37 /*variables=*/Case::kUnknown, // Unused.
38 /*variants=*/Case::kKeep,
39 /*enum_variant_seperator=*/"::",
40 /*namespaces=*/Case::kSnake,
41 /*namespace_seperator=*/"::",
42 /*object_prefix=*/"",
43 /*object_suffix=*/"T",
44 /*keyword_prefix=*/"",
45 /*keyword_suffix=*/"_",
46 /*filenames=*/Case::kSnake,
47 /*directories=*/Case::kSnake,
48 /*output_path=*/"",
49 /*filename_suffix=*/"_generated",
50 /*filename_extension=*/".rs" };
Austin Schuhe89fa2d2019-08-14 20:24:23 -070051}
52
James Kuszmaul8e62b022022-03-22 09:33:25 -070053std::set<std::string> RustKeywords() {
54 return {
55 // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
56 "as",
57 "break",
58 "const",
59 "continue",
60 "crate",
61 "else",
62 "enum",
63 "extern",
64 "false",
65 "fn",
66 "for",
67 "if",
68 "impl",
69 "in",
70 "let",
71 "loop",
72 "match",
73 "mod",
74 "move",
75 "mut",
76 "pub",
77 "ref",
78 "return",
79 "Self",
80 "self",
81 "static",
82 "struct",
83 "super",
84 "trait",
85 "true",
86 "type",
87 "unsafe",
88 "use",
89 "where",
90 "while",
91 // future possible keywords
92 "abstract",
93 "alignof",
94 "become",
95 "box",
96 "do",
97 "final",
98 "macro",
99 "offsetof",
100 "override",
101 "priv",
102 "proc",
103 "pure",
104 "sizeof",
105 "typeof",
106 "unsized",
107 "virtual",
108 "yield",
109 // other rust terms we should not use
110 "std",
111 "usize",
112 "isize",
113 "u8",
114 "i8",
115 "u16",
116 "i16",
117 "u32",
118 "i32",
119 "u64",
120 "i64",
121 "u128",
122 "i128",
123 "f32",
124 "f64",
125 // Terms that we use ourselves
126 "follow",
127 "push",
128 "size",
129 "alignment",
130 "to_little_endian",
131 "from_little_endian",
132 "ENUM_MAX",
133 "ENUM_MIN",
134 "ENUM_VALUES",
135 };
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700136}
137
138// Encapsulate all logical field types in this enum. This allows us to write
139// field logic based on type switches, instead of branches on the properties
140// set on the Type.
141// TODO(rw): for backwards compatibility, we can't use a strict `enum class`
142// declaration here. could we use the `-Wswitch-enum` warning to
143// achieve the same effect?
144enum FullType {
145 ftInteger = 0,
146 ftFloat = 1,
147 ftBool = 2,
148
149 ftStruct = 3,
150 ftTable = 4,
151
152 ftEnumKey = 5,
153 ftUnionKey = 6,
154
155 ftUnionValue = 7,
156
157 // TODO(rw): bytestring?
158 ftString = 8,
159
160 ftVectorOfInteger = 9,
161 ftVectorOfFloat = 10,
162 ftVectorOfBool = 11,
163 ftVectorOfEnumKey = 12,
164 ftVectorOfStruct = 13,
165 ftVectorOfTable = 14,
166 ftVectorOfString = 15,
167 ftVectorOfUnionValue = 16,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700168
169 ftArrayOfBuiltin = 17,
170 ftArrayOfEnum = 18,
171 ftArrayOfStruct = 19,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700172};
173
174// Convert a Type to a FullType (exhaustive).
175FullType GetFullType(const Type &type) {
176 // N.B. The order of these conditionals matters for some types.
177
Austin Schuh272c6132020-11-14 16:37:52 -0800178 if (IsString(type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700179 return ftString;
180 } else if (type.base_type == BASE_TYPE_STRUCT) {
181 if (type.struct_def->fixed) {
182 return ftStruct;
183 } else {
184 return ftTable;
185 }
Austin Schuh272c6132020-11-14 16:37:52 -0800186 } else if (IsVector(type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700187 switch (GetFullType(type.VectorType())) {
188 case ftInteger: {
189 return ftVectorOfInteger;
190 }
191 case ftFloat: {
192 return ftVectorOfFloat;
193 }
194 case ftBool: {
195 return ftVectorOfBool;
196 }
197 case ftStruct: {
198 return ftVectorOfStruct;
199 }
200 case ftTable: {
201 return ftVectorOfTable;
202 }
203 case ftString: {
204 return ftVectorOfString;
205 }
206 case ftEnumKey: {
207 return ftVectorOfEnumKey;
208 }
209 case ftUnionKey:
210 case ftUnionValue: {
211 FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
212 break;
213 }
214 default: {
215 FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
216 }
217 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700218 } else if (IsArray(type)) {
219 switch (GetFullType(type.VectorType())) {
220 case ftInteger:
221 case ftFloat:
222 case ftBool: {
223 return ftArrayOfBuiltin;
224 }
225 case ftStruct: {
226 return ftArrayOfStruct;
227 }
228 case ftEnumKey: {
229 return ftArrayOfEnum;
230 }
231 default: {
232 FLATBUFFERS_ASSERT(false && "Unsupported type for fixed array");
233 }
234 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700235 } else if (type.enum_def != nullptr) {
236 if (type.enum_def->is_union) {
237 if (type.base_type == BASE_TYPE_UNION) {
238 return ftUnionValue;
239 } else if (IsInteger(type.base_type)) {
240 return ftUnionKey;
241 } else {
242 FLATBUFFERS_ASSERT(false && "unknown union field type");
243 }
244 } else {
245 return ftEnumKey;
246 }
247 } else if (IsScalar(type.base_type)) {
248 if (IsBool(type.base_type)) {
249 return ftBool;
250 } else if (IsInteger(type.base_type)) {
251 return ftInteger;
252 } else if (IsFloat(type.base_type)) {
253 return ftFloat;
254 } else {
255 FLATBUFFERS_ASSERT(false && "unknown number type");
256 }
257 }
258
259 FLATBUFFERS_ASSERT(false && "completely unknown type");
260
261 // this is only to satisfy the compiler's return analysis.
262 return ftBool;
263}
264
Austin Schuh272c6132020-11-14 16:37:52 -0800265bool IsBitFlagsEnum(const EnumDef &enum_def) {
266 return enum_def.attributes.Lookup("bit_flags") != nullptr;
267}
James Kuszmaul8e62b022022-03-22 09:33:25 -0700268
269// TableArgs make required non-scalars "Option<_>".
270// TODO(cneo): Rework how we do defaults and stuff.
271bool IsOptionalToBuilder(const FieldDef &field) {
272 return field.IsOptional() || !IsScalar(field.value.type.base_type);
273}
274
275bool GenerateRustModuleRootFile(const Parser &parser,
276 const std::string &output_dir) {
277 if (!parser.opts.rust_module_root_file) {
278 // Don't generate a root file when generating one file. This isn't an error
279 // so return true.
280 return true;
281 }
282 Namer namer(RustDefaultConfig().WithFlagOptions(parser.opts, output_dir),
283 RustKeywords());
284 // We gather the symbols into a tree of namespaces (which are rust mods) and
285 // generate a file that gathers them all.
286 struct Module {
287 std::map<std::string, Module> sub_modules;
288 std::vector<std::string> generated_files;
289 // Add a symbol into the tree.
290 void Insert(const Namer &namer, const Definition *s) {
291 const Definition &symbol = *s;
292 Module *current_module = this;
293 for (auto it = symbol.defined_namespace->components.begin();
294 it != symbol.defined_namespace->components.end(); it++) {
295 std::string ns_component = namer.Namespace(*it);
296 current_module = &current_module->sub_modules[ns_component];
297 }
298 current_module->generated_files.push_back(
299 namer.File(symbol.name, SkipFile::Extension));
300 }
301 // Recursively create the importer file.
302 void GenerateImports(CodeWriter &code) {
303 for (auto it = sub_modules.begin(); it != sub_modules.end(); it++) {
304 code += "pub mod " + it->first + " {";
305 code.IncrementIdentLevel();
306 code += "use super::*;";
307 it->second.GenerateImports(code);
308 code.DecrementIdentLevel();
309 code += "} // " + it->first;
310 }
311 for (auto it = generated_files.begin(); it != generated_files.end();
312 it++) {
313 code += "mod " + *it + ";";
314 code += "pub use self::" + *it + "::*;";
315 }
316 }
317 };
318 Module root_module;
319 for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
320 it++) {
321 root_module.Insert(namer, *it);
322 }
323 for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
324 it++) {
325 root_module.Insert(namer, *it);
326 }
327 CodeWriter code(" ");
328 // TODO(caspern): Move generated warning out of BaseGenerator.
329 code +=
330 "// Automatically generated by the Flatbuffers compiler. "
331 "Do not modify.";
332 root_module.GenerateImports(code);
333 const bool success =
334 SaveFile((output_dir + "mod.rs").c_str(), code.ToString(), false);
335 code.Clear();
336 return success;
Austin Schuh272c6132020-11-14 16:37:52 -0800337}
338
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700339namespace rust {
340
341class RustGenerator : public BaseGenerator {
342 public:
343 RustGenerator(const Parser &parser, const std::string &path,
344 const std::string &file_name)
Austin Schuh272c6132020-11-14 16:37:52 -0800345 : BaseGenerator(parser, path, file_name, "", "::", "rs"),
James Kuszmaul8e62b022022-03-22 09:33:25 -0700346 cur_name_space_(nullptr),
347 namer_({ RustDefaultConfig().WithFlagOptions(parser.opts, path),
348 RustKeywords() }) {
349 // TODO: Namer flag overrides should be in flatc or flatc_main.
350 code_.SetPadding(" ");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700351 }
352
James Kuszmaul8e62b022022-03-22 09:33:25 -0700353 bool generate() {
354 if (!parser_.opts.rust_module_root_file) {
355 return GenerateOneFile();
356 } else {
357 return GenerateIndividualFiles();
358 }
359 }
360
361 template<typename T>
362 bool GenerateSymbols(const SymbolTable<T> &symbols,
363 std::function<void(const T &)> gen_symbol) {
364 for (auto it = symbols.vec.begin(); it != symbols.vec.end(); it++) {
365 const T &symbol = **it;
366 if (symbol.generated) continue;
367 code_.Clear();
368 code_ += "// " + std::string(FlatBuffersGeneratedWarning());
369 code_ += "extern crate flatbuffers;";
370 code_ += "use std::mem;";
371 code_ += "use std::cmp::Ordering;";
372 if (parser_.opts.rust_serialize) {
373 code_ += "extern crate serde;";
374 code_ +=
375 "use self::serde::ser::{Serialize, Serializer, SerializeStruct};";
376 }
377 code_ += "use self::flatbuffers::{EndianScalar, Follow};";
378 code_ += "use super::*;";
379 cur_name_space_ = symbol.defined_namespace;
380 gen_symbol(symbol);
381
382 const std::string directories =
383 namer_.Directories(symbol.defined_namespace->components);
384 EnsureDirExists(directories);
385 const std::string file_path = directories + namer_.File(symbol.name);
386 const bool save_success =
387 SaveFile(file_path.c_str(), code_.ToString(), /*binary=*/false);
388 if (!save_success) return false;
389 }
390 return true;
391 }
392
393 bool GenerateIndividualFiles() {
394 code_.Clear();
395 // Don't bother with imports. Use absolute paths everywhere.
396 return GenerateSymbols<EnumDef>(
397 parser_.enums_, [&](const EnumDef &e) { this->GenEnum(e); }) &&
398 GenerateSymbols<StructDef>(
399 parser_.structs_, [&](const StructDef &s) {
400 if (s.fixed) {
401 this->GenStruct(s);
402 } else {
403 this->GenTable(s);
404 if (this->parser_.opts.generate_object_based_api) {
405 this->GenTableObject(s);
406 }
407 }
408 if (this->parser_.root_struct_def_ == &s) {
409 this->GenRootTableFuncs(s);
410 }
411 });
412 }
413
414 // Generates code organized by .fbs files. This is broken legacy behavior
415 // that does not work with multiple fbs files with shared namespaces.
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700416 // Iterate through all definitions we haven't generated code for (enums,
417 // structs, and tables) and output them to a single file.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700418 bool GenerateOneFile() {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700419 code_.Clear();
420 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
421
422 assert(!cur_name_space_);
423
424 // Generate imports for the global scope in case no namespace is used
425 // in the schema file.
426 GenNamespaceImports(0);
427 code_ += "";
428
429 // Generate all code in their namespaces, once, because Rust does not
430 // permit re-opening modules.
431 //
432 // TODO(rw): Use a set data structure to reduce namespace evaluations from
433 // O(n**2) to O(n).
434 for (auto ns_it = parser_.namespaces_.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800435 ns_it != parser_.namespaces_.end(); ++ns_it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700436 const auto &ns = *ns_it;
437
438 // Generate code for all the enum declarations.
439 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
440 ++it) {
441 const auto &enum_def = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700442 if (enum_def.defined_namespace == ns && !enum_def.generated) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700443 SetNameSpace(enum_def.defined_namespace);
444 GenEnum(enum_def);
445 }
446 }
447
448 // Generate code for all structs.
449 for (auto it = parser_.structs_.vec.begin();
450 it != parser_.structs_.vec.end(); ++it) {
451 const auto &struct_def = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700452 if (struct_def.defined_namespace == ns && struct_def.fixed &&
453 !struct_def.generated) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700454 SetNameSpace(struct_def.defined_namespace);
455 GenStruct(struct_def);
456 }
457 }
458
459 // Generate code for all tables.
460 for (auto it = parser_.structs_.vec.begin();
461 it != parser_.structs_.vec.end(); ++it) {
462 const auto &struct_def = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700463 if (struct_def.defined_namespace == ns && !struct_def.fixed &&
464 !struct_def.generated) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700465 SetNameSpace(struct_def.defined_namespace);
466 GenTable(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700467 if (parser_.opts.generate_object_based_api) {
468 GenTableObject(struct_def);
469 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700470 }
471 }
472
473 // Generate global helper functions.
474 if (parser_.root_struct_def_) {
475 auto &struct_def = *parser_.root_struct_def_;
476 if (struct_def.defined_namespace != ns) { continue; }
477 SetNameSpace(struct_def.defined_namespace);
478 GenRootTableFuncs(struct_def);
479 }
480 }
481 if (cur_name_space_) SetNameSpace(nullptr);
482
Austin Schuh272c6132020-11-14 16:37:52 -0800483 const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700484 const auto final_code = code_.ToString();
485 return SaveFile(file_path.c_str(), final_code, false);
486 }
487
488 private:
489 CodeWriter code_;
490
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700491 // This tracks the current namespace so we can insert namespace declarations.
492 const Namespace *cur_name_space_;
493
494 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
495
496 // Determine if a Type needs a lifetime template parameter when used in the
497 // Rust builder args.
498 bool TableBuilderTypeNeedsLifetime(const Type &type) const {
499 switch (GetFullType(type)) {
500 case ftInteger:
501 case ftFloat:
502 case ftBool:
503 case ftEnumKey:
504 case ftUnionKey:
Austin Schuh272c6132020-11-14 16:37:52 -0800505 case ftUnionValue: {
506 return false;
507 }
508 default: {
509 return true;
510 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700511 }
512 }
513
514 // Determine if a table args rust type needs a lifetime template parameter.
515 bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
516 FLATBUFFERS_ASSERT(!struct_def.fixed);
517
518 for (auto it = struct_def.fields.vec.begin();
519 it != struct_def.fields.vec.end(); ++it) {
520 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -0800521 if (field.deprecated) { continue; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700522
Austin Schuh272c6132020-11-14 16:37:52 -0800523 if (TableBuilderTypeNeedsLifetime(field.value.type)) { return true; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700524 }
525
526 return false;
527 }
528
James Kuszmaul8e62b022022-03-22 09:33:25 -0700529 std::string NamespacedNativeName(const Definition &def) {
530 return WrapInNameSpace(def.defined_namespace, namer_.ObjectType(def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700531 }
532
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700533 std::string WrapInNameSpace(const Definition &def) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700534 return WrapInNameSpace(def.defined_namespace,
535 namer_.EscapeKeyword(def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700536 }
537 std::string WrapInNameSpace(const Namespace *ns,
538 const std::string &name) const {
539 if (CurrentNameSpace() == ns) return name;
540 std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
541 return prefix + name;
542 }
543
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700544 // Determine the relative namespace traversal needed to reference one
545 // namespace from another namespace. This is useful because it does not force
546 // the user to have a particular file layout. (If we output absolute
547 // namespace paths, that may require users to organize their Rust crates in a
548 // particular way.)
549 std::string GetRelativeNamespaceTraversal(const Namespace *src,
550 const Namespace *dst) const {
551 // calculate the path needed to reference dst from src.
552 // example: f(A::B::C, A::B::C) -> (none)
553 // example: f(A::B::C, A::B) -> super::
554 // example: f(A::B::C, A::B::D) -> super::D
555 // example: f(A::B::C, A) -> super::super::
556 // example: f(A::B::C, D) -> super::super::super::D
557 // example: f(A::B::C, D::E) -> super::super::super::D::E
558 // example: f(A, D::E) -> super::D::E
559 // does not include leaf object (typically a struct type).
560
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700561 std::stringstream stream;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700562 size_t common = 0;
563 std::vector<std::string> s, d;
564 if (src) s = src->components;
565 if (dst) d = dst->components;
566 while (common < s.size() && common < d.size() && s[common] == d[common])
567 common++;
568 // If src namespace is empty, this must be an absolute path.
569 for (size_t i = common; i < s.size(); i++) stream << "super::";
570 for (size_t i = common; i < d.size(); i++)
571 stream << namer_.Namespace(d[i]) + "::";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700572 return stream.str();
573 }
574
575 // Generate a comment from the schema.
576 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700577 for (auto it = dc.begin(); it != dc.end(); it++) {
578 code_ += std::string(prefix) + "///" + *it;
579 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700580 }
581
582 // Return a Rust type from the table in idl.h.
583 std::string GetTypeBasic(const Type &type) const {
584 switch (GetFullType(type)) {
585 case ftInteger:
586 case ftFloat:
587 case ftBool:
588 case ftEnumKey:
Austin Schuh272c6132020-11-14 16:37:52 -0800589 case ftUnionKey: {
590 break;
591 }
592 default: {
593 FLATBUFFERS_ASSERT(false && "incorrect type given");
594 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700595 }
596
597 // clang-format off
598 static const char * const ctypename[] = {
599 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -0800600 RTYPE, ...) \
601 #RTYPE,
602 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700603 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700604 };
Austin Schuh272c6132020-11-14 16:37:52 -0800605 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700606
607 if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
608 return ctypename[type.base_type];
609 }
610
611 // Look up the native type for an enum. This will always be an integer like
612 // u8, i32, etc.
613 std::string GetEnumTypeForDecl(const Type &type) {
614 const auto ft = GetFullType(type);
615 if (!(ft == ftEnumKey || ft == ftUnionKey)) {
616 FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
617 }
618
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700619 // clang-format off
Austin Schuh272c6132020-11-14 16:37:52 -0800620 static const char *ctypename[] = {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700621 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -0800622 RTYPE, ...) \
623 #RTYPE,
624 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700625 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700626 };
Austin Schuh272c6132020-11-14 16:37:52 -0800627 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700628
629 // Enums can be bools, but their Rust representation must be a u8, as used
630 // in the repr attribute (#[repr(bool)] is an invalid attribute).
631 if (type.base_type == BASE_TYPE_BOOL) return "u8";
632 return ctypename[type.base_type];
633 }
634
635 // Return a Rust type for any type (scalar, table, struct) specifically for
636 // using a FlatBuffer.
637 std::string GetTypeGet(const Type &type) const {
638 switch (GetFullType(type)) {
639 case ftInteger:
640 case ftFloat:
641 case ftBool:
642 case ftEnumKey:
643 case ftUnionKey: {
Austin Schuh272c6132020-11-14 16:37:52 -0800644 return GetTypeBasic(type);
645 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700646 case ftArrayOfBuiltin:
647 case ftArrayOfEnum:
648 case ftArrayOfStruct: {
649 return "[" + GetTypeGet(type.VectorType()) + "; " +
650 NumToString(type.fixed_length) + "]";
651 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700652 case ftTable: {
653 return WrapInNameSpace(type.struct_def->defined_namespace,
Austin Schuh272c6132020-11-14 16:37:52 -0800654 type.struct_def->name) +
655 "<'a>";
656 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700657 default: {
658 return WrapInNameSpace(type.struct_def->defined_namespace,
Austin Schuh272c6132020-11-14 16:37:52 -0800659 type.struct_def->name);
660 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700661 }
662 }
663
Austin Schuh272c6132020-11-14 16:37:52 -0800664 std::string GetEnumValue(const EnumDef &enum_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700665 const EnumVal &enum_val) const {
666 return namer_.EnumVariant(enum_def.name, enum_val.name);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700667 }
668
Austin Schuh272c6132020-11-14 16:37:52 -0800669 // 1 suffix since old C++ can't figure out the overload.
670 void ForAllEnumValues1(const EnumDef &enum_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700671 std::function<void(const EnumVal &)> cb) {
Austin Schuh272c6132020-11-14 16:37:52 -0800672 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
673 const auto &ev = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700674 code_.SetValue("VARIANT", namer_.Variant(ev.name));
Austin Schuh272c6132020-11-14 16:37:52 -0800675 code_.SetValue("VALUE", enum_def.ToString(ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700676 code_.IncrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -0800677 cb(ev);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700678 code_.DecrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -0800679 }
680 }
681 void ForAllEnumValues(const EnumDef &enum_def, std::function<void()> cb) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700682 std::function<void(const EnumVal &)> wrapped = [&](const EnumVal &unused) {
683 (void)unused;
684 cb();
685 };
686 ForAllEnumValues1(enum_def, wrapped);
Austin Schuh272c6132020-11-14 16:37:52 -0800687 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700688 // Generate an enum declaration,
689 // an enum string lookup table,
690 // an enum match function,
691 // and an enum array of values
692 void GenEnum(const EnumDef &enum_def) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700693 code_.SetValue("ENUM_TY", namer_.Type(enum_def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700694 code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700695 code_.SetValue("ENUM_NAMESPACE", namer_.Namespace(enum_def.name));
696 code_.SetValue("ENUM_CONSTANT", namer_.Constant(enum_def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700697 const EnumVal *minv = enum_def.MinValue();
698 const EnumVal *maxv = enum_def.MaxValue();
699 FLATBUFFERS_ASSERT(minv && maxv);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700700 code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
701 code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
702
Austin Schuh272c6132020-11-14 16:37:52 -0800703 if (IsBitFlagsEnum(enum_def)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700704 // Defer to the convenient and canonical bitflags crate. We declare it in
705 // a module to #allow camel case constants in a smaller scope. This
706 // matches Flatbuffers c-modeled enums where variants are associated
707 // constants but in camel case.
Austin Schuh272c6132020-11-14 16:37:52 -0800708 code_ += "#[allow(non_upper_case_globals)]";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700709 code_ += "mod bitflags_{{ENUM_NAMESPACE}} {";
Austin Schuh272c6132020-11-14 16:37:52 -0800710 code_ += " flatbuffers::bitflags::bitflags! {";
711 GenComment(enum_def.doc_comment, " ");
James Kuszmaul8e62b022022-03-22 09:33:25 -0700712 code_ += " #[derive(Default)]";
713 code_ += " pub struct {{ENUM_TY}}: {{BASE_TYPE}} {";
714 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
715 this->GenComment(ev.doc_comment, " ");
716 code_ += " const {{VARIANT}} = {{VALUE}};";
Austin Schuh272c6132020-11-14 16:37:52 -0800717 });
718 code_ += " }";
719 code_ += " }";
720 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700721 code_ += "pub use self::bitflags_{{ENUM_NAMESPACE}}::{{ENUM_TY}};";
Austin Schuh272c6132020-11-14 16:37:52 -0800722 code_ += "";
723
James Kuszmaul8e62b022022-03-22 09:33:25 -0700724 code_.SetValue("FROM_BASE", "unsafe { Self::from_bits_unchecked(b) }");
725 code_.SetValue("INTO_BASE", "self.bits()");
726 } else {
727 // Normal, c-modelled enums.
728 // Deprecated associated constants;
729 const std::string deprecation_warning =
730 "#[deprecated(since = \"2.0.0\", note = \"Use associated constants"
731 " instead. This will no longer be generated in 2021.\")]";
732 code_ += deprecation_warning;
733 code_ +=
734 "pub const ENUM_MIN_{{ENUM_CONSTANT}}: {{BASE_TYPE}}"
735 " = {{ENUM_MIN_BASE_VALUE}};";
736 code_ += deprecation_warning;
737 code_ +=
738 "pub const ENUM_MAX_{{ENUM_CONSTANT}}: {{BASE_TYPE}}"
739 " = {{ENUM_MAX_BASE_VALUE}};";
740 auto num_fields = NumToString(enum_def.size());
741 code_ += deprecation_warning;
742 code_ += "#[allow(non_camel_case_types)]";
743 code_ += "pub const ENUM_VALUES_{{ENUM_CONSTANT}}: [{{ENUM_TY}}; " +
744 num_fields + "] = [";
745 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
746 code_ += namer_.EnumVariant(enum_def.name, ev.name) + ",";
747 });
748 code_ += "];";
Austin Schuh272c6132020-11-14 16:37:52 -0800749 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700750
751 GenComment(enum_def.doc_comment);
752 // Derive Default to be 0. flatc enforces this when the enum
753 // is put into a struct, though this isn't documented behavior, it is
754 // needed to derive defaults in struct objects.
755 code_ +=
756 "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, "
757 "Default)]";
758 code_ += "#[repr(transparent)]";
759 code_ += "pub struct {{ENUM_TY}}(pub {{BASE_TYPE}});";
760 code_ += "#[allow(non_upper_case_globals)]";
761 code_ += "impl {{ENUM_TY}} {";
762 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
763 this->GenComment(ev.doc_comment);
764 code_ += "pub const {{VARIANT}}: Self = Self({{VALUE}});";
765 });
766 code_ += "";
767 // Generate Associated constants
768 code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};";
769 code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};";
770 code_ += " pub const ENUM_VALUES: &'static [Self] = &[";
771 ForAllEnumValues(enum_def, [&]() { code_ += " Self::{{VARIANT}},"; });
772 code_ += " ];";
773 code_ += " /// Returns the variant's name or \"\" if unknown.";
774 code_ += " pub fn variant_name(self) -> Option<&'static str> {";
775 code_ += " match self {";
776 ForAllEnumValues(enum_def, [&]() {
777 code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),";
778 });
779 code_ += " _ => None,";
Austin Schuh272c6132020-11-14 16:37:52 -0800780 code_ += " }";
Austin Schuh272c6132020-11-14 16:37:52 -0800781 code_ += " }";
782 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700783
784 // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>".
785 code_ += "impl std::fmt::Debug for {{ENUM_TY}} {";
786 code_ +=
787 " fn fmt(&self, f: &mut std::fmt::Formatter) ->"
788 " std::fmt::Result {";
789 code_ += " if let Some(name) = self.variant_name() {";
790 code_ += " f.write_str(name)";
791 code_ += " } else {";
792 code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))";
793 code_ += " }";
794 code_ += " }";
795 code_ += "}";
796
797 code_.SetValue("FROM_BASE", "Self(b)");
798 code_.SetValue("INTO_BASE", "self.0");
Austin Schuh272c6132020-11-14 16:37:52 -0800799 }
800
James Kuszmaul8e62b022022-03-22 09:33:25 -0700801 // Implement serde::Serialize
802 if (parser_.opts.rust_serialize) {
803 code_ += "impl Serialize for {{ENUM_TY}} {";
804 code_ +=
805 " fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
806 code_ += " where";
807 code_ += " S: Serializer,";
808 code_ += " {";
809 if (IsBitFlagsEnum(enum_def)) {
810 code_ += " serializer.serialize_u32(self.bits() as u32)";
811 } else {
812 code_ +=
813 " serializer.serialize_unit_variant(\"{{ENUM_TY}}\", self.0 "
814 "as "
815 "u32, self.variant_name().unwrap())";
816 }
817 code_ += " }";
818 code_ += "}";
819 code_ += "";
820 }
Austin Schuh272c6132020-11-14 16:37:52 -0800821
822 // Generate Follow and Push so we can serialize and stuff.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700823 code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_TY}} {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700824 code_ += " type Inner = Self;";
825 code_ += " #[inline]";
826 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700827 code_ += " let b = unsafe {";
828 code_ += " flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc)";
829 code_ += " };";
830 code_ += " {{FROM_BASE}}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700831 code_ += " }";
832 code_ += "}";
833 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700834 code_ += "impl flatbuffers::Push for {{ENUM_TY}} {";
835 code_ += " type Output = {{ENUM_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700836 code_ += " #[inline]";
837 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700838 code_ +=
839 " unsafe { flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
840 "(dst, {{INTO_BASE}}); }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700841 code_ += " }";
842 code_ += "}";
843 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700844 code_ += "impl flatbuffers::EndianScalar for {{ENUM_TY}} {";
Austin Schuh272c6132020-11-14 16:37:52 -0800845 code_ += " #[inline]";
846 code_ += " fn to_little_endian(self) -> Self {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700847 code_ += " let b = {{BASE_TYPE}}::to_le({{INTO_BASE}});";
848 code_ += " {{FROM_BASE}}";
Austin Schuh272c6132020-11-14 16:37:52 -0800849 code_ += " }";
850 code_ += " #[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700851 code_ += " #[allow(clippy::wrong_self_convention)]";
Austin Schuh272c6132020-11-14 16:37:52 -0800852 code_ += " fn from_little_endian(self) -> Self {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700853 code_ += " let b = {{BASE_TYPE}}::from_le({{INTO_BASE}});";
854 code_ += " {{FROM_BASE}}";
Austin Schuh272c6132020-11-14 16:37:52 -0800855 code_ += " }";
856 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700857 code_ += "";
858
James Kuszmaul8e62b022022-03-22 09:33:25 -0700859 // Generate verifier - deferring to the base type.
860 code_ += "impl<'a> flatbuffers::Verifiable for {{ENUM_TY}} {";
861 code_ += " #[inline]";
862 code_ += " fn run_verifier(";
863 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
864 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
865 code_ += " use self::flatbuffers::Verifiable;";
866 code_ += " {{BASE_TYPE}}::run_verifier(v, pos)";
867 code_ += " }";
868 code_ += "}";
869 code_ += "";
870 // Enums are basically integers.
871 code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{ENUM_TY}} {}";
872
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700873 if (enum_def.is_union) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700874 // Generate typesafe offset(s) for unions
875 code_.SetValue("UNION_TYPE", namer_.Type(enum_def.name));
876 code_ += "pub struct {{UNION_TYPE}}UnionTableOffset {}";
877 code_ += "";
878 if (parser_.opts.generate_object_based_api) { GenUnionObject(enum_def); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700879 }
880 }
881
James Kuszmaul8e62b022022-03-22 09:33:25 -0700882 // TODO(cneo): dedup Object versions from non object versions.
883 void ForAllUnionObjectVariantsBesidesNone(const EnumDef &enum_def,
884 std::function<void()> cb) {
885 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
886 auto &enum_val = **it;
887 if (enum_val.union_type.base_type == BASE_TYPE_NONE) continue;
888 code_.SetValue("VARIANT_NAME", namer_.Variant(enum_val.name));
889 // For legacy reasons, enum variants are Keep case while enum native
890 // variants are UpperCamel case.
891 code_.SetValue(
892 "NATIVE_VARIANT",
893 ConvertCase(namer_.EscapeKeyword(enum_val.name), Case::kUpperCamel));
894 code_.SetValue("U_ELEMENT_NAME", namer_.Method(enum_val.name));
895 code_.SetValue("U_ELEMENT_TABLE_TYPE",
896 NamespacedNativeName(*enum_val.union_type.struct_def));
897 code_.IncrementIdentLevel();
898 cb();
899 code_.DecrementIdentLevel();
900 }
901 }
902 void GenUnionObject(const EnumDef &enum_def) {
903 code_.SetValue("ENUM_TY", namer_.Type(enum_def.name));
904 code_.SetValue("ENUM_FN", namer_.Function(enum_def.name));
905 code_.SetValue("ENUM_OTY", namer_.ObjectType(enum_def.name));
906
907 // Generate native union.
908 code_ += "#[allow(clippy::upper_case_acronyms)]"; // NONE's spelling is
909 // intended.
910 code_ += "#[non_exhaustive]";
911 code_ += "#[derive(Debug, Clone, PartialEq)]";
912 code_ += "pub enum {{ENUM_OTY}} {";
913 code_ += " NONE,";
914 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
915 code_ += "{{NATIVE_VARIANT}}(Box<{{U_ELEMENT_TABLE_TYPE}}>),";
916 });
917 code_ += "}";
918 // Generate Default (NONE).
919 code_ += "impl Default for {{ENUM_OTY}} {";
920 code_ += " fn default() -> Self {";
921 code_ += " Self::NONE";
922 code_ += " }";
923 code_ += "}";
924
925 // Generate native union methods.
926 code_ += "impl {{ENUM_OTY}} {";
927
928 // Get flatbuffers union key.
929 // TODO(cneo): add docstrings?
930 code_ += " pub fn {{ENUM_FN}}_type(&self) -> {{ENUM_TY}} {";
931 code_ += " match self {";
932 code_ += " Self::NONE => {{ENUM_TY}}::NONE,";
933 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
934 code_ +=
935 " Self::{{NATIVE_VARIANT}}(_) => {{ENUM_TY}}::"
936 "{{VARIANT_NAME}},";
937 });
938 code_ += " }";
939 code_ += " }";
940 // Pack flatbuffers union value
941 code_ +=
942 " pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder)"
943 " -> Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>"
944 " {";
945 code_ += " match self {";
946 code_ += " Self::NONE => None,";
947 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
948 code_ += " Self::{{NATIVE_VARIANT}}(v) => \\";
949 code_ += "Some(v.pack(fbb).as_union_value()),";
950 });
951 code_ += " }";
952 code_ += " }";
953
954 // Generate some accessors;
955 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
956 // Move accessor.
957 code_ +=
958 "/// If the union variant matches, return the owned "
959 "{{U_ELEMENT_TABLE_TYPE}}, setting the union to NONE.";
960 code_ +=
961 "pub fn take_{{U_ELEMENT_NAME}}(&mut self) -> "
962 "Option<Box<{{U_ELEMENT_TABLE_TYPE}}>> {";
963 code_ += " if let Self::{{NATIVE_VARIANT}}(_) = self {";
964 code_ += " let v = std::mem::replace(self, Self::NONE);";
965 code_ += " if let Self::{{NATIVE_VARIANT}}(w) = v {";
966 code_ += " Some(w)";
967 code_ += " } else {";
968 code_ += " unreachable!()";
969 code_ += " }";
970 code_ += " } else {";
971 code_ += " None";
972 code_ += " }";
973 code_ += "}";
974 // Immutable reference accessor.
975 code_ +=
976 "/// If the union variant matches, return a reference to the "
977 "{{U_ELEMENT_TABLE_TYPE}}.";
978 code_ +=
979 "pub fn as_{{U_ELEMENT_NAME}}(&self) -> "
980 "Option<&{{U_ELEMENT_TABLE_TYPE}}> {";
981 code_ +=
982 " if let Self::{{NATIVE_VARIANT}}(v) = self "
983 "{ Some(v.as_ref()) } else { None }";
984 code_ += "}";
985 // Mutable reference accessor.
986 code_ +=
987 "/// If the union variant matches, return a mutable reference"
988 " to the {{U_ELEMENT_TABLE_TYPE}}.";
989 code_ +=
990 "pub fn as_{{U_ELEMENT_NAME}}_mut(&mut self) -> "
991 "Option<&mut {{U_ELEMENT_TABLE_TYPE}}> {";
992 code_ +=
993 " if let Self::{{NATIVE_VARIANT}}(v) = self "
994 "{ Some(v.as_mut()) } else { None }";
995 code_ += "}";
996 });
997 code_ += "}"; // End union methods impl.
998 }
999
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001000 std::string GetFieldOffsetName(const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001001 // FIXME: VT_FIELD_NAME is not screaming snake case by legacy mistake.
1002 // but changing this is probably a breaking change.
1003 return "VT_" +
1004 ConvertCase(namer_.EscapeKeyword(field.name), Case::kAllUpper);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001005 }
1006
James Kuszmaul8e62b022022-03-22 09:33:25 -07001007 enum DefaultContext { kBuilder, kAccessor, kObject };
1008 std::string GetDefaultValue(const FieldDef &field,
1009 const DefaultContext context) {
1010 if (context == kBuilder) {
1011 // Builders and Args structs model nonscalars "optional" even if they're
1012 // required or have defaults according to the schema. I guess its because
1013 // WIPOffset is not nullable.
1014 if (!IsScalar(field.value.type.base_type) || field.IsOptional()) {
1015 return "None";
1016 }
1017 } else {
1018 // This for defaults in objects.
1019 // Unions have a NONE variant instead of using Rust's None.
1020 if (field.IsOptional() && !IsUnion(field.value.type)) { return "None"; }
1021 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001022 switch (GetFullType(field.value.type)) {
Austin Schuh272c6132020-11-14 16:37:52 -08001023 case ftInteger:
1024 case ftFloat: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001025 return field.value.constant;
Austin Schuh272c6132020-11-14 16:37:52 -08001026 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001027 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001028 return field.value.constant == "0" ? "false" : "true";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001029 }
1030 case ftUnionKey:
1031 case ftEnumKey: {
1032 auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001033 if (!ev) return "Default::default()"; // Bitflags enum.
1034 return WrapInNameSpace(
1035 field.value.type.enum_def->defined_namespace,
1036 namer_.EnumVariant(field.value.type.enum_def->name, ev->name));
1037 }
1038 case ftUnionValue: {
1039 return ObjectFieldType(field, true) + "::NONE";
1040 }
1041 case ftString: {
1042 // Required fields do not have defaults defined by the schema, but we
1043 // need one for Rust's Default trait so we use empty string. The usual
1044 // value of field.value.constant is `0`, which is non-sensical except
1045 // maybe to c++ (nullptr == 0).
1046 // TODO: Escape strings?
1047 const std::string defval =
1048 field.IsRequired() ? "\"\"" : "\"" + field.value.constant + "\"";
1049 if (context == kObject) return defval + ".to_string()";
1050 if (context == kAccessor) return "&" + defval;
1051 FLATBUFFERS_ASSERT(false);
1052 return "INVALID_CODE_GENERATION";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001053 }
1054
James Kuszmaul8e62b022022-03-22 09:33:25 -07001055 case ftArrayOfStruct:
1056 case ftArrayOfEnum:
1057 case ftArrayOfBuiltin:
1058 case ftVectorOfBool:
1059 case ftVectorOfFloat:
1060 case ftVectorOfInteger:
1061 case ftVectorOfString:
1062 case ftVectorOfStruct:
1063 case ftVectorOfTable:
1064 case ftVectorOfEnumKey:
1065 case ftVectorOfUnionValue:
1066 case ftStruct:
1067 case ftTable: {
1068 // We only support empty vectors which matches the defaults for
1069 // &[T] and Vec<T> anyway.
1070 //
1071 // For required structs and tables fields, we defer to their object API
1072 // defaults. This works so long as there's nothing recursive happening,
1073 // but `table Infinity { i: Infinity (required); }` does compile.
1074 return "Default::default()";
Austin Schuh272c6132020-11-14 16:37:52 -08001075 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001076 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001077 FLATBUFFERS_ASSERT(false);
1078 return "INVALID_CODE_GENERATION";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001079 }
1080
1081 // Create the return type for fields in the *BuilderArgs structs that are
1082 // used to create Tables.
1083 //
1084 // Note: we could make all inputs to the BuilderArgs be an Option, as well
1085 // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
1086 // know if the value is default or not, because there are three ways to
1087 // return a default value:
1088 // 1) return a stored value that happens to be the default,
1089 // 2) return a hardcoded value because the relevant vtable field is not in
1090 // the vtable, or
1091 // 3) return a hardcoded value because the vtable field value is set to zero.
1092 std::string TableBuilderArgsDefnType(const FieldDef &field,
1093 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -08001094 const Type &type = field.value.type;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001095 auto WrapOption = [&](std::string s) {
1096 return IsOptionalToBuilder(field) ? "Option<" + s + ">" : s;
1097 };
1098 auto WrapVector = [&](std::string ty) {
1099 return WrapOption("flatbuffers::WIPOffset<flatbuffers::Vector<" +
1100 lifetime + ", " + ty + ">>");
1101 };
1102 auto WrapUOffsetsVector = [&](std::string ty) {
1103 return WrapVector("flatbuffers::ForwardsUOffset<" + ty + ">");
1104 };
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001105
1106 switch (GetFullType(type)) {
1107 case ftInteger:
1108 case ftFloat:
1109 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001110 return WrapOption(GetTypeBasic(type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001111 }
1112 case ftStruct: {
1113 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001114 return WrapOption("&" + lifetime + " " + typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001115 }
1116 case ftTable: {
1117 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001118 return WrapOption("flatbuffers::WIPOffset<" + typname + "<" + lifetime +
1119 ">>");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001120 }
1121 case ftString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001122 return WrapOption("flatbuffers::WIPOffset<&" + lifetime + " str>");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001123 }
1124 case ftEnumKey:
1125 case ftUnionKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001126 return WrapOption(WrapInNameSpace(*type.enum_def));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001127 }
1128 case ftUnionValue: {
1129 return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
1130 }
1131
1132 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001133 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001134 case ftVectorOfFloat: {
1135 const auto typname = GetTypeBasic(type.VectorType());
James Kuszmaul8e62b022022-03-22 09:33:25 -07001136 return WrapVector(typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001137 }
1138 case ftVectorOfEnumKey: {
1139 const auto typname = WrapInNameSpace(*type.enum_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001140 return WrapVector(typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001141 }
1142 case ftVectorOfStruct: {
1143 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001144 return WrapVector(typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001145 }
1146 case ftVectorOfTable: {
1147 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001148 return WrapUOffsetsVector(typname + "<" + lifetime + ">");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001149 }
1150 case ftVectorOfString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001151 return WrapUOffsetsVector("&" + lifetime + " str");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001152 }
1153 case ftVectorOfUnionValue: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001154 return WrapUOffsetsVector("flatbuffers::Table<" + lifetime + ">");
1155 }
1156 case ftArrayOfEnum:
1157 case ftArrayOfStruct:
1158 case ftArrayOfBuiltin: {
1159 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1160 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001161 }
1162 }
Austin Schuh272c6132020-11-14 16:37:52 -08001163 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001164 }
1165
James Kuszmaul8e62b022022-03-22 09:33:25 -07001166 std::string ObjectFieldType(const FieldDef &field, bool in_a_table) {
1167 const Type &type = field.value.type;
1168 std::string ty;
1169 switch (GetFullType(type)) {
1170 case ftInteger:
1171 case ftBool:
1172 case ftFloat: {
1173 ty = GetTypeBasic(type);
1174 break;
1175 }
1176 case ftString: {
1177 ty = "String";
1178 break;
1179 }
1180 case ftStruct: {
1181 ty = NamespacedNativeName(*type.struct_def);
1182 break;
1183 }
1184 case ftTable: {
1185 // Since Tables can contain themselves, Box is required to avoid
1186 // infinite types.
1187 ty = "Box<" + NamespacedNativeName(*type.struct_def) + ">";
1188 break;
1189 }
1190 case ftUnionKey: {
1191 // There is no native "UnionKey", natively, unions are rust enums with
1192 // newtype-struct-variants.
1193 return "INVALID_CODE_GENERATION";
1194 }
1195 case ftUnionValue: {
1196 ty = NamespacedNativeName(*type.enum_def);
1197 break;
1198 }
1199 case ftEnumKey: {
1200 ty = WrapInNameSpace(*type.enum_def);
1201 break;
1202 }
1203 // Vectors are in tables and are optional
1204 case ftVectorOfEnumKey: {
1205 ty = "Vec<" + WrapInNameSpace(*type.VectorType().enum_def) + ">";
1206 break;
1207 }
1208 case ftVectorOfInteger:
1209 case ftVectorOfBool:
1210 case ftVectorOfFloat: {
1211 ty = "Vec<" + GetTypeBasic(type.VectorType()) + ">";
1212 break;
1213 }
1214 case ftVectorOfString: {
1215 ty = "Vec<String>";
1216 break;
1217 }
1218 case ftVectorOfTable:
1219 case ftVectorOfStruct: {
1220 ty = NamespacedNativeName(*type.VectorType().struct_def);
1221 ty = "Vec<" + ty + ">";
1222 break;
1223 }
1224 case ftVectorOfUnionValue: {
1225 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1226 return "INVALID_CODE_GENERATION"; // OH NO!
1227 }
1228 case ftArrayOfEnum: {
1229 ty = "[" + WrapInNameSpace(*type.VectorType().enum_def) + "; " +
1230 NumToString(type.fixed_length) + "]";
1231 break;
1232 }
1233 case ftArrayOfStruct: {
1234 ty = "[" + NamespacedNativeName(*type.VectorType().struct_def) + "; " +
1235 NumToString(type.fixed_length) + "]";
1236 break;
1237 }
1238 case ftArrayOfBuiltin: {
1239 ty = "[" + GetTypeBasic(type.VectorType()) + "; " +
1240 NumToString(type.fixed_length) + "]";
1241 break;
1242 }
1243 }
1244 if (in_a_table && !IsUnion(type) && field.IsOptional()) {
1245 return "Option<" + ty + ">";
1246 } else {
1247 return ty;
1248 }
1249 }
1250
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001251 std::string TableBuilderArgsAddFuncType(const FieldDef &field,
1252 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -08001253 const Type &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001254
1255 switch (GetFullType(field.value.type)) {
1256 case ftVectorOfStruct: {
1257 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001258 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1259 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001260 }
1261 case ftVectorOfTable: {
1262 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001263 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1264 ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
1265 ">>>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001266 }
1267 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001268 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001269 case ftVectorOfFloat: {
1270 const auto typname = GetTypeBasic(type.VectorType());
Austin Schuh272c6132020-11-14 16:37:52 -08001271 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1272 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001273 }
1274 case ftVectorOfString: {
Austin Schuh272c6132020-11-14 16:37:52 -08001275 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001276 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
1277 }
1278 case ftVectorOfEnumKey: {
1279 const auto typname = WrapInNameSpace(*type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001280 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1281 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001282 }
1283 case ftVectorOfUnionValue: {
Austin Schuh272c6132020-11-14 16:37:52 -08001284 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1285 ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + lifetime +
1286 ">>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001287 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001288 case ftEnumKey:
1289 case ftUnionKey: {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001290 const auto typname = WrapInNameSpace(*type.enum_def);
1291 return typname;
1292 }
1293 case ftStruct: {
1294 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001295 return "&" + typname + "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001296 }
1297 case ftTable: {
1298 const auto typname = WrapInNameSpace(*type.struct_def);
1299 return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
1300 }
1301 case ftInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001302 case ftBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001303 case ftFloat: {
Austin Schuh272c6132020-11-14 16:37:52 -08001304 return GetTypeBasic(type);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001305 }
1306 case ftString: {
1307 return "flatbuffers::WIPOffset<&" + lifetime + " str>";
1308 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001309 case ftUnionValue: {
1310 return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
1311 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001312 case ftArrayOfBuiltin: {
1313 const auto typname = GetTypeBasic(type.VectorType());
1314 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1315 NumToString(type.fixed_length) + ">";
1316 }
1317 case ftArrayOfEnum: {
1318 const auto typname = WrapInNameSpace(*type.enum_def);
1319 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1320 NumToString(type.fixed_length) + ">";
1321 }
1322 case ftArrayOfStruct: {
1323 const auto typname = WrapInNameSpace(*type.struct_def);
1324 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1325 NumToString(type.fixed_length) + ">";
1326 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001327 }
1328
Austin Schuh272c6132020-11-14 16:37:52 -08001329 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001330 }
1331
1332 std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
Austin Schuh272c6132020-11-14 16:37:52 -08001333 const Type &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001334
1335 switch (GetFullType(field.value.type)) {
1336 case ftInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001337 case ftBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001338 case ftFloat: {
1339 const auto typname = GetTypeBasic(field.value.type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001340 return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
1341 : "self.fbb_.push_slot::<") +
Austin Schuh272c6132020-11-14 16:37:52 -08001342 typname + ">";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001343 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001344 case ftEnumKey:
1345 case ftUnionKey: {
1346 const auto underlying_typname = GetTypeBasic(type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001347 return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
1348 : "self.fbb_.push_slot::<") +
1349 underlying_typname + ">";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001350 }
1351
1352 case ftStruct: {
1353 const std::string typname = WrapInNameSpace(*type.struct_def);
1354 return "self.fbb_.push_slot_always::<&" + typname + ">";
1355 }
1356 case ftTable: {
1357 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001358 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" +
1359 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001360 }
1361
1362 case ftUnionValue:
1363 case ftString:
1364 case ftVectorOfInteger:
1365 case ftVectorOfFloat:
1366 case ftVectorOfBool:
1367 case ftVectorOfEnumKey:
1368 case ftVectorOfStruct:
1369 case ftVectorOfTable:
1370 case ftVectorOfString:
1371 case ftVectorOfUnionValue: {
1372 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
1373 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001374 case ftArrayOfEnum:
1375 case ftArrayOfStruct:
1376 case ftArrayOfBuiltin: {
1377 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1378 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1379 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001380 }
Austin Schuh272c6132020-11-14 16:37:52 -08001381 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001382 }
1383
1384 std::string GenTableAccessorFuncReturnType(const FieldDef &field,
1385 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -08001386 const Type &type = field.value.type;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001387 const auto WrapOption = [&](std::string s) {
1388 return field.IsOptional() ? "Option<" + s + ">" : s;
1389 };
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001390
1391 switch (GetFullType(field.value.type)) {
1392 case ftInteger:
1393 case ftFloat:
1394 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001395 return WrapOption(GetTypeBasic(type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001396 }
1397 case ftStruct: {
1398 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001399 return WrapOption("&" + lifetime + " " + typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001400 }
1401 case ftTable: {
1402 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001403 return WrapOption(typname + "<" + lifetime + ">");
Austin Schuh272c6132020-11-14 16:37:52 -08001404 }
1405 case ftEnumKey:
1406 case ftUnionKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001407 return WrapOption(WrapInNameSpace(*type.enum_def));
Austin Schuh272c6132020-11-14 16:37:52 -08001408 }
1409
1410 case ftUnionValue: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001411 return WrapOption("flatbuffers::Table<" + lifetime + ">");
Austin Schuh272c6132020-11-14 16:37:52 -08001412 }
1413 case ftString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001414 return WrapOption("&" + lifetime + " str");
Austin Schuh272c6132020-11-14 16:37:52 -08001415 }
1416 case ftVectorOfInteger:
1417 case ftVectorOfBool:
1418 case ftVectorOfFloat: {
1419 const auto typname = GetTypeBasic(type.VectorType());
James Kuszmaul8e62b022022-03-22 09:33:25 -07001420 const auto vector_type =
1421 IsOneByte(type.VectorType().base_type)
1422 ? "&" + lifetime + " [" + typname + "]"
1423 : "flatbuffers::Vector<" + lifetime + ", " + typname + ">";
1424 return WrapOption(vector_type);
Austin Schuh272c6132020-11-14 16:37:52 -08001425 }
1426 case ftVectorOfEnumKey: {
1427 const auto typname = WrapInNameSpace(*type.enum_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001428 return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname +
1429 ">");
Austin Schuh272c6132020-11-14 16:37:52 -08001430 }
1431 case ftVectorOfStruct: {
1432 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001433 return WrapOption("&" + lifetime + " [" + typname + "]");
Austin Schuh272c6132020-11-14 16:37:52 -08001434 }
1435 case ftVectorOfTable: {
1436 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001437 return WrapOption("flatbuffers::Vector<" + lifetime +
1438 ", flatbuffers::ForwardsUOffset<" + typname + "<" +
1439 lifetime + ">>>");
Austin Schuh272c6132020-11-14 16:37:52 -08001440 }
1441 case ftVectorOfString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001442 return WrapOption("flatbuffers::Vector<" + lifetime +
1443 ", flatbuffers::ForwardsUOffset<&" + lifetime +
1444 " str>>");
Austin Schuh272c6132020-11-14 16:37:52 -08001445 }
1446 case ftVectorOfUnionValue: {
1447 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1448 // TODO(rw): when we do support these, we should consider using the
1449 // Into trait to convert tables to typesafe union values.
1450 return "INVALID_CODE_GENERATION"; // for return analysis
1451 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001452 case ftArrayOfEnum:
1453 case ftArrayOfStruct:
1454 case ftArrayOfBuiltin: {
1455 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1456 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1457 }
Austin Schuh272c6132020-11-14 16:37:52 -08001458 }
1459 return "INVALID_CODE_GENERATION"; // for return analysis
1460 }
1461
James Kuszmaul8e62b022022-03-22 09:33:25 -07001462 std::string FollowType(const Type &type, const std::string &lifetime) {
1463 // IsVector... This can be made iterative?
Austin Schuh272c6132020-11-14 16:37:52 -08001464
James Kuszmaul8e62b022022-03-22 09:33:25 -07001465 const auto WrapForwardsUOffset = [](std::string ty) -> std::string {
1466 return "flatbuffers::ForwardsUOffset<" + ty + ">";
1467 };
1468 const auto WrapVector = [&](std::string ty) -> std::string {
1469 return "flatbuffers::Vector<" + lifetime + ", " + ty + ">";
1470 };
1471 const auto WrapArray = [&](std::string ty, uint16_t length) -> std::string {
1472 return "flatbuffers::Array<" + lifetime + ", " + ty + ", " +
1473 NumToString(length) + ">";
1474 };
1475 switch (GetFullType(type)) {
Austin Schuh272c6132020-11-14 16:37:52 -08001476 case ftInteger:
1477 case ftFloat:
1478 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001479 return GetTypeBasic(type);
Austin Schuh272c6132020-11-14 16:37:52 -08001480 }
1481 case ftStruct: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001482 return WrapInNameSpace(*type.struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001483 }
1484 case ftUnionKey:
1485 case ftEnumKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001486 return WrapInNameSpace(*type.enum_def);
1487 }
1488 case ftTable: {
1489 const auto typname = WrapInNameSpace(*type.struct_def);
1490 return WrapForwardsUOffset(typname);
1491 }
1492 case ftUnionValue: {
1493 return WrapForwardsUOffset("flatbuffers::Table<" + lifetime + ">");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001494 }
1495 case ftString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001496 return WrapForwardsUOffset("&str");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001497 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001498 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001499 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001500 case ftVectorOfFloat: {
1501 const auto typname = GetTypeBasic(type.VectorType());
James Kuszmaul8e62b022022-03-22 09:33:25 -07001502 return WrapForwardsUOffset(WrapVector(typname));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001503 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001504 case ftVectorOfEnumKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001505 const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
1506 return WrapForwardsUOffset(WrapVector(typname));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001507 }
1508 case ftVectorOfStruct: {
1509 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001510 return WrapForwardsUOffset(WrapVector(typname));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001511 }
1512 case ftVectorOfTable: {
1513 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001514 return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(typname)));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001515 }
1516 case ftVectorOfString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001517 return WrapForwardsUOffset(
1518 WrapVector(WrapForwardsUOffset("&" + lifetime + " str")));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001519 }
1520 case ftVectorOfUnionValue: {
1521 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
Austin Schuh272c6132020-11-14 16:37:52 -08001522 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001523 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001524 case ftArrayOfEnum: {
1525 const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
1526 return WrapArray(typname, type.fixed_length);
1527 }
1528 case ftArrayOfStruct: {
1529 const auto typname = WrapInNameSpace(*type.struct_def);
1530 return WrapArray(typname, type.fixed_length);
1531 }
1532 case ftArrayOfBuiltin: {
1533 const auto typname = GetTypeBasic(type.VectorType());
1534 return WrapArray(typname, type.fixed_length);
1535 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001536 }
Austin Schuh272c6132020-11-14 16:37:52 -08001537 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001538 }
1539
James Kuszmaul8e62b022022-03-22 09:33:25 -07001540 std::string GenTableAccessorFuncBody(const FieldDef &field,
1541 const std::string &lifetime) {
1542 const std::string vt_offset = GetFieldOffsetName(field);
1543 const std::string typname = FollowType(field.value.type, lifetime);
1544 // Default-y fields (scalars so far) are neither optional nor required.
1545 const std::string default_value =
1546 !(field.IsOptional() || field.IsRequired())
1547 ? "Some(" + GetDefaultValue(field, kAccessor) + ")"
1548 : "None";
1549 const std::string unwrap = field.IsOptional() ? "" : ".unwrap()";
1550
1551 const auto t = GetFullType(field.value.type);
1552
1553 // TODO(caspern): Shouldn't 1byte VectorOfEnumKey be slice too?
1554 const std::string safe_slice =
1555 (t == ftVectorOfStruct ||
1556 ((t == ftVectorOfBool || t == ftVectorOfFloat ||
1557 t == ftVectorOfInteger) &&
1558 IsOneByte(field.value.type.VectorType().base_type)))
1559 ? ".map(|v| v.safe_slice())"
1560 : "";
1561
1562 return "self._tab.get::<" + typname + ">({{STRUCT_TY}}::" + vt_offset +
1563 ", " + default_value + ")" + safe_slice + unwrap;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001564 }
1565
Austin Schuh272c6132020-11-14 16:37:52 -08001566 // Generates a fully-qualified name getter for use with --gen-name-strings
1567 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1568 const std::string &name) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001569 const std::string fully_qualified_name =
1570 struct_def.defined_namespace->GetFullyQualifiedName(name);
1571 code_ += " pub const fn get_fully_qualified_name() -> &'static str {";
1572 code_ += " \"" + fully_qualified_name + "\"";
1573 code_ += " }";
Austin Schuh272c6132020-11-14 16:37:52 -08001574 code_ += "";
1575 }
1576
1577 void ForAllUnionVariantsBesidesNone(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001578 const EnumDef &def, std::function<void(const EnumVal &ev)> cb) {
Austin Schuh272c6132020-11-14 16:37:52 -08001579 FLATBUFFERS_ASSERT(def.is_union);
1580
1581 for (auto it = def.Vals().begin(); it != def.Vals().end(); ++it) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001582 const EnumVal &ev = **it;
Austin Schuh272c6132020-11-14 16:37:52 -08001583 // TODO(cneo): Can variants be deprecated, should we skip them?
1584 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001585 code_.SetValue("U_ELEMENT_ENUM_TYPE",
1586 WrapInNameSpace(def.defined_namespace,
1587 namer_.EnumVariant(def.name, ev.name)));
Austin Schuh272c6132020-11-14 16:37:52 -08001588 code_.SetValue(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001589 "U_ELEMENT_TABLE_TYPE",
Austin Schuh272c6132020-11-14 16:37:52 -08001590 WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
1591 ev.union_type.struct_def->name));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001592 code_.SetValue("U_ELEMENT_NAME", namer_.Function(ev.name));
Austin Schuh272c6132020-11-14 16:37:52 -08001593 cb(ev);
1594 }
1595 }
1596
James Kuszmaul8e62b022022-03-22 09:33:25 -07001597 void ForAllTableFields(const StructDef &struct_def,
1598 std::function<void(const FieldDef &)> cb,
1599 bool reversed = false) {
Austin Schuh272c6132020-11-14 16:37:52 -08001600 // TODO(cneo): Remove `reversed` overload. It's only here to minimize the
1601 // diff when refactoring to the `ForAllX` helper functions.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001602 auto go = [&](const FieldDef &field) {
Austin Schuh272c6132020-11-14 16:37:52 -08001603 if (field.deprecated) return;
1604 code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1605 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001606 code_.SetValue("FIELD", namer_.Field(field.name));
1607 code_.SetValue("BLDR_DEF_VAL", GetDefaultValue(field, kBuilder));
1608 code_.SetValue("DISCRIMINANT", namer_.Method(field.name) + "_type");
1609 code_.IncrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -08001610 cb(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001611 code_.DecrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -08001612 };
1613 const auto &fields = struct_def.fields.vec;
1614 if (reversed) {
1615 for (auto it = fields.rbegin(); it != fields.rend(); ++it) go(**it);
1616 } else {
1617 for (auto it = fields.begin(); it != fields.end(); ++it) go(**it);
1618 }
1619 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001620 // Generate an accessor struct, builder struct, and create function for a
1621 // table.
1622 void GenTable(const StructDef &struct_def) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001623 code_.SetValue("STRUCT_TY", namer_.Type(struct_def.name));
1624 code_.SetValue("STRUCT_FN", namer_.Function(struct_def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001625
1626 // Generate an offset type, the base type, the Follow impl, and the
1627 // init_from_table impl.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001628 code_ += "pub enum {{STRUCT_TY}}Offset {}";
Austin Schuh272c6132020-11-14 16:37:52 -08001629 code_ += "#[derive(Copy, Clone, PartialEq)]";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001630 code_ += "";
1631
1632 GenComment(struct_def.doc_comment);
1633
James Kuszmaul8e62b022022-03-22 09:33:25 -07001634 code_ += "pub struct {{STRUCT_TY}}<'a> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001635 code_ += " pub _tab: flatbuffers::Table<'a>,";
1636 code_ += "}";
1637 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001638 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_TY}}<'a> {";
1639 code_ += " type Inner = {{STRUCT_TY}}<'a>;";
1640 code_ += " #[inline]";
1641 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1642 code_ += " Self { _tab: flatbuffers::Table { buf, loc } }";
1643 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001644 code_ += "}";
1645 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001646 code_ += "impl<'a> {{STRUCT_TY}}<'a> {";
1647
1648 // Generate field id constants.
1649 ForAllTableFields(struct_def, [&](const FieldDef &unused) {
1650 (void)unused;
1651 code_ +=
1652 "pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1653 "{{OFFSET_VALUE}};";
1654 });
1655 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08001656
1657 if (parser_.opts.generate_name_strings) {
1658 GenFullyQualifiedNameGetter(struct_def, struct_def.name);
1659 }
1660
James Kuszmaul8e62b022022-03-22 09:33:25 -07001661 code_ += " #[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08001662 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07001663 " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
Austin Schuh272c6132020-11-14 16:37:52 -08001664 "Self {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001665 code_ += " {{STRUCT_TY}} { _tab: table }";
1666 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001667
1668 // Generate a convenient create* function that uses the above builder
1669 // to create a table in one function call.
Austin Schuh272c6132020-11-14 16:37:52 -08001670 code_.SetValue("MAYBE_US", struct_def.fields.vec.size() == 0 ? "_" : "");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001671 code_.SetValue("MAYBE_LT",
Austin Schuh272c6132020-11-14 16:37:52 -08001672 TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001673 code_ += " #[allow(unused_mut)]";
1674 code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
1675 code_ += " _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1676 code_ += " {{MAYBE_US}}args: &'args {{STRUCT_TY}}Args{{MAYBE_LT}}";
1677 code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_TY}}<'bldr>> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001678
James Kuszmaul8e62b022022-03-22 09:33:25 -07001679 code_ += " let mut builder = {{STRUCT_TY}}Builder::new(_fbb);";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001680 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1681 size; size /= 2) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001682 ForAllTableFields(
1683 struct_def,
1684 [&](const FieldDef &field) {
1685 if (struct_def.sortbysize &&
1686 size != SizeOf(field.value.type.base_type))
1687 return;
1688 if (IsOptionalToBuilder(field)) {
1689 code_ +=
1690 " if let Some(x) = args.{{FIELD}} "
1691 "{ builder.add_{{FIELD}}(x); }";
1692 } else {
1693 code_ += " builder.add_{{FIELD}}(args.{{FIELD}});";
1694 }
1695 },
1696 /*reverse=*/true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001697 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001698 code_ += " builder.finish()";
1699 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001700 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001701 // Generate Object API Packer function.
1702 if (parser_.opts.generate_object_based_api) {
1703 // TODO(cneo): Replace more for loops with ForAllX stuff.
1704 // TODO(cneo): Manage indentation with IncrementIdentLevel?
1705 code_.SetValue("STRUCT_OTY", namer_.ObjectType(struct_def.name));
1706 code_ += " pub fn unpack(&self) -> {{STRUCT_OTY}} {";
1707 ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
1708 const Type &type = field.value.type;
1709 switch (GetFullType(type)) {
1710 case ftInteger:
1711 case ftBool:
1712 case ftFloat:
1713 case ftEnumKey: {
1714 code_ += " let {{FIELD}} = self.{{FIELD}}();";
1715 return;
1716 }
1717 case ftUnionKey: return;
1718 case ftUnionValue: {
1719 const auto &enum_def = *type.enum_def;
1720 code_.SetValue("ENUM_TY", WrapInNameSpace(enum_def));
1721 code_.SetValue("NATIVE_ENUM_NAME", NamespacedNativeName(enum_def));
1722 code_ += " let {{FIELD}} = match self.{{FIELD}}_type() {";
1723 code_ += " {{ENUM_TY}}::NONE => {{NATIVE_ENUM_NAME}}::NONE,";
1724 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
1725 code_ +=
1726 " {{ENUM_TY}}::{{VARIANT_NAME}} => "
1727 "{{NATIVE_ENUM_NAME}}::{{NATIVE_VARIANT}}(Box::new(";
1728 code_ += " self.{{FIELD}}_as_{{U_ELEMENT_NAME}}()";
1729 code_ +=
1730 " .expect(\"Invalid union table, "
1731 "expected `{{ENUM_TY}}::{{VARIANT_NAME}}`.\")";
1732 code_ += " .unpack()";
1733 code_ += " )),";
1734 });
1735 // Maybe we shouldn't throw away unknown discriminants?
1736 code_ += " _ => {{NATIVE_ENUM_NAME}}::NONE,";
1737 code_ += " };";
1738 return;
1739 }
1740 // The rest of the types need special handling based on if the field
1741 // is optional or not.
1742 case ftString: {
1743 code_.SetValue("EXPR", "x.to_string()");
1744 break;
1745 }
1746 case ftStruct: {
1747 code_.SetValue("EXPR", "x.unpack()");
1748 break;
1749 }
1750 case ftTable: {
1751 code_.SetValue("EXPR", "Box::new(x.unpack())");
1752 break;
1753 }
1754 case ftVectorOfInteger:
1755 case ftVectorOfBool: {
1756 if (IsOneByte(type.VectorType().base_type)) {
1757 // 1 byte stuff is viewed w/ slice instead of flatbuffer::Vector
1758 // and thus needs to be cloned out of the slice.
1759 code_.SetValue("EXPR", "x.to_vec()");
1760 break;
1761 }
1762 code_.SetValue("EXPR", "x.into_iter().collect()");
1763 break;
1764 }
1765 case ftVectorOfFloat:
1766 case ftVectorOfEnumKey: {
1767 code_.SetValue("EXPR", "x.into_iter().collect()");
1768 break;
1769 }
1770 case ftVectorOfString: {
1771 code_.SetValue("EXPR", "x.iter().map(|s| s.to_string()).collect()");
1772 break;
1773 }
1774 case ftVectorOfStruct:
1775 case ftVectorOfTable: {
1776 code_.SetValue("EXPR", "x.iter().map(|t| t.unpack()).collect()");
1777 break;
1778 }
1779 case ftVectorOfUnionValue: {
1780 FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
1781 return;
1782 }
1783 case ftArrayOfEnum:
1784 case ftArrayOfStruct:
1785 case ftArrayOfBuiltin: {
1786 FLATBUFFERS_ASSERT(false &&
1787 "arrays are not supported within tables");
1788 return;
1789 }
1790 }
1791 if (field.IsOptional()) {
1792 code_ += " let {{FIELD}} = self.{{FIELD}}().map(|x| {";
1793 code_ += " {{EXPR}}";
1794 code_ += " });";
1795 } else {
1796 code_ += " let {{FIELD}} = {";
1797 code_ += " let x = self.{{FIELD}}();";
1798 code_ += " {{EXPR}}";
1799 code_ += " };";
1800 }
1801 });
1802 code_ += " {{STRUCT_OTY}} {";
1803 ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
1804 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
1805 code_ += " {{FIELD}},";
1806 });
1807 code_ += " }";
1808 code_ += " }";
1809 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001810
Austin Schuh272c6132020-11-14 16:37:52 -08001811 if (struct_def.fields.vec.size() > 0) code_ += "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001812
1813 // Generate the accessors. Each has one of two forms:
1814 //
1815 // If a value can be None:
1816 // pub fn name(&'a self) -> Option<user_facing_type> {
1817 // self._tab.get::<internal_type>(offset, defaultval)
1818 // }
1819 //
1820 // If a value is always Some:
1821 // pub fn name(&'a self) -> user_facing_type {
1822 // self._tab.get::<internal_type>(offset, defaultval).unwrap()
1823 // }
Austin Schuh272c6132020-11-14 16:37:52 -08001824 ForAllTableFields(struct_def, [&](const FieldDef &field) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001825 code_.SetValue("RETURN_TYPE",
1826 GenTableAccessorFuncReturnType(field, "'a"));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001827
James Kuszmaul8e62b022022-03-22 09:33:25 -07001828 this->GenComment(field.doc_comment);
1829 code_ += "#[inline]";
1830 code_ += "pub fn {{FIELD}}(&self) -> {{RETURN_TYPE}} {";
1831 code_ += " " + GenTableAccessorFuncBody(field, "'a");
1832 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001833
1834 // Generate a comparison function for this field if it is a key.
Austin Schuh272c6132020-11-14 16:37:52 -08001835 if (field.key) { GenKeyFieldMethods(field); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001836
1837 // Generate a nested flatbuffer field, if applicable.
1838 auto nested = field.attributes.Lookup("nested_flatbuffer");
1839 if (nested) {
1840 std::string qualified_name = nested->constant;
1841 auto nested_root = parser_.LookupStruct(nested->constant);
1842 if (nested_root == nullptr) {
1843 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1844 nested->constant);
1845 nested_root = parser_.LookupStruct(qualified_name);
1846 }
1847 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001848
Austin Schuh272c6132020-11-14 16:37:52 -08001849 code_.SetValue("NESTED", WrapInNameSpace(*nested_root));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001850 code_ += "pub fn {{FIELD}}_nested_flatbuffer(&'a self) -> \\";
1851 if (field.IsRequired()) {
Austin Schuh272c6132020-11-14 16:37:52 -08001852 code_ += "{{NESTED}}<'a> {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001853 code_ += " let data = self.{{FIELD}}();";
1854 code_ += " use flatbuffers::Follow;";
1855 code_ +=
1856 " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1857 "::follow(data, 0)";
Austin Schuh272c6132020-11-14 16:37:52 -08001858 } else {
1859 code_ += "Option<{{NESTED}}<'a>> {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001860 code_ += " self.{{FIELD}}().map(|data| {";
1861 code_ += " use flatbuffers::Follow;";
1862 code_ +=
1863 " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1864 "::follow(data, 0)";
1865 code_ += " })";
Austin Schuh272c6132020-11-14 16:37:52 -08001866 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001867 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001868 }
Austin Schuh272c6132020-11-14 16:37:52 -08001869 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001870
1871 // Explicit specializations for union accessors
Austin Schuh272c6132020-11-14 16:37:52 -08001872 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1873 if (field.value.type.base_type != BASE_TYPE_UNION) return;
Austin Schuh272c6132020-11-14 16:37:52 -08001874 ForAllUnionVariantsBesidesNone(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001875 *field.value.type.enum_def, [&](const EnumVal &unused) {
1876 (void)unused;
1877 code_ += "#[inline]";
1878 code_ += "#[allow(non_snake_case)]";
1879 code_ +=
1880 "pub fn {{FIELD}}_as_{{U_ELEMENT_NAME}}(&self) -> "
1881 "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
1882 // If the user defined schemas name a field that clashes with a
1883 // language reserved word, flatc will try to escape the field name
1884 // by appending an underscore. This works well for most cases,
1885 // except one. When generating union accessors (and referring to
1886 // them internally within the code generated here), an extra
1887 // underscore will be appended to the name, causing build failures.
1888 //
1889 // This only happens when unions have members that overlap with
1890 // language reserved words.
1891 //
1892 // To avoid this problem the type field name is used unescaped here:
1893 code_ +=
1894 " if self.{{DISCRIMINANT}}() == {{U_ELEMENT_ENUM_TYPE}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08001895
James Kuszmaul8e62b022022-03-22 09:33:25 -07001896 // The following logic is not tested in the integration test,
1897 // as of April 10, 2020
1898 if (field.IsRequired()) {
1899 code_ += " let u = self.{{FIELD}}();";
1900 code_ += " Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
1901 } else {
1902 code_ +=
1903 " self.{{FIELD}}().map("
1904 "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)";
1905 }
1906 code_ += " } else {";
1907 code_ += " None";
1908 code_ += " }";
1909 code_ += "}";
1910 code_ += "";
1911 });
Austin Schuh272c6132020-11-14 16:37:52 -08001912 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001913 code_ += "}"; // End of table impl.
1914 code_ += "";
1915
James Kuszmaul8e62b022022-03-22 09:33:25 -07001916 // Generate Verifier;
1917 code_ += "impl flatbuffers::Verifiable for {{STRUCT_TY}}<'_> {";
1918 code_ += " #[inline]";
1919 code_ += " fn run_verifier(";
1920 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
1921 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
1922 code_ += " use self::flatbuffers::Verifiable;";
1923 code_ += " v.visit_table(pos)?\\";
1924 // Escape newline and insert it onthe next line so we can end the builder
1925 // with a nice semicolon.
1926 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1927 if (GetFullType(field.value.type) == ftUnionKey) return;
1928
1929 code_.SetValue("IS_REQ", field.IsRequired() ? "true" : "false");
1930 if (GetFullType(field.value.type) != ftUnionValue) {
1931 // All types besides unions.
1932 code_.SetValue("TY", FollowType(field.value.type, "'_"));
1933 code_ +=
1934 "\n .visit_field::<{{TY}}>(\"{{FIELD}}\", "
1935 "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\";
1936 return;
1937 }
1938 // Unions.
1939 const EnumDef &union_def = *field.value.type.enum_def;
1940 code_.SetValue("UNION_TYPE", WrapInNameSpace(union_def));
1941 code_.SetValue("UNION_TYPE_OFFSET_NAME",
1942 GetFieldOffsetName(field) + "_TYPE");
1943 code_ +=
1944 "\n .visit_union::<{{UNION_TYPE}}, _>("
1945 "\"{{FIELD}}_type\", Self::{{UNION_TYPE_OFFSET_NAME}}, "
1946 "\"{{FIELD}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, "
1947 "|key, v, pos| {";
1948 code_ += " match key {";
1949 ForAllUnionVariantsBesidesNone(union_def, [&](const EnumVal &unused) {
1950 (void)unused;
1951 code_ +=
1952 " {{U_ELEMENT_ENUM_TYPE}} => v.verify_union_variant::"
1953 "<flatbuffers::ForwardsUOffset<{{U_ELEMENT_TABLE_TYPE}}>>("
1954 "\"{{U_ELEMENT_ENUM_TYPE}}\", pos),";
1955 });
1956 code_ += " _ => Ok(()),";
1957 code_ += " }";
1958 code_ += " })?\\";
1959 });
1960 code_ += "\n .finish();";
1961 code_ += " Ok(())";
1962 code_ += " }";
1963 code_ += "}";
1964
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001965 // Generate an args struct:
1966 code_.SetValue("MAYBE_LT",
Austin Schuh272c6132020-11-14 16:37:52 -08001967 TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001968 code_ += "pub struct {{STRUCT_TY}}Args{{MAYBE_LT}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08001969 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1970 code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001971 code_ += " pub {{FIELD}}: {{PARAM_TYPE}},";
Austin Schuh272c6132020-11-14 16:37:52 -08001972 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001973 code_ += "}";
1974
1975 // Generate an impl of Default for the *Args type:
James Kuszmaul8e62b022022-03-22 09:33:25 -07001976 code_ += "impl<'a> Default for {{STRUCT_TY}}Args{{MAYBE_LT}} {";
1977 code_ += " #[inline]";
1978 code_ += " fn default() -> Self {";
1979 code_ += " {{STRUCT_TY}}Args {";
Austin Schuh272c6132020-11-14 16:37:52 -08001980 ForAllTableFields(struct_def, [&](const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001981 code_ += " {{FIELD}}: {{BLDR_DEF_VAL}},\\";
1982 code_ += field.IsRequired() ? " // required field" : "";
Austin Schuh272c6132020-11-14 16:37:52 -08001983 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001984 code_ += " }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001985 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001986 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001987 code_ += "";
1988
1989 // Implement serde::Serialize
1990 if (parser_.opts.rust_serialize) {
1991 const auto numFields = struct_def.fields.vec.size();
1992 code_.SetValue("NUM_FIELDS", NumToString(numFields));
1993 code_ += "impl Serialize for {{STRUCT_TY}}<'_> {";
1994 code_ +=
1995 " fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
1996 code_ += " where";
1997 code_ += " S: Serializer,";
1998 code_ += " {";
1999 if (numFields == 0) {
2000 code_ +=
2001 " let s = serializer.serialize_struct(\"{{STRUCT_TY}}\", 0)?;";
2002 } else {
2003 code_ +=
2004 " let mut s = serializer.serialize_struct(\"{{STRUCT_TY}}\", "
2005 "{{NUM_FIELDS}})?;";
2006 }
2007 ForAllTableFields(struct_def, [&](const FieldDef &field) {
2008 const Type &type = field.value.type;
2009 if (IsUnion(type)) {
2010 if (type.base_type == BASE_TYPE_UNION) {
2011 const auto &enum_def = *type.enum_def;
2012 code_.SetValue("ENUM_TY", WrapInNameSpace(enum_def));
2013 code_.SetValue("FIELD", namer_.Field(field.name));
2014
2015 code_ += " match self.{{FIELD}}_type() {";
2016 code_ += " {{ENUM_TY}}::NONE => (),";
2017 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
2018 code_.SetValue("FIELD", namer_.Field(field.name));
2019 code_ += " {{ENUM_TY}}::{{VARIANT_NAME}} => {";
2020 code_ +=
2021 " let f = "
2022 "self.{{FIELD}}_as_{{U_ELEMENT_NAME}}()";
2023 code_ +=
2024 " .expect(\"Invalid union table, expected "
2025 "`{{ENUM_TY}}::{{VARIANT_NAME}}`.\");";
2026 code_ += " s.serialize_field(\"{{FIELD}}\", &f)?;";
2027 code_ += " }";
2028 });
2029 code_ += " _ => unimplemented!(),";
2030 code_ += " }";
2031 } else {
2032 code_ +=
2033 " s.serialize_field(\"{{FIELD}}\", "
2034 "&self.{{FIELD}}())?;";
2035 }
2036 } else {
2037 if (field.IsOptional()) {
2038 code_ += " if let Some(f) = self.{{FIELD}}() {";
2039 code_ += " s.serialize_field(\"{{FIELD}}\", &f)?;";
2040 code_ += " } else {";
2041 code_ += " s.skip_field(\"{{FIELD}}\")?;";
2042 code_ += " }";
2043 } else {
2044 code_ +=
2045 " s.serialize_field(\"{{FIELD}}\", "
2046 "&self.{{FIELD}}())?;";
2047 }
2048 }
2049 });
2050 code_ += " s.end()";
2051 code_ += " }";
2052 code_ += "}";
2053 code_ += "";
2054 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002055
2056 // Generate a builder struct:
James Kuszmaul8e62b022022-03-22 09:33:25 -07002057 code_ += "pub struct {{STRUCT_TY}}Builder<'a: 'b, 'b> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002058 code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
Austin Schuh272c6132020-11-14 16:37:52 -08002059 code_ +=
2060 " start_: flatbuffers::WIPOffset<"
2061 "flatbuffers::TableUnfinishedWIPOffset>,";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002062 code_ += "}";
2063
2064 // Generate builder functions:
James Kuszmaul8e62b022022-03-22 09:33:25 -07002065 code_ += "impl<'a: 'b, 'b> {{STRUCT_TY}}Builder<'a, 'b> {";
Austin Schuh272c6132020-11-14 16:37:52 -08002066 ForAllTableFields(struct_def, [&](const FieldDef &field) {
2067 const bool is_scalar = IsScalar(field.value.type.base_type);
2068 std::string offset = GetFieldOffsetName(field);
2069 // Generate functions to add data, which take one of two forms.
2070 //
2071 // If a value has a default:
2072 // fn add_x(x_: type) {
2073 // fbb_.push_slot::<type>(offset, x_, Some(default));
2074 // }
2075 //
2076 // If a value does not have a default:
2077 // fn add_x(x_: type) {
2078 // fbb_.push_slot_always::<type>(offset, x_);
2079 // }
James Kuszmaul8e62b022022-03-22 09:33:25 -07002080 code_.SetValue("FIELD_OFFSET",
2081 namer_.Type(struct_def.name) + "::" + offset);
Austin Schuh272c6132020-11-14 16:37:52 -08002082 code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
2083 code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002084 code_ += "#[inline]";
2085 code_ +=
2086 "pub fn add_{{FIELD}}(&mut self, {{FIELD}}: "
2087 "{{FIELD_TYPE}}) {";
2088 if (is_scalar && !field.IsOptional()) {
Austin Schuh272c6132020-11-14 16:37:52 -08002089 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002090 " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD}}, "
2091 "{{BLDR_DEF_VAL}});";
Austin Schuh272c6132020-11-14 16:37:52 -08002092 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002093 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD}});";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002094 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07002095 code_ += "}";
Austin Schuh272c6132020-11-14 16:37:52 -08002096 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002097
2098 // Struct initializer (all fields required);
2099 code_ += " #[inline]";
2100 code_ +=
2101 " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002102 "{{STRUCT_TY}}Builder<'a, 'b> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002103 code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
2104 code_ += " let start = _fbb.start_table();";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002105 code_ += " {{STRUCT_TY}}Builder {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002106 code_ += " fbb_: _fbb,";
2107 code_ += " start_: start,";
2108 code_ += " }";
2109 code_ += " }";
2110
2111 // finish() function.
2112 code_ += " #[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002113 code_ +=
2114 " pub fn finish(self) -> "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002115 "flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002116 code_ += " let o = self.fbb_.end_table(self.start_);";
2117
Austin Schuh272c6132020-11-14 16:37:52 -08002118 ForAllTableFields(struct_def, [&](const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002119 if (!field.IsRequired()) return;
Austin Schuh272c6132020-11-14 16:37:52 -08002120 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002121 " self.fbb_.required(o, {{STRUCT_TY}}::{{OFFSET_NAME}},"
2122 "\"{{FIELD}}\");";
Austin Schuh272c6132020-11-14 16:37:52 -08002123 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002124 code_ += " flatbuffers::WIPOffset::new(o.value())";
2125 code_ += " }";
2126 code_ += "}";
2127 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08002128
James Kuszmaul8e62b022022-03-22 09:33:25 -07002129 code_ += "impl std::fmt::Debug for {{STRUCT_TY}}<'_> {";
2130 code_ +=
2131 " fn fmt(&self, f: &mut std::fmt::Formatter<'_>"
2132 ") -> std::fmt::Result {";
2133 code_ += " let mut ds = f.debug_struct(\"{{STRUCT_TY}}\");";
Austin Schuh272c6132020-11-14 16:37:52 -08002134 ForAllTableFields(struct_def, [&](const FieldDef &field) {
2135 if (GetFullType(field.value.type) == ftUnionValue) {
2136 // Generate a match statement to handle unions properly.
2137 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002138 code_.SetValue("UNION_ERR",
2139 "&\"InvalidFlatbuffer: Union discriminant"
2140 " does not match value.\"");
Austin Schuh272c6132020-11-14 16:37:52 -08002141
James Kuszmaul8e62b022022-03-22 09:33:25 -07002142 code_ += " match self.{{DISCRIMINANT}}() {";
2143 ForAllUnionVariantsBesidesNone(
2144 *field.value.type.enum_def, [&](const EnumVal &unused) {
2145 (void)unused;
2146 code_ += " {{U_ELEMENT_ENUM_TYPE}} => {";
2147 code_ +=
2148 " if let Some(x) = "
2149 "self.{{FIELD}}_as_"
2150 "{{U_ELEMENT_NAME}}() {";
2151 code_ += " ds.field(\"{{FIELD}}\", &x)";
2152 code_ += " } else {";
2153 code_ += " ds.field(\"{{FIELD}}\", {{UNION_ERR}})";
2154 code_ += " }";
2155 code_ += " },";
2156 });
2157 code_ += " _ => {";
2158 code_ += " let x: Option<()> = None;";
2159 code_ += " ds.field(\"{{FIELD}}\", &x)";
2160 code_ += " },";
2161 code_ += " };";
Austin Schuh272c6132020-11-14 16:37:52 -08002162 } else {
2163 // Most fields.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002164 code_ += " ds.field(\"{{FIELD}}\", &self.{{FIELD}}());";
Austin Schuh272c6132020-11-14 16:37:52 -08002165 }
2166 });
2167 code_ += " ds.finish()";
2168 code_ += " }";
2169 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002170 }
2171
James Kuszmaul8e62b022022-03-22 09:33:25 -07002172 void GenTableObject(const StructDef &table) {
2173 code_.SetValue("STRUCT_OTY", namer_.ObjectType(table.name));
2174 code_.SetValue("STRUCT_TY", namer_.Type(table.name));
2175
2176 // Generate the native object.
2177 code_ += "#[non_exhaustive]";
2178 code_ += "#[derive(Debug, Clone, PartialEq)]";
2179 code_ += "pub struct {{STRUCT_OTY}} {";
2180 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2181 // Union objects combine both the union discriminant and value, so we
2182 // skip making a field for the discriminant.
2183 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
2184 code_ += "pub {{FIELD}}: {{FIELD_OTY}},";
2185 });
2186 code_ += "}";
2187
2188 code_ += "impl Default for {{STRUCT_OTY}} {";
2189 code_ += " fn default() -> Self {";
2190 code_ += " Self {";
2191 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2192 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
2193 std::string default_value = GetDefaultValue(field, kObject);
2194 code_ += " {{FIELD}}: " + default_value + ",";
2195 });
2196 code_ += " }";
2197 code_ += " }";
2198 code_ += "}";
2199
2200 // TODO(cneo): Generate defaults for Native tables. However, since structs
2201 // may be required, they, and therefore enums need defaults.
2202
2203 // Generate pack function.
2204 code_ += "impl {{STRUCT_OTY}} {";
2205 code_ += " pub fn pack<'b>(";
2206 code_ += " &self,";
2207 code_ += " _fbb: &mut flatbuffers::FlatBufferBuilder<'b>";
2208 code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_TY}}<'b>> {";
2209 // First we generate variables for each field and then later assemble them
2210 // using "StructArgs" to more easily manage ownership of the builder.
2211 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2212 const Type &type = field.value.type;
2213 switch (GetFullType(type)) {
2214 case ftInteger:
2215 case ftBool:
2216 case ftFloat:
2217 case ftEnumKey: {
2218 code_ += " let {{FIELD}} = self.{{FIELD}};";
2219 return;
2220 }
2221 case ftUnionKey: return; // Generate union type with union value.
2222 case ftUnionValue: {
2223 code_.SetValue("ENUM_METHOD",
2224 namer_.Method(field.value.type.enum_def->name));
2225 code_ +=
2226 " let {{FIELD}}_type = "
2227 "self.{{FIELD}}.{{ENUM_METHOD}}_type();";
2228 code_ += " let {{FIELD}} = self.{{FIELD}}.pack(_fbb);";
2229 return;
2230 }
2231 // The rest of the types require special casing around optionalness
2232 // due to "required" annotation.
2233 case ftString: {
2234 MapNativeTableField(field, "_fbb.create_string(x)");
2235 return;
2236 }
2237 case ftStruct: {
2238 // Hold the struct in a variable so we can reference it.
2239 if (field.IsRequired()) {
2240 code_ += " let {{FIELD}}_tmp = Some(self.{{FIELD}}.pack());";
2241 } else {
2242 code_ +=
2243 " let {{FIELD}}_tmp = self.{{FIELD}}"
2244 ".as_ref().map(|x| x.pack());";
2245 }
2246 code_ += " let {{FIELD}} = {{FIELD}}_tmp.as_ref();";
2247
2248 return;
2249 }
2250 case ftTable: {
2251 MapNativeTableField(field, "x.pack(_fbb)");
2252 return;
2253 }
2254 case ftVectorOfEnumKey:
2255 case ftVectorOfInteger:
2256 case ftVectorOfBool:
2257 case ftVectorOfFloat: {
2258 MapNativeTableField(field, "_fbb.create_vector(x)");
2259 return;
2260 }
2261 case ftVectorOfStruct: {
2262 MapNativeTableField(
2263 field,
2264 "let w: Vec<_> = x.iter().map(|t| t.pack()).collect();"
2265 "_fbb.create_vector(&w)");
2266 return;
2267 }
2268 case ftVectorOfString: {
2269 // TODO(cneo): create_vector* should be more generic to avoid
2270 // allocations.
2271
2272 MapNativeTableField(
2273 field,
2274 "let w: Vec<_> = x.iter().map(|s| s.as_ref()).collect();"
2275 "_fbb.create_vector_of_strings(&w)");
2276 return;
2277 }
2278 case ftVectorOfTable: {
2279 MapNativeTableField(
2280 field,
2281 "let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();"
2282 "_fbb.create_vector(&w)");
2283 return;
2284 }
2285 case ftVectorOfUnionValue: {
2286 FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
2287 return;
2288 }
2289 case ftArrayOfEnum:
2290 case ftArrayOfStruct:
2291 case ftArrayOfBuiltin: {
2292 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
2293 return;
2294 }
2295 }
2296 });
2297 code_ += " {{STRUCT_TY}}::create(_fbb, &{{STRUCT_TY}}Args{";
2298 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2299 (void)field; // Unused.
2300 code_ += " {{FIELD}},";
2301 });
2302 code_ += " })";
2303 code_ += " }";
2304 code_ += "}";
2305 }
2306 void ForAllObjectTableFields(const StructDef &table,
2307 std::function<void(const FieldDef &)> cb) {
2308 const std::vector<FieldDef *> &v = table.fields.vec;
2309 for (auto it = v.begin(); it != v.end(); it++) {
2310 const FieldDef &field = **it;
2311 if (field.deprecated) continue;
2312 code_.SetValue("FIELD", namer_.Field(field.name));
2313 code_.SetValue("FIELD_OTY", ObjectFieldType(field, true));
2314 code_.IncrementIdentLevel();
2315 cb(field);
2316 code_.DecrementIdentLevel();
2317 }
2318 }
2319 void MapNativeTableField(const FieldDef &field, const std::string &expr) {
2320 if (field.IsOptional()) {
2321 code_ += " let {{FIELD}} = self.{{FIELD}}.as_ref().map(|x|{";
2322 code_ += " " + expr;
2323 code_ += " });";
2324 } else {
2325 // For some reason Args has optional types for required fields.
2326 // TODO(cneo): Fix this... but its a breaking change?
2327 code_ += " let {{FIELD}} = Some({";
2328 code_ += " let x = &self.{{FIELD}};";
2329 code_ += " " + expr;
2330 code_ += " });";
2331 }
2332 }
2333
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002334 // Generate functions to compare tables and structs by key. This function
2335 // must only be called if the field key is defined.
2336 void GenKeyFieldMethods(const FieldDef &field) {
2337 FLATBUFFERS_ASSERT(field.key);
2338
2339 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002340 code_.SetValue("REF", IsString(field.value.type) ? "" : "&");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002341
James Kuszmaul8e62b022022-03-22 09:33:25 -07002342 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002343 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002344 "pub fn key_compare_less_than(&self, o: &{{STRUCT_TY}}) -> "
2345 "bool {";
2346 code_ += " self.{{FIELD}}() < o.{{FIELD}}()";
2347 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002348 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002349 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002350 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002351 "pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
2352 "::std::cmp::Ordering {";
2353 code_ += " let key = self.{{FIELD}}();";
2354 code_ += " key.cmp({{REF}}val)";
2355 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002356 }
2357
2358 // Generate functions for accessing the root table object. This function
2359 // must only be called if the root table is defined.
2360 void GenRootTableFuncs(const StructDef &struct_def) {
2361 FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
James Kuszmaul8e62b022022-03-22 09:33:25 -07002362 code_.SetValue("STRUCT_TY", namer_.Type(struct_def.name));
2363 code_.SetValue("STRUCT_FN", namer_.Function(struct_def.name));
2364 code_.SetValue("STRUCT_CONST", namer_.Constant(struct_def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002365
2366 // The root datatype accessors:
2367 code_ += "#[inline]";
2368 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002369 "#[deprecated(since=\"2.0.0\", "
2370 "note=\"Deprecated in favor of `root_as...` methods.\")]";
2371 code_ +=
2372 "pub fn get_root_as_{{STRUCT_FN}}<'a>(buf: &'a [u8])"
2373 " -> {{STRUCT_TY}}<'a> {";
2374 code_ +=
2375 " unsafe { flatbuffers::root_unchecked::<{{STRUCT_TY}}"
2376 "<'a>>(buf) }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002377 code_ += "}";
2378 code_ += "";
2379
2380 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002381 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002382 "#[deprecated(since=\"2.0.0\", "
2383 "note=\"Deprecated in favor of `root_as...` methods.\")]";
Austin Schuh272c6132020-11-14 16:37:52 -08002384 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002385 "pub fn get_size_prefixed_root_as_{{STRUCT_FN}}"
2386 "<'a>(buf: &'a [u8]) -> {{STRUCT_TY}}<'a> {";
2387 code_ +=
2388 " unsafe { flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_TY}}"
2389 "<'a>>(buf) }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002390 code_ += "}";
2391 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002392 // Default verifier root fns.
2393 code_ += "#[inline]";
2394 code_ += "/// Verifies that a buffer of bytes contains a `{{STRUCT_TY}}`";
2395 code_ += "/// and returns it.";
2396 code_ += "/// Note that verification is still experimental and may not";
2397 code_ += "/// catch every error, or be maximally performant. For the";
2398 code_ += "/// previous, unchecked, behavior use";
2399 code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
2400 code_ +=
2401 "pub fn root_as_{{STRUCT_FN}}(buf: &[u8]) "
2402 "-> Result<{{STRUCT_TY}}, flatbuffers::InvalidFlatbuffer> {";
2403 code_ += " flatbuffers::root::<{{STRUCT_TY}}>(buf)";
2404 code_ += "}";
2405 code_ += "#[inline]";
2406 code_ += "/// Verifies that a buffer of bytes contains a size prefixed";
2407 code_ += "/// `{{STRUCT_TY}}` and returns it.";
2408 code_ += "/// Note that verification is still experimental and may not";
2409 code_ += "/// catch every error, or be maximally performant. For the";
2410 code_ += "/// previous, unchecked, behavior use";
2411 code_ += "/// `size_prefixed_root_as_{{STRUCT_FN}}_unchecked`.";
2412 code_ +=
2413 "pub fn size_prefixed_root_as_{{STRUCT_FN}}"
2414 "(buf: &[u8]) -> Result<{{STRUCT_TY}}, "
2415 "flatbuffers::InvalidFlatbuffer> {";
2416 code_ += " flatbuffers::size_prefixed_root::<{{STRUCT_TY}}>(buf)";
2417 code_ += "}";
2418 // Verifier with options root fns.
2419 code_ += "#[inline]";
2420 code_ += "/// Verifies, with the given options, that a buffer of bytes";
2421 code_ += "/// contains a `{{STRUCT_TY}}` and returns it.";
2422 code_ += "/// Note that verification is still experimental and may not";
2423 code_ += "/// catch every error, or be maximally performant. For the";
2424 code_ += "/// previous, unchecked, behavior use";
2425 code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
2426 code_ += "pub fn root_as_{{STRUCT_FN}}_with_opts<'b, 'o>(";
2427 code_ += " opts: &'o flatbuffers::VerifierOptions,";
2428 code_ += " buf: &'b [u8],";
2429 code_ +=
2430 ") -> Result<{{STRUCT_TY}}<'b>, flatbuffers::InvalidFlatbuffer>"
2431 " {";
2432 code_ += " flatbuffers::root_with_opts::<{{STRUCT_TY}}<'b>>(opts, buf)";
2433 code_ += "}";
2434 code_ += "#[inline]";
2435 code_ += "/// Verifies, with the given verifier options, that a buffer of";
2436 code_ += "/// bytes contains a size prefixed `{{STRUCT_TY}}` and returns";
2437 code_ += "/// it. Note that verification is still experimental and may not";
2438 code_ += "/// catch every error, or be maximally performant. For the";
2439 code_ += "/// previous, unchecked, behavior use";
2440 code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
2441 code_ +=
2442 "pub fn size_prefixed_root_as_{{STRUCT_FN}}_with_opts"
2443 "<'b, 'o>(";
2444 code_ += " opts: &'o flatbuffers::VerifierOptions,";
2445 code_ += " buf: &'b [u8],";
2446 code_ +=
2447 ") -> Result<{{STRUCT_TY}}<'b>, flatbuffers::InvalidFlatbuffer>"
2448 " {";
2449 code_ +=
2450 " flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_TY}}"
2451 "<'b>>(opts, buf)";
2452 code_ += "}";
2453 // Unchecked root fns.
2454 code_ += "#[inline]";
2455 code_ +=
2456 "/// Assumes, without verification, that a buffer of bytes "
2457 "contains a {{STRUCT_TY}} and returns it.";
2458 code_ += "/// # Safety";
2459 code_ +=
2460 "/// Callers must trust the given bytes do indeed contain a valid"
2461 " `{{STRUCT_TY}}`.";
2462 code_ +=
2463 "pub unsafe fn root_as_{{STRUCT_FN}}_unchecked"
2464 "(buf: &[u8]) -> {{STRUCT_TY}} {";
2465 code_ += " flatbuffers::root_unchecked::<{{STRUCT_TY}}>(buf)";
2466 code_ += "}";
2467 code_ += "#[inline]";
2468 code_ +=
2469 "/// Assumes, without verification, that a buffer of bytes "
2470 "contains a size prefixed {{STRUCT_TY}} and returns it.";
2471 code_ += "/// # Safety";
2472 code_ +=
2473 "/// Callers must trust the given bytes do indeed contain a valid"
2474 " size prefixed `{{STRUCT_TY}}`.";
2475 code_ +=
2476 "pub unsafe fn size_prefixed_root_as_{{STRUCT_FN}}"
2477 "_unchecked(buf: &[u8]) -> {{STRUCT_TY}} {";
2478 code_ +=
2479 " flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_TY}}>"
2480 "(buf)";
2481 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002482
2483 if (parser_.file_identifier_.length()) {
2484 // Declare the identifier
Austin Schuh272c6132020-11-14 16:37:52 -08002485 // (no lifetime needed as constants have static lifetimes by default)
James Kuszmaul8e62b022022-03-22 09:33:25 -07002486 code_ += "pub const {{STRUCT_CONST}}_IDENTIFIER: &str\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002487 code_ += " = \"" + parser_.file_identifier_ + "\";";
2488 code_ += "";
2489
2490 // Check if a buffer has the identifier.
2491 code_ += "#[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002492 code_ += "pub fn {{STRUCT_FN}}_buffer_has_identifier\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002493 code_ += "(buf: &[u8]) -> bool {";
Austin Schuh272c6132020-11-14 16:37:52 -08002494 code_ += " flatbuffers::buffer_has_identifier(buf, \\";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002495 code_ += "{{STRUCT_CONST}}_IDENTIFIER, false)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002496 code_ += "}";
2497 code_ += "";
2498 code_ += "#[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002499 code_ += "pub fn {{STRUCT_FN}}_size_prefixed\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002500 code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
Austin Schuh272c6132020-11-14 16:37:52 -08002501 code_ += " flatbuffers::buffer_has_identifier(buf, \\";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002502 code_ += "{{STRUCT_CONST}}_IDENTIFIER, true)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002503 code_ += "}";
2504 code_ += "";
2505 }
2506
2507 if (parser_.file_extension_.length()) {
2508 // Return the extension
James Kuszmaul8e62b022022-03-22 09:33:25 -07002509 code_ += "pub const {{STRUCT_CONST}}_EXTENSION: &str = \\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002510 code_ += "\"" + parser_.file_extension_ + "\";";
2511 code_ += "";
2512 }
2513
2514 // Finish a buffer with a given root object:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002515 code_ += "#[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002516 code_ += "pub fn finish_{{STRUCT_FN}}_buffer<'a, 'b>(";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002517 code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002518 code_ += " root: flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>>) {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002519 if (parser_.file_identifier_.length()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002520 code_ += " fbb.finish(root, Some({{STRUCT_CONST}}_IDENTIFIER));";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002521 } else {
2522 code_ += " fbb.finish(root, None);";
2523 }
2524 code_ += "}";
2525 code_ += "";
2526 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002527 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002528 "pub fn finish_size_prefixed_{{STRUCT_FN}}_buffer"
Austin Schuh272c6132020-11-14 16:37:52 -08002529 "<'a, 'b>("
2530 "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002531 "root: flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>>) {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002532 if (parser_.file_identifier_.length()) {
Austin Schuh272c6132020-11-14 16:37:52 -08002533 code_ +=
2534 " fbb.finish_size_prefixed(root, "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002535 "Some({{STRUCT_CONST}}_IDENTIFIER));";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002536 } else {
2537 code_ += " fbb.finish_size_prefixed(root, None);";
2538 }
2539 code_ += "}";
2540 }
2541
2542 static void GenPadding(
2543 const FieldDef &field, std::string *code_ptr, int *id,
2544 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
2545 if (field.padding) {
2546 for (int i = 0; i < 4; i++) {
2547 if (static_cast<int>(field.padding) & (1 << i)) {
2548 f((1 << i) * 8, code_ptr, id);
2549 }
2550 }
2551 assert(!(field.padding & ~0xF));
2552 }
2553 }
2554
2555 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
Austin Schuh272c6132020-11-14 16:37:52 -08002556 *code_ptr +=
2557 " padding" + NumToString((*id)++) + "__: u" + NumToString(bits) + ",";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002558 }
2559
2560 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
2561 (void)bits;
2562 *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
2563 }
2564
James Kuszmaul8e62b022022-03-22 09:33:25 -07002565 void ForAllStructFields(const StructDef &struct_def,
2566 std::function<void(const FieldDef &field)> cb) {
2567 size_t offset_to_field = 0;
Austin Schuh272c6132020-11-14 16:37:52 -08002568 for (auto it = struct_def.fields.vec.begin();
2569 it != struct_def.fields.vec.end(); ++it) {
2570 const auto &field = **it;
2571 code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002572 code_.SetValue("FIELD_OTY", ObjectFieldType(field, false));
2573 code_.SetValue("FIELD", namer_.Field(field.name));
2574 code_.SetValue("FIELD_OFFSET", NumToString(offset_to_field));
2575 code_.SetValue(
2576 "REF",
2577 IsStruct(field.value.type) || IsArray(field.value.type) ? "&" : "");
2578 code_.IncrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -08002579 cb(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07002580 code_.DecrementIdentLevel();
2581 const size_t size = InlineSize(field.value.type);
2582 offset_to_field += size + field.padding;
Austin Schuh272c6132020-11-14 16:37:52 -08002583 }
2584 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002585 // Generate an accessor struct with constructor for a flatbuffers struct.
2586 void GenStruct(const StructDef &struct_def) {
2587 // Generates manual padding and alignment.
2588 // Variables are private because they contain little endian data on all
2589 // platforms.
2590 GenComment(struct_def.doc_comment);
2591 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002592 code_.SetValue("STRUCT_TY", namer_.Type(struct_def.name));
2593 code_.SetValue("STRUCT_SIZE", NumToString(struct_def.bytesize));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002594
James Kuszmaul8e62b022022-03-22 09:33:25 -07002595 // We represent Flatbuffers-structs in Rust-u8-arrays since the data may be
2596 // of the wrong endianness and alignment 1.
2597 //
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002598 // PartialEq is useful to derive because we can correctly compare structs
2599 // for equality by just comparing their underlying byte data. This doesn't
2600 // hold for PartialOrd/Ord.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002601 code_ += "// struct {{STRUCT_TY}}, aligned to {{ALIGN}}";
2602 code_ += "#[repr(transparent)]";
Austin Schuh272c6132020-11-14 16:37:52 -08002603 code_ += "#[derive(Clone, Copy, PartialEq)]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002604 code_ += "pub struct {{STRUCT_TY}}(pub [u8; {{STRUCT_SIZE}}]);";
2605 code_ += "impl Default for {{STRUCT_TY}} { ";
2606 code_ += " fn default() -> Self { ";
2607 code_ += " Self([0; {{STRUCT_SIZE}}])";
2608 code_ += " }";
2609 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002610
Austin Schuh272c6132020-11-14 16:37:52 -08002611 // Debug for structs.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002612 code_ += "impl std::fmt::Debug for {{STRUCT_TY}} {";
2613 code_ +=
2614 " fn fmt(&self, f: &mut std::fmt::Formatter"
2615 ") -> std::fmt::Result {";
2616 code_ += " f.debug_struct(\"{{STRUCT_TY}}\")";
Austin Schuh272c6132020-11-14 16:37:52 -08002617 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002618 (void)unused;
2619 code_ += " .field(\"{{FIELD}}\", &self.{{FIELD}}())";
Austin Schuh272c6132020-11-14 16:37:52 -08002620 });
2621 code_ += " .finish()";
2622 code_ += " }";
2623 code_ += "}";
2624 code_ += "";
2625
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002626 // Generate impls for SafeSliceAccess (because all structs are endian-safe),
2627 // Follow for the value type, Follow for the reference type, Push for the
2628 // value type, and Push for the reference type.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002629 code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{STRUCT_TY}} {}";
2630 code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_TY}} {}";
2631 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_TY}} {";
2632 code_ += " type Inner = &'a {{STRUCT_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002633 code_ += " #[inline]";
2634 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002635 code_ += " <&'a {{STRUCT_TY}}>::follow(buf, loc)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002636 code_ += " }";
2637 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002638 code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_TY}} {";
2639 code_ += " type Inner = &'a {{STRUCT_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002640 code_ += " #[inline]";
2641 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002642 code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_TY}}>(buf, loc)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002643 code_ += " }";
2644 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002645 code_ += "impl<'b> flatbuffers::Push for {{STRUCT_TY}} {";
2646 code_ += " type Output = {{STRUCT_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002647 code_ += " #[inline]";
2648 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
2649 code_ += " let src = unsafe {";
Austin Schuh272c6132020-11-14 16:37:52 -08002650 code_ +=
2651 " ::std::slice::from_raw_parts("
James Kuszmaul8e62b022022-03-22 09:33:25 -07002652 "self as *const {{STRUCT_TY}} as *const u8, Self::size())";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002653 code_ += " };";
2654 code_ += " dst.copy_from_slice(src);";
2655 code_ += " }";
2656 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002657 code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_TY}} {";
2658 code_ += " type Output = {{STRUCT_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002659 code_ += "";
2660 code_ += " #[inline]";
2661 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
2662 code_ += " let src = unsafe {";
Austin Schuh272c6132020-11-14 16:37:52 -08002663 code_ +=
2664 " ::std::slice::from_raw_parts("
James Kuszmaul8e62b022022-03-22 09:33:25 -07002665 "*self as *const {{STRUCT_TY}} as *const u8, Self::size())";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002666 code_ += " };";
2667 code_ += " dst.copy_from_slice(src);";
2668 code_ += " }";
2669 code_ += "}";
2670 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002671
2672 // Generate verifier: Structs are simple so presence and alignment are
2673 // all that need to be checked.
2674 code_ += "impl<'a> flatbuffers::Verifiable for {{STRUCT_TY}} {";
2675 code_ += " #[inline]";
2676 code_ += " fn run_verifier(";
2677 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
2678 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
2679 code_ += " use self::flatbuffers::Verifiable;";
2680 code_ += " v.in_buffer::<Self>(pos)";
2681 code_ += " }";
2682 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002683 code_ += "";
2684
James Kuszmaul8e62b022022-03-22 09:33:25 -07002685 // Implement serde::Serialize
2686 if (parser_.opts.rust_serialize) {
2687 const auto numFields = struct_def.fields.vec.size();
2688 code_.SetValue("NUM_FIELDS", NumToString(numFields));
2689 code_ += "impl Serialize for {{STRUCT_TY}} {";
2690 code_ +=
2691 " fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
2692 code_ += " where";
2693 code_ += " S: Serializer,";
2694 code_ += " {";
2695 if (numFields == 0) {
2696 code_ +=
2697 " let s = serializer.serialize_struct(\"{{STRUCT_TY}}\", 0)?;";
2698 } else {
2699 code_ +=
2700 " let mut s = serializer.serialize_struct(\"{{STRUCT_TY}}\", "
2701 "{{NUM_FIELDS}})?;";
2702 }
2703 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2704 (void)unused;
2705 code_ +=
2706 " s.serialize_field(\"{{FIELD}}\", "
2707 "&self.{{FIELD}}())?;";
2708 });
2709 code_ += " s.end()";
2710 code_ += " }";
2711 code_ += "}";
2712 code_ += "";
2713 }
2714
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002715 // Generate a constructor that takes all fields as arguments.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002716 code_ += "impl<'a> {{STRUCT_TY}} {";
2717 code_ += " #[allow(clippy::too_many_arguments)]";
2718 code_ += " pub fn new(";
2719 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2720 (void)unused;
2721 code_ += " {{FIELD}}: {{REF}}{{FIELD_TYPE}},";
Austin Schuh272c6132020-11-14 16:37:52 -08002722 });
James Kuszmaul8e62b022022-03-22 09:33:25 -07002723 code_ += " ) -> Self {";
2724 code_ += " let mut s = Self([0; {{STRUCT_SIZE}}]);";
2725 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2726 (void)unused;
2727 code_ += " s.set_{{FIELD}}({{FIELD}});";
Austin Schuh272c6132020-11-14 16:37:52 -08002728 });
James Kuszmaul8e62b022022-03-22 09:33:25 -07002729 code_ += " s";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002730 code_ += " }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002731 code_ += "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002732
Austin Schuh272c6132020-11-14 16:37:52 -08002733 if (parser_.opts.generate_name_strings) {
2734 GenFullyQualifiedNameGetter(struct_def, struct_def.name);
2735 }
2736
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002737 // Generate accessor methods for the struct.
Austin Schuh272c6132020-11-14 16:37:52 -08002738 ForAllStructFields(struct_def, [&](const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002739 this->GenComment(field.doc_comment);
2740 // Getter.
2741 if (IsStruct(field.value.type)) {
2742 code_ += "pub fn {{FIELD}}(&self) -> &{{FIELD_TYPE}} {";
2743 code_ +=
2744 " unsafe {"
2745 " &*(self.0[{{FIELD_OFFSET}}..].as_ptr() as *const"
2746 " {{FIELD_TYPE}}) }";
2747 } else if (IsArray(field.value.type)) {
2748 code_.SetValue("ARRAY_SIZE",
2749 NumToString(field.value.type.fixed_length));
2750 code_.SetValue("ARRAY_ITEM", GetTypeGet(field.value.type.VectorType()));
2751 code_ +=
2752 "pub fn {{FIELD}}(&'a self) -> "
2753 "flatbuffers::Array<'a, {{ARRAY_ITEM}}, {{ARRAY_SIZE}}> {";
2754 code_ += " flatbuffers::Array::follow(&self.0, {{FIELD_OFFSET}})";
2755 } else {
2756 code_ += "pub fn {{FIELD}}(&self) -> {{FIELD_TYPE}} {";
2757 code_ +=
2758 " let mut mem = core::mem::MaybeUninit::"
2759 "<{{FIELD_TYPE}}>::uninit();";
2760 code_ += " unsafe {";
2761 code_ += " core::ptr::copy_nonoverlapping(";
2762 code_ += " self.0[{{FIELD_OFFSET}}..].as_ptr(),";
2763 code_ += " mem.as_mut_ptr() as *mut u8,";
2764 code_ += " core::mem::size_of::<{{FIELD_TYPE}}>(),";
2765 code_ += " );";
2766 code_ += " mem.assume_init()";
2767 code_ += " }.from_little_endian()";
2768 }
2769 code_ += "}\n";
2770 // Setter.
2771 if (IsStruct(field.value.type)) {
2772 code_.SetValue("FIELD_SIZE", NumToString(InlineSize(field.value.type)));
2773 code_ += "#[allow(clippy::identity_op)]"; // If FIELD_OFFSET=0.
2774 code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {";
2775 code_ +=
2776 " self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}} + {{FIELD_SIZE}}]"
2777 ".copy_from_slice(&x.0)";
2778 } else if (IsArray(field.value.type)) {
2779 if (GetFullType(field.value.type) == ftArrayOfBuiltin) {
2780 code_.SetValue("ARRAY_ITEM",
2781 GetTypeGet(field.value.type.VectorType()));
2782 code_.SetValue(
2783 "ARRAY_ITEM_SIZE",
2784 NumToString(InlineSize(field.value.type.VectorType())));
2785 code_ +=
2786 "pub fn set_{{FIELD}}(&mut self, items: &{{FIELD_TYPE}}) "
2787 "{";
2788 code_ +=
2789 " flatbuffers::emplace_scalar_array(&mut self.0, "
2790 "{{FIELD_OFFSET}}, items);";
2791 } else {
2792 code_.SetValue("FIELD_SIZE",
2793 NumToString(InlineSize(field.value.type)));
2794 code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {";
2795 code_ += " unsafe {";
2796 code_ += " std::ptr::copy(";
2797 code_ += " x.as_ptr() as *const u8,";
2798 code_ += " self.0.as_mut_ptr().add({{FIELD_OFFSET}}),";
2799 code_ += " {{FIELD_SIZE}},";
2800 code_ += " );";
2801 code_ += " }";
2802 }
2803 } else {
2804 code_ += "pub fn set_{{FIELD}}(&mut self, x: {{FIELD_TYPE}}) {";
2805 code_ += " let x_le = x.to_little_endian();";
2806 code_ += " unsafe {";
2807 code_ += " core::ptr::copy_nonoverlapping(";
2808 code_ += " &x_le as *const {{FIELD_TYPE}} as *const u8,";
2809 code_ += " self.0[{{FIELD_OFFSET}}..].as_mut_ptr(),";
2810 code_ += " core::mem::size_of::<{{FIELD_TYPE}}>(),";
2811 code_ += " );";
2812 code_ += " }";
2813 }
2814 code_ += "}\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002815
2816 // Generate a comparison function for this field if it is a key.
Austin Schuh272c6132020-11-14 16:37:52 -08002817 if (field.key) { GenKeyFieldMethods(field); }
2818 });
James Kuszmaul8e62b022022-03-22 09:33:25 -07002819
2820 // Generate Object API unpack method.
2821 if (parser_.opts.generate_object_based_api) {
2822 code_.SetValue("STRUCT_OTY", namer_.ObjectType(struct_def.name));
2823 code_ += " pub fn unpack(&self) -> {{STRUCT_OTY}} {";
2824 code_ += " {{STRUCT_OTY}} {";
2825 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2826 if (IsArray(field.value.type)) {
2827 if (GetFullType(field.value.type) == ftArrayOfStruct) {
2828 code_ +=
2829 " {{FIELD}}: { let {{FIELD}} = "
2830 "self.{{FIELD}}(); flatbuffers::array_init(|i| "
2831 "{{FIELD}}.get(i).unpack()) },";
2832 } else {
2833 code_ += " {{FIELD}}: self.{{FIELD}}().into(),";
2834 }
2835 } else {
2836 std::string unpack = IsStruct(field.value.type) ? ".unpack()" : "";
2837 code_ += " {{FIELD}}: self.{{FIELD}}()" + unpack + ",";
2838 }
2839 });
2840 code_ += " }";
2841 code_ += " }";
2842 }
2843
2844 code_ += "}"; // End impl Struct methods.
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002845 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002846
2847 // Generate Struct Object.
2848 if (parser_.opts.generate_object_based_api) {
2849 // Struct declaration
2850 code_ += "#[derive(Debug, Clone, PartialEq, Default)]";
2851 code_ += "pub struct {{STRUCT_OTY}} {";
2852 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2853 (void)field; // unused.
2854 code_ += "pub {{FIELD}}: {{FIELD_OTY}},";
2855 });
2856 code_ += "}";
2857 // The `pack` method that turns the native struct into its Flatbuffers
2858 // counterpart.
2859 code_ += "impl {{STRUCT_OTY}} {";
2860 code_ += " pub fn pack(&self) -> {{STRUCT_TY}} {";
2861 code_ += " {{STRUCT_TY}}::new(";
2862 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2863 if (IsStruct(field.value.type)) {
2864 code_ += " &self.{{FIELD}}.pack(),";
2865 } else if (IsArray(field.value.type)) {
2866 if (GetFullType(field.value.type) == ftArrayOfStruct) {
2867 code_ +=
2868 " &flatbuffers::array_init(|i| "
2869 "self.{{FIELD}}[i].pack()),";
2870 } else {
2871 code_ += " &self.{{FIELD}},";
2872 }
2873 } else {
2874 code_ += " self.{{FIELD}},";
2875 }
2876 });
2877 code_ += " )";
2878 code_ += " }";
2879 code_ += "}";
2880 code_ += "";
2881 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002882 }
2883
2884 void GenNamespaceImports(const int white_spaces) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002885 // DO not use global attributes (i.e. #![...]) since it interferes
2886 // with users who include! generated files.
2887 // See: https://github.com/google/flatbuffers/issues/6261
Austin Schuh272c6132020-11-14 16:37:52 -08002888 std::string indent = std::string(white_spaces, ' ');
2889 code_ += "";
2890 if (!parser_.opts.generate_all) {
2891 for (auto it = parser_.included_files_.begin();
2892 it != parser_.included_files_.end(); ++it) {
2893 if (it->second.empty()) continue;
2894 auto noext = flatbuffers::StripExtension(it->second);
2895 auto basename = flatbuffers::StripPath(noext);
2896
James Kuszmaul8e62b022022-03-22 09:33:25 -07002897 if (parser_.opts.include_prefix.empty()) {
2898 code_ += indent + "use crate::" + basename +
2899 parser_.opts.filename_suffix + "::*;";
2900 } else {
2901 auto prefix = parser_.opts.include_prefix;
2902 prefix.pop_back();
2903
2904 code_ += indent + "use crate::" + prefix + "::" + basename +
2905 parser_.opts.filename_suffix + "::*;";
2906 }
Austin Schuh272c6132020-11-14 16:37:52 -08002907 }
2908 }
Austin Schuh272c6132020-11-14 16:37:52 -08002909 code_ += indent + "use std::mem;";
2910 code_ += indent + "use std::cmp::Ordering;";
2911 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002912 if (parser_.opts.rust_serialize) {
2913 code_ += indent + "extern crate serde;";
2914 code_ +=
2915 indent +
2916 "use self::serde::ser::{Serialize, Serializer, SerializeStruct};";
2917 code_ += "";
2918 }
Austin Schuh272c6132020-11-14 16:37:52 -08002919 code_ += indent + "extern crate flatbuffers;";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002920 code_ += indent + "use self::flatbuffers::{EndianScalar, Follow};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002921 }
2922
2923 // Set up the correct namespace. This opens a namespace if the current
2924 // namespace is different from the target namespace. This function
2925 // closes and opens the namespaces only as necessary.
2926 //
2927 // The file must start and end with an empty (or null) namespace so that
2928 // namespaces are properly opened and closed.
2929 void SetNameSpace(const Namespace *ns) {
2930 if (cur_name_space_ == ns) { return; }
2931
2932 // Compute the size of the longest common namespace prefix.
2933 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
2934 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
2935 // and common_prefix_size = 2
2936 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
2937 size_t new_size = ns ? ns->components.size() : 0;
2938
2939 size_t common_prefix_size = 0;
2940 while (common_prefix_size < old_size && common_prefix_size < new_size &&
2941 ns->components[common_prefix_size] ==
2942 cur_name_space_->components[common_prefix_size]) {
2943 common_prefix_size++;
2944 }
2945
2946 // Close cur_name_space in reverse order to reach the common prefix.
2947 // In the previous example, D then C are closed.
2948 for (size_t j = old_size; j > common_prefix_size; --j) {
2949 code_ += "} // pub mod " + cur_name_space_->components[j - 1];
2950 }
2951 if (old_size != common_prefix_size) { code_ += ""; }
2952
2953 // open namespace parts to reach the ns namespace
2954 // in the previous example, E, then F, then G are opened
2955 for (auto j = common_prefix_size; j != new_size; ++j) {
2956 code_ += "#[allow(unused_imports, dead_code)]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002957 code_ += "pub mod " + namer_.Namespace(ns->components[j]) + " {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002958 // Generate local namespace imports.
2959 GenNamespaceImports(2);
2960 }
2961 if (new_size != common_prefix_size) { code_ += ""; }
2962
2963 cur_name_space_ = ns;
2964 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07002965
2966 private:
2967 Namer namer_;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002968};
2969
2970} // namespace rust
2971
2972bool GenerateRust(const Parser &parser, const std::string &path,
2973 const std::string &file_name) {
2974 rust::RustGenerator generator(parser, path, file_name);
2975 return generator.generate();
2976}
2977
2978std::string RustMakeRule(const Parser &parser, const std::string &path,
2979 const std::string &file_name) {
2980 std::string filebase =
2981 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
Austin Schuh272c6132020-11-14 16:37:52 -08002982 rust::RustGenerator generator(parser, path, file_name);
2983 std::string make_rule =
2984 generator.GeneratedFileName(path, filebase, parser.opts) + ": ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002985
2986 auto included_files = parser.GetIncludedFilesRecursive(file_name);
2987 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
2988 make_rule += " " + *it;
2989 }
2990 return make_rule;
2991}
2992
2993} // namespace flatbuffers
2994
2995// TODO(rw): Generated code should import other generated files.
2996// TODO(rw): Generated code should refer to namespaces in included files in a
2997// way that makes them referrable.
2998// TODO(rw): Generated code should indent according to nesting level.
2999// TODO(rw): Generated code should generate endian-safe Debug impls.
3000// TODO(rw): Generated code could use a Rust-only enum type to access unions,
3001// instead of making the user use _type() to manually switch.
Austin Schuh272c6132020-11-14 16:37:52 -08003002// TODO(maxburke): There should be test schemas added that use language
3003// keywords as fields of structs, tables, unions, enums, to make sure
3004// that internal code generated references escaped names correctly.
3005// TODO(maxburke): We should see if there is a more flexible way of resolving
3006// module paths for use declarations. Right now if schemas refer to
3007// other flatbuffer files, the include paths in emitted Rust bindings
3008// are crate-relative which may undesirable.