blob: c01410a6498bdf8bc1e40c9b4b63d2074227b87f [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
James Kuszmaul3b15b0c2022-11-08 14:03:16 -080019#include <cmath>
20
Austin Schuhe89fa2d2019-08-14 20:24:23 -070021#include "flatbuffers/code_generators.h"
22#include "flatbuffers/flatbuffers.h"
23#include "flatbuffers/idl.h"
24#include "flatbuffers/util.h"
Austin Schuh2dd86a92022-09-14 21:19:23 -070025#include "idl_namer.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070026
27namespace flatbuffers {
Austin Schuh2dd86a92022-09-14 21:19:23 -070028namespace {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070029
Austin Schuh2dd86a92022-09-14 21:19:23 -070030static Namer::Config RustDefaultConfig() {
James Kuszmaul8e62b022022-03-22 09:33:25 -070031 // Historical note: We've been using "keep" casing since the original
32 // implementation, presumably because Flatbuffers schema style and Rust style
33 // roughly align. We are not going to enforce proper casing since its an
34 // unnecessary breaking change.
35 return { /*types=*/Case::kKeep,
36 /*constants=*/Case::kScreamingSnake,
37 /*methods=*/Case::kSnake,
38 /*functions=*/Case::kSnake,
39 /*fields=*/Case::kKeep,
40 /*variables=*/Case::kUnknown, // Unused.
41 /*variants=*/Case::kKeep,
42 /*enum_variant_seperator=*/"::",
Austin Schuh2dd86a92022-09-14 21:19:23 -070043 /*escape_keywords=*/Namer::Config::Escape::BeforeConvertingCase,
James Kuszmaul8e62b022022-03-22 09:33:25 -070044 /*namespaces=*/Case::kSnake,
45 /*namespace_seperator=*/"::",
46 /*object_prefix=*/"",
47 /*object_suffix=*/"T",
48 /*keyword_prefix=*/"",
49 /*keyword_suffix=*/"_",
50 /*filenames=*/Case::kSnake,
51 /*directories=*/Case::kSnake,
52 /*output_path=*/"",
53 /*filename_suffix=*/"_generated",
54 /*filename_extension=*/".rs" };
Austin Schuhe89fa2d2019-08-14 20:24:23 -070055}
56
Austin Schuh2dd86a92022-09-14 21:19:23 -070057static std::set<std::string> RustKeywords() {
James Kuszmaul8e62b022022-03-22 09:33:25 -070058 return {
59 // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
60 "as",
61 "break",
62 "const",
63 "continue",
64 "crate",
65 "else",
66 "enum",
67 "extern",
68 "false",
69 "fn",
70 "for",
71 "if",
72 "impl",
73 "in",
74 "let",
75 "loop",
76 "match",
77 "mod",
78 "move",
79 "mut",
80 "pub",
81 "ref",
82 "return",
83 "Self",
84 "self",
85 "static",
86 "struct",
87 "super",
88 "trait",
89 "true",
90 "type",
91 "unsafe",
92 "use",
93 "where",
94 "while",
95 // future possible keywords
96 "abstract",
97 "alignof",
98 "become",
99 "box",
100 "do",
101 "final",
102 "macro",
103 "offsetof",
104 "override",
105 "priv",
106 "proc",
107 "pure",
108 "sizeof",
109 "typeof",
110 "unsized",
111 "virtual",
112 "yield",
113 // other rust terms we should not use
114 "std",
115 "usize",
116 "isize",
117 "u8",
118 "i8",
119 "u16",
120 "i16",
121 "u32",
122 "i32",
123 "u64",
124 "i64",
125 "u128",
126 "i128",
127 "f32",
128 "f64",
129 // Terms that we use ourselves
130 "follow",
131 "push",
132 "size",
133 "alignment",
134 "to_little_endian",
135 "from_little_endian",
136 "ENUM_MAX",
137 "ENUM_MIN",
138 "ENUM_VALUES",
139 };
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700140}
141
142// Encapsulate all logical field types in this enum. This allows us to write
143// field logic based on type switches, instead of branches on the properties
144// set on the Type.
145// TODO(rw): for backwards compatibility, we can't use a strict `enum class`
146// declaration here. could we use the `-Wswitch-enum` warning to
147// achieve the same effect?
148enum FullType {
149 ftInteger = 0,
150 ftFloat = 1,
151 ftBool = 2,
152
153 ftStruct = 3,
154 ftTable = 4,
155
156 ftEnumKey = 5,
157 ftUnionKey = 6,
158
159 ftUnionValue = 7,
160
161 // TODO(rw): bytestring?
162 ftString = 8,
163
164 ftVectorOfInteger = 9,
165 ftVectorOfFloat = 10,
166 ftVectorOfBool = 11,
167 ftVectorOfEnumKey = 12,
168 ftVectorOfStruct = 13,
169 ftVectorOfTable = 14,
170 ftVectorOfString = 15,
171 ftVectorOfUnionValue = 16,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700172
173 ftArrayOfBuiltin = 17,
174 ftArrayOfEnum = 18,
175 ftArrayOfStruct = 19,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700176};
177
178// Convert a Type to a FullType (exhaustive).
Austin Schuh2dd86a92022-09-14 21:19:23 -0700179static FullType GetFullType(const Type &type) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700180 // N.B. The order of these conditionals matters for some types.
181
Austin Schuh272c6132020-11-14 16:37:52 -0800182 if (IsString(type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700183 return ftString;
184 } else if (type.base_type == BASE_TYPE_STRUCT) {
185 if (type.struct_def->fixed) {
186 return ftStruct;
187 } else {
188 return ftTable;
189 }
Austin Schuh272c6132020-11-14 16:37:52 -0800190 } else if (IsVector(type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700191 switch (GetFullType(type.VectorType())) {
192 case ftInteger: {
193 return ftVectorOfInteger;
194 }
195 case ftFloat: {
196 return ftVectorOfFloat;
197 }
198 case ftBool: {
199 return ftVectorOfBool;
200 }
201 case ftStruct: {
202 return ftVectorOfStruct;
203 }
204 case ftTable: {
205 return ftVectorOfTable;
206 }
207 case ftString: {
208 return ftVectorOfString;
209 }
210 case ftEnumKey: {
211 return ftVectorOfEnumKey;
212 }
213 case ftUnionKey:
214 case ftUnionValue: {
215 FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
216 break;
217 }
218 default: {
219 FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
220 }
221 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700222 } else if (IsArray(type)) {
223 switch (GetFullType(type.VectorType())) {
224 case ftInteger:
225 case ftFloat:
226 case ftBool: {
227 return ftArrayOfBuiltin;
228 }
229 case ftStruct: {
230 return ftArrayOfStruct;
231 }
232 case ftEnumKey: {
233 return ftArrayOfEnum;
234 }
235 default: {
236 FLATBUFFERS_ASSERT(false && "Unsupported type for fixed array");
237 }
238 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700239 } else if (type.enum_def != nullptr) {
240 if (type.enum_def->is_union) {
241 if (type.base_type == BASE_TYPE_UNION) {
242 return ftUnionValue;
243 } else if (IsInteger(type.base_type)) {
244 return ftUnionKey;
245 } else {
246 FLATBUFFERS_ASSERT(false && "unknown union field type");
247 }
248 } else {
249 return ftEnumKey;
250 }
251 } else if (IsScalar(type.base_type)) {
252 if (IsBool(type.base_type)) {
253 return ftBool;
254 } else if (IsInteger(type.base_type)) {
255 return ftInteger;
256 } else if (IsFloat(type.base_type)) {
257 return ftFloat;
258 } else {
259 FLATBUFFERS_ASSERT(false && "unknown number type");
260 }
261 }
262
263 FLATBUFFERS_ASSERT(false && "completely unknown type");
264
265 // this is only to satisfy the compiler's return analysis.
266 return ftBool;
267}
268
Austin Schuh2dd86a92022-09-14 21:19:23 -0700269static bool IsBitFlagsEnum(const EnumDef &enum_def) {
Austin Schuh272c6132020-11-14 16:37:52 -0800270 return enum_def.attributes.Lookup("bit_flags") != nullptr;
271}
James Kuszmaul8e62b022022-03-22 09:33:25 -0700272
273// TableArgs make required non-scalars "Option<_>".
274// TODO(cneo): Rework how we do defaults and stuff.
Austin Schuh2dd86a92022-09-14 21:19:23 -0700275static bool IsOptionalToBuilder(const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700276 return field.IsOptional() || !IsScalar(field.value.type.base_type);
277}
Austin Schuh2dd86a92022-09-14 21:19:23 -0700278} // namespace
James Kuszmaul8e62b022022-03-22 09:33:25 -0700279
280bool GenerateRustModuleRootFile(const Parser &parser,
281 const std::string &output_dir) {
282 if (!parser.opts.rust_module_root_file) {
283 // Don't generate a root file when generating one file. This isn't an error
284 // so return true.
285 return true;
286 }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700287 Namer namer(WithFlagOptions(RustDefaultConfig(), parser.opts, output_dir),
James Kuszmaul8e62b022022-03-22 09:33:25 -0700288 RustKeywords());
289 // We gather the symbols into a tree of namespaces (which are rust mods) and
290 // generate a file that gathers them all.
291 struct Module {
292 std::map<std::string, Module> sub_modules;
293 std::vector<std::string> generated_files;
294 // Add a symbol into the tree.
295 void Insert(const Namer &namer, const Definition *s) {
296 const Definition &symbol = *s;
297 Module *current_module = this;
298 for (auto it = symbol.defined_namespace->components.begin();
299 it != symbol.defined_namespace->components.end(); it++) {
300 std::string ns_component = namer.Namespace(*it);
301 current_module = &current_module->sub_modules[ns_component];
302 }
303 current_module->generated_files.push_back(
304 namer.File(symbol.name, SkipFile::Extension));
305 }
306 // Recursively create the importer file.
307 void GenerateImports(CodeWriter &code) {
308 for (auto it = sub_modules.begin(); it != sub_modules.end(); it++) {
309 code += "pub mod " + it->first + " {";
310 code.IncrementIdentLevel();
311 code += "use super::*;";
312 it->second.GenerateImports(code);
313 code.DecrementIdentLevel();
314 code += "} // " + it->first;
315 }
316 for (auto it = generated_files.begin(); it != generated_files.end();
317 it++) {
318 code += "mod " + *it + ";";
319 code += "pub use self::" + *it + "::*;";
320 }
321 }
322 };
323 Module root_module;
324 for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
325 it++) {
326 root_module.Insert(namer, *it);
327 }
328 for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
329 it++) {
330 root_module.Insert(namer, *it);
331 }
332 CodeWriter code(" ");
333 // TODO(caspern): Move generated warning out of BaseGenerator.
334 code +=
335 "// Automatically generated by the Flatbuffers compiler. "
336 "Do not modify.";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700337 code += "// @generated";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700338 root_module.GenerateImports(code);
339 const bool success =
340 SaveFile((output_dir + "mod.rs").c_str(), code.ToString(), false);
341 code.Clear();
342 return success;
Austin Schuh272c6132020-11-14 16:37:52 -0800343}
344
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700345namespace rust {
346
347class RustGenerator : public BaseGenerator {
348 public:
349 RustGenerator(const Parser &parser, const std::string &path,
350 const std::string &file_name)
Austin Schuh272c6132020-11-14 16:37:52 -0800351 : BaseGenerator(parser, path, file_name, "", "::", "rs"),
James Kuszmaul8e62b022022-03-22 09:33:25 -0700352 cur_name_space_(nullptr),
Austin Schuh2dd86a92022-09-14 21:19:23 -0700353 namer_(WithFlagOptions(RustDefaultConfig(), parser.opts, path),
354 RustKeywords()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700355 // TODO: Namer flag overrides should be in flatc or flatc_main.
356 code_.SetPadding(" ");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700357 }
358
James Kuszmaul8e62b022022-03-22 09:33:25 -0700359 bool generate() {
360 if (!parser_.opts.rust_module_root_file) {
361 return GenerateOneFile();
362 } else {
363 return GenerateIndividualFiles();
364 }
365 }
366
367 template<typename T>
368 bool GenerateSymbols(const SymbolTable<T> &symbols,
369 std::function<void(const T &)> gen_symbol) {
370 for (auto it = symbols.vec.begin(); it != symbols.vec.end(); it++) {
371 const T &symbol = **it;
372 if (symbol.generated) continue;
373 code_.Clear();
374 code_ += "// " + std::string(FlatBuffersGeneratedWarning());
Austin Schuh2dd86a92022-09-14 21:19:23 -0700375 code_ += "// @generated";
376 code_ += "extern crate alloc;";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700377 code_ += "extern crate flatbuffers;";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700378 code_ += "use alloc::boxed::Box;";
379 code_ += "use alloc::string::{String, ToString};";
380 code_ += "use alloc::vec::Vec;";
381 code_ += "use core::mem;";
382 code_ += "use core::cmp::Ordering;";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700383 if (parser_.opts.rust_serialize) {
384 code_ += "extern crate serde;";
385 code_ +=
386 "use self::serde::ser::{Serialize, Serializer, SerializeStruct};";
387 }
388 code_ += "use self::flatbuffers::{EndianScalar, Follow};";
389 code_ += "use super::*;";
390 cur_name_space_ = symbol.defined_namespace;
391 gen_symbol(symbol);
392
393 const std::string directories =
Austin Schuh2dd86a92022-09-14 21:19:23 -0700394 namer_.Directories(*symbol.defined_namespace);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700395 EnsureDirExists(directories);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700396 const std::string file_path = directories + namer_.File(symbol);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700397 const bool save_success =
398 SaveFile(file_path.c_str(), code_.ToString(), /*binary=*/false);
399 if (!save_success) return false;
400 }
401 return true;
402 }
403
404 bool GenerateIndividualFiles() {
405 code_.Clear();
406 // Don't bother with imports. Use absolute paths everywhere.
407 return GenerateSymbols<EnumDef>(
408 parser_.enums_, [&](const EnumDef &e) { this->GenEnum(e); }) &&
409 GenerateSymbols<StructDef>(
410 parser_.structs_, [&](const StructDef &s) {
411 if (s.fixed) {
412 this->GenStruct(s);
413 } else {
414 this->GenTable(s);
415 if (this->parser_.opts.generate_object_based_api) {
416 this->GenTableObject(s);
417 }
418 }
419 if (this->parser_.root_struct_def_ == &s) {
420 this->GenRootTableFuncs(s);
421 }
422 });
423 }
424
425 // Generates code organized by .fbs files. This is broken legacy behavior
426 // that does not work with multiple fbs files with shared namespaces.
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700427 // Iterate through all definitions we haven't generated code for (enums,
428 // structs, and tables) and output them to a single file.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700429 bool GenerateOneFile() {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700430 code_.Clear();
431 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700432 code_ += "// @generated";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700433
434 assert(!cur_name_space_);
435
436 // Generate imports for the global scope in case no namespace is used
437 // in the schema file.
438 GenNamespaceImports(0);
439 code_ += "";
440
441 // Generate all code in their namespaces, once, because Rust does not
442 // permit re-opening modules.
443 //
444 // TODO(rw): Use a set data structure to reduce namespace evaluations from
445 // O(n**2) to O(n).
446 for (auto ns_it = parser_.namespaces_.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800447 ns_it != parser_.namespaces_.end(); ++ns_it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700448 const auto &ns = *ns_it;
449
450 // Generate code for all the enum declarations.
451 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
452 ++it) {
453 const auto &enum_def = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700454 if (enum_def.defined_namespace == ns && !enum_def.generated) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700455 SetNameSpace(enum_def.defined_namespace);
456 GenEnum(enum_def);
457 }
458 }
459
460 // Generate code for all structs.
461 for (auto it = parser_.structs_.vec.begin();
462 it != parser_.structs_.vec.end(); ++it) {
463 const auto &struct_def = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700464 if (struct_def.defined_namespace == ns && struct_def.fixed &&
465 !struct_def.generated) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700466 SetNameSpace(struct_def.defined_namespace);
467 GenStruct(struct_def);
468 }
469 }
470
471 // Generate code for all tables.
472 for (auto it = parser_.structs_.vec.begin();
473 it != parser_.structs_.vec.end(); ++it) {
474 const auto &struct_def = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700475 if (struct_def.defined_namespace == ns && !struct_def.fixed &&
476 !struct_def.generated) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700477 SetNameSpace(struct_def.defined_namespace);
478 GenTable(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700479 if (parser_.opts.generate_object_based_api) {
480 GenTableObject(struct_def);
481 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700482 }
483 }
484
485 // Generate global helper functions.
486 if (parser_.root_struct_def_) {
487 auto &struct_def = *parser_.root_struct_def_;
488 if (struct_def.defined_namespace != ns) { continue; }
489 SetNameSpace(struct_def.defined_namespace);
490 GenRootTableFuncs(struct_def);
491 }
492 }
493 if (cur_name_space_) SetNameSpace(nullptr);
494
Austin Schuh272c6132020-11-14 16:37:52 -0800495 const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700496 const auto final_code = code_.ToString();
497 return SaveFile(file_path.c_str(), final_code, false);
498 }
499
500 private:
501 CodeWriter code_;
502
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700503 // This tracks the current namespace so we can insert namespace declarations.
504 const Namespace *cur_name_space_;
505
506 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
507
508 // Determine if a Type needs a lifetime template parameter when used in the
509 // Rust builder args.
510 bool TableBuilderTypeNeedsLifetime(const Type &type) const {
511 switch (GetFullType(type)) {
512 case ftInteger:
513 case ftFloat:
514 case ftBool:
515 case ftEnumKey:
516 case ftUnionKey:
Austin Schuh272c6132020-11-14 16:37:52 -0800517 case ftUnionValue: {
518 return false;
519 }
520 default: {
521 return true;
522 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700523 }
524 }
525
526 // Determine if a table args rust type needs a lifetime template parameter.
527 bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
528 FLATBUFFERS_ASSERT(!struct_def.fixed);
529
530 for (auto it = struct_def.fields.vec.begin();
531 it != struct_def.fields.vec.end(); ++it) {
532 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -0800533 if (field.deprecated) { continue; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700534
Austin Schuh272c6132020-11-14 16:37:52 -0800535 if (TableBuilderTypeNeedsLifetime(field.value.type)) { return true; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700536 }
537
538 return false;
539 }
540
Austin Schuh2dd86a92022-09-14 21:19:23 -0700541 std::string NamespacedNativeName(const EnumDef &def) {
542 return WrapInNameSpace(def.defined_namespace, namer_.ObjectType(def));
543 }
544 std::string NamespacedNativeName(const StructDef &def) {
545 return WrapInNameSpace(def.defined_namespace, namer_.ObjectType(def));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700546 }
547
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700548 std::string WrapInNameSpace(const Definition &def) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700549 return WrapInNameSpace(def.defined_namespace,
550 namer_.EscapeKeyword(def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700551 }
552 std::string WrapInNameSpace(const Namespace *ns,
553 const std::string &name) const {
554 if (CurrentNameSpace() == ns) return name;
555 std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
556 return prefix + name;
557 }
558
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700559 // Determine the relative namespace traversal needed to reference one
560 // namespace from another namespace. This is useful because it does not force
561 // the user to have a particular file layout. (If we output absolute
562 // namespace paths, that may require users to organize their Rust crates in a
563 // particular way.)
564 std::string GetRelativeNamespaceTraversal(const Namespace *src,
565 const Namespace *dst) const {
566 // calculate the path needed to reference dst from src.
567 // example: f(A::B::C, A::B::C) -> (none)
568 // example: f(A::B::C, A::B) -> super::
569 // example: f(A::B::C, A::B::D) -> super::D
570 // example: f(A::B::C, A) -> super::super::
571 // example: f(A::B::C, D) -> super::super::super::D
572 // example: f(A::B::C, D::E) -> super::super::super::D::E
573 // example: f(A, D::E) -> super::D::E
574 // does not include leaf object (typically a struct type).
575
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700576 std::stringstream stream;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700577 size_t common = 0;
578 std::vector<std::string> s, d;
579 if (src) s = src->components;
580 if (dst) d = dst->components;
581 while (common < s.size() && common < d.size() && s[common] == d[common])
582 common++;
583 // If src namespace is empty, this must be an absolute path.
584 for (size_t i = common; i < s.size(); i++) stream << "super::";
585 for (size_t i = common; i < d.size(); i++)
586 stream << namer_.Namespace(d[i]) + "::";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700587 return stream.str();
588 }
589
590 // Generate a comment from the schema.
591 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700592 for (auto it = dc.begin(); it != dc.end(); it++) {
593 code_ += std::string(prefix) + "///" + *it;
594 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700595 }
596
597 // Return a Rust type from the table in idl.h.
598 std::string GetTypeBasic(const Type &type) const {
599 switch (GetFullType(type)) {
600 case ftInteger:
601 case ftFloat:
602 case ftBool:
603 case ftEnumKey:
Austin Schuh272c6132020-11-14 16:37:52 -0800604 case ftUnionKey: {
605 break;
606 }
607 default: {
608 FLATBUFFERS_ASSERT(false && "incorrect type given");
609 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700610 }
611
612 // clang-format off
613 static const char * const ctypename[] = {
614 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -0800615 RTYPE, ...) \
616 #RTYPE,
617 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700618 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700619 };
Austin Schuh272c6132020-11-14 16:37:52 -0800620 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700621
622 if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
623 return ctypename[type.base_type];
624 }
625
626 // Look up the native type for an enum. This will always be an integer like
627 // u8, i32, etc.
628 std::string GetEnumTypeForDecl(const Type &type) {
629 const auto ft = GetFullType(type);
630 if (!(ft == ftEnumKey || ft == ftUnionKey)) {
631 FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
632 }
633
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700634 // clang-format off
Austin Schuh272c6132020-11-14 16:37:52 -0800635 static const char *ctypename[] = {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700636 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -0800637 RTYPE, ...) \
638 #RTYPE,
639 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700640 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700641 };
Austin Schuh272c6132020-11-14 16:37:52 -0800642 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700643
644 // Enums can be bools, but their Rust representation must be a u8, as used
645 // in the repr attribute (#[repr(bool)] is an invalid attribute).
646 if (type.base_type == BASE_TYPE_BOOL) return "u8";
647 return ctypename[type.base_type];
648 }
649
650 // Return a Rust type for any type (scalar, table, struct) specifically for
651 // using a FlatBuffer.
652 std::string GetTypeGet(const Type &type) const {
653 switch (GetFullType(type)) {
654 case ftInteger:
655 case ftFloat:
656 case ftBool:
657 case ftEnumKey:
658 case ftUnionKey: {
Austin Schuh272c6132020-11-14 16:37:52 -0800659 return GetTypeBasic(type);
660 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700661 case ftArrayOfBuiltin:
662 case ftArrayOfEnum:
663 case ftArrayOfStruct: {
664 return "[" + GetTypeGet(type.VectorType()) + "; " +
665 NumToString(type.fixed_length) + "]";
666 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700667 case ftTable: {
668 return WrapInNameSpace(type.struct_def->defined_namespace,
Austin Schuh272c6132020-11-14 16:37:52 -0800669 type.struct_def->name) +
670 "<'a>";
671 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700672 default: {
673 return WrapInNameSpace(type.struct_def->defined_namespace,
Austin Schuh272c6132020-11-14 16:37:52 -0800674 type.struct_def->name);
675 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700676 }
677 }
678
Austin Schuh272c6132020-11-14 16:37:52 -0800679 std::string GetEnumValue(const EnumDef &enum_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700680 const EnumVal &enum_val) const {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700681 return namer_.EnumVariant(enum_def, enum_val);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700682 }
683
Austin Schuh272c6132020-11-14 16:37:52 -0800684 // 1 suffix since old C++ can't figure out the overload.
685 void ForAllEnumValues1(const EnumDef &enum_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700686 std::function<void(const EnumVal &)> cb) {
Austin Schuh272c6132020-11-14 16:37:52 -0800687 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
688 const auto &ev = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700689 code_.SetValue("VARIANT", namer_.Variant(ev));
Austin Schuh272c6132020-11-14 16:37:52 -0800690 code_.SetValue("VALUE", enum_def.ToString(ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700691 code_.IncrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -0800692 cb(ev);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700693 code_.DecrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -0800694 }
695 }
696 void ForAllEnumValues(const EnumDef &enum_def, std::function<void()> cb) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700697 std::function<void(const EnumVal &)> wrapped = [&](const EnumVal &unused) {
698 (void)unused;
699 cb();
700 };
701 ForAllEnumValues1(enum_def, wrapped);
Austin Schuh272c6132020-11-14 16:37:52 -0800702 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700703 // Generate an enum declaration,
704 // an enum string lookup table,
705 // an enum match function,
706 // and an enum array of values
707 void GenEnum(const EnumDef &enum_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700708 const bool is_private = parser_.opts.no_leak_private_annotations &&
709 (enum_def.attributes.Lookup("private") != nullptr);
710 code_.SetValue("ACCESS_TYPE", is_private ? "pub(crate)" : "pub");
711 code_.SetValue("ENUM_TY", namer_.Type(enum_def));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700712 code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700713 code_.SetValue("ENUM_NAMESPACE", namer_.Namespace(enum_def.name));
714 code_.SetValue("ENUM_CONSTANT", namer_.Constant(enum_def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700715 const EnumVal *minv = enum_def.MinValue();
716 const EnumVal *maxv = enum_def.MaxValue();
717 FLATBUFFERS_ASSERT(minv && maxv);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700718 code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
719 code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
720
Austin Schuh272c6132020-11-14 16:37:52 -0800721 if (IsBitFlagsEnum(enum_def)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700722 // Defer to the convenient and canonical bitflags crate. We declare it in
723 // a module to #allow camel case constants in a smaller scope. This
724 // matches Flatbuffers c-modeled enums where variants are associated
725 // constants but in camel case.
Austin Schuh272c6132020-11-14 16:37:52 -0800726 code_ += "#[allow(non_upper_case_globals)]";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700727 code_ += "mod bitflags_{{ENUM_NAMESPACE}} {";
Austin Schuh272c6132020-11-14 16:37:52 -0800728 code_ += " flatbuffers::bitflags::bitflags! {";
729 GenComment(enum_def.doc_comment, " ");
James Kuszmaul8e62b022022-03-22 09:33:25 -0700730 code_ += " #[derive(Default)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700731 code_ += " {{ACCESS_TYPE}} struct {{ENUM_TY}}: {{BASE_TYPE}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700732 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
733 this->GenComment(ev.doc_comment, " ");
734 code_ += " const {{VARIANT}} = {{VALUE}};";
Austin Schuh272c6132020-11-14 16:37:52 -0800735 });
736 code_ += " }";
737 code_ += " }";
738 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700739 code_ += "pub use self::bitflags_{{ENUM_NAMESPACE}}::{{ENUM_TY}};";
Austin Schuh272c6132020-11-14 16:37:52 -0800740 code_ += "";
741
James Kuszmaul8e62b022022-03-22 09:33:25 -0700742 code_.SetValue("INTO_BASE", "self.bits()");
743 } else {
744 // Normal, c-modelled enums.
745 // Deprecated associated constants;
746 const std::string deprecation_warning =
747 "#[deprecated(since = \"2.0.0\", note = \"Use associated constants"
748 " instead. This will no longer be generated in 2021.\")]";
749 code_ += deprecation_warning;
750 code_ +=
751 "pub const ENUM_MIN_{{ENUM_CONSTANT}}: {{BASE_TYPE}}"
752 " = {{ENUM_MIN_BASE_VALUE}};";
753 code_ += deprecation_warning;
754 code_ +=
755 "pub const ENUM_MAX_{{ENUM_CONSTANT}}: {{BASE_TYPE}}"
756 " = {{ENUM_MAX_BASE_VALUE}};";
757 auto num_fields = NumToString(enum_def.size());
758 code_ += deprecation_warning;
759 code_ += "#[allow(non_camel_case_types)]";
760 code_ += "pub const ENUM_VALUES_{{ENUM_CONSTANT}}: [{{ENUM_TY}}; " +
761 num_fields + "] = [";
762 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700763 code_ += namer_.EnumVariant(enum_def, ev) + ",";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700764 });
765 code_ += "];";
Austin Schuh272c6132020-11-14 16:37:52 -0800766 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700767
768 GenComment(enum_def.doc_comment);
769 // Derive Default to be 0. flatc enforces this when the enum
770 // is put into a struct, though this isn't documented behavior, it is
771 // needed to derive defaults in struct objects.
772 code_ +=
773 "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, "
774 "Default)]";
775 code_ += "#[repr(transparent)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700776 code_ += "{{ACCESS_TYPE}} struct {{ENUM_TY}}(pub {{BASE_TYPE}});";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700777 code_ += "#[allow(non_upper_case_globals)]";
778 code_ += "impl {{ENUM_TY}} {";
779 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
780 this->GenComment(ev.doc_comment);
781 code_ += "pub const {{VARIANT}}: Self = Self({{VALUE}});";
782 });
783 code_ += "";
784 // Generate Associated constants
785 code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};";
786 code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};";
787 code_ += " pub const ENUM_VALUES: &'static [Self] = &[";
788 ForAllEnumValues(enum_def, [&]() { code_ += " Self::{{VARIANT}},"; });
789 code_ += " ];";
790 code_ += " /// Returns the variant's name or \"\" if unknown.";
791 code_ += " pub fn variant_name(self) -> Option<&'static str> {";
792 code_ += " match self {";
793 ForAllEnumValues(enum_def, [&]() {
794 code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),";
795 });
796 code_ += " _ => None,";
Austin Schuh272c6132020-11-14 16:37:52 -0800797 code_ += " }";
Austin Schuh272c6132020-11-14 16:37:52 -0800798 code_ += " }";
799 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700800
801 // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>".
Austin Schuh2dd86a92022-09-14 21:19:23 -0700802 code_ += "impl core::fmt::Debug for {{ENUM_TY}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700803 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -0700804 " fn fmt(&self, f: &mut core::fmt::Formatter) ->"
805 " core::fmt::Result {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700806 code_ += " if let Some(name) = self.variant_name() {";
807 code_ += " f.write_str(name)";
808 code_ += " } else {";
809 code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))";
810 code_ += " }";
811 code_ += " }";
812 code_ += "}";
813
James Kuszmaul8e62b022022-03-22 09:33:25 -0700814 code_.SetValue("INTO_BASE", "self.0");
Austin Schuh272c6132020-11-14 16:37:52 -0800815 }
816
James Kuszmaul8e62b022022-03-22 09:33:25 -0700817 // Implement serde::Serialize
818 if (parser_.opts.rust_serialize) {
819 code_ += "impl Serialize for {{ENUM_TY}} {";
820 code_ +=
821 " fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
822 code_ += " where";
823 code_ += " S: Serializer,";
824 code_ += " {";
825 if (IsBitFlagsEnum(enum_def)) {
826 code_ += " serializer.serialize_u32(self.bits() as u32)";
827 } else {
828 code_ +=
829 " serializer.serialize_unit_variant(\"{{ENUM_TY}}\", self.0 "
830 "as "
831 "u32, self.variant_name().unwrap())";
832 }
833 code_ += " }";
834 code_ += "}";
835 code_ += "";
836 }
Austin Schuh272c6132020-11-14 16:37:52 -0800837
838 // Generate Follow and Push so we can serialize and stuff.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700839 code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_TY}} {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700840 code_ += " type Inner = Self;";
841 code_ += " #[inline]";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800842 code_ += " unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
843 code_ += " let b = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc);";
844 if (IsBitFlagsEnum(enum_def)) {
845 // Safety:
846 // This is safe because we know bitflags is implemented with a repr transparent uint of the correct size.
847 // from_bits_unchecked will be replaced by an equivalent but safe from_bits_retain in bitflags 2.0
848 // https://github.com/bitflags/bitflags/issues/262
849 code_ += " // Safety:";
850 code_ += " // This is safe because we know bitflags is implemented with a repr transparent uint of the correct size.";
851 code_ += " // from_bits_unchecked will be replaced by an equivalent but safe from_bits_retain in bitflags 2.0";
852 code_ += " // https://github.com/bitflags/bitflags/issues/262";
853 code_ += " Self::from_bits_unchecked(b)";
854 } else {
855 code_ += " Self(b)";
856 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700857 code_ += " }";
858 code_ += "}";
859 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700860 code_ += "impl flatbuffers::Push for {{ENUM_TY}} {";
861 code_ += " type Output = {{ENUM_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700862 code_ += " #[inline]";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800863 code_ += " unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {";
864 code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>(dst, {{INTO_BASE}});";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700865 code_ += " }";
866 code_ += "}";
867 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700868 code_ += "impl flatbuffers::EndianScalar for {{ENUM_TY}} {";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800869 code_ += " type Scalar = {{BASE_TYPE}};";
Austin Schuh272c6132020-11-14 16:37:52 -0800870 code_ += " #[inline]";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800871 code_ += " fn to_little_endian(self) -> {{BASE_TYPE}} {";
872 code_ += " {{INTO_BASE}}.to_le()";
Austin Schuh272c6132020-11-14 16:37:52 -0800873 code_ += " }";
874 code_ += " #[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700875 code_ += " #[allow(clippy::wrong_self_convention)]";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800876 code_ += " fn from_little_endian(v: {{BASE_TYPE}}) -> Self {";
877 code_ += " let b = {{BASE_TYPE}}::from_le(v);";
878 if (IsBitFlagsEnum(enum_def)) {
879 // Safety:
880 // This is safe because we know bitflags is implemented with a repr transparent uint of the correct size.
881 // from_bits_unchecked will be replaced by an equivalent but safe from_bits_retain in bitflags 2.0
882 // https://github.com/bitflags/bitflags/issues/262
883 code_ += " // Safety:";
884 code_ += " // This is safe because we know bitflags is implemented with a repr transparent uint of the correct size.";
885 code_ += " // from_bits_unchecked will be replaced by an equivalent but safe from_bits_retain in bitflags 2.0";
886 code_ += " // https://github.com/bitflags/bitflags/issues/262";
887 code_ += " unsafe { Self::from_bits_unchecked(b) }";
888 } else {
889 code_ += " Self(b)";
890 }
Austin Schuh272c6132020-11-14 16:37:52 -0800891 code_ += " }";
892 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700893 code_ += "";
894
James Kuszmaul8e62b022022-03-22 09:33:25 -0700895 // Generate verifier - deferring to the base type.
896 code_ += "impl<'a> flatbuffers::Verifiable for {{ENUM_TY}} {";
897 code_ += " #[inline]";
898 code_ += " fn run_verifier(";
899 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
900 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
901 code_ += " use self::flatbuffers::Verifiable;";
902 code_ += " {{BASE_TYPE}}::run_verifier(v, pos)";
903 code_ += " }";
904 code_ += "}";
905 code_ += "";
906 // Enums are basically integers.
907 code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{ENUM_TY}} {}";
908
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700909 if (enum_def.is_union) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700910 // Generate typesafe offset(s) for unions
Austin Schuh2dd86a92022-09-14 21:19:23 -0700911 code_.SetValue("UNION_TYPE", namer_.Type(enum_def));
912 code_ += "{{ACCESS_TYPE}} struct {{UNION_TYPE}}UnionTableOffset {}";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700913 code_ += "";
914 if (parser_.opts.generate_object_based_api) { GenUnionObject(enum_def); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700915 }
916 }
917
James Kuszmaul8e62b022022-03-22 09:33:25 -0700918 // TODO(cneo): dedup Object versions from non object versions.
919 void ForAllUnionObjectVariantsBesidesNone(const EnumDef &enum_def,
920 std::function<void()> cb) {
921 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
922 auto &enum_val = **it;
923 if (enum_val.union_type.base_type == BASE_TYPE_NONE) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700924 code_.SetValue("VARIANT_NAME", namer_.Variant(enum_val));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700925 // For legacy reasons, enum variants are Keep case while enum native
926 // variants are UpperCamel case.
Austin Schuh2dd86a92022-09-14 21:19:23 -0700927 code_.SetValue("NATIVE_VARIANT",
928 namer_.LegacyRustNativeVariant(enum_val));
929 code_.SetValue("U_ELEMENT_NAME", namer_.Method(enum_val));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700930 code_.SetValue("U_ELEMENT_TABLE_TYPE",
931 NamespacedNativeName(*enum_val.union_type.struct_def));
932 code_.IncrementIdentLevel();
933 cb();
934 code_.DecrementIdentLevel();
935 }
936 }
937 void GenUnionObject(const EnumDef &enum_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700938 code_.SetValue("ENUM_TY", namer_.Type(enum_def));
939 code_.SetValue("ENUM_FN", namer_.Function(enum_def));
940 code_.SetValue("ENUM_OTY", namer_.ObjectType(enum_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700941
942 // Generate native union.
943 code_ += "#[allow(clippy::upper_case_acronyms)]"; // NONE's spelling is
944 // intended.
945 code_ += "#[non_exhaustive]";
946 code_ += "#[derive(Debug, Clone, PartialEq)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700947 code_ += "{{ACCESS_TYPE}} enum {{ENUM_OTY}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700948 code_ += " NONE,";
949 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
950 code_ += "{{NATIVE_VARIANT}}(Box<{{U_ELEMENT_TABLE_TYPE}}>),";
951 });
952 code_ += "}";
953 // Generate Default (NONE).
954 code_ += "impl Default for {{ENUM_OTY}} {";
955 code_ += " fn default() -> Self {";
956 code_ += " Self::NONE";
957 code_ += " }";
958 code_ += "}";
959
960 // Generate native union methods.
961 code_ += "impl {{ENUM_OTY}} {";
962
963 // Get flatbuffers union key.
964 // TODO(cneo): add docstrings?
965 code_ += " pub fn {{ENUM_FN}}_type(&self) -> {{ENUM_TY}} {";
966 code_ += " match self {";
967 code_ += " Self::NONE => {{ENUM_TY}}::NONE,";
968 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
969 code_ +=
970 " Self::{{NATIVE_VARIANT}}(_) => {{ENUM_TY}}::"
971 "{{VARIANT_NAME}},";
972 });
973 code_ += " }";
974 code_ += " }";
975 // Pack flatbuffers union value
976 code_ +=
977 " pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder)"
978 " -> Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>"
979 " {";
980 code_ += " match self {";
981 code_ += " Self::NONE => None,";
982 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
983 code_ += " Self::{{NATIVE_VARIANT}}(v) => \\";
984 code_ += "Some(v.pack(fbb).as_union_value()),";
985 });
986 code_ += " }";
987 code_ += " }";
988
989 // Generate some accessors;
990 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
991 // Move accessor.
992 code_ +=
993 "/// If the union variant matches, return the owned "
994 "{{U_ELEMENT_TABLE_TYPE}}, setting the union to NONE.";
995 code_ +=
996 "pub fn take_{{U_ELEMENT_NAME}}(&mut self) -> "
997 "Option<Box<{{U_ELEMENT_TABLE_TYPE}}>> {";
998 code_ += " if let Self::{{NATIVE_VARIANT}}(_) = self {";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700999 code_ += " let v = core::mem::replace(self, Self::NONE);";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001000 code_ += " if let Self::{{NATIVE_VARIANT}}(w) = v {";
1001 code_ += " Some(w)";
1002 code_ += " } else {";
1003 code_ += " unreachable!()";
1004 code_ += " }";
1005 code_ += " } else {";
1006 code_ += " None";
1007 code_ += " }";
1008 code_ += "}";
1009 // Immutable reference accessor.
1010 code_ +=
1011 "/// If the union variant matches, return a reference to the "
1012 "{{U_ELEMENT_TABLE_TYPE}}.";
1013 code_ +=
1014 "pub fn as_{{U_ELEMENT_NAME}}(&self) -> "
1015 "Option<&{{U_ELEMENT_TABLE_TYPE}}> {";
1016 code_ +=
1017 " if let Self::{{NATIVE_VARIANT}}(v) = self "
1018 "{ Some(v.as_ref()) } else { None }";
1019 code_ += "}";
1020 // Mutable reference accessor.
1021 code_ +=
1022 "/// If the union variant matches, return a mutable reference"
1023 " to the {{U_ELEMENT_TABLE_TYPE}}.";
1024 code_ +=
1025 "pub fn as_{{U_ELEMENT_NAME}}_mut(&mut self) -> "
1026 "Option<&mut {{U_ELEMENT_TABLE_TYPE}}> {";
1027 code_ +=
1028 " if let Self::{{NATIVE_VARIANT}}(v) = self "
1029 "{ Some(v.as_mut()) } else { None }";
1030 code_ += "}";
1031 });
1032 code_ += "}"; // End union methods impl.
1033 }
1034
James Kuszmaul8e62b022022-03-22 09:33:25 -07001035 enum DefaultContext { kBuilder, kAccessor, kObject };
1036 std::string GetDefaultValue(const FieldDef &field,
1037 const DefaultContext context) {
1038 if (context == kBuilder) {
1039 // Builders and Args structs model nonscalars "optional" even if they're
1040 // required or have defaults according to the schema. I guess its because
1041 // WIPOffset is not nullable.
1042 if (!IsScalar(field.value.type.base_type) || field.IsOptional()) {
1043 return "None";
1044 }
1045 } else {
1046 // This for defaults in objects.
1047 // Unions have a NONE variant instead of using Rust's None.
1048 if (field.IsOptional() && !IsUnion(field.value.type)) { return "None"; }
1049 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001050 switch (GetFullType(field.value.type)) {
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001051 case ftInteger: {
1052 return field.value.constant;
1053 }
Austin Schuh272c6132020-11-14 16:37:52 -08001054 case ftFloat: {
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001055 const std::string float_prefix =
1056 (field.value.type.base_type == BASE_TYPE_FLOAT) ? "f32::" : "f64::";
1057 if (StringIsFlatbufferNan(field.value.constant)) {
1058 return float_prefix + "NAN";
1059 } else if (StringIsFlatbufferPositiveInfinity(field.value.constant)) {
1060 return float_prefix + "INFINITY";
1061 } else if (StringIsFlatbufferNegativeInfinity(field.value.constant)) {
1062 return float_prefix + "NEG_INFINITY";
1063 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001064 return field.value.constant;
Austin Schuh272c6132020-11-14 16:37:52 -08001065 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001066 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001067 return field.value.constant == "0" ? "false" : "true";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001068 }
1069 case ftUnionKey:
1070 case ftEnumKey: {
1071 auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001072 if (!ev) return "Default::default()"; // Bitflags enum.
1073 return WrapInNameSpace(
1074 field.value.type.enum_def->defined_namespace,
Austin Schuh2dd86a92022-09-14 21:19:23 -07001075 namer_.EnumVariant(*field.value.type.enum_def, *ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001076 }
1077 case ftUnionValue: {
1078 return ObjectFieldType(field, true) + "::NONE";
1079 }
1080 case ftString: {
1081 // Required fields do not have defaults defined by the schema, but we
1082 // need one for Rust's Default trait so we use empty string. The usual
1083 // value of field.value.constant is `0`, which is non-sensical except
1084 // maybe to c++ (nullptr == 0).
1085 // TODO: Escape strings?
1086 const std::string defval =
1087 field.IsRequired() ? "\"\"" : "\"" + field.value.constant + "\"";
1088 if (context == kObject) return defval + ".to_string()";
1089 if (context == kAccessor) return "&" + defval;
1090 FLATBUFFERS_ASSERT(false);
1091 return "INVALID_CODE_GENERATION";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001092 }
1093
James Kuszmaul8e62b022022-03-22 09:33:25 -07001094 case ftArrayOfStruct:
1095 case ftArrayOfEnum:
1096 case ftArrayOfBuiltin:
1097 case ftVectorOfBool:
1098 case ftVectorOfFloat:
1099 case ftVectorOfInteger:
1100 case ftVectorOfString:
1101 case ftVectorOfStruct:
1102 case ftVectorOfTable:
1103 case ftVectorOfEnumKey:
1104 case ftVectorOfUnionValue:
1105 case ftStruct:
1106 case ftTable: {
1107 // We only support empty vectors which matches the defaults for
1108 // &[T] and Vec<T> anyway.
1109 //
1110 // For required structs and tables fields, we defer to their object API
1111 // defaults. This works so long as there's nothing recursive happening,
1112 // but `table Infinity { i: Infinity (required); }` does compile.
1113 return "Default::default()";
Austin Schuh272c6132020-11-14 16:37:52 -08001114 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001115 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001116 FLATBUFFERS_ASSERT(false);
1117 return "INVALID_CODE_GENERATION";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001118 }
1119
1120 // Create the return type for fields in the *BuilderArgs structs that are
1121 // used to create Tables.
1122 //
1123 // Note: we could make all inputs to the BuilderArgs be an Option, as well
1124 // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
1125 // know if the value is default or not, because there are three ways to
1126 // return a default value:
1127 // 1) return a stored value that happens to be the default,
1128 // 2) return a hardcoded value because the relevant vtable field is not in
1129 // the vtable, or
1130 // 3) return a hardcoded value because the vtable field value is set to zero.
1131 std::string TableBuilderArgsDefnType(const FieldDef &field,
1132 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -08001133 const Type &type = field.value.type;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001134 auto WrapOption = [&](std::string s) {
1135 return IsOptionalToBuilder(field) ? "Option<" + s + ">" : s;
1136 };
1137 auto WrapVector = [&](std::string ty) {
1138 return WrapOption("flatbuffers::WIPOffset<flatbuffers::Vector<" +
1139 lifetime + ", " + ty + ">>");
1140 };
1141 auto WrapUOffsetsVector = [&](std::string ty) {
1142 return WrapVector("flatbuffers::ForwardsUOffset<" + ty + ">");
1143 };
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001144
1145 switch (GetFullType(type)) {
1146 case ftInteger:
1147 case ftFloat:
1148 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001149 return WrapOption(GetTypeBasic(type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001150 }
1151 case ftStruct: {
1152 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001153 return WrapOption("&" + lifetime + " " + typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001154 }
1155 case ftTable: {
1156 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001157 return WrapOption("flatbuffers::WIPOffset<" + typname + "<" + lifetime +
1158 ">>");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001159 }
1160 case ftString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001161 return WrapOption("flatbuffers::WIPOffset<&" + lifetime + " str>");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001162 }
1163 case ftEnumKey:
1164 case ftUnionKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001165 return WrapOption(WrapInNameSpace(*type.enum_def));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001166 }
1167 case ftUnionValue: {
1168 return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
1169 }
1170
1171 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001172 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001173 case ftVectorOfFloat: {
1174 const auto typname = GetTypeBasic(type.VectorType());
James Kuszmaul8e62b022022-03-22 09:33:25 -07001175 return WrapVector(typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001176 }
1177 case ftVectorOfEnumKey: {
1178 const auto typname = WrapInNameSpace(*type.enum_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001179 return WrapVector(typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001180 }
1181 case ftVectorOfStruct: {
1182 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001183 return WrapVector(typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001184 }
1185 case ftVectorOfTable: {
1186 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001187 return WrapUOffsetsVector(typname + "<" + lifetime + ">");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001188 }
1189 case ftVectorOfString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001190 return WrapUOffsetsVector("&" + lifetime + " str");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001191 }
1192 case ftVectorOfUnionValue: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001193 return WrapUOffsetsVector("flatbuffers::Table<" + lifetime + ">");
1194 }
1195 case ftArrayOfEnum:
1196 case ftArrayOfStruct:
1197 case ftArrayOfBuiltin: {
1198 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1199 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001200 }
1201 }
Austin Schuh272c6132020-11-14 16:37:52 -08001202 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001203 }
1204
James Kuszmaul8e62b022022-03-22 09:33:25 -07001205 std::string ObjectFieldType(const FieldDef &field, bool in_a_table) {
1206 const Type &type = field.value.type;
1207 std::string ty;
1208 switch (GetFullType(type)) {
1209 case ftInteger:
1210 case ftBool:
1211 case ftFloat: {
1212 ty = GetTypeBasic(type);
1213 break;
1214 }
1215 case ftString: {
1216 ty = "String";
1217 break;
1218 }
1219 case ftStruct: {
1220 ty = NamespacedNativeName(*type.struct_def);
1221 break;
1222 }
1223 case ftTable: {
1224 // Since Tables can contain themselves, Box is required to avoid
1225 // infinite types.
1226 ty = "Box<" + NamespacedNativeName(*type.struct_def) + ">";
1227 break;
1228 }
1229 case ftUnionKey: {
1230 // There is no native "UnionKey", natively, unions are rust enums with
1231 // newtype-struct-variants.
1232 return "INVALID_CODE_GENERATION";
1233 }
1234 case ftUnionValue: {
1235 ty = NamespacedNativeName(*type.enum_def);
1236 break;
1237 }
1238 case ftEnumKey: {
1239 ty = WrapInNameSpace(*type.enum_def);
1240 break;
1241 }
1242 // Vectors are in tables and are optional
1243 case ftVectorOfEnumKey: {
1244 ty = "Vec<" + WrapInNameSpace(*type.VectorType().enum_def) + ">";
1245 break;
1246 }
1247 case ftVectorOfInteger:
1248 case ftVectorOfBool:
1249 case ftVectorOfFloat: {
1250 ty = "Vec<" + GetTypeBasic(type.VectorType()) + ">";
1251 break;
1252 }
1253 case ftVectorOfString: {
1254 ty = "Vec<String>";
1255 break;
1256 }
1257 case ftVectorOfTable:
1258 case ftVectorOfStruct: {
1259 ty = NamespacedNativeName(*type.VectorType().struct_def);
1260 ty = "Vec<" + ty + ">";
1261 break;
1262 }
1263 case ftVectorOfUnionValue: {
1264 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1265 return "INVALID_CODE_GENERATION"; // OH NO!
1266 }
1267 case ftArrayOfEnum: {
1268 ty = "[" + WrapInNameSpace(*type.VectorType().enum_def) + "; " +
1269 NumToString(type.fixed_length) + "]";
1270 break;
1271 }
1272 case ftArrayOfStruct: {
1273 ty = "[" + NamespacedNativeName(*type.VectorType().struct_def) + "; " +
1274 NumToString(type.fixed_length) + "]";
1275 break;
1276 }
1277 case ftArrayOfBuiltin: {
1278 ty = "[" + GetTypeBasic(type.VectorType()) + "; " +
1279 NumToString(type.fixed_length) + "]";
1280 break;
1281 }
1282 }
1283 if (in_a_table && !IsUnion(type) && field.IsOptional()) {
1284 return "Option<" + ty + ">";
1285 } else {
1286 return ty;
1287 }
1288 }
1289
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001290 std::string TableBuilderArgsAddFuncType(const FieldDef &field,
1291 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -08001292 const Type &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001293
1294 switch (GetFullType(field.value.type)) {
1295 case ftVectorOfStruct: {
1296 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001297 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1298 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001299 }
1300 case ftVectorOfTable: {
1301 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001302 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1303 ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
1304 ">>>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001305 }
1306 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001307 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001308 case ftVectorOfFloat: {
1309 const auto typname = GetTypeBasic(type.VectorType());
Austin Schuh272c6132020-11-14 16:37:52 -08001310 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1311 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001312 }
1313 case ftVectorOfString: {
Austin Schuh272c6132020-11-14 16:37:52 -08001314 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001315 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
1316 }
1317 case ftVectorOfEnumKey: {
1318 const auto typname = WrapInNameSpace(*type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001319 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1320 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001321 }
1322 case ftVectorOfUnionValue: {
Austin Schuh272c6132020-11-14 16:37:52 -08001323 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1324 ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + lifetime +
1325 ">>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001326 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001327 case ftEnumKey:
1328 case ftUnionKey: {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001329 const auto typname = WrapInNameSpace(*type.enum_def);
1330 return typname;
1331 }
1332 case ftStruct: {
1333 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001334 return "&" + typname + "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001335 }
1336 case ftTable: {
1337 const auto typname = WrapInNameSpace(*type.struct_def);
1338 return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
1339 }
1340 case ftInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001341 case ftBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001342 case ftFloat: {
Austin Schuh272c6132020-11-14 16:37:52 -08001343 return GetTypeBasic(type);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001344 }
1345 case ftString: {
1346 return "flatbuffers::WIPOffset<&" + lifetime + " str>";
1347 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001348 case ftUnionValue: {
1349 return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
1350 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001351 case ftArrayOfBuiltin: {
1352 const auto typname = GetTypeBasic(type.VectorType());
1353 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1354 NumToString(type.fixed_length) + ">";
1355 }
1356 case ftArrayOfEnum: {
1357 const auto typname = WrapInNameSpace(*type.enum_def);
1358 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1359 NumToString(type.fixed_length) + ">";
1360 }
1361 case ftArrayOfStruct: {
1362 const auto typname = WrapInNameSpace(*type.struct_def);
1363 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1364 NumToString(type.fixed_length) + ">";
1365 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001366 }
1367
Austin Schuh272c6132020-11-14 16:37:52 -08001368 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001369 }
1370
1371 std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
Austin Schuh272c6132020-11-14 16:37:52 -08001372 const Type &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001373
1374 switch (GetFullType(field.value.type)) {
1375 case ftInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001376 case ftBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001377 case ftFloat: {
1378 const auto typname = GetTypeBasic(field.value.type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001379 return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
1380 : "self.fbb_.push_slot::<") +
Austin Schuh272c6132020-11-14 16:37:52 -08001381 typname + ">";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001382 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001383 case ftEnumKey:
1384 case ftUnionKey: {
1385 const auto underlying_typname = GetTypeBasic(type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001386 return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
1387 : "self.fbb_.push_slot::<") +
1388 underlying_typname + ">";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001389 }
1390
1391 case ftStruct: {
1392 const std::string typname = WrapInNameSpace(*type.struct_def);
1393 return "self.fbb_.push_slot_always::<&" + typname + ">";
1394 }
1395 case ftTable: {
1396 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001397 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" +
1398 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001399 }
1400
1401 case ftUnionValue:
1402 case ftString:
1403 case ftVectorOfInteger:
1404 case ftVectorOfFloat:
1405 case ftVectorOfBool:
1406 case ftVectorOfEnumKey:
1407 case ftVectorOfStruct:
1408 case ftVectorOfTable:
1409 case ftVectorOfString:
1410 case ftVectorOfUnionValue: {
1411 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
1412 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001413 case ftArrayOfEnum:
1414 case ftArrayOfStruct:
1415 case ftArrayOfBuiltin: {
1416 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1417 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1418 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001419 }
Austin Schuh272c6132020-11-14 16:37:52 -08001420 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001421 }
1422
1423 std::string GenTableAccessorFuncReturnType(const FieldDef &field,
1424 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -08001425 const Type &type = field.value.type;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001426 const auto WrapOption = [&](std::string s) {
1427 return field.IsOptional() ? "Option<" + s + ">" : s;
1428 };
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001429
1430 switch (GetFullType(field.value.type)) {
1431 case ftInteger:
1432 case ftFloat:
1433 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001434 return WrapOption(GetTypeBasic(type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001435 }
1436 case ftStruct: {
1437 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001438 return WrapOption("&" + lifetime + " " + typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001439 }
1440 case ftTable: {
1441 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001442 return WrapOption(typname + "<" + lifetime + ">");
Austin Schuh272c6132020-11-14 16:37:52 -08001443 }
1444 case ftEnumKey:
1445 case ftUnionKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001446 return WrapOption(WrapInNameSpace(*type.enum_def));
Austin Schuh272c6132020-11-14 16:37:52 -08001447 }
1448
1449 case ftUnionValue: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001450 return WrapOption("flatbuffers::Table<" + lifetime + ">");
Austin Schuh272c6132020-11-14 16:37:52 -08001451 }
1452 case ftString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001453 return WrapOption("&" + lifetime + " str");
Austin Schuh272c6132020-11-14 16:37:52 -08001454 }
1455 case ftVectorOfInteger:
1456 case ftVectorOfBool:
1457 case ftVectorOfFloat: {
1458 const auto typname = GetTypeBasic(type.VectorType());
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001459 return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname + ">");
Austin Schuh272c6132020-11-14 16:37:52 -08001460 }
1461 case ftVectorOfEnumKey: {
1462 const auto typname = WrapInNameSpace(*type.enum_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001463 return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname +
1464 ">");
Austin Schuh272c6132020-11-14 16:37:52 -08001465 }
1466 case ftVectorOfStruct: {
1467 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001468 return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname + ">");
Austin Schuh272c6132020-11-14 16:37:52 -08001469 }
1470 case ftVectorOfTable: {
1471 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001472 return WrapOption("flatbuffers::Vector<" + lifetime +
1473 ", flatbuffers::ForwardsUOffset<" + typname + "<" +
1474 lifetime + ">>>");
Austin Schuh272c6132020-11-14 16:37:52 -08001475 }
1476 case ftVectorOfString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001477 return WrapOption("flatbuffers::Vector<" + lifetime +
1478 ", flatbuffers::ForwardsUOffset<&" + lifetime +
1479 " str>>");
Austin Schuh272c6132020-11-14 16:37:52 -08001480 }
1481 case ftVectorOfUnionValue: {
1482 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1483 // TODO(rw): when we do support these, we should consider using the
1484 // Into trait to convert tables to typesafe union values.
1485 return "INVALID_CODE_GENERATION"; // for return analysis
1486 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001487 case ftArrayOfEnum:
1488 case ftArrayOfStruct:
1489 case ftArrayOfBuiltin: {
1490 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1491 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1492 }
Austin Schuh272c6132020-11-14 16:37:52 -08001493 }
1494 return "INVALID_CODE_GENERATION"; // for return analysis
1495 }
1496
James Kuszmaul8e62b022022-03-22 09:33:25 -07001497 std::string FollowType(const Type &type, const std::string &lifetime) {
1498 // IsVector... This can be made iterative?
Austin Schuh272c6132020-11-14 16:37:52 -08001499
James Kuszmaul8e62b022022-03-22 09:33:25 -07001500 const auto WrapForwardsUOffset = [](std::string ty) -> std::string {
1501 return "flatbuffers::ForwardsUOffset<" + ty + ">";
1502 };
1503 const auto WrapVector = [&](std::string ty) -> std::string {
1504 return "flatbuffers::Vector<" + lifetime + ", " + ty + ">";
1505 };
1506 const auto WrapArray = [&](std::string ty, uint16_t length) -> std::string {
1507 return "flatbuffers::Array<" + lifetime + ", " + ty + ", " +
1508 NumToString(length) + ">";
1509 };
1510 switch (GetFullType(type)) {
Austin Schuh272c6132020-11-14 16:37:52 -08001511 case ftInteger:
1512 case ftFloat:
1513 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001514 return GetTypeBasic(type);
Austin Schuh272c6132020-11-14 16:37:52 -08001515 }
1516 case ftStruct: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001517 return WrapInNameSpace(*type.struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001518 }
1519 case ftUnionKey:
1520 case ftEnumKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001521 return WrapInNameSpace(*type.enum_def);
1522 }
1523 case ftTable: {
1524 const auto typname = WrapInNameSpace(*type.struct_def);
1525 return WrapForwardsUOffset(typname);
1526 }
1527 case ftUnionValue: {
1528 return WrapForwardsUOffset("flatbuffers::Table<" + lifetime + ">");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001529 }
1530 case ftString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001531 return WrapForwardsUOffset("&str");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001532 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001533 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001534 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001535 case ftVectorOfFloat: {
1536 const auto typname = GetTypeBasic(type.VectorType());
James Kuszmaul8e62b022022-03-22 09:33:25 -07001537 return WrapForwardsUOffset(WrapVector(typname));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001538 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001539 case ftVectorOfEnumKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001540 const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
1541 return WrapForwardsUOffset(WrapVector(typname));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001542 }
1543 case ftVectorOfStruct: {
1544 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001545 return WrapForwardsUOffset(WrapVector(typname));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001546 }
1547 case ftVectorOfTable: {
1548 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001549 return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(typname)));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001550 }
1551 case ftVectorOfString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001552 return WrapForwardsUOffset(
1553 WrapVector(WrapForwardsUOffset("&" + lifetime + " str")));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001554 }
1555 case ftVectorOfUnionValue: {
1556 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
Austin Schuh272c6132020-11-14 16:37:52 -08001557 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001558 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001559 case ftArrayOfEnum: {
1560 const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
1561 return WrapArray(typname, type.fixed_length);
1562 }
1563 case ftArrayOfStruct: {
1564 const auto typname = WrapInNameSpace(*type.struct_def);
1565 return WrapArray(typname, type.fixed_length);
1566 }
1567 case ftArrayOfBuiltin: {
1568 const auto typname = GetTypeBasic(type.VectorType());
1569 return WrapArray(typname, type.fixed_length);
1570 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001571 }
Austin Schuh272c6132020-11-14 16:37:52 -08001572 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001573 }
1574
James Kuszmaul8e62b022022-03-22 09:33:25 -07001575 std::string GenTableAccessorFuncBody(const FieldDef &field,
1576 const std::string &lifetime) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001577 const std::string vt_offset = namer_.LegacyRustFieldOffsetName(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001578 const std::string typname = FollowType(field.value.type, lifetime);
1579 // Default-y fields (scalars so far) are neither optional nor required.
1580 const std::string default_value =
1581 !(field.IsOptional() || field.IsRequired())
1582 ? "Some(" + GetDefaultValue(field, kAccessor) + ")"
1583 : "None";
1584 const std::string unwrap = field.IsOptional() ? "" : ".unwrap()";
1585
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001586 return "unsafe { self._tab.get::<" + typname + ">({{STRUCT_TY}}::" + vt_offset +
1587 ", " + default_value + ")" + unwrap + "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001588 }
1589
Austin Schuh272c6132020-11-14 16:37:52 -08001590 // Generates a fully-qualified name getter for use with --gen-name-strings
1591 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1592 const std::string &name) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001593 const std::string fully_qualified_name =
1594 struct_def.defined_namespace->GetFullyQualifiedName(name);
1595 code_ += " pub const fn get_fully_qualified_name() -> &'static str {";
1596 code_ += " \"" + fully_qualified_name + "\"";
1597 code_ += " }";
Austin Schuh272c6132020-11-14 16:37:52 -08001598 code_ += "";
1599 }
1600
1601 void ForAllUnionVariantsBesidesNone(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001602 const EnumDef &def, std::function<void(const EnumVal &ev)> cb) {
Austin Schuh272c6132020-11-14 16:37:52 -08001603 FLATBUFFERS_ASSERT(def.is_union);
1604
1605 for (auto it = def.Vals().begin(); it != def.Vals().end(); ++it) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001606 const EnumVal &ev = **it;
Austin Schuh272c6132020-11-14 16:37:52 -08001607 // TODO(cneo): Can variants be deprecated, should we skip them?
1608 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
Austin Schuh2dd86a92022-09-14 21:19:23 -07001609 code_.SetValue(
1610 "U_ELEMENT_ENUM_TYPE",
1611 WrapInNameSpace(def.defined_namespace, namer_.EnumVariant(def, ev)));
Austin Schuh272c6132020-11-14 16:37:52 -08001612 code_.SetValue(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001613 "U_ELEMENT_TABLE_TYPE",
Austin Schuh272c6132020-11-14 16:37:52 -08001614 WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
1615 ev.union_type.struct_def->name));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001616 code_.SetValue("U_ELEMENT_NAME", namer_.Function(ev.name));
Austin Schuh272c6132020-11-14 16:37:52 -08001617 cb(ev);
1618 }
1619 }
1620
James Kuszmaul8e62b022022-03-22 09:33:25 -07001621 void ForAllTableFields(const StructDef &struct_def,
1622 std::function<void(const FieldDef &)> cb,
1623 bool reversed = false) {
Austin Schuh272c6132020-11-14 16:37:52 -08001624 // TODO(cneo): Remove `reversed` overload. It's only here to minimize the
1625 // diff when refactoring to the `ForAllX` helper functions.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001626 auto go = [&](const FieldDef &field) {
Austin Schuh272c6132020-11-14 16:37:52 -08001627 if (field.deprecated) return;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001628 code_.SetValue("OFFSET_NAME", namer_.LegacyRustFieldOffsetName(field));
Austin Schuh272c6132020-11-14 16:37:52 -08001629 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
Austin Schuh2dd86a92022-09-14 21:19:23 -07001630 code_.SetValue("FIELD", namer_.Field(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001631 code_.SetValue("BLDR_DEF_VAL", GetDefaultValue(field, kBuilder));
Austin Schuh2dd86a92022-09-14 21:19:23 -07001632 code_.SetValue("DISCRIMINANT", namer_.Field(field) + "_type");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001633 code_.IncrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -08001634 cb(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001635 code_.DecrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -08001636 };
1637 const auto &fields = struct_def.fields.vec;
1638 if (reversed) {
1639 for (auto it = fields.rbegin(); it != fields.rend(); ++it) go(**it);
1640 } else {
1641 for (auto it = fields.begin(); it != fields.end(); ++it) go(**it);
1642 }
1643 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001644 // Generate an accessor struct, builder struct, and create function for a
1645 // table.
1646 void GenTable(const StructDef &struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001647
1648 const bool is_private = parser_.opts.no_leak_private_annotations &&
1649 (struct_def.attributes.Lookup("private") != nullptr);
1650 code_.SetValue("ACCESS_TYPE", is_private ? "pub(crate)" : "pub");
1651 code_.SetValue("STRUCT_TY", namer_.Type(struct_def));
1652 code_.SetValue("STRUCT_FN", namer_.Function(struct_def));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001653
1654 // Generate an offset type, the base type, the Follow impl, and the
1655 // init_from_table impl.
Austin Schuh2dd86a92022-09-14 21:19:23 -07001656 code_ += "{{ACCESS_TYPE}} enum {{STRUCT_TY}}Offset {}";
Austin Schuh272c6132020-11-14 16:37:52 -08001657 code_ += "#[derive(Copy, Clone, PartialEq)]";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001658 code_ += "";
1659
1660 GenComment(struct_def.doc_comment);
1661
Austin Schuh2dd86a92022-09-14 21:19:23 -07001662 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}<'a> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001663 code_ += " pub _tab: flatbuffers::Table<'a>,";
1664 code_ += "}";
1665 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001666 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_TY}}<'a> {";
1667 code_ += " type Inner = {{STRUCT_TY}}<'a>;";
1668 code_ += " #[inline]";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001669 code_ += " unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1670 code_ += " Self { _tab: flatbuffers::Table::new(buf, loc) }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001671 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001672 code_ += "}";
1673 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001674 code_ += "impl<'a> {{STRUCT_TY}}<'a> {";
1675
1676 // Generate field id constants.
1677 ForAllTableFields(struct_def, [&](const FieldDef &unused) {
1678 (void)unused;
1679 code_ +=
1680 "pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1681 "{{OFFSET_VALUE}};";
1682 });
1683 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08001684
1685 if (parser_.opts.generate_name_strings) {
1686 GenFullyQualifiedNameGetter(struct_def, struct_def.name);
1687 }
1688
James Kuszmaul8e62b022022-03-22 09:33:25 -07001689 code_ += " #[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08001690 code_ +=
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001691 " pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> "
Austin Schuh272c6132020-11-14 16:37:52 -08001692 "Self {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001693 code_ += " {{STRUCT_TY}} { _tab: table }";
1694 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001695
1696 // Generate a convenient create* function that uses the above builder
1697 // to create a table in one function call.
Austin Schuh272c6132020-11-14 16:37:52 -08001698 code_.SetValue("MAYBE_US", struct_def.fields.vec.size() == 0 ? "_" : "");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001699 code_.SetValue("MAYBE_LT",
Austin Schuh272c6132020-11-14 16:37:52 -08001700 TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001701 code_ += " #[allow(unused_mut)]";
1702 code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
1703 code_ += " _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1704 code_ += " {{MAYBE_US}}args: &'args {{STRUCT_TY}}Args{{MAYBE_LT}}";
1705 code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_TY}}<'bldr>> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001706
James Kuszmaul8e62b022022-03-22 09:33:25 -07001707 code_ += " let mut builder = {{STRUCT_TY}}Builder::new(_fbb);";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001708 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1709 size; size /= 2) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001710 ForAllTableFields(
1711 struct_def,
1712 [&](const FieldDef &field) {
1713 if (struct_def.sortbysize &&
1714 size != SizeOf(field.value.type.base_type))
1715 return;
1716 if (IsOptionalToBuilder(field)) {
1717 code_ +=
1718 " if let Some(x) = args.{{FIELD}} "
1719 "{ builder.add_{{FIELD}}(x); }";
1720 } else {
1721 code_ += " builder.add_{{FIELD}}(args.{{FIELD}});";
1722 }
1723 },
1724 /*reverse=*/true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001725 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001726 code_ += " builder.finish()";
1727 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001728 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001729 // Generate Object API Packer function.
1730 if (parser_.opts.generate_object_based_api) {
1731 // TODO(cneo): Replace more for loops with ForAllX stuff.
1732 // TODO(cneo): Manage indentation with IncrementIdentLevel?
Austin Schuh2dd86a92022-09-14 21:19:23 -07001733 code_.SetValue("STRUCT_OTY", namer_.ObjectType(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001734 code_ += " pub fn unpack(&self) -> {{STRUCT_OTY}} {";
1735 ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
1736 const Type &type = field.value.type;
1737 switch (GetFullType(type)) {
1738 case ftInteger:
1739 case ftBool:
1740 case ftFloat:
1741 case ftEnumKey: {
1742 code_ += " let {{FIELD}} = self.{{FIELD}}();";
1743 return;
1744 }
1745 case ftUnionKey: return;
1746 case ftUnionValue: {
1747 const auto &enum_def = *type.enum_def;
1748 code_.SetValue("ENUM_TY", WrapInNameSpace(enum_def));
1749 code_.SetValue("NATIVE_ENUM_NAME", NamespacedNativeName(enum_def));
1750 code_ += " let {{FIELD}} = match self.{{FIELD}}_type() {";
1751 code_ += " {{ENUM_TY}}::NONE => {{NATIVE_ENUM_NAME}}::NONE,";
1752 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
1753 code_ +=
1754 " {{ENUM_TY}}::{{VARIANT_NAME}} => "
1755 "{{NATIVE_ENUM_NAME}}::{{NATIVE_VARIANT}}(Box::new(";
1756 code_ += " self.{{FIELD}}_as_{{U_ELEMENT_NAME}}()";
1757 code_ +=
1758 " .expect(\"Invalid union table, "
1759 "expected `{{ENUM_TY}}::{{VARIANT_NAME}}`.\")";
1760 code_ += " .unpack()";
1761 code_ += " )),";
1762 });
1763 // Maybe we shouldn't throw away unknown discriminants?
1764 code_ += " _ => {{NATIVE_ENUM_NAME}}::NONE,";
1765 code_ += " };";
1766 return;
1767 }
1768 // The rest of the types need special handling based on if the field
1769 // is optional or not.
1770 case ftString: {
1771 code_.SetValue("EXPR", "x.to_string()");
1772 break;
1773 }
1774 case ftStruct: {
1775 code_.SetValue("EXPR", "x.unpack()");
1776 break;
1777 }
1778 case ftTable: {
1779 code_.SetValue("EXPR", "Box::new(x.unpack())");
1780 break;
1781 }
1782 case ftVectorOfInteger:
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001783 case ftVectorOfBool:
James Kuszmaul8e62b022022-03-22 09:33:25 -07001784 case ftVectorOfFloat:
1785 case ftVectorOfEnumKey: {
1786 code_.SetValue("EXPR", "x.into_iter().collect()");
1787 break;
1788 }
1789 case ftVectorOfString: {
1790 code_.SetValue("EXPR", "x.iter().map(|s| s.to_string()).collect()");
1791 break;
1792 }
1793 case ftVectorOfStruct:
1794 case ftVectorOfTable: {
1795 code_.SetValue("EXPR", "x.iter().map(|t| t.unpack()).collect()");
1796 break;
1797 }
1798 case ftVectorOfUnionValue: {
1799 FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
1800 return;
1801 }
1802 case ftArrayOfEnum:
1803 case ftArrayOfStruct:
1804 case ftArrayOfBuiltin: {
1805 FLATBUFFERS_ASSERT(false &&
1806 "arrays are not supported within tables");
1807 return;
1808 }
1809 }
1810 if (field.IsOptional()) {
1811 code_ += " let {{FIELD}} = self.{{FIELD}}().map(|x| {";
1812 code_ += " {{EXPR}}";
1813 code_ += " });";
1814 } else {
1815 code_ += " let {{FIELD}} = {";
1816 code_ += " let x = self.{{FIELD}}();";
1817 code_ += " {{EXPR}}";
1818 code_ += " };";
1819 }
1820 });
1821 code_ += " {{STRUCT_OTY}} {";
1822 ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
1823 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
1824 code_ += " {{FIELD}},";
1825 });
1826 code_ += " }";
1827 code_ += " }";
1828 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001829
Austin Schuh272c6132020-11-14 16:37:52 -08001830 if (struct_def.fields.vec.size() > 0) code_ += "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001831
1832 // Generate the accessors. Each has one of two forms:
1833 //
1834 // If a value can be None:
1835 // pub fn name(&'a self) -> Option<user_facing_type> {
1836 // self._tab.get::<internal_type>(offset, defaultval)
1837 // }
1838 //
1839 // If a value is always Some:
1840 // pub fn name(&'a self) -> user_facing_type {
1841 // self._tab.get::<internal_type>(offset, defaultval).unwrap()
1842 // }
Austin Schuh272c6132020-11-14 16:37:52 -08001843 ForAllTableFields(struct_def, [&](const FieldDef &field) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001844 code_.SetValue("RETURN_TYPE",
1845 GenTableAccessorFuncReturnType(field, "'a"));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001846
James Kuszmaul8e62b022022-03-22 09:33:25 -07001847 this->GenComment(field.doc_comment);
1848 code_ += "#[inline]";
1849 code_ += "pub fn {{FIELD}}(&self) -> {{RETURN_TYPE}} {";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001850 code_ += " // Safety:";
1851 code_ += " // Created from valid Table for this object";
1852 code_ += " // which contains a valid value in this slot";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001853 code_ += " " + GenTableAccessorFuncBody(field, "'a");
1854 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001855
1856 // Generate a comparison function for this field if it is a key.
Austin Schuh272c6132020-11-14 16:37:52 -08001857 if (field.key) { GenKeyFieldMethods(field); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001858
1859 // Generate a nested flatbuffer field, if applicable.
1860 auto nested = field.attributes.Lookup("nested_flatbuffer");
1861 if (nested) {
1862 std::string qualified_name = nested->constant;
1863 auto nested_root = parser_.LookupStruct(nested->constant);
1864 if (nested_root == nullptr) {
1865 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1866 nested->constant);
1867 nested_root = parser_.LookupStruct(qualified_name);
1868 }
1869 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001870
Austin Schuh272c6132020-11-14 16:37:52 -08001871 code_.SetValue("NESTED", WrapInNameSpace(*nested_root));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001872 code_ += "pub fn {{FIELD}}_nested_flatbuffer(&'a self) -> \\";
1873 if (field.IsRequired()) {
Austin Schuh272c6132020-11-14 16:37:52 -08001874 code_ += "{{NESTED}}<'a> {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001875 code_ += " let data = self.{{FIELD}}();";
1876 code_ += " use flatbuffers::Follow;";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001877 code_ += " // Safety:";
1878 code_ += " // Created from a valid Table for this object";
1879 code_ += " // Which contains a valid flatbuffer in this slot";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001880 code_ +=
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001881 " unsafe { <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1882 "::follow(data.bytes(), 0) }";
Austin Schuh272c6132020-11-14 16:37:52 -08001883 } else {
1884 code_ += "Option<{{NESTED}}<'a>> {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001885 code_ += " self.{{FIELD}}().map(|data| {";
1886 code_ += " use flatbuffers::Follow;";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001887 code_ += " // Safety:";
1888 code_ += " // Created from a valid Table for this object";
1889 code_ += " // Which contains a valid flatbuffer in this slot";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001890 code_ +=
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001891 " unsafe { <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1892 "::follow(data.bytes(), 0) }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001893 code_ += " })";
Austin Schuh272c6132020-11-14 16:37:52 -08001894 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001895 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001896 }
Austin Schuh272c6132020-11-14 16:37:52 -08001897 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001898
1899 // Explicit specializations for union accessors
Austin Schuh272c6132020-11-14 16:37:52 -08001900 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1901 if (field.value.type.base_type != BASE_TYPE_UNION) return;
Austin Schuh272c6132020-11-14 16:37:52 -08001902 ForAllUnionVariantsBesidesNone(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001903 *field.value.type.enum_def, [&](const EnumVal &unused) {
1904 (void)unused;
1905 code_ += "#[inline]";
1906 code_ += "#[allow(non_snake_case)]";
1907 code_ +=
1908 "pub fn {{FIELD}}_as_{{U_ELEMENT_NAME}}(&self) -> "
1909 "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
1910 // If the user defined schemas name a field that clashes with a
1911 // language reserved word, flatc will try to escape the field name
1912 // by appending an underscore. This works well for most cases,
1913 // except one. When generating union accessors (and referring to
1914 // them internally within the code generated here), an extra
1915 // underscore will be appended to the name, causing build failures.
1916 //
1917 // This only happens when unions have members that overlap with
1918 // language reserved words.
1919 //
1920 // To avoid this problem the type field name is used unescaped here:
1921 code_ +=
1922 " if self.{{DISCRIMINANT}}() == {{U_ELEMENT_ENUM_TYPE}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08001923
James Kuszmaul8e62b022022-03-22 09:33:25 -07001924 // The following logic is not tested in the integration test,
1925 // as of April 10, 2020
1926 if (field.IsRequired()) {
1927 code_ += " let u = self.{{FIELD}}();";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001928 code_ += " // Safety:";
1929 code_ += " // Created from a valid Table for this object";
1930 code_ += " // Which contains a valid union in this slot";
1931 code_ += " Some(unsafe { {{U_ELEMENT_TABLE_TYPE}}::init_from_table(u) })";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001932 } else {
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001933 code_ +=" self.{{FIELD}}().map(|t| {";
1934 code_ += " // Safety:";
1935 code_ += " // Created from a valid Table for this object";
1936 code_ += " // Which contains a valid union in this slot";
1937 code_ += " unsafe { {{U_ELEMENT_TABLE_TYPE}}::init_from_table(t) }";
1938 code_ += " })";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001939 }
1940 code_ += " } else {";
1941 code_ += " None";
1942 code_ += " }";
1943 code_ += "}";
1944 code_ += "";
1945 });
Austin Schuh272c6132020-11-14 16:37:52 -08001946 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001947 code_ += "}"; // End of table impl.
1948 code_ += "";
1949
James Kuszmaul8e62b022022-03-22 09:33:25 -07001950 // Generate Verifier;
1951 code_ += "impl flatbuffers::Verifiable for {{STRUCT_TY}}<'_> {";
1952 code_ += " #[inline]";
1953 code_ += " fn run_verifier(";
1954 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
1955 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
1956 code_ += " use self::flatbuffers::Verifiable;";
1957 code_ += " v.visit_table(pos)?\\";
1958 // Escape newline and insert it onthe next line so we can end the builder
1959 // with a nice semicolon.
1960 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1961 if (GetFullType(field.value.type) == ftUnionKey) return;
1962
1963 code_.SetValue("IS_REQ", field.IsRequired() ? "true" : "false");
1964 if (GetFullType(field.value.type) != ftUnionValue) {
1965 // All types besides unions.
1966 code_.SetValue("TY", FollowType(field.value.type, "'_"));
1967 code_ +=
1968 "\n .visit_field::<{{TY}}>(\"{{FIELD}}\", "
1969 "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\";
1970 return;
1971 }
1972 // Unions.
1973 const EnumDef &union_def = *field.value.type.enum_def;
1974 code_.SetValue("UNION_TYPE", WrapInNameSpace(union_def));
1975 code_.SetValue("UNION_TYPE_OFFSET_NAME",
Austin Schuh2dd86a92022-09-14 21:19:23 -07001976 namer_.LegacyRustFieldOffsetName(field) + "_TYPE");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001977 code_ +=
1978 "\n .visit_union::<{{UNION_TYPE}}, _>("
1979 "\"{{FIELD}}_type\", Self::{{UNION_TYPE_OFFSET_NAME}}, "
1980 "\"{{FIELD}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, "
1981 "|key, v, pos| {";
1982 code_ += " match key {";
1983 ForAllUnionVariantsBesidesNone(union_def, [&](const EnumVal &unused) {
1984 (void)unused;
1985 code_ +=
1986 " {{U_ELEMENT_ENUM_TYPE}} => v.verify_union_variant::"
1987 "<flatbuffers::ForwardsUOffset<{{U_ELEMENT_TABLE_TYPE}}>>("
1988 "\"{{U_ELEMENT_ENUM_TYPE}}\", pos),";
1989 });
1990 code_ += " _ => Ok(()),";
1991 code_ += " }";
1992 code_ += " })?\\";
1993 });
1994 code_ += "\n .finish();";
1995 code_ += " Ok(())";
1996 code_ += " }";
1997 code_ += "}";
1998
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001999 // Generate an args struct:
2000 code_.SetValue("MAYBE_LT",
Austin Schuh272c6132020-11-14 16:37:52 -08002001 TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
Austin Schuh2dd86a92022-09-14 21:19:23 -07002002 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}Args{{MAYBE_LT}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08002003 ForAllTableFields(struct_def, [&](const FieldDef &field) {
2004 code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002005 code_ += " pub {{FIELD}}: {{PARAM_TYPE}},";
Austin Schuh272c6132020-11-14 16:37:52 -08002006 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002007 code_ += "}";
2008
2009 // Generate an impl of Default for the *Args type:
James Kuszmaul8e62b022022-03-22 09:33:25 -07002010 code_ += "impl<'a> Default for {{STRUCT_TY}}Args{{MAYBE_LT}} {";
2011 code_ += " #[inline]";
2012 code_ += " fn default() -> Self {";
2013 code_ += " {{STRUCT_TY}}Args {";
Austin Schuh272c6132020-11-14 16:37:52 -08002014 ForAllTableFields(struct_def, [&](const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002015 code_ += " {{FIELD}}: {{BLDR_DEF_VAL}},\\";
2016 code_ += field.IsRequired() ? " // required field" : "";
Austin Schuh272c6132020-11-14 16:37:52 -08002017 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002018 code_ += " }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002019 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002020 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002021 code_ += "";
2022
2023 // Implement serde::Serialize
2024 if (parser_.opts.rust_serialize) {
2025 const auto numFields = struct_def.fields.vec.size();
2026 code_.SetValue("NUM_FIELDS", NumToString(numFields));
2027 code_ += "impl Serialize for {{STRUCT_TY}}<'_> {";
2028 code_ +=
2029 " fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
2030 code_ += " where";
2031 code_ += " S: Serializer,";
2032 code_ += " {";
2033 if (numFields == 0) {
2034 code_ +=
2035 " let s = serializer.serialize_struct(\"{{STRUCT_TY}}\", 0)?;";
2036 } else {
2037 code_ +=
2038 " let mut s = serializer.serialize_struct(\"{{STRUCT_TY}}\", "
2039 "{{NUM_FIELDS}})?;";
2040 }
2041 ForAllTableFields(struct_def, [&](const FieldDef &field) {
2042 const Type &type = field.value.type;
2043 if (IsUnion(type)) {
2044 if (type.base_type == BASE_TYPE_UNION) {
2045 const auto &enum_def = *type.enum_def;
2046 code_.SetValue("ENUM_TY", WrapInNameSpace(enum_def));
Austin Schuh2dd86a92022-09-14 21:19:23 -07002047 code_.SetValue("FIELD", namer_.Field(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002048
2049 code_ += " match self.{{FIELD}}_type() {";
2050 code_ += " {{ENUM_TY}}::NONE => (),";
2051 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
Austin Schuh2dd86a92022-09-14 21:19:23 -07002052 code_.SetValue("FIELD", namer_.Field(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002053 code_ += " {{ENUM_TY}}::{{VARIANT_NAME}} => {";
2054 code_ +=
2055 " let f = "
2056 "self.{{FIELD}}_as_{{U_ELEMENT_NAME}}()";
2057 code_ +=
2058 " .expect(\"Invalid union table, expected "
2059 "`{{ENUM_TY}}::{{VARIANT_NAME}}`.\");";
2060 code_ += " s.serialize_field(\"{{FIELD}}\", &f)?;";
2061 code_ += " }";
2062 });
2063 code_ += " _ => unimplemented!(),";
2064 code_ += " }";
2065 } else {
2066 code_ +=
2067 " s.serialize_field(\"{{FIELD}}\", "
2068 "&self.{{FIELD}}())?;";
2069 }
2070 } else {
2071 if (field.IsOptional()) {
2072 code_ += " if let Some(f) = self.{{FIELD}}() {";
2073 code_ += " s.serialize_field(\"{{FIELD}}\", &f)?;";
2074 code_ += " } else {";
2075 code_ += " s.skip_field(\"{{FIELD}}\")?;";
2076 code_ += " }";
2077 } else {
2078 code_ +=
2079 " s.serialize_field(\"{{FIELD}}\", "
2080 "&self.{{FIELD}}())?;";
2081 }
2082 }
2083 });
2084 code_ += " s.end()";
2085 code_ += " }";
2086 code_ += "}";
2087 code_ += "";
2088 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002089
2090 // Generate a builder struct:
Austin Schuh2dd86a92022-09-14 21:19:23 -07002091 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}Builder<'a: 'b, 'b> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002092 code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
Austin Schuh272c6132020-11-14 16:37:52 -08002093 code_ +=
2094 " start_: flatbuffers::WIPOffset<"
2095 "flatbuffers::TableUnfinishedWIPOffset>,";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002096 code_ += "}";
2097
2098 // Generate builder functions:
James Kuszmaul8e62b022022-03-22 09:33:25 -07002099 code_ += "impl<'a: 'b, 'b> {{STRUCT_TY}}Builder<'a, 'b> {";
Austin Schuh272c6132020-11-14 16:37:52 -08002100 ForAllTableFields(struct_def, [&](const FieldDef &field) {
2101 const bool is_scalar = IsScalar(field.value.type.base_type);
Austin Schuh2dd86a92022-09-14 21:19:23 -07002102 std::string offset = namer_.LegacyRustFieldOffsetName(field);
Austin Schuh272c6132020-11-14 16:37:52 -08002103 // Generate functions to add data, which take one of two forms.
2104 //
2105 // If a value has a default:
2106 // fn add_x(x_: type) {
2107 // fbb_.push_slot::<type>(offset, x_, Some(default));
2108 // }
2109 //
2110 // If a value does not have a default:
2111 // fn add_x(x_: type) {
2112 // fbb_.push_slot_always::<type>(offset, x_);
2113 // }
Austin Schuh2dd86a92022-09-14 21:19:23 -07002114 code_.SetValue("FIELD_OFFSET", namer_.Type(struct_def) + "::" + offset);
Austin Schuh272c6132020-11-14 16:37:52 -08002115 code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
2116 code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002117 code_ += "#[inline]";
2118 code_ +=
2119 "pub fn add_{{FIELD}}(&mut self, {{FIELD}}: "
2120 "{{FIELD_TYPE}}) {";
2121 if (is_scalar && !field.IsOptional()) {
Austin Schuh272c6132020-11-14 16:37:52 -08002122 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002123 " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD}}, "
2124 "{{BLDR_DEF_VAL}});";
Austin Schuh272c6132020-11-14 16:37:52 -08002125 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002126 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD}});";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002127 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07002128 code_ += "}";
Austin Schuh272c6132020-11-14 16:37:52 -08002129 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002130
2131 // Struct initializer (all fields required);
2132 code_ += " #[inline]";
2133 code_ +=
2134 " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002135 "{{STRUCT_TY}}Builder<'a, 'b> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002136 code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
2137 code_ += " let start = _fbb.start_table();";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002138 code_ += " {{STRUCT_TY}}Builder {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002139 code_ += " fbb_: _fbb,";
2140 code_ += " start_: start,";
2141 code_ += " }";
2142 code_ += " }";
2143
2144 // finish() function.
2145 code_ += " #[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002146 code_ +=
2147 " pub fn finish(self) -> "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002148 "flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002149 code_ += " let o = self.fbb_.end_table(self.start_);";
2150
Austin Schuh272c6132020-11-14 16:37:52 -08002151 ForAllTableFields(struct_def, [&](const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002152 if (!field.IsRequired()) return;
Austin Schuh272c6132020-11-14 16:37:52 -08002153 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002154 " self.fbb_.required(o, {{STRUCT_TY}}::{{OFFSET_NAME}},"
2155 "\"{{FIELD}}\");";
Austin Schuh272c6132020-11-14 16:37:52 -08002156 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002157 code_ += " flatbuffers::WIPOffset::new(o.value())";
2158 code_ += " }";
2159 code_ += "}";
2160 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08002161
Austin Schuh2dd86a92022-09-14 21:19:23 -07002162 code_ += "impl core::fmt::Debug for {{STRUCT_TY}}<'_> {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002163 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07002164 " fn fmt(&self, f: &mut core::fmt::Formatter<'_>"
2165 ") -> core::fmt::Result {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002166 code_ += " let mut ds = f.debug_struct(\"{{STRUCT_TY}}\");";
Austin Schuh272c6132020-11-14 16:37:52 -08002167 ForAllTableFields(struct_def, [&](const FieldDef &field) {
2168 if (GetFullType(field.value.type) == ftUnionValue) {
2169 // Generate a match statement to handle unions properly.
2170 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002171 code_.SetValue("UNION_ERR",
2172 "&\"InvalidFlatbuffer: Union discriminant"
2173 " does not match value.\"");
Austin Schuh272c6132020-11-14 16:37:52 -08002174
James Kuszmaul8e62b022022-03-22 09:33:25 -07002175 code_ += " match self.{{DISCRIMINANT}}() {";
2176 ForAllUnionVariantsBesidesNone(
2177 *field.value.type.enum_def, [&](const EnumVal &unused) {
2178 (void)unused;
2179 code_ += " {{U_ELEMENT_ENUM_TYPE}} => {";
2180 code_ +=
2181 " if let Some(x) = "
2182 "self.{{FIELD}}_as_"
2183 "{{U_ELEMENT_NAME}}() {";
2184 code_ += " ds.field(\"{{FIELD}}\", &x)";
2185 code_ += " } else {";
2186 code_ += " ds.field(\"{{FIELD}}\", {{UNION_ERR}})";
2187 code_ += " }";
2188 code_ += " },";
2189 });
2190 code_ += " _ => {";
2191 code_ += " let x: Option<()> = None;";
2192 code_ += " ds.field(\"{{FIELD}}\", &x)";
2193 code_ += " },";
2194 code_ += " };";
Austin Schuh272c6132020-11-14 16:37:52 -08002195 } else {
2196 // Most fields.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002197 code_ += " ds.field(\"{{FIELD}}\", &self.{{FIELD}}());";
Austin Schuh272c6132020-11-14 16:37:52 -08002198 }
2199 });
2200 code_ += " ds.finish()";
2201 code_ += " }";
2202 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002203 }
2204
James Kuszmaul8e62b022022-03-22 09:33:25 -07002205 void GenTableObject(const StructDef &table) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07002206 code_.SetValue("STRUCT_OTY", namer_.ObjectType(table));
2207 code_.SetValue("STRUCT_TY", namer_.Type(table));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002208
2209 // Generate the native object.
2210 code_ += "#[non_exhaustive]";
2211 code_ += "#[derive(Debug, Clone, PartialEq)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -07002212 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_OTY}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002213 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2214 // Union objects combine both the union discriminant and value, so we
2215 // skip making a field for the discriminant.
2216 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
2217 code_ += "pub {{FIELD}}: {{FIELD_OTY}},";
2218 });
2219 code_ += "}";
2220
2221 code_ += "impl Default for {{STRUCT_OTY}} {";
2222 code_ += " fn default() -> Self {";
2223 code_ += " Self {";
2224 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2225 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
2226 std::string default_value = GetDefaultValue(field, kObject);
2227 code_ += " {{FIELD}}: " + default_value + ",";
2228 });
2229 code_ += " }";
2230 code_ += " }";
2231 code_ += "}";
2232
2233 // TODO(cneo): Generate defaults for Native tables. However, since structs
2234 // may be required, they, and therefore enums need defaults.
2235
2236 // Generate pack function.
2237 code_ += "impl {{STRUCT_OTY}} {";
2238 code_ += " pub fn pack<'b>(";
2239 code_ += " &self,";
2240 code_ += " _fbb: &mut flatbuffers::FlatBufferBuilder<'b>";
2241 code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_TY}}<'b>> {";
2242 // First we generate variables for each field and then later assemble them
2243 // using "StructArgs" to more easily manage ownership of the builder.
2244 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2245 const Type &type = field.value.type;
2246 switch (GetFullType(type)) {
2247 case ftInteger:
2248 case ftBool:
2249 case ftFloat:
2250 case ftEnumKey: {
2251 code_ += " let {{FIELD}} = self.{{FIELD}};";
2252 return;
2253 }
2254 case ftUnionKey: return; // Generate union type with union value.
2255 case ftUnionValue: {
2256 code_.SetValue("ENUM_METHOD",
Austin Schuh2dd86a92022-09-14 21:19:23 -07002257 namer_.Method(*field.value.type.enum_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002258 code_ +=
2259 " let {{FIELD}}_type = "
2260 "self.{{FIELD}}.{{ENUM_METHOD}}_type();";
2261 code_ += " let {{FIELD}} = self.{{FIELD}}.pack(_fbb);";
2262 return;
2263 }
2264 // The rest of the types require special casing around optionalness
2265 // due to "required" annotation.
2266 case ftString: {
2267 MapNativeTableField(field, "_fbb.create_string(x)");
2268 return;
2269 }
2270 case ftStruct: {
2271 // Hold the struct in a variable so we can reference it.
2272 if (field.IsRequired()) {
2273 code_ += " let {{FIELD}}_tmp = Some(self.{{FIELD}}.pack());";
2274 } else {
2275 code_ +=
2276 " let {{FIELD}}_tmp = self.{{FIELD}}"
2277 ".as_ref().map(|x| x.pack());";
2278 }
2279 code_ += " let {{FIELD}} = {{FIELD}}_tmp.as_ref();";
2280
2281 return;
2282 }
2283 case ftTable: {
2284 MapNativeTableField(field, "x.pack(_fbb)");
2285 return;
2286 }
2287 case ftVectorOfEnumKey:
2288 case ftVectorOfInteger:
2289 case ftVectorOfBool:
2290 case ftVectorOfFloat: {
2291 MapNativeTableField(field, "_fbb.create_vector(x)");
2292 return;
2293 }
2294 case ftVectorOfStruct: {
2295 MapNativeTableField(
2296 field,
2297 "let w: Vec<_> = x.iter().map(|t| t.pack()).collect();"
2298 "_fbb.create_vector(&w)");
2299 return;
2300 }
2301 case ftVectorOfString: {
2302 // TODO(cneo): create_vector* should be more generic to avoid
2303 // allocations.
2304
2305 MapNativeTableField(
2306 field,
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002307 "let w: Vec<_> = x.iter().map(|s| _fbb.create_string(s)).collect();"
2308 "_fbb.create_vector(&w)");
James Kuszmaul8e62b022022-03-22 09:33:25 -07002309 return;
2310 }
2311 case ftVectorOfTable: {
2312 MapNativeTableField(
2313 field,
2314 "let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();"
2315 "_fbb.create_vector(&w)");
2316 return;
2317 }
2318 case ftVectorOfUnionValue: {
2319 FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
2320 return;
2321 }
2322 case ftArrayOfEnum:
2323 case ftArrayOfStruct:
2324 case ftArrayOfBuiltin: {
2325 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
2326 return;
2327 }
2328 }
2329 });
2330 code_ += " {{STRUCT_TY}}::create(_fbb, &{{STRUCT_TY}}Args{";
2331 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2332 (void)field; // Unused.
2333 code_ += " {{FIELD}},";
2334 });
2335 code_ += " })";
2336 code_ += " }";
2337 code_ += "}";
2338 }
2339 void ForAllObjectTableFields(const StructDef &table,
2340 std::function<void(const FieldDef &)> cb) {
2341 const std::vector<FieldDef *> &v = table.fields.vec;
2342 for (auto it = v.begin(); it != v.end(); it++) {
2343 const FieldDef &field = **it;
2344 if (field.deprecated) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -07002345 code_.SetValue("FIELD", namer_.Field(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002346 code_.SetValue("FIELD_OTY", ObjectFieldType(field, true));
2347 code_.IncrementIdentLevel();
2348 cb(field);
2349 code_.DecrementIdentLevel();
2350 }
2351 }
2352 void MapNativeTableField(const FieldDef &field, const std::string &expr) {
2353 if (field.IsOptional()) {
2354 code_ += " let {{FIELD}} = self.{{FIELD}}.as_ref().map(|x|{";
2355 code_ += " " + expr;
2356 code_ += " });";
2357 } else {
2358 // For some reason Args has optional types for required fields.
2359 // TODO(cneo): Fix this... but its a breaking change?
2360 code_ += " let {{FIELD}} = Some({";
2361 code_ += " let x = &self.{{FIELD}};";
2362 code_ += " " + expr;
2363 code_ += " });";
2364 }
2365 }
2366
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002367 // Generate functions to compare tables and structs by key. This function
2368 // must only be called if the field key is defined.
2369 void GenKeyFieldMethods(const FieldDef &field) {
2370 FLATBUFFERS_ASSERT(field.key);
2371
2372 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002373 code_.SetValue("REF", IsString(field.value.type) ? "" : "&");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002374
James Kuszmaul8e62b022022-03-22 09:33:25 -07002375 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002376 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002377 "pub fn key_compare_less_than(&self, o: &{{STRUCT_TY}}) -> "
2378 "bool {";
2379 code_ += " self.{{FIELD}}() < o.{{FIELD}}()";
2380 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002381 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002382 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002383 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002384 "pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
Austin Schuh2dd86a92022-09-14 21:19:23 -07002385 "::core::cmp::Ordering {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002386 code_ += " let key = self.{{FIELD}}();";
2387 code_ += " key.cmp({{REF}}val)";
2388 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002389 }
2390
2391 // Generate functions for accessing the root table object. This function
2392 // must only be called if the root table is defined.
2393 void GenRootTableFuncs(const StructDef &struct_def) {
2394 FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
Austin Schuh2dd86a92022-09-14 21:19:23 -07002395 code_.SetValue("STRUCT_TY", namer_.Type(struct_def));
2396 code_.SetValue("STRUCT_FN", namer_.Function(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002397 code_.SetValue("STRUCT_CONST", namer_.Constant(struct_def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002398
James Kuszmaul8e62b022022-03-22 09:33:25 -07002399 // Default verifier root fns.
2400 code_ += "#[inline]";
2401 code_ += "/// Verifies that a buffer of bytes contains a `{{STRUCT_TY}}`";
2402 code_ += "/// and returns it.";
2403 code_ += "/// Note that verification is still experimental and may not";
2404 code_ += "/// catch every error, or be maximally performant. For the";
2405 code_ += "/// previous, unchecked, behavior use";
2406 code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
2407 code_ +=
2408 "pub fn root_as_{{STRUCT_FN}}(buf: &[u8]) "
2409 "-> Result<{{STRUCT_TY}}, flatbuffers::InvalidFlatbuffer> {";
2410 code_ += " flatbuffers::root::<{{STRUCT_TY}}>(buf)";
2411 code_ += "}";
2412 code_ += "#[inline]";
2413 code_ += "/// Verifies that a buffer of bytes contains a size prefixed";
2414 code_ += "/// `{{STRUCT_TY}}` and returns it.";
2415 code_ += "/// Note that verification is still experimental and may not";
2416 code_ += "/// catch every error, or be maximally performant. For the";
2417 code_ += "/// previous, unchecked, behavior use";
2418 code_ += "/// `size_prefixed_root_as_{{STRUCT_FN}}_unchecked`.";
2419 code_ +=
2420 "pub fn size_prefixed_root_as_{{STRUCT_FN}}"
2421 "(buf: &[u8]) -> Result<{{STRUCT_TY}}, "
2422 "flatbuffers::InvalidFlatbuffer> {";
2423 code_ += " flatbuffers::size_prefixed_root::<{{STRUCT_TY}}>(buf)";
2424 code_ += "}";
2425 // Verifier with options root fns.
2426 code_ += "#[inline]";
2427 code_ += "/// Verifies, with the given options, that a buffer of bytes";
2428 code_ += "/// contains a `{{STRUCT_TY}}` and returns it.";
2429 code_ += "/// Note that verification is still experimental and may not";
2430 code_ += "/// catch every error, or be maximally performant. For the";
2431 code_ += "/// previous, unchecked, behavior use";
2432 code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
2433 code_ += "pub fn root_as_{{STRUCT_FN}}_with_opts<'b, 'o>(";
2434 code_ += " opts: &'o flatbuffers::VerifierOptions,";
2435 code_ += " buf: &'b [u8],";
2436 code_ +=
2437 ") -> Result<{{STRUCT_TY}}<'b>, flatbuffers::InvalidFlatbuffer>"
2438 " {";
2439 code_ += " flatbuffers::root_with_opts::<{{STRUCT_TY}}<'b>>(opts, buf)";
2440 code_ += "}";
2441 code_ += "#[inline]";
2442 code_ += "/// Verifies, with the given verifier options, that a buffer of";
2443 code_ += "/// bytes contains a size prefixed `{{STRUCT_TY}}` and returns";
2444 code_ += "/// it. Note that verification is still experimental and may not";
2445 code_ += "/// catch every error, or be maximally performant. For the";
2446 code_ += "/// previous, unchecked, behavior use";
2447 code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
2448 code_ +=
2449 "pub fn size_prefixed_root_as_{{STRUCT_FN}}_with_opts"
2450 "<'b, 'o>(";
2451 code_ += " opts: &'o flatbuffers::VerifierOptions,";
2452 code_ += " buf: &'b [u8],";
2453 code_ +=
2454 ") -> Result<{{STRUCT_TY}}<'b>, flatbuffers::InvalidFlatbuffer>"
2455 " {";
2456 code_ +=
2457 " flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_TY}}"
2458 "<'b>>(opts, buf)";
2459 code_ += "}";
2460 // Unchecked root fns.
2461 code_ += "#[inline]";
2462 code_ +=
2463 "/// Assumes, without verification, that a buffer of bytes "
2464 "contains a {{STRUCT_TY}} and returns it.";
2465 code_ += "/// # Safety";
2466 code_ +=
2467 "/// Callers must trust the given bytes do indeed contain a valid"
2468 " `{{STRUCT_TY}}`.";
2469 code_ +=
2470 "pub unsafe fn root_as_{{STRUCT_FN}}_unchecked"
2471 "(buf: &[u8]) -> {{STRUCT_TY}} {";
2472 code_ += " flatbuffers::root_unchecked::<{{STRUCT_TY}}>(buf)";
2473 code_ += "}";
2474 code_ += "#[inline]";
2475 code_ +=
2476 "/// Assumes, without verification, that a buffer of bytes "
2477 "contains a size prefixed {{STRUCT_TY}} and returns it.";
2478 code_ += "/// # Safety";
2479 code_ +=
2480 "/// Callers must trust the given bytes do indeed contain a valid"
2481 " size prefixed `{{STRUCT_TY}}`.";
2482 code_ +=
2483 "pub unsafe fn size_prefixed_root_as_{{STRUCT_FN}}"
2484 "_unchecked(buf: &[u8]) -> {{STRUCT_TY}} {";
2485 code_ +=
2486 " flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_TY}}>"
2487 "(buf)";
2488 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002489
2490 if (parser_.file_identifier_.length()) {
2491 // Declare the identifier
Austin Schuh272c6132020-11-14 16:37:52 -08002492 // (no lifetime needed as constants have static lifetimes by default)
James Kuszmaul8e62b022022-03-22 09:33:25 -07002493 code_ += "pub const {{STRUCT_CONST}}_IDENTIFIER: &str\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002494 code_ += " = \"" + parser_.file_identifier_ + "\";";
2495 code_ += "";
2496
2497 // Check if a buffer has the identifier.
2498 code_ += "#[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002499 code_ += "pub fn {{STRUCT_FN}}_buffer_has_identifier\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002500 code_ += "(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, false)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002503 code_ += "}";
2504 code_ += "";
2505 code_ += "#[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002506 code_ += "pub fn {{STRUCT_FN}}_size_prefixed\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002507 code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
Austin Schuh272c6132020-11-14 16:37:52 -08002508 code_ += " flatbuffers::buffer_has_identifier(buf, \\";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002509 code_ += "{{STRUCT_CONST}}_IDENTIFIER, true)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002510 code_ += "}";
2511 code_ += "";
2512 }
2513
2514 if (parser_.file_extension_.length()) {
2515 // Return the extension
James Kuszmaul8e62b022022-03-22 09:33:25 -07002516 code_ += "pub const {{STRUCT_CONST}}_EXTENSION: &str = \\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002517 code_ += "\"" + parser_.file_extension_ + "\";";
2518 code_ += "";
2519 }
2520
2521 // Finish a buffer with a given root object:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002522 code_ += "#[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002523 code_ += "pub fn finish_{{STRUCT_FN}}_buffer<'a, 'b>(";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002524 code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002525 code_ += " root: flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>>) {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002526 if (parser_.file_identifier_.length()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002527 code_ += " fbb.finish(root, Some({{STRUCT_CONST}}_IDENTIFIER));";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002528 } else {
2529 code_ += " fbb.finish(root, None);";
2530 }
2531 code_ += "}";
2532 code_ += "";
2533 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002534 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002535 "pub fn finish_size_prefixed_{{STRUCT_FN}}_buffer"
Austin Schuh272c6132020-11-14 16:37:52 -08002536 "<'a, 'b>("
2537 "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002538 "root: flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>>) {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002539 if (parser_.file_identifier_.length()) {
Austin Schuh272c6132020-11-14 16:37:52 -08002540 code_ +=
2541 " fbb.finish_size_prefixed(root, "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002542 "Some({{STRUCT_CONST}}_IDENTIFIER));";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002543 } else {
2544 code_ += " fbb.finish_size_prefixed(root, None);";
2545 }
2546 code_ += "}";
2547 }
2548
2549 static void GenPadding(
2550 const FieldDef &field, std::string *code_ptr, int *id,
2551 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
2552 if (field.padding) {
2553 for (int i = 0; i < 4; i++) {
2554 if (static_cast<int>(field.padding) & (1 << i)) {
2555 f((1 << i) * 8, code_ptr, id);
2556 }
2557 }
2558 assert(!(field.padding & ~0xF));
2559 }
2560 }
2561
2562 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
Austin Schuh272c6132020-11-14 16:37:52 -08002563 *code_ptr +=
2564 " padding" + NumToString((*id)++) + "__: u" + NumToString(bits) + ",";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002565 }
2566
2567 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
2568 (void)bits;
2569 *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
2570 }
2571
James Kuszmaul8e62b022022-03-22 09:33:25 -07002572 void ForAllStructFields(const StructDef &struct_def,
2573 std::function<void(const FieldDef &field)> cb) {
2574 size_t offset_to_field = 0;
Austin Schuh272c6132020-11-14 16:37:52 -08002575 for (auto it = struct_def.fields.vec.begin();
2576 it != struct_def.fields.vec.end(); ++it) {
2577 const auto &field = **it;
2578 code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002579 code_.SetValue("FIELD_OTY", ObjectFieldType(field, false));
Austin Schuh2dd86a92022-09-14 21:19:23 -07002580 code_.SetValue("FIELD", namer_.Field(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002581 code_.SetValue("FIELD_OFFSET", NumToString(offset_to_field));
2582 code_.SetValue(
2583 "REF",
2584 IsStruct(field.value.type) || IsArray(field.value.type) ? "&" : "");
2585 code_.IncrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -08002586 cb(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07002587 code_.DecrementIdentLevel();
2588 const size_t size = InlineSize(field.value.type);
2589 offset_to_field += size + field.padding;
Austin Schuh272c6132020-11-14 16:37:52 -08002590 }
2591 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002592 // Generate an accessor struct with constructor for a flatbuffers struct.
2593 void GenStruct(const StructDef &struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07002594 const bool is_private = parser_.opts.no_leak_private_annotations &&
2595 (struct_def.attributes.Lookup("private") != nullptr);
2596 code_.SetValue("ACCESS_TYPE", is_private ? "pub(crate)" : "pub");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002597 // Generates manual padding and alignment.
2598 // Variables are private because they contain little endian data on all
2599 // platforms.
2600 GenComment(struct_def.doc_comment);
2601 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
Austin Schuh2dd86a92022-09-14 21:19:23 -07002602 code_.SetValue("STRUCT_TY", namer_.Type(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002603 code_.SetValue("STRUCT_SIZE", NumToString(struct_def.bytesize));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002604
James Kuszmaul8e62b022022-03-22 09:33:25 -07002605 // We represent Flatbuffers-structs in Rust-u8-arrays since the data may be
2606 // of the wrong endianness and alignment 1.
2607 //
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002608 // PartialEq is useful to derive because we can correctly compare structs
2609 // for equality by just comparing their underlying byte data. This doesn't
2610 // hold for PartialOrd/Ord.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002611 code_ += "// struct {{STRUCT_TY}}, aligned to {{ALIGN}}";
2612 code_ += "#[repr(transparent)]";
Austin Schuh272c6132020-11-14 16:37:52 -08002613 code_ += "#[derive(Clone, Copy, PartialEq)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -07002614 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}(pub [u8; {{STRUCT_SIZE}}]);";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002615 code_ += "impl Default for {{STRUCT_TY}} { ";
2616 code_ += " fn default() -> Self { ";
2617 code_ += " Self([0; {{STRUCT_SIZE}}])";
2618 code_ += " }";
2619 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002620
Austin Schuh272c6132020-11-14 16:37:52 -08002621 // Debug for structs.
Austin Schuh2dd86a92022-09-14 21:19:23 -07002622 code_ += "impl core::fmt::Debug for {{STRUCT_TY}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002623 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07002624 " fn fmt(&self, f: &mut core::fmt::Formatter"
2625 ") -> core::fmt::Result {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002626 code_ += " f.debug_struct(\"{{STRUCT_TY}}\")";
Austin Schuh272c6132020-11-14 16:37:52 -08002627 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002628 (void)unused;
2629 code_ += " .field(\"{{FIELD}}\", &self.{{FIELD}}())";
Austin Schuh272c6132020-11-14 16:37:52 -08002630 });
2631 code_ += " .finish()";
2632 code_ += " }";
2633 code_ += "}";
2634 code_ += "";
2635
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002636 // Generate impls for SafeSliceAccess (because all structs are endian-safe),
2637 // Follow for the value type, Follow for the reference type, Push for the
2638 // value type, and Push for the reference type.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002639 code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{STRUCT_TY}} {}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002640 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_TY}} {";
2641 code_ += " type Inner = &'a {{STRUCT_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002642 code_ += " #[inline]";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002643 code_ += " unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002644 code_ += " <&'a {{STRUCT_TY}}>::follow(buf, loc)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002645 code_ += " }";
2646 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002647 code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_TY}} {";
2648 code_ += " type Inner = &'a {{STRUCT_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002649 code_ += " #[inline]";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002650 code_ += " unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002651 code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_TY}}>(buf, loc)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002652 code_ += " }";
2653 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002654 code_ += "impl<'b> flatbuffers::Push for {{STRUCT_TY}} {";
2655 code_ += " type Output = {{STRUCT_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002656 code_ += " #[inline]";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002657 code_ += " unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {";
2658 code_ += " let src = ::core::slice::from_raw_parts(self as *const {{STRUCT_TY}} as *const u8, Self::size());";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002659 code_ += " dst.copy_from_slice(src);";
2660 code_ += " }";
2661 code_ += "}";
2662 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002663
2664 // Generate verifier: Structs are simple so presence and alignment are
2665 // all that need to be checked.
2666 code_ += "impl<'a> flatbuffers::Verifiable for {{STRUCT_TY}} {";
2667 code_ += " #[inline]";
2668 code_ += " fn run_verifier(";
2669 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
2670 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
2671 code_ += " use self::flatbuffers::Verifiable;";
2672 code_ += " v.in_buffer::<Self>(pos)";
2673 code_ += " }";
2674 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002675 code_ += "";
2676
James Kuszmaul8e62b022022-03-22 09:33:25 -07002677 // Implement serde::Serialize
2678 if (parser_.opts.rust_serialize) {
2679 const auto numFields = struct_def.fields.vec.size();
2680 code_.SetValue("NUM_FIELDS", NumToString(numFields));
2681 code_ += "impl Serialize for {{STRUCT_TY}} {";
2682 code_ +=
2683 " fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
2684 code_ += " where";
2685 code_ += " S: Serializer,";
2686 code_ += " {";
2687 if (numFields == 0) {
2688 code_ +=
2689 " let s = serializer.serialize_struct(\"{{STRUCT_TY}}\", 0)?;";
2690 } else {
2691 code_ +=
2692 " let mut s = serializer.serialize_struct(\"{{STRUCT_TY}}\", "
2693 "{{NUM_FIELDS}})?;";
2694 }
2695 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2696 (void)unused;
2697 code_ +=
2698 " s.serialize_field(\"{{FIELD}}\", "
2699 "&self.{{FIELD}}())?;";
2700 });
2701 code_ += " s.end()";
2702 code_ += " }";
2703 code_ += "}";
2704 code_ += "";
2705 }
2706
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002707 // Generate a constructor that takes all fields as arguments.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002708 code_ += "impl<'a> {{STRUCT_TY}} {";
2709 code_ += " #[allow(clippy::too_many_arguments)]";
2710 code_ += " pub fn new(";
2711 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2712 (void)unused;
2713 code_ += " {{FIELD}}: {{REF}}{{FIELD_TYPE}},";
Austin Schuh272c6132020-11-14 16:37:52 -08002714 });
James Kuszmaul8e62b022022-03-22 09:33:25 -07002715 code_ += " ) -> Self {";
2716 code_ += " let mut s = Self([0; {{STRUCT_SIZE}}]);";
2717 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2718 (void)unused;
2719 code_ += " s.set_{{FIELD}}({{FIELD}});";
Austin Schuh272c6132020-11-14 16:37:52 -08002720 });
James Kuszmaul8e62b022022-03-22 09:33:25 -07002721 code_ += " s";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002722 code_ += " }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002723 code_ += "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002724
Austin Schuh272c6132020-11-14 16:37:52 -08002725 if (parser_.opts.generate_name_strings) {
2726 GenFullyQualifiedNameGetter(struct_def, struct_def.name);
2727 }
2728
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002729 // Generate accessor methods for the struct.
Austin Schuh272c6132020-11-14 16:37:52 -08002730 ForAllStructFields(struct_def, [&](const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002731 this->GenComment(field.doc_comment);
2732 // Getter.
2733 if (IsStruct(field.value.type)) {
2734 code_ += "pub fn {{FIELD}}(&self) -> &{{FIELD_TYPE}} {";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002735 code_ += " // Safety:";
2736 code_ += " // Created from a valid Table for this object";
2737 code_ += " // Which contains a valid struct in this slot";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002738 code_ +=
2739 " unsafe {"
2740 " &*(self.0[{{FIELD_OFFSET}}..].as_ptr() as *const"
2741 " {{FIELD_TYPE}}) }";
2742 } else if (IsArray(field.value.type)) {
2743 code_.SetValue("ARRAY_SIZE",
2744 NumToString(field.value.type.fixed_length));
2745 code_.SetValue("ARRAY_ITEM", GetTypeGet(field.value.type.VectorType()));
2746 code_ +=
2747 "pub fn {{FIELD}}(&'a self) -> "
2748 "flatbuffers::Array<'a, {{ARRAY_ITEM}}, {{ARRAY_SIZE}}> {";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002749 code_ += " // Safety:";
2750 code_ += " // Created from a valid Table for this object";
2751 code_ += " // Which contains a valid array in this slot";
2752 code_ += " unsafe { flatbuffers::Array::follow(&self.0, {{FIELD_OFFSET}}) }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002753 } else {
2754 code_ += "pub fn {{FIELD}}(&self) -> {{FIELD_TYPE}} {";
2755 code_ +=
2756 " let mut mem = core::mem::MaybeUninit::"
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002757 "<<{{FIELD_TYPE}} as EndianScalar>::Scalar>::uninit();";
2758 code_ += " // Safety:";
2759 code_ += " // Created from a valid Table for this object";
2760 code_ += " // Which contains a valid value in this slot";
2761 code_ += " EndianScalar::from_little_endian(unsafe {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002762 code_ += " core::ptr::copy_nonoverlapping(";
2763 code_ += " self.0[{{FIELD_OFFSET}}..].as_ptr(),";
2764 code_ += " mem.as_mut_ptr() as *mut u8,";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002765 code_ += " core::mem::size_of::<<{{FIELD_TYPE}} as EndianScalar>::Scalar>(),";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002766 code_ += " );";
2767 code_ += " mem.assume_init()";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002768 code_ += " })";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002769 }
2770 code_ += "}\n";
2771 // Setter.
2772 if (IsStruct(field.value.type)) {
2773 code_.SetValue("FIELD_SIZE", NumToString(InlineSize(field.value.type)));
2774 code_ += "#[allow(clippy::identity_op)]"; // If FIELD_OFFSET=0.
2775 code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {";
2776 code_ +=
2777 " self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}} + {{FIELD_SIZE}}]"
2778 ".copy_from_slice(&x.0)";
2779 } else if (IsArray(field.value.type)) {
2780 if (GetFullType(field.value.type) == ftArrayOfBuiltin) {
2781 code_.SetValue("ARRAY_ITEM",
2782 GetTypeGet(field.value.type.VectorType()));
2783 code_.SetValue(
2784 "ARRAY_ITEM_SIZE",
2785 NumToString(InlineSize(field.value.type.VectorType())));
2786 code_ +=
2787 "pub fn set_{{FIELD}}(&mut self, items: &{{FIELD_TYPE}}) "
2788 "{";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002789 code_ += " // Safety:";
2790 code_ += " // Created from a valid Table for this object";
2791 code_ += " // Which contains a valid array in this slot";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002792 code_ +=
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002793 " unsafe { flatbuffers::emplace_scalar_array(&mut self.0, "
2794 "{{FIELD_OFFSET}}, items) };";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002795 } else {
2796 code_.SetValue("FIELD_SIZE",
2797 NumToString(InlineSize(field.value.type)));
2798 code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002799 code_ += " // Safety:";
2800 code_ += " // Created from a valid Table for this object";
2801 code_ += " // Which contains a valid array in this slot";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002802 code_ += " unsafe {";
Austin Schuh2dd86a92022-09-14 21:19:23 -07002803 code_ += " core::ptr::copy(";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002804 code_ += " x.as_ptr() as *const u8,";
2805 code_ += " self.0.as_mut_ptr().add({{FIELD_OFFSET}}),";
2806 code_ += " {{FIELD_SIZE}},";
2807 code_ += " );";
2808 code_ += " }";
2809 }
2810 } else {
2811 code_ += "pub fn set_{{FIELD}}(&mut self, x: {{FIELD_TYPE}}) {";
2812 code_ += " let x_le = x.to_little_endian();";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002813 code_ += " // Safety:";
2814 code_ += " // Created from a valid Table for this object";
2815 code_ += " // Which contains a valid value in this slot";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002816 code_ += " unsafe {";
2817 code_ += " core::ptr::copy_nonoverlapping(";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002818 code_ += " &x_le as *const _ as *const u8,";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002819 code_ += " self.0[{{FIELD_OFFSET}}..].as_mut_ptr(),";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08002820 code_ += " core::mem::size_of::<<{{FIELD_TYPE}} as EndianScalar>::Scalar>(),";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002821 code_ += " );";
2822 code_ += " }";
2823 }
2824 code_ += "}\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002825
2826 // Generate a comparison function for this field if it is a key.
Austin Schuh272c6132020-11-14 16:37:52 -08002827 if (field.key) { GenKeyFieldMethods(field); }
2828 });
James Kuszmaul8e62b022022-03-22 09:33:25 -07002829
2830 // Generate Object API unpack method.
2831 if (parser_.opts.generate_object_based_api) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07002832 code_.SetValue("STRUCT_OTY", namer_.ObjectType(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002833 code_ += " pub fn unpack(&self) -> {{STRUCT_OTY}} {";
2834 code_ += " {{STRUCT_OTY}} {";
2835 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2836 if (IsArray(field.value.type)) {
2837 if (GetFullType(field.value.type) == ftArrayOfStruct) {
2838 code_ +=
2839 " {{FIELD}}: { let {{FIELD}} = "
2840 "self.{{FIELD}}(); flatbuffers::array_init(|i| "
2841 "{{FIELD}}.get(i).unpack()) },";
2842 } else {
2843 code_ += " {{FIELD}}: self.{{FIELD}}().into(),";
2844 }
2845 } else {
2846 std::string unpack = IsStruct(field.value.type) ? ".unpack()" : "";
2847 code_ += " {{FIELD}}: self.{{FIELD}}()" + unpack + ",";
2848 }
2849 });
2850 code_ += " }";
2851 code_ += " }";
2852 }
2853
2854 code_ += "}"; // End impl Struct methods.
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002855 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002856
2857 // Generate Struct Object.
2858 if (parser_.opts.generate_object_based_api) {
2859 // Struct declaration
2860 code_ += "#[derive(Debug, Clone, PartialEq, Default)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -07002861 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_OTY}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002862 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2863 (void)field; // unused.
2864 code_ += "pub {{FIELD}}: {{FIELD_OTY}},";
2865 });
2866 code_ += "}";
2867 // The `pack` method that turns the native struct into its Flatbuffers
2868 // counterpart.
2869 code_ += "impl {{STRUCT_OTY}} {";
2870 code_ += " pub fn pack(&self) -> {{STRUCT_TY}} {";
2871 code_ += " {{STRUCT_TY}}::new(";
2872 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2873 if (IsStruct(field.value.type)) {
2874 code_ += " &self.{{FIELD}}.pack(),";
2875 } else if (IsArray(field.value.type)) {
2876 if (GetFullType(field.value.type) == ftArrayOfStruct) {
2877 code_ +=
2878 " &flatbuffers::array_init(|i| "
2879 "self.{{FIELD}}[i].pack()),";
2880 } else {
2881 code_ += " &self.{{FIELD}},";
2882 }
2883 } else {
2884 code_ += " self.{{FIELD}},";
2885 }
2886 });
2887 code_ += " )";
2888 code_ += " }";
2889 code_ += "}";
2890 code_ += "";
2891 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002892 }
2893
2894 void GenNamespaceImports(const int white_spaces) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002895 // DO not use global attributes (i.e. #![...]) since it interferes
2896 // with users who include! generated files.
2897 // See: https://github.com/google/flatbuffers/issues/6261
Austin Schuh272c6132020-11-14 16:37:52 -08002898 std::string indent = std::string(white_spaces, ' ');
2899 code_ += "";
2900 if (!parser_.opts.generate_all) {
2901 for (auto it = parser_.included_files_.begin();
2902 it != parser_.included_files_.end(); ++it) {
2903 if (it->second.empty()) continue;
2904 auto noext = flatbuffers::StripExtension(it->second);
2905 auto basename = flatbuffers::StripPath(noext);
2906
James Kuszmaul8e62b022022-03-22 09:33:25 -07002907 if (parser_.opts.include_prefix.empty()) {
2908 code_ += indent + "use crate::" + basename +
2909 parser_.opts.filename_suffix + "::*;";
2910 } else {
2911 auto prefix = parser_.opts.include_prefix;
2912 prefix.pop_back();
2913
2914 code_ += indent + "use crate::" + prefix + "::" + basename +
2915 parser_.opts.filename_suffix + "::*;";
2916 }
Austin Schuh272c6132020-11-14 16:37:52 -08002917 }
2918 }
Austin Schuh2dd86a92022-09-14 21:19:23 -07002919 code_ += indent + "use core::mem;";
2920 code_ += indent + "use core::cmp::Ordering;";
Austin Schuh272c6132020-11-14 16:37:52 -08002921 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002922 if (parser_.opts.rust_serialize) {
2923 code_ += indent + "extern crate serde;";
2924 code_ +=
2925 indent +
2926 "use self::serde::ser::{Serialize, Serializer, SerializeStruct};";
2927 code_ += "";
2928 }
Austin Schuh272c6132020-11-14 16:37:52 -08002929 code_ += indent + "extern crate flatbuffers;";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002930 code_ += indent + "use self::flatbuffers::{EndianScalar, Follow};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002931 }
2932
2933 // Set up the correct namespace. This opens a namespace if the current
2934 // namespace is different from the target namespace. This function
2935 // closes and opens the namespaces only as necessary.
2936 //
2937 // The file must start and end with an empty (or null) namespace so that
2938 // namespaces are properly opened and closed.
2939 void SetNameSpace(const Namespace *ns) {
2940 if (cur_name_space_ == ns) { return; }
2941
2942 // Compute the size of the longest common namespace prefix.
2943 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
2944 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
2945 // and common_prefix_size = 2
2946 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
2947 size_t new_size = ns ? ns->components.size() : 0;
2948
2949 size_t common_prefix_size = 0;
2950 while (common_prefix_size < old_size && common_prefix_size < new_size &&
2951 ns->components[common_prefix_size] ==
2952 cur_name_space_->components[common_prefix_size]) {
2953 common_prefix_size++;
2954 }
2955
2956 // Close cur_name_space in reverse order to reach the common prefix.
2957 // In the previous example, D then C are closed.
2958 for (size_t j = old_size; j > common_prefix_size; --j) {
2959 code_ += "} // pub mod " + cur_name_space_->components[j - 1];
2960 }
2961 if (old_size != common_prefix_size) { code_ += ""; }
2962
2963 // open namespace parts to reach the ns namespace
2964 // in the previous example, E, then F, then G are opened
2965 for (auto j = common_prefix_size; j != new_size; ++j) {
2966 code_ += "#[allow(unused_imports, dead_code)]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002967 code_ += "pub mod " + namer_.Namespace(ns->components[j]) + " {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002968 // Generate local namespace imports.
2969 GenNamespaceImports(2);
2970 }
2971 if (new_size != common_prefix_size) { code_ += ""; }
2972
2973 cur_name_space_ = ns;
2974 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07002975
2976 private:
Austin Schuh2dd86a92022-09-14 21:19:23 -07002977 IdlNamer namer_;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002978};
2979
2980} // namespace rust
2981
2982bool GenerateRust(const Parser &parser, const std::string &path,
2983 const std::string &file_name) {
2984 rust::RustGenerator generator(parser, path, file_name);
2985 return generator.generate();
2986}
2987
2988std::string RustMakeRule(const Parser &parser, const std::string &path,
2989 const std::string &file_name) {
2990 std::string filebase =
2991 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
Austin Schuh272c6132020-11-14 16:37:52 -08002992 rust::RustGenerator generator(parser, path, file_name);
2993 std::string make_rule =
2994 generator.GeneratedFileName(path, filebase, parser.opts) + ": ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002995
2996 auto included_files = parser.GetIncludedFilesRecursive(file_name);
2997 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
2998 make_rule += " " + *it;
2999 }
3000 return make_rule;
3001}
3002
3003} // namespace flatbuffers
3004
3005// TODO(rw): Generated code should import other generated files.
3006// TODO(rw): Generated code should refer to namespaces in included files in a
3007// way that makes them referrable.
3008// TODO(rw): Generated code should indent according to nesting level.
3009// TODO(rw): Generated code should generate endian-safe Debug impls.
3010// TODO(rw): Generated code could use a Rust-only enum type to access unions,
3011// instead of making the user use _type() to manually switch.
Austin Schuh272c6132020-11-14 16:37:52 -08003012// TODO(maxburke): There should be test schemas added that use language
3013// keywords as fields of structs, tables, unions, enums, to make sure
3014// that internal code generated references escaped names correctly.
3015// TODO(maxburke): We should see if there is a more flexible way of resolving
3016// module paths for use declarations. Right now if schemas refer to
3017// other flatbuffer files, the include paths in emitted Rust bindings
3018// are crate-relative which may undesirable.