blob: a5ce2f72a050f95dfbd21b5bb16b0817025d82ba [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
2 * Copyright 2018 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// independent from idl_parser, since this code is not needed for most clients
18
19#include "flatbuffers/code_generators.h"
20#include "flatbuffers/flatbuffers.h"
21#include "flatbuffers/idl.h"
22#include "flatbuffers/util.h"
Austin Schuh2dd86a92022-09-14 21:19:23 -070023#include "idl_namer.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070024
25namespace flatbuffers {
Austin Schuh2dd86a92022-09-14 21:19:23 -070026namespace {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070027
Austin Schuh2dd86a92022-09-14 21:19:23 -070028static Namer::Config RustDefaultConfig() {
James Kuszmaul8e62b022022-03-22 09:33:25 -070029 // Historical note: We've been using "keep" casing since the original
30 // implementation, presumably because Flatbuffers schema style and Rust style
31 // roughly align. We are not going to enforce proper casing since its an
32 // unnecessary breaking change.
33 return { /*types=*/Case::kKeep,
34 /*constants=*/Case::kScreamingSnake,
35 /*methods=*/Case::kSnake,
36 /*functions=*/Case::kSnake,
37 /*fields=*/Case::kKeep,
38 /*variables=*/Case::kUnknown, // Unused.
39 /*variants=*/Case::kKeep,
40 /*enum_variant_seperator=*/"::",
Austin Schuh2dd86a92022-09-14 21:19:23 -070041 /*escape_keywords=*/Namer::Config::Escape::BeforeConvertingCase,
James Kuszmaul8e62b022022-03-22 09:33:25 -070042 /*namespaces=*/Case::kSnake,
43 /*namespace_seperator=*/"::",
44 /*object_prefix=*/"",
45 /*object_suffix=*/"T",
46 /*keyword_prefix=*/"",
47 /*keyword_suffix=*/"_",
48 /*filenames=*/Case::kSnake,
49 /*directories=*/Case::kSnake,
50 /*output_path=*/"",
51 /*filename_suffix=*/"_generated",
52 /*filename_extension=*/".rs" };
Austin Schuhe89fa2d2019-08-14 20:24:23 -070053}
54
Austin Schuh2dd86a92022-09-14 21:19:23 -070055static std::set<std::string> RustKeywords() {
James Kuszmaul8e62b022022-03-22 09:33:25 -070056 return {
57 // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
58 "as",
59 "break",
60 "const",
61 "continue",
62 "crate",
63 "else",
64 "enum",
65 "extern",
66 "false",
67 "fn",
68 "for",
69 "if",
70 "impl",
71 "in",
72 "let",
73 "loop",
74 "match",
75 "mod",
76 "move",
77 "mut",
78 "pub",
79 "ref",
80 "return",
81 "Self",
82 "self",
83 "static",
84 "struct",
85 "super",
86 "trait",
87 "true",
88 "type",
89 "unsafe",
90 "use",
91 "where",
92 "while",
93 // future possible keywords
94 "abstract",
95 "alignof",
96 "become",
97 "box",
98 "do",
99 "final",
100 "macro",
101 "offsetof",
102 "override",
103 "priv",
104 "proc",
105 "pure",
106 "sizeof",
107 "typeof",
108 "unsized",
109 "virtual",
110 "yield",
111 // other rust terms we should not use
112 "std",
113 "usize",
114 "isize",
115 "u8",
116 "i8",
117 "u16",
118 "i16",
119 "u32",
120 "i32",
121 "u64",
122 "i64",
123 "u128",
124 "i128",
125 "f32",
126 "f64",
127 // Terms that we use ourselves
128 "follow",
129 "push",
130 "size",
131 "alignment",
132 "to_little_endian",
133 "from_little_endian",
134 "ENUM_MAX",
135 "ENUM_MIN",
136 "ENUM_VALUES",
137 };
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700138}
139
140// Encapsulate all logical field types in this enum. This allows us to write
141// field logic based on type switches, instead of branches on the properties
142// set on the Type.
143// TODO(rw): for backwards compatibility, we can't use a strict `enum class`
144// declaration here. could we use the `-Wswitch-enum` warning to
145// achieve the same effect?
146enum FullType {
147 ftInteger = 0,
148 ftFloat = 1,
149 ftBool = 2,
150
151 ftStruct = 3,
152 ftTable = 4,
153
154 ftEnumKey = 5,
155 ftUnionKey = 6,
156
157 ftUnionValue = 7,
158
159 // TODO(rw): bytestring?
160 ftString = 8,
161
162 ftVectorOfInteger = 9,
163 ftVectorOfFloat = 10,
164 ftVectorOfBool = 11,
165 ftVectorOfEnumKey = 12,
166 ftVectorOfStruct = 13,
167 ftVectorOfTable = 14,
168 ftVectorOfString = 15,
169 ftVectorOfUnionValue = 16,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700170
171 ftArrayOfBuiltin = 17,
172 ftArrayOfEnum = 18,
173 ftArrayOfStruct = 19,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700174};
175
176// Convert a Type to a FullType (exhaustive).
Austin Schuh2dd86a92022-09-14 21:19:23 -0700177static FullType GetFullType(const Type &type) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700178 // N.B. The order of these conditionals matters for some types.
179
Austin Schuh272c6132020-11-14 16:37:52 -0800180 if (IsString(type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700181 return ftString;
182 } else if (type.base_type == BASE_TYPE_STRUCT) {
183 if (type.struct_def->fixed) {
184 return ftStruct;
185 } else {
186 return ftTable;
187 }
Austin Schuh272c6132020-11-14 16:37:52 -0800188 } else if (IsVector(type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700189 switch (GetFullType(type.VectorType())) {
190 case ftInteger: {
191 return ftVectorOfInteger;
192 }
193 case ftFloat: {
194 return ftVectorOfFloat;
195 }
196 case ftBool: {
197 return ftVectorOfBool;
198 }
199 case ftStruct: {
200 return ftVectorOfStruct;
201 }
202 case ftTable: {
203 return ftVectorOfTable;
204 }
205 case ftString: {
206 return ftVectorOfString;
207 }
208 case ftEnumKey: {
209 return ftVectorOfEnumKey;
210 }
211 case ftUnionKey:
212 case ftUnionValue: {
213 FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
214 break;
215 }
216 default: {
217 FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
218 }
219 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700220 } else if (IsArray(type)) {
221 switch (GetFullType(type.VectorType())) {
222 case ftInteger:
223 case ftFloat:
224 case ftBool: {
225 return ftArrayOfBuiltin;
226 }
227 case ftStruct: {
228 return ftArrayOfStruct;
229 }
230 case ftEnumKey: {
231 return ftArrayOfEnum;
232 }
233 default: {
234 FLATBUFFERS_ASSERT(false && "Unsupported type for fixed array");
235 }
236 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700237 } else if (type.enum_def != nullptr) {
238 if (type.enum_def->is_union) {
239 if (type.base_type == BASE_TYPE_UNION) {
240 return ftUnionValue;
241 } else if (IsInteger(type.base_type)) {
242 return ftUnionKey;
243 } else {
244 FLATBUFFERS_ASSERT(false && "unknown union field type");
245 }
246 } else {
247 return ftEnumKey;
248 }
249 } else if (IsScalar(type.base_type)) {
250 if (IsBool(type.base_type)) {
251 return ftBool;
252 } else if (IsInteger(type.base_type)) {
253 return ftInteger;
254 } else if (IsFloat(type.base_type)) {
255 return ftFloat;
256 } else {
257 FLATBUFFERS_ASSERT(false && "unknown number type");
258 }
259 }
260
261 FLATBUFFERS_ASSERT(false && "completely unknown type");
262
263 // this is only to satisfy the compiler's return analysis.
264 return ftBool;
265}
266
Austin Schuh2dd86a92022-09-14 21:19:23 -0700267static bool IsBitFlagsEnum(const EnumDef &enum_def) {
Austin Schuh272c6132020-11-14 16:37:52 -0800268 return enum_def.attributes.Lookup("bit_flags") != nullptr;
269}
James Kuszmaul8e62b022022-03-22 09:33:25 -0700270
271// TableArgs make required non-scalars "Option<_>".
272// TODO(cneo): Rework how we do defaults and stuff.
Austin Schuh2dd86a92022-09-14 21:19:23 -0700273static bool IsOptionalToBuilder(const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700274 return field.IsOptional() || !IsScalar(field.value.type.base_type);
275}
Austin Schuh2dd86a92022-09-14 21:19:23 -0700276} // namespace
James Kuszmaul8e62b022022-03-22 09:33:25 -0700277
278bool GenerateRustModuleRootFile(const Parser &parser,
279 const std::string &output_dir) {
280 if (!parser.opts.rust_module_root_file) {
281 // Don't generate a root file when generating one file. This isn't an error
282 // so return true.
283 return true;
284 }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700285 Namer namer(WithFlagOptions(RustDefaultConfig(), parser.opts, output_dir),
James Kuszmaul8e62b022022-03-22 09:33:25 -0700286 RustKeywords());
287 // We gather the symbols into a tree of namespaces (which are rust mods) and
288 // generate a file that gathers them all.
289 struct Module {
290 std::map<std::string, Module> sub_modules;
291 std::vector<std::string> generated_files;
292 // Add a symbol into the tree.
293 void Insert(const Namer &namer, const Definition *s) {
294 const Definition &symbol = *s;
295 Module *current_module = this;
296 for (auto it = symbol.defined_namespace->components.begin();
297 it != symbol.defined_namespace->components.end(); it++) {
298 std::string ns_component = namer.Namespace(*it);
299 current_module = &current_module->sub_modules[ns_component];
300 }
301 current_module->generated_files.push_back(
302 namer.File(symbol.name, SkipFile::Extension));
303 }
304 // Recursively create the importer file.
305 void GenerateImports(CodeWriter &code) {
306 for (auto it = sub_modules.begin(); it != sub_modules.end(); it++) {
307 code += "pub mod " + it->first + " {";
308 code.IncrementIdentLevel();
309 code += "use super::*;";
310 it->second.GenerateImports(code);
311 code.DecrementIdentLevel();
312 code += "} // " + it->first;
313 }
314 for (auto it = generated_files.begin(); it != generated_files.end();
315 it++) {
316 code += "mod " + *it + ";";
317 code += "pub use self::" + *it + "::*;";
318 }
319 }
320 };
321 Module root_module;
322 for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
323 it++) {
324 root_module.Insert(namer, *it);
325 }
326 for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
327 it++) {
328 root_module.Insert(namer, *it);
329 }
330 CodeWriter code(" ");
331 // TODO(caspern): Move generated warning out of BaseGenerator.
332 code +=
333 "// Automatically generated by the Flatbuffers compiler. "
334 "Do not modify.";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700335 code += "// @generated";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700336 root_module.GenerateImports(code);
337 const bool success =
338 SaveFile((output_dir + "mod.rs").c_str(), code.ToString(), false);
339 code.Clear();
340 return success;
Austin Schuh272c6132020-11-14 16:37:52 -0800341}
342
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700343namespace rust {
344
345class RustGenerator : public BaseGenerator {
346 public:
347 RustGenerator(const Parser &parser, const std::string &path,
348 const std::string &file_name)
Austin Schuh272c6132020-11-14 16:37:52 -0800349 : BaseGenerator(parser, path, file_name, "", "::", "rs"),
James Kuszmaul8e62b022022-03-22 09:33:25 -0700350 cur_name_space_(nullptr),
Austin Schuh2dd86a92022-09-14 21:19:23 -0700351 namer_(WithFlagOptions(RustDefaultConfig(), parser.opts, path),
352 RustKeywords()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700353 // TODO: Namer flag overrides should be in flatc or flatc_main.
354 code_.SetPadding(" ");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700355 }
356
James Kuszmaul8e62b022022-03-22 09:33:25 -0700357 bool generate() {
358 if (!parser_.opts.rust_module_root_file) {
359 return GenerateOneFile();
360 } else {
361 return GenerateIndividualFiles();
362 }
363 }
364
365 template<typename T>
366 bool GenerateSymbols(const SymbolTable<T> &symbols,
367 std::function<void(const T &)> gen_symbol) {
368 for (auto it = symbols.vec.begin(); it != symbols.vec.end(); it++) {
369 const T &symbol = **it;
370 if (symbol.generated) continue;
371 code_.Clear();
372 code_ += "// " + std::string(FlatBuffersGeneratedWarning());
Austin Schuh2dd86a92022-09-14 21:19:23 -0700373 code_ += "// @generated";
374 code_ += "extern crate alloc;";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700375 code_ += "extern crate flatbuffers;";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700376 code_ += "use alloc::boxed::Box;";
377 code_ += "use alloc::string::{String, ToString};";
378 code_ += "use alloc::vec::Vec;";
379 code_ += "use core::mem;";
380 code_ += "use core::cmp::Ordering;";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700381 if (parser_.opts.rust_serialize) {
382 code_ += "extern crate serde;";
383 code_ +=
384 "use self::serde::ser::{Serialize, Serializer, SerializeStruct};";
385 }
386 code_ += "use self::flatbuffers::{EndianScalar, Follow};";
387 code_ += "use super::*;";
388 cur_name_space_ = symbol.defined_namespace;
389 gen_symbol(symbol);
390
391 const std::string directories =
Austin Schuh2dd86a92022-09-14 21:19:23 -0700392 namer_.Directories(*symbol.defined_namespace);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700393 EnsureDirExists(directories);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700394 const std::string file_path = directories + namer_.File(symbol);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700395 const bool save_success =
396 SaveFile(file_path.c_str(), code_.ToString(), /*binary=*/false);
397 if (!save_success) return false;
398 }
399 return true;
400 }
401
402 bool GenerateIndividualFiles() {
403 code_.Clear();
404 // Don't bother with imports. Use absolute paths everywhere.
405 return GenerateSymbols<EnumDef>(
406 parser_.enums_, [&](const EnumDef &e) { this->GenEnum(e); }) &&
407 GenerateSymbols<StructDef>(
408 parser_.structs_, [&](const StructDef &s) {
409 if (s.fixed) {
410 this->GenStruct(s);
411 } else {
412 this->GenTable(s);
413 if (this->parser_.opts.generate_object_based_api) {
414 this->GenTableObject(s);
415 }
416 }
417 if (this->parser_.root_struct_def_ == &s) {
418 this->GenRootTableFuncs(s);
419 }
420 });
421 }
422
423 // Generates code organized by .fbs files. This is broken legacy behavior
424 // that does not work with multiple fbs files with shared namespaces.
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700425 // Iterate through all definitions we haven't generated code for (enums,
426 // structs, and tables) and output them to a single file.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700427 bool GenerateOneFile() {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700428 code_.Clear();
429 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700430 code_ += "// @generated";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700431
432 assert(!cur_name_space_);
433
434 // Generate imports for the global scope in case no namespace is used
435 // in the schema file.
436 GenNamespaceImports(0);
437 code_ += "";
438
439 // Generate all code in their namespaces, once, because Rust does not
440 // permit re-opening modules.
441 //
442 // TODO(rw): Use a set data structure to reduce namespace evaluations from
443 // O(n**2) to O(n).
444 for (auto ns_it = parser_.namespaces_.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800445 ns_it != parser_.namespaces_.end(); ++ns_it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700446 const auto &ns = *ns_it;
447
448 // Generate code for all the enum declarations.
449 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
450 ++it) {
451 const auto &enum_def = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700452 if (enum_def.defined_namespace == ns && !enum_def.generated) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700453 SetNameSpace(enum_def.defined_namespace);
454 GenEnum(enum_def);
455 }
456 }
457
458 // Generate code for all structs.
459 for (auto it = parser_.structs_.vec.begin();
460 it != parser_.structs_.vec.end(); ++it) {
461 const auto &struct_def = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700462 if (struct_def.defined_namespace == ns && struct_def.fixed &&
463 !struct_def.generated) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700464 SetNameSpace(struct_def.defined_namespace);
465 GenStruct(struct_def);
466 }
467 }
468
469 // Generate code for all tables.
470 for (auto it = parser_.structs_.vec.begin();
471 it != parser_.structs_.vec.end(); ++it) {
472 const auto &struct_def = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700473 if (struct_def.defined_namespace == ns && !struct_def.fixed &&
474 !struct_def.generated) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700475 SetNameSpace(struct_def.defined_namespace);
476 GenTable(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700477 if (parser_.opts.generate_object_based_api) {
478 GenTableObject(struct_def);
479 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700480 }
481 }
482
483 // Generate global helper functions.
484 if (parser_.root_struct_def_) {
485 auto &struct_def = *parser_.root_struct_def_;
486 if (struct_def.defined_namespace != ns) { continue; }
487 SetNameSpace(struct_def.defined_namespace);
488 GenRootTableFuncs(struct_def);
489 }
490 }
491 if (cur_name_space_) SetNameSpace(nullptr);
492
Austin Schuh272c6132020-11-14 16:37:52 -0800493 const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700494 const auto final_code = code_.ToString();
495 return SaveFile(file_path.c_str(), final_code, false);
496 }
497
498 private:
499 CodeWriter code_;
500
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700501 // This tracks the current namespace so we can insert namespace declarations.
502 const Namespace *cur_name_space_;
503
504 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
505
506 // Determine if a Type needs a lifetime template parameter when used in the
507 // Rust builder args.
508 bool TableBuilderTypeNeedsLifetime(const Type &type) const {
509 switch (GetFullType(type)) {
510 case ftInteger:
511 case ftFloat:
512 case ftBool:
513 case ftEnumKey:
514 case ftUnionKey:
Austin Schuh272c6132020-11-14 16:37:52 -0800515 case ftUnionValue: {
516 return false;
517 }
518 default: {
519 return true;
520 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700521 }
522 }
523
524 // Determine if a table args rust type needs a lifetime template parameter.
525 bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
526 FLATBUFFERS_ASSERT(!struct_def.fixed);
527
528 for (auto it = struct_def.fields.vec.begin();
529 it != struct_def.fields.vec.end(); ++it) {
530 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -0800531 if (field.deprecated) { continue; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700532
Austin Schuh272c6132020-11-14 16:37:52 -0800533 if (TableBuilderTypeNeedsLifetime(field.value.type)) { return true; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700534 }
535
536 return false;
537 }
538
Austin Schuh2dd86a92022-09-14 21:19:23 -0700539 std::string NamespacedNativeName(const EnumDef &def) {
540 return WrapInNameSpace(def.defined_namespace, namer_.ObjectType(def));
541 }
542 std::string NamespacedNativeName(const StructDef &def) {
543 return WrapInNameSpace(def.defined_namespace, namer_.ObjectType(def));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700544 }
545
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700546 std::string WrapInNameSpace(const Definition &def) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700547 return WrapInNameSpace(def.defined_namespace,
548 namer_.EscapeKeyword(def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700549 }
550 std::string WrapInNameSpace(const Namespace *ns,
551 const std::string &name) const {
552 if (CurrentNameSpace() == ns) return name;
553 std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
554 return prefix + name;
555 }
556
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700557 // Determine the relative namespace traversal needed to reference one
558 // namespace from another namespace. This is useful because it does not force
559 // the user to have a particular file layout. (If we output absolute
560 // namespace paths, that may require users to organize their Rust crates in a
561 // particular way.)
562 std::string GetRelativeNamespaceTraversal(const Namespace *src,
563 const Namespace *dst) const {
564 // calculate the path needed to reference dst from src.
565 // example: f(A::B::C, A::B::C) -> (none)
566 // example: f(A::B::C, A::B) -> super::
567 // example: f(A::B::C, A::B::D) -> super::D
568 // example: f(A::B::C, A) -> super::super::
569 // example: f(A::B::C, D) -> super::super::super::D
570 // example: f(A::B::C, D::E) -> super::super::super::D::E
571 // example: f(A, D::E) -> super::D::E
572 // does not include leaf object (typically a struct type).
573
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700574 std::stringstream stream;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700575 size_t common = 0;
576 std::vector<std::string> s, d;
577 if (src) s = src->components;
578 if (dst) d = dst->components;
579 while (common < s.size() && common < d.size() && s[common] == d[common])
580 common++;
581 // If src namespace is empty, this must be an absolute path.
582 for (size_t i = common; i < s.size(); i++) stream << "super::";
583 for (size_t i = common; i < d.size(); i++)
584 stream << namer_.Namespace(d[i]) + "::";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700585 return stream.str();
586 }
587
588 // Generate a comment from the schema.
589 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700590 for (auto it = dc.begin(); it != dc.end(); it++) {
591 code_ += std::string(prefix) + "///" + *it;
592 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700593 }
594
595 // Return a Rust type from the table in idl.h.
596 std::string GetTypeBasic(const Type &type) const {
597 switch (GetFullType(type)) {
598 case ftInteger:
599 case ftFloat:
600 case ftBool:
601 case ftEnumKey:
Austin Schuh272c6132020-11-14 16:37:52 -0800602 case ftUnionKey: {
603 break;
604 }
605 default: {
606 FLATBUFFERS_ASSERT(false && "incorrect type given");
607 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700608 }
609
610 // clang-format off
611 static const char * const ctypename[] = {
612 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -0800613 RTYPE, ...) \
614 #RTYPE,
615 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700616 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700617 };
Austin Schuh272c6132020-11-14 16:37:52 -0800618 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700619
620 if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
621 return ctypename[type.base_type];
622 }
623
624 // Look up the native type for an enum. This will always be an integer like
625 // u8, i32, etc.
626 std::string GetEnumTypeForDecl(const Type &type) {
627 const auto ft = GetFullType(type);
628 if (!(ft == ftEnumKey || ft == ftUnionKey)) {
629 FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
630 }
631
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700632 // clang-format off
Austin Schuh272c6132020-11-14 16:37:52 -0800633 static const char *ctypename[] = {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700634 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -0800635 RTYPE, ...) \
636 #RTYPE,
637 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700638 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700639 };
Austin Schuh272c6132020-11-14 16:37:52 -0800640 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700641
642 // Enums can be bools, but their Rust representation must be a u8, as used
643 // in the repr attribute (#[repr(bool)] is an invalid attribute).
644 if (type.base_type == BASE_TYPE_BOOL) return "u8";
645 return ctypename[type.base_type];
646 }
647
648 // Return a Rust type for any type (scalar, table, struct) specifically for
649 // using a FlatBuffer.
650 std::string GetTypeGet(const Type &type) const {
651 switch (GetFullType(type)) {
652 case ftInteger:
653 case ftFloat:
654 case ftBool:
655 case ftEnumKey:
656 case ftUnionKey: {
Austin Schuh272c6132020-11-14 16:37:52 -0800657 return GetTypeBasic(type);
658 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700659 case ftArrayOfBuiltin:
660 case ftArrayOfEnum:
661 case ftArrayOfStruct: {
662 return "[" + GetTypeGet(type.VectorType()) + "; " +
663 NumToString(type.fixed_length) + "]";
664 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700665 case ftTable: {
666 return WrapInNameSpace(type.struct_def->defined_namespace,
Austin Schuh272c6132020-11-14 16:37:52 -0800667 type.struct_def->name) +
668 "<'a>";
669 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700670 default: {
671 return WrapInNameSpace(type.struct_def->defined_namespace,
Austin Schuh272c6132020-11-14 16:37:52 -0800672 type.struct_def->name);
673 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700674 }
675 }
676
Austin Schuh272c6132020-11-14 16:37:52 -0800677 std::string GetEnumValue(const EnumDef &enum_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700678 const EnumVal &enum_val) const {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700679 return namer_.EnumVariant(enum_def, enum_val);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700680 }
681
Austin Schuh272c6132020-11-14 16:37:52 -0800682 // 1 suffix since old C++ can't figure out the overload.
683 void ForAllEnumValues1(const EnumDef &enum_def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700684 std::function<void(const EnumVal &)> cb) {
Austin Schuh272c6132020-11-14 16:37:52 -0800685 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
686 const auto &ev = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700687 code_.SetValue("VARIANT", namer_.Variant(ev));
Austin Schuh272c6132020-11-14 16:37:52 -0800688 code_.SetValue("VALUE", enum_def.ToString(ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700689 code_.IncrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -0800690 cb(ev);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700691 code_.DecrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -0800692 }
693 }
694 void ForAllEnumValues(const EnumDef &enum_def, std::function<void()> cb) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700695 std::function<void(const EnumVal &)> wrapped = [&](const EnumVal &unused) {
696 (void)unused;
697 cb();
698 };
699 ForAllEnumValues1(enum_def, wrapped);
Austin Schuh272c6132020-11-14 16:37:52 -0800700 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700701 // Generate an enum declaration,
702 // an enum string lookup table,
703 // an enum match function,
704 // and an enum array of values
705 void GenEnum(const EnumDef &enum_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700706 const bool is_private = parser_.opts.no_leak_private_annotations &&
707 (enum_def.attributes.Lookup("private") != nullptr);
708 code_.SetValue("ACCESS_TYPE", is_private ? "pub(crate)" : "pub");
709 code_.SetValue("ENUM_TY", namer_.Type(enum_def));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700710 code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700711 code_.SetValue("ENUM_NAMESPACE", namer_.Namespace(enum_def.name));
712 code_.SetValue("ENUM_CONSTANT", namer_.Constant(enum_def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700713 const EnumVal *minv = enum_def.MinValue();
714 const EnumVal *maxv = enum_def.MaxValue();
715 FLATBUFFERS_ASSERT(minv && maxv);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700716 code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
717 code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
718
Austin Schuh272c6132020-11-14 16:37:52 -0800719 if (IsBitFlagsEnum(enum_def)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700720 // Defer to the convenient and canonical bitflags crate. We declare it in
721 // a module to #allow camel case constants in a smaller scope. This
722 // matches Flatbuffers c-modeled enums where variants are associated
723 // constants but in camel case.
Austin Schuh272c6132020-11-14 16:37:52 -0800724 code_ += "#[allow(non_upper_case_globals)]";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700725 code_ += "mod bitflags_{{ENUM_NAMESPACE}} {";
Austin Schuh272c6132020-11-14 16:37:52 -0800726 code_ += " flatbuffers::bitflags::bitflags! {";
727 GenComment(enum_def.doc_comment, " ");
James Kuszmaul8e62b022022-03-22 09:33:25 -0700728 code_ += " #[derive(Default)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700729 code_ += " {{ACCESS_TYPE}} struct {{ENUM_TY}}: {{BASE_TYPE}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700730 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
731 this->GenComment(ev.doc_comment, " ");
732 code_ += " const {{VARIANT}} = {{VALUE}};";
Austin Schuh272c6132020-11-14 16:37:52 -0800733 });
734 code_ += " }";
735 code_ += " }";
736 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700737 code_ += "pub use self::bitflags_{{ENUM_NAMESPACE}}::{{ENUM_TY}};";
Austin Schuh272c6132020-11-14 16:37:52 -0800738 code_ += "";
739
James Kuszmaul8e62b022022-03-22 09:33:25 -0700740 code_.SetValue("FROM_BASE", "unsafe { Self::from_bits_unchecked(b) }");
741 code_.SetValue("INTO_BASE", "self.bits()");
742 } else {
743 // Normal, c-modelled enums.
744 // Deprecated associated constants;
745 const std::string deprecation_warning =
746 "#[deprecated(since = \"2.0.0\", note = \"Use associated constants"
747 " instead. This will no longer be generated in 2021.\")]";
748 code_ += deprecation_warning;
749 code_ +=
750 "pub const ENUM_MIN_{{ENUM_CONSTANT}}: {{BASE_TYPE}}"
751 " = {{ENUM_MIN_BASE_VALUE}};";
752 code_ += deprecation_warning;
753 code_ +=
754 "pub const ENUM_MAX_{{ENUM_CONSTANT}}: {{BASE_TYPE}}"
755 " = {{ENUM_MAX_BASE_VALUE}};";
756 auto num_fields = NumToString(enum_def.size());
757 code_ += deprecation_warning;
758 code_ += "#[allow(non_camel_case_types)]";
759 code_ += "pub const ENUM_VALUES_{{ENUM_CONSTANT}}: [{{ENUM_TY}}; " +
760 num_fields + "] = [";
761 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700762 code_ += namer_.EnumVariant(enum_def, ev) + ",";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700763 });
764 code_ += "];";
Austin Schuh272c6132020-11-14 16:37:52 -0800765 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700766
767 GenComment(enum_def.doc_comment);
768 // Derive Default to be 0. flatc enforces this when the enum
769 // is put into a struct, though this isn't documented behavior, it is
770 // needed to derive defaults in struct objects.
771 code_ +=
772 "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, "
773 "Default)]";
774 code_ += "#[repr(transparent)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700775 code_ += "{{ACCESS_TYPE}} struct {{ENUM_TY}}(pub {{BASE_TYPE}});";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700776 code_ += "#[allow(non_upper_case_globals)]";
777 code_ += "impl {{ENUM_TY}} {";
778 ForAllEnumValues1(enum_def, [&](const EnumVal &ev) {
779 this->GenComment(ev.doc_comment);
780 code_ += "pub const {{VARIANT}}: Self = Self({{VALUE}});";
781 });
782 code_ += "";
783 // Generate Associated constants
784 code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};";
785 code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};";
786 code_ += " pub const ENUM_VALUES: &'static [Self] = &[";
787 ForAllEnumValues(enum_def, [&]() { code_ += " Self::{{VARIANT}},"; });
788 code_ += " ];";
789 code_ += " /// Returns the variant's name or \"\" if unknown.";
790 code_ += " pub fn variant_name(self) -> Option<&'static str> {";
791 code_ += " match self {";
792 ForAllEnumValues(enum_def, [&]() {
793 code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),";
794 });
795 code_ += " _ => None,";
Austin Schuh272c6132020-11-14 16:37:52 -0800796 code_ += " }";
Austin Schuh272c6132020-11-14 16:37:52 -0800797 code_ += " }";
798 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700799
800 // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>".
Austin Schuh2dd86a92022-09-14 21:19:23 -0700801 code_ += "impl core::fmt::Debug for {{ENUM_TY}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700802 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -0700803 " fn fmt(&self, f: &mut core::fmt::Formatter) ->"
804 " core::fmt::Result {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700805 code_ += " if let Some(name) = self.variant_name() {";
806 code_ += " f.write_str(name)";
807 code_ += " } else {";
808 code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))";
809 code_ += " }";
810 code_ += " }";
811 code_ += "}";
812
813 code_.SetValue("FROM_BASE", "Self(b)");
814 code_.SetValue("INTO_BASE", "self.0");
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]";
842 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700843 code_ += " let b = unsafe {";
844 code_ += " flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc)";
845 code_ += " };";
846 code_ += " {{FROM_BASE}}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700847 code_ += " }";
848 code_ += "}";
849 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700850 code_ += "impl flatbuffers::Push for {{ENUM_TY}} {";
851 code_ += " type Output = {{ENUM_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700852 code_ += " #[inline]";
853 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700854 code_ +=
855 " unsafe { flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
856 "(dst, {{INTO_BASE}}); }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700857 code_ += " }";
858 code_ += "}";
859 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700860 code_ += "impl flatbuffers::EndianScalar for {{ENUM_TY}} {";
Austin Schuh272c6132020-11-14 16:37:52 -0800861 code_ += " #[inline]";
862 code_ += " fn to_little_endian(self) -> Self {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700863 code_ += " let b = {{BASE_TYPE}}::to_le({{INTO_BASE}});";
864 code_ += " {{FROM_BASE}}";
Austin Schuh272c6132020-11-14 16:37:52 -0800865 code_ += " }";
866 code_ += " #[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700867 code_ += " #[allow(clippy::wrong_self_convention)]";
Austin Schuh272c6132020-11-14 16:37:52 -0800868 code_ += " fn from_little_endian(self) -> Self {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700869 code_ += " let b = {{BASE_TYPE}}::from_le({{INTO_BASE}});";
870 code_ += " {{FROM_BASE}}";
Austin Schuh272c6132020-11-14 16:37:52 -0800871 code_ += " }";
872 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700873 code_ += "";
874
James Kuszmaul8e62b022022-03-22 09:33:25 -0700875 // Generate verifier - deferring to the base type.
876 code_ += "impl<'a> flatbuffers::Verifiable for {{ENUM_TY}} {";
877 code_ += " #[inline]";
878 code_ += " fn run_verifier(";
879 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
880 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
881 code_ += " use self::flatbuffers::Verifiable;";
882 code_ += " {{BASE_TYPE}}::run_verifier(v, pos)";
883 code_ += " }";
884 code_ += "}";
885 code_ += "";
886 // Enums are basically integers.
887 code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{ENUM_TY}} {}";
888
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700889 if (enum_def.is_union) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700890 // Generate typesafe offset(s) for unions
Austin Schuh2dd86a92022-09-14 21:19:23 -0700891 code_.SetValue("UNION_TYPE", namer_.Type(enum_def));
892 code_ += "{{ACCESS_TYPE}} struct {{UNION_TYPE}}UnionTableOffset {}";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700893 code_ += "";
894 if (parser_.opts.generate_object_based_api) { GenUnionObject(enum_def); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700895 }
896 }
897
James Kuszmaul8e62b022022-03-22 09:33:25 -0700898 // TODO(cneo): dedup Object versions from non object versions.
899 void ForAllUnionObjectVariantsBesidesNone(const EnumDef &enum_def,
900 std::function<void()> cb) {
901 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
902 auto &enum_val = **it;
903 if (enum_val.union_type.base_type == BASE_TYPE_NONE) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700904 code_.SetValue("VARIANT_NAME", namer_.Variant(enum_val));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700905 // For legacy reasons, enum variants are Keep case while enum native
906 // variants are UpperCamel case.
Austin Schuh2dd86a92022-09-14 21:19:23 -0700907 code_.SetValue("NATIVE_VARIANT",
908 namer_.LegacyRustNativeVariant(enum_val));
909 code_.SetValue("U_ELEMENT_NAME", namer_.Method(enum_val));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700910 code_.SetValue("U_ELEMENT_TABLE_TYPE",
911 NamespacedNativeName(*enum_val.union_type.struct_def));
912 code_.IncrementIdentLevel();
913 cb();
914 code_.DecrementIdentLevel();
915 }
916 }
917 void GenUnionObject(const EnumDef &enum_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700918 code_.SetValue("ENUM_TY", namer_.Type(enum_def));
919 code_.SetValue("ENUM_FN", namer_.Function(enum_def));
920 code_.SetValue("ENUM_OTY", namer_.ObjectType(enum_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700921
922 // Generate native union.
923 code_ += "#[allow(clippy::upper_case_acronyms)]"; // NONE's spelling is
924 // intended.
925 code_ += "#[non_exhaustive]";
926 code_ += "#[derive(Debug, Clone, PartialEq)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700927 code_ += "{{ACCESS_TYPE}} enum {{ENUM_OTY}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700928 code_ += " NONE,";
929 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
930 code_ += "{{NATIVE_VARIANT}}(Box<{{U_ELEMENT_TABLE_TYPE}}>),";
931 });
932 code_ += "}";
933 // Generate Default (NONE).
934 code_ += "impl Default for {{ENUM_OTY}} {";
935 code_ += " fn default() -> Self {";
936 code_ += " Self::NONE";
937 code_ += " }";
938 code_ += "}";
939
940 // Generate native union methods.
941 code_ += "impl {{ENUM_OTY}} {";
942
943 // Get flatbuffers union key.
944 // TODO(cneo): add docstrings?
945 code_ += " pub fn {{ENUM_FN}}_type(&self) -> {{ENUM_TY}} {";
946 code_ += " match self {";
947 code_ += " Self::NONE => {{ENUM_TY}}::NONE,";
948 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
949 code_ +=
950 " Self::{{NATIVE_VARIANT}}(_) => {{ENUM_TY}}::"
951 "{{VARIANT_NAME}},";
952 });
953 code_ += " }";
954 code_ += " }";
955 // Pack flatbuffers union value
956 code_ +=
957 " pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder)"
958 " -> Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>"
959 " {";
960 code_ += " match self {";
961 code_ += " Self::NONE => None,";
962 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
963 code_ += " Self::{{NATIVE_VARIANT}}(v) => \\";
964 code_ += "Some(v.pack(fbb).as_union_value()),";
965 });
966 code_ += " }";
967 code_ += " }";
968
969 // Generate some accessors;
970 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
971 // Move accessor.
972 code_ +=
973 "/// If the union variant matches, return the owned "
974 "{{U_ELEMENT_TABLE_TYPE}}, setting the union to NONE.";
975 code_ +=
976 "pub fn take_{{U_ELEMENT_NAME}}(&mut self) -> "
977 "Option<Box<{{U_ELEMENT_TABLE_TYPE}}>> {";
978 code_ += " if let Self::{{NATIVE_VARIANT}}(_) = self {";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700979 code_ += " let v = core::mem::replace(self, Self::NONE);";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700980 code_ += " if let Self::{{NATIVE_VARIANT}}(w) = v {";
981 code_ += " Some(w)";
982 code_ += " } else {";
983 code_ += " unreachable!()";
984 code_ += " }";
985 code_ += " } else {";
986 code_ += " None";
987 code_ += " }";
988 code_ += "}";
989 // Immutable reference accessor.
990 code_ +=
991 "/// If the union variant matches, return a reference to the "
992 "{{U_ELEMENT_TABLE_TYPE}}.";
993 code_ +=
994 "pub fn as_{{U_ELEMENT_NAME}}(&self) -> "
995 "Option<&{{U_ELEMENT_TABLE_TYPE}}> {";
996 code_ +=
997 " if let Self::{{NATIVE_VARIANT}}(v) = self "
998 "{ Some(v.as_ref()) } else { None }";
999 code_ += "}";
1000 // Mutable reference accessor.
1001 code_ +=
1002 "/// If the union variant matches, return a mutable reference"
1003 " to the {{U_ELEMENT_TABLE_TYPE}}.";
1004 code_ +=
1005 "pub fn as_{{U_ELEMENT_NAME}}_mut(&mut self) -> "
1006 "Option<&mut {{U_ELEMENT_TABLE_TYPE}}> {";
1007 code_ +=
1008 " if let Self::{{NATIVE_VARIANT}}(v) = self "
1009 "{ Some(v.as_mut()) } else { None }";
1010 code_ += "}";
1011 });
1012 code_ += "}"; // End union methods impl.
1013 }
1014
James Kuszmaul8e62b022022-03-22 09:33:25 -07001015 enum DefaultContext { kBuilder, kAccessor, kObject };
1016 std::string GetDefaultValue(const FieldDef &field,
1017 const DefaultContext context) {
1018 if (context == kBuilder) {
1019 // Builders and Args structs model nonscalars "optional" even if they're
1020 // required or have defaults according to the schema. I guess its because
1021 // WIPOffset is not nullable.
1022 if (!IsScalar(field.value.type.base_type) || field.IsOptional()) {
1023 return "None";
1024 }
1025 } else {
1026 // This for defaults in objects.
1027 // Unions have a NONE variant instead of using Rust's None.
1028 if (field.IsOptional() && !IsUnion(field.value.type)) { return "None"; }
1029 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001030 switch (GetFullType(field.value.type)) {
Austin Schuh272c6132020-11-14 16:37:52 -08001031 case ftInteger:
1032 case ftFloat: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001033 return field.value.constant;
Austin Schuh272c6132020-11-14 16:37:52 -08001034 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001035 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001036 return field.value.constant == "0" ? "false" : "true";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001037 }
1038 case ftUnionKey:
1039 case ftEnumKey: {
1040 auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001041 if (!ev) return "Default::default()"; // Bitflags enum.
1042 return WrapInNameSpace(
1043 field.value.type.enum_def->defined_namespace,
Austin Schuh2dd86a92022-09-14 21:19:23 -07001044 namer_.EnumVariant(*field.value.type.enum_def, *ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001045 }
1046 case ftUnionValue: {
1047 return ObjectFieldType(field, true) + "::NONE";
1048 }
1049 case ftString: {
1050 // Required fields do not have defaults defined by the schema, but we
1051 // need one for Rust's Default trait so we use empty string. The usual
1052 // value of field.value.constant is `0`, which is non-sensical except
1053 // maybe to c++ (nullptr == 0).
1054 // TODO: Escape strings?
1055 const std::string defval =
1056 field.IsRequired() ? "\"\"" : "\"" + field.value.constant + "\"";
1057 if (context == kObject) return defval + ".to_string()";
1058 if (context == kAccessor) return "&" + defval;
1059 FLATBUFFERS_ASSERT(false);
1060 return "INVALID_CODE_GENERATION";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001061 }
1062
James Kuszmaul8e62b022022-03-22 09:33:25 -07001063 case ftArrayOfStruct:
1064 case ftArrayOfEnum:
1065 case ftArrayOfBuiltin:
1066 case ftVectorOfBool:
1067 case ftVectorOfFloat:
1068 case ftVectorOfInteger:
1069 case ftVectorOfString:
1070 case ftVectorOfStruct:
1071 case ftVectorOfTable:
1072 case ftVectorOfEnumKey:
1073 case ftVectorOfUnionValue:
1074 case ftStruct:
1075 case ftTable: {
1076 // We only support empty vectors which matches the defaults for
1077 // &[T] and Vec<T> anyway.
1078 //
1079 // For required structs and tables fields, we defer to their object API
1080 // defaults. This works so long as there's nothing recursive happening,
1081 // but `table Infinity { i: Infinity (required); }` does compile.
1082 return "Default::default()";
Austin Schuh272c6132020-11-14 16:37:52 -08001083 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001084 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001085 FLATBUFFERS_ASSERT(false);
1086 return "INVALID_CODE_GENERATION";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001087 }
1088
1089 // Create the return type for fields in the *BuilderArgs structs that are
1090 // used to create Tables.
1091 //
1092 // Note: we could make all inputs to the BuilderArgs be an Option, as well
1093 // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
1094 // know if the value is default or not, because there are three ways to
1095 // return a default value:
1096 // 1) return a stored value that happens to be the default,
1097 // 2) return a hardcoded value because the relevant vtable field is not in
1098 // the vtable, or
1099 // 3) return a hardcoded value because the vtable field value is set to zero.
1100 std::string TableBuilderArgsDefnType(const FieldDef &field,
1101 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -08001102 const Type &type = field.value.type;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001103 auto WrapOption = [&](std::string s) {
1104 return IsOptionalToBuilder(field) ? "Option<" + s + ">" : s;
1105 };
1106 auto WrapVector = [&](std::string ty) {
1107 return WrapOption("flatbuffers::WIPOffset<flatbuffers::Vector<" +
1108 lifetime + ", " + ty + ">>");
1109 };
1110 auto WrapUOffsetsVector = [&](std::string ty) {
1111 return WrapVector("flatbuffers::ForwardsUOffset<" + ty + ">");
1112 };
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001113
1114 switch (GetFullType(type)) {
1115 case ftInteger:
1116 case ftFloat:
1117 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001118 return WrapOption(GetTypeBasic(type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001119 }
1120 case ftStruct: {
1121 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001122 return WrapOption("&" + lifetime + " " + typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001123 }
1124 case ftTable: {
1125 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001126 return WrapOption("flatbuffers::WIPOffset<" + typname + "<" + lifetime +
1127 ">>");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001128 }
1129 case ftString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001130 return WrapOption("flatbuffers::WIPOffset<&" + lifetime + " str>");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001131 }
1132 case ftEnumKey:
1133 case ftUnionKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001134 return WrapOption(WrapInNameSpace(*type.enum_def));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001135 }
1136 case ftUnionValue: {
1137 return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
1138 }
1139
1140 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001141 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001142 case ftVectorOfFloat: {
1143 const auto typname = GetTypeBasic(type.VectorType());
James Kuszmaul8e62b022022-03-22 09:33:25 -07001144 return WrapVector(typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001145 }
1146 case ftVectorOfEnumKey: {
1147 const auto typname = WrapInNameSpace(*type.enum_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001148 return WrapVector(typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001149 }
1150 case ftVectorOfStruct: {
1151 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001152 return WrapVector(typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001153 }
1154 case ftVectorOfTable: {
1155 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001156 return WrapUOffsetsVector(typname + "<" + lifetime + ">");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001157 }
1158 case ftVectorOfString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001159 return WrapUOffsetsVector("&" + lifetime + " str");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001160 }
1161 case ftVectorOfUnionValue: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001162 return WrapUOffsetsVector("flatbuffers::Table<" + lifetime + ">");
1163 }
1164 case ftArrayOfEnum:
1165 case ftArrayOfStruct:
1166 case ftArrayOfBuiltin: {
1167 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1168 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001169 }
1170 }
Austin Schuh272c6132020-11-14 16:37:52 -08001171 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001172 }
1173
James Kuszmaul8e62b022022-03-22 09:33:25 -07001174 std::string ObjectFieldType(const FieldDef &field, bool in_a_table) {
1175 const Type &type = field.value.type;
1176 std::string ty;
1177 switch (GetFullType(type)) {
1178 case ftInteger:
1179 case ftBool:
1180 case ftFloat: {
1181 ty = GetTypeBasic(type);
1182 break;
1183 }
1184 case ftString: {
1185 ty = "String";
1186 break;
1187 }
1188 case ftStruct: {
1189 ty = NamespacedNativeName(*type.struct_def);
1190 break;
1191 }
1192 case ftTable: {
1193 // Since Tables can contain themselves, Box is required to avoid
1194 // infinite types.
1195 ty = "Box<" + NamespacedNativeName(*type.struct_def) + ">";
1196 break;
1197 }
1198 case ftUnionKey: {
1199 // There is no native "UnionKey", natively, unions are rust enums with
1200 // newtype-struct-variants.
1201 return "INVALID_CODE_GENERATION";
1202 }
1203 case ftUnionValue: {
1204 ty = NamespacedNativeName(*type.enum_def);
1205 break;
1206 }
1207 case ftEnumKey: {
1208 ty = WrapInNameSpace(*type.enum_def);
1209 break;
1210 }
1211 // Vectors are in tables and are optional
1212 case ftVectorOfEnumKey: {
1213 ty = "Vec<" + WrapInNameSpace(*type.VectorType().enum_def) + ">";
1214 break;
1215 }
1216 case ftVectorOfInteger:
1217 case ftVectorOfBool:
1218 case ftVectorOfFloat: {
1219 ty = "Vec<" + GetTypeBasic(type.VectorType()) + ">";
1220 break;
1221 }
1222 case ftVectorOfString: {
1223 ty = "Vec<String>";
1224 break;
1225 }
1226 case ftVectorOfTable:
1227 case ftVectorOfStruct: {
1228 ty = NamespacedNativeName(*type.VectorType().struct_def);
1229 ty = "Vec<" + ty + ">";
1230 break;
1231 }
1232 case ftVectorOfUnionValue: {
1233 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1234 return "INVALID_CODE_GENERATION"; // OH NO!
1235 }
1236 case ftArrayOfEnum: {
1237 ty = "[" + WrapInNameSpace(*type.VectorType().enum_def) + "; " +
1238 NumToString(type.fixed_length) + "]";
1239 break;
1240 }
1241 case ftArrayOfStruct: {
1242 ty = "[" + NamespacedNativeName(*type.VectorType().struct_def) + "; " +
1243 NumToString(type.fixed_length) + "]";
1244 break;
1245 }
1246 case ftArrayOfBuiltin: {
1247 ty = "[" + GetTypeBasic(type.VectorType()) + "; " +
1248 NumToString(type.fixed_length) + "]";
1249 break;
1250 }
1251 }
1252 if (in_a_table && !IsUnion(type) && field.IsOptional()) {
1253 return "Option<" + ty + ">";
1254 } else {
1255 return ty;
1256 }
1257 }
1258
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001259 std::string TableBuilderArgsAddFuncType(const FieldDef &field,
1260 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -08001261 const Type &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001262
1263 switch (GetFullType(field.value.type)) {
1264 case ftVectorOfStruct: {
1265 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001266 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1267 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001268 }
1269 case ftVectorOfTable: {
1270 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001271 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1272 ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
1273 ">>>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001274 }
1275 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001276 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001277 case ftVectorOfFloat: {
1278 const auto typname = GetTypeBasic(type.VectorType());
Austin Schuh272c6132020-11-14 16:37:52 -08001279 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1280 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001281 }
1282 case ftVectorOfString: {
Austin Schuh272c6132020-11-14 16:37:52 -08001283 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001284 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
1285 }
1286 case ftVectorOfEnumKey: {
1287 const auto typname = WrapInNameSpace(*type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001288 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
1289 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001290 }
1291 case ftVectorOfUnionValue: {
Austin Schuh272c6132020-11-14 16:37:52 -08001292 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
1293 ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + lifetime +
1294 ">>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001295 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001296 case ftEnumKey:
1297 case ftUnionKey: {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001298 const auto typname = WrapInNameSpace(*type.enum_def);
1299 return typname;
1300 }
1301 case ftStruct: {
1302 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001303 return "&" + typname + "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001304 }
1305 case ftTable: {
1306 const auto typname = WrapInNameSpace(*type.struct_def);
1307 return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
1308 }
1309 case ftInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001310 case ftBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001311 case ftFloat: {
Austin Schuh272c6132020-11-14 16:37:52 -08001312 return GetTypeBasic(type);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001313 }
1314 case ftString: {
1315 return "flatbuffers::WIPOffset<&" + lifetime + " str>";
1316 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001317 case ftUnionValue: {
1318 return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
1319 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001320 case ftArrayOfBuiltin: {
1321 const auto typname = GetTypeBasic(type.VectorType());
1322 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1323 NumToString(type.fixed_length) + ">";
1324 }
1325 case ftArrayOfEnum: {
1326 const auto typname = WrapInNameSpace(*type.enum_def);
1327 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1328 NumToString(type.fixed_length) + ">";
1329 }
1330 case ftArrayOfStruct: {
1331 const auto typname = WrapInNameSpace(*type.struct_def);
1332 return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
1333 NumToString(type.fixed_length) + ">";
1334 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001335 }
1336
Austin Schuh272c6132020-11-14 16:37:52 -08001337 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001338 }
1339
1340 std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
Austin Schuh272c6132020-11-14 16:37:52 -08001341 const Type &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001342
1343 switch (GetFullType(field.value.type)) {
1344 case ftInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001345 case ftBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001346 case ftFloat: {
1347 const auto typname = GetTypeBasic(field.value.type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001348 return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
1349 : "self.fbb_.push_slot::<") +
Austin Schuh272c6132020-11-14 16:37:52 -08001350 typname + ">";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001351 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001352 case ftEnumKey:
1353 case ftUnionKey: {
1354 const auto underlying_typname = GetTypeBasic(type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001355 return (field.IsOptional() ? "self.fbb_.push_slot_always::<"
1356 : "self.fbb_.push_slot::<") +
1357 underlying_typname + ">";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001358 }
1359
1360 case ftStruct: {
1361 const std::string typname = WrapInNameSpace(*type.struct_def);
1362 return "self.fbb_.push_slot_always::<&" + typname + ">";
1363 }
1364 case ftTable: {
1365 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001366 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" +
1367 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001368 }
1369
1370 case ftUnionValue:
1371 case ftString:
1372 case ftVectorOfInteger:
1373 case ftVectorOfFloat:
1374 case ftVectorOfBool:
1375 case ftVectorOfEnumKey:
1376 case ftVectorOfStruct:
1377 case ftVectorOfTable:
1378 case ftVectorOfString:
1379 case ftVectorOfUnionValue: {
1380 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
1381 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001382 case ftArrayOfEnum:
1383 case ftArrayOfStruct:
1384 case ftArrayOfBuiltin: {
1385 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1386 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1387 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001388 }
Austin Schuh272c6132020-11-14 16:37:52 -08001389 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001390 }
1391
1392 std::string GenTableAccessorFuncReturnType(const FieldDef &field,
1393 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -08001394 const Type &type = field.value.type;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001395 const auto WrapOption = [&](std::string s) {
1396 return field.IsOptional() ? "Option<" + s + ">" : s;
1397 };
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001398
1399 switch (GetFullType(field.value.type)) {
1400 case ftInteger:
1401 case ftFloat:
1402 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001403 return WrapOption(GetTypeBasic(type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001404 }
1405 case ftStruct: {
1406 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001407 return WrapOption("&" + lifetime + " " + typname);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001408 }
1409 case ftTable: {
1410 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001411 return WrapOption(typname + "<" + lifetime + ">");
Austin Schuh272c6132020-11-14 16:37:52 -08001412 }
1413 case ftEnumKey:
1414 case ftUnionKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001415 return WrapOption(WrapInNameSpace(*type.enum_def));
Austin Schuh272c6132020-11-14 16:37:52 -08001416 }
1417
1418 case ftUnionValue: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001419 return WrapOption("flatbuffers::Table<" + lifetime + ">");
Austin Schuh272c6132020-11-14 16:37:52 -08001420 }
1421 case ftString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001422 return WrapOption("&" + lifetime + " str");
Austin Schuh272c6132020-11-14 16:37:52 -08001423 }
1424 case ftVectorOfInteger:
1425 case ftVectorOfBool:
1426 case ftVectorOfFloat: {
1427 const auto typname = GetTypeBasic(type.VectorType());
James Kuszmaul8e62b022022-03-22 09:33:25 -07001428 const auto vector_type =
1429 IsOneByte(type.VectorType().base_type)
1430 ? "&" + lifetime + " [" + typname + "]"
1431 : "flatbuffers::Vector<" + lifetime + ", " + typname + ">";
1432 return WrapOption(vector_type);
Austin Schuh272c6132020-11-14 16:37:52 -08001433 }
1434 case ftVectorOfEnumKey: {
1435 const auto typname = WrapInNameSpace(*type.enum_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001436 return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname +
1437 ">");
Austin Schuh272c6132020-11-14 16:37:52 -08001438 }
1439 case ftVectorOfStruct: {
1440 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001441 return WrapOption("&" + lifetime + " [" + typname + "]");
Austin Schuh272c6132020-11-14 16:37:52 -08001442 }
1443 case ftVectorOfTable: {
1444 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001445 return WrapOption("flatbuffers::Vector<" + lifetime +
1446 ", flatbuffers::ForwardsUOffset<" + typname + "<" +
1447 lifetime + ">>>");
Austin Schuh272c6132020-11-14 16:37:52 -08001448 }
1449 case ftVectorOfString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001450 return WrapOption("flatbuffers::Vector<" + lifetime +
1451 ", flatbuffers::ForwardsUOffset<&" + lifetime +
1452 " str>>");
Austin Schuh272c6132020-11-14 16:37:52 -08001453 }
1454 case ftVectorOfUnionValue: {
1455 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1456 // TODO(rw): when we do support these, we should consider using the
1457 // Into trait to convert tables to typesafe union values.
1458 return "INVALID_CODE_GENERATION"; // for return analysis
1459 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001460 case ftArrayOfEnum:
1461 case ftArrayOfStruct:
1462 case ftArrayOfBuiltin: {
1463 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
1464 return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
1465 }
Austin Schuh272c6132020-11-14 16:37:52 -08001466 }
1467 return "INVALID_CODE_GENERATION"; // for return analysis
1468 }
1469
James Kuszmaul8e62b022022-03-22 09:33:25 -07001470 std::string FollowType(const Type &type, const std::string &lifetime) {
1471 // IsVector... This can be made iterative?
Austin Schuh272c6132020-11-14 16:37:52 -08001472
James Kuszmaul8e62b022022-03-22 09:33:25 -07001473 const auto WrapForwardsUOffset = [](std::string ty) -> std::string {
1474 return "flatbuffers::ForwardsUOffset<" + ty + ">";
1475 };
1476 const auto WrapVector = [&](std::string ty) -> std::string {
1477 return "flatbuffers::Vector<" + lifetime + ", " + ty + ">";
1478 };
1479 const auto WrapArray = [&](std::string ty, uint16_t length) -> std::string {
1480 return "flatbuffers::Array<" + lifetime + ", " + ty + ", " +
1481 NumToString(length) + ">";
1482 };
1483 switch (GetFullType(type)) {
Austin Schuh272c6132020-11-14 16:37:52 -08001484 case ftInteger:
1485 case ftFloat:
1486 case ftBool: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001487 return GetTypeBasic(type);
Austin Schuh272c6132020-11-14 16:37:52 -08001488 }
1489 case ftStruct: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001490 return WrapInNameSpace(*type.struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001491 }
1492 case ftUnionKey:
1493 case ftEnumKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001494 return WrapInNameSpace(*type.enum_def);
1495 }
1496 case ftTable: {
1497 const auto typname = WrapInNameSpace(*type.struct_def);
1498 return WrapForwardsUOffset(typname);
1499 }
1500 case ftUnionValue: {
1501 return WrapForwardsUOffset("flatbuffers::Table<" + lifetime + ">");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001502 }
1503 case ftString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001504 return WrapForwardsUOffset("&str");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001505 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001506 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001507 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001508 case ftVectorOfFloat: {
1509 const auto typname = GetTypeBasic(type.VectorType());
James Kuszmaul8e62b022022-03-22 09:33:25 -07001510 return WrapForwardsUOffset(WrapVector(typname));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001511 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001512 case ftVectorOfEnumKey: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001513 const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
1514 return WrapForwardsUOffset(WrapVector(typname));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001515 }
1516 case ftVectorOfStruct: {
1517 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001518 return WrapForwardsUOffset(WrapVector(typname));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001519 }
1520 case ftVectorOfTable: {
1521 const auto typname = WrapInNameSpace(*type.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001522 return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(typname)));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001523 }
1524 case ftVectorOfString: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001525 return WrapForwardsUOffset(
1526 WrapVector(WrapForwardsUOffset("&" + lifetime + " str")));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001527 }
1528 case ftVectorOfUnionValue: {
1529 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
Austin Schuh272c6132020-11-14 16:37:52 -08001530 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001531 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001532 case ftArrayOfEnum: {
1533 const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
1534 return WrapArray(typname, type.fixed_length);
1535 }
1536 case ftArrayOfStruct: {
1537 const auto typname = WrapInNameSpace(*type.struct_def);
1538 return WrapArray(typname, type.fixed_length);
1539 }
1540 case ftArrayOfBuiltin: {
1541 const auto typname = GetTypeBasic(type.VectorType());
1542 return WrapArray(typname, type.fixed_length);
1543 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001544 }
Austin Schuh272c6132020-11-14 16:37:52 -08001545 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001546 }
1547
James Kuszmaul8e62b022022-03-22 09:33:25 -07001548 std::string GenTableAccessorFuncBody(const FieldDef &field,
1549 const std::string &lifetime) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001550 const std::string vt_offset = namer_.LegacyRustFieldOffsetName(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001551 const std::string typname = FollowType(field.value.type, lifetime);
1552 // Default-y fields (scalars so far) are neither optional nor required.
1553 const std::string default_value =
1554 !(field.IsOptional() || field.IsRequired())
1555 ? "Some(" + GetDefaultValue(field, kAccessor) + ")"
1556 : "None";
1557 const std::string unwrap = field.IsOptional() ? "" : ".unwrap()";
1558
1559 const auto t = GetFullType(field.value.type);
1560
1561 // TODO(caspern): Shouldn't 1byte VectorOfEnumKey be slice too?
1562 const std::string safe_slice =
1563 (t == ftVectorOfStruct ||
1564 ((t == ftVectorOfBool || t == ftVectorOfFloat ||
1565 t == ftVectorOfInteger) &&
1566 IsOneByte(field.value.type.VectorType().base_type)))
1567 ? ".map(|v| v.safe_slice())"
1568 : "";
1569
1570 return "self._tab.get::<" + typname + ">({{STRUCT_TY}}::" + vt_offset +
1571 ", " + default_value + ")" + safe_slice + unwrap;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001572 }
1573
Austin Schuh272c6132020-11-14 16:37:52 -08001574 // Generates a fully-qualified name getter for use with --gen-name-strings
1575 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1576 const std::string &name) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001577 const std::string fully_qualified_name =
1578 struct_def.defined_namespace->GetFullyQualifiedName(name);
1579 code_ += " pub const fn get_fully_qualified_name() -> &'static str {";
1580 code_ += " \"" + fully_qualified_name + "\"";
1581 code_ += " }";
Austin Schuh272c6132020-11-14 16:37:52 -08001582 code_ += "";
1583 }
1584
1585 void ForAllUnionVariantsBesidesNone(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001586 const EnumDef &def, std::function<void(const EnumVal &ev)> cb) {
Austin Schuh272c6132020-11-14 16:37:52 -08001587 FLATBUFFERS_ASSERT(def.is_union);
1588
1589 for (auto it = def.Vals().begin(); it != def.Vals().end(); ++it) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001590 const EnumVal &ev = **it;
Austin Schuh272c6132020-11-14 16:37:52 -08001591 // TODO(cneo): Can variants be deprecated, should we skip them?
1592 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
Austin Schuh2dd86a92022-09-14 21:19:23 -07001593 code_.SetValue(
1594 "U_ELEMENT_ENUM_TYPE",
1595 WrapInNameSpace(def.defined_namespace, namer_.EnumVariant(def, ev)));
Austin Schuh272c6132020-11-14 16:37:52 -08001596 code_.SetValue(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001597 "U_ELEMENT_TABLE_TYPE",
Austin Schuh272c6132020-11-14 16:37:52 -08001598 WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
1599 ev.union_type.struct_def->name));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001600 code_.SetValue("U_ELEMENT_NAME", namer_.Function(ev.name));
Austin Schuh272c6132020-11-14 16:37:52 -08001601 cb(ev);
1602 }
1603 }
1604
James Kuszmaul8e62b022022-03-22 09:33:25 -07001605 void ForAllTableFields(const StructDef &struct_def,
1606 std::function<void(const FieldDef &)> cb,
1607 bool reversed = false) {
Austin Schuh272c6132020-11-14 16:37:52 -08001608 // TODO(cneo): Remove `reversed` overload. It's only here to minimize the
1609 // diff when refactoring to the `ForAllX` helper functions.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001610 auto go = [&](const FieldDef &field) {
Austin Schuh272c6132020-11-14 16:37:52 -08001611 if (field.deprecated) return;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001612 code_.SetValue("OFFSET_NAME", namer_.LegacyRustFieldOffsetName(field));
Austin Schuh272c6132020-11-14 16:37:52 -08001613 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
Austin Schuh2dd86a92022-09-14 21:19:23 -07001614 code_.SetValue("FIELD", namer_.Field(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001615 code_.SetValue("BLDR_DEF_VAL", GetDefaultValue(field, kBuilder));
Austin Schuh2dd86a92022-09-14 21:19:23 -07001616 code_.SetValue("DISCRIMINANT", namer_.Field(field) + "_type");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001617 code_.IncrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -08001618 cb(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001619 code_.DecrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -08001620 };
1621 const auto &fields = struct_def.fields.vec;
1622 if (reversed) {
1623 for (auto it = fields.rbegin(); it != fields.rend(); ++it) go(**it);
1624 } else {
1625 for (auto it = fields.begin(); it != fields.end(); ++it) go(**it);
1626 }
1627 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001628 // Generate an accessor struct, builder struct, and create function for a
1629 // table.
1630 void GenTable(const StructDef &struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001631
1632 const bool is_private = parser_.opts.no_leak_private_annotations &&
1633 (struct_def.attributes.Lookup("private") != nullptr);
1634 code_.SetValue("ACCESS_TYPE", is_private ? "pub(crate)" : "pub");
1635 code_.SetValue("STRUCT_TY", namer_.Type(struct_def));
1636 code_.SetValue("STRUCT_FN", namer_.Function(struct_def));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001637
1638 // Generate an offset type, the base type, the Follow impl, and the
1639 // init_from_table impl.
Austin Schuh2dd86a92022-09-14 21:19:23 -07001640 code_ += "{{ACCESS_TYPE}} enum {{STRUCT_TY}}Offset {}";
Austin Schuh272c6132020-11-14 16:37:52 -08001641 code_ += "#[derive(Copy, Clone, PartialEq)]";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001642 code_ += "";
1643
1644 GenComment(struct_def.doc_comment);
1645
Austin Schuh2dd86a92022-09-14 21:19:23 -07001646 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}<'a> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001647 code_ += " pub _tab: flatbuffers::Table<'a>,";
1648 code_ += "}";
1649 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001650 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_TY}}<'a> {";
1651 code_ += " type Inner = {{STRUCT_TY}}<'a>;";
1652 code_ += " #[inline]";
1653 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1654 code_ += " Self { _tab: flatbuffers::Table { buf, loc } }";
1655 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001656 code_ += "}";
1657 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001658 code_ += "impl<'a> {{STRUCT_TY}}<'a> {";
1659
1660 // Generate field id constants.
1661 ForAllTableFields(struct_def, [&](const FieldDef &unused) {
1662 (void)unused;
1663 code_ +=
1664 "pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1665 "{{OFFSET_VALUE}};";
1666 });
1667 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08001668
1669 if (parser_.opts.generate_name_strings) {
1670 GenFullyQualifiedNameGetter(struct_def, struct_def.name);
1671 }
1672
James Kuszmaul8e62b022022-03-22 09:33:25 -07001673 code_ += " #[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08001674 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07001675 " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
Austin Schuh272c6132020-11-14 16:37:52 -08001676 "Self {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001677 code_ += " {{STRUCT_TY}} { _tab: table }";
1678 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001679
1680 // Generate a convenient create* function that uses the above builder
1681 // to create a table in one function call.
Austin Schuh272c6132020-11-14 16:37:52 -08001682 code_.SetValue("MAYBE_US", struct_def.fields.vec.size() == 0 ? "_" : "");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001683 code_.SetValue("MAYBE_LT",
Austin Schuh272c6132020-11-14 16:37:52 -08001684 TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001685 code_ += " #[allow(unused_mut)]";
1686 code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
1687 code_ += " _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1688 code_ += " {{MAYBE_US}}args: &'args {{STRUCT_TY}}Args{{MAYBE_LT}}";
1689 code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_TY}}<'bldr>> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001690
James Kuszmaul8e62b022022-03-22 09:33:25 -07001691 code_ += " let mut builder = {{STRUCT_TY}}Builder::new(_fbb);";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001692 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1693 size; size /= 2) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001694 ForAllTableFields(
1695 struct_def,
1696 [&](const FieldDef &field) {
1697 if (struct_def.sortbysize &&
1698 size != SizeOf(field.value.type.base_type))
1699 return;
1700 if (IsOptionalToBuilder(field)) {
1701 code_ +=
1702 " if let Some(x) = args.{{FIELD}} "
1703 "{ builder.add_{{FIELD}}(x); }";
1704 } else {
1705 code_ += " builder.add_{{FIELD}}(args.{{FIELD}});";
1706 }
1707 },
1708 /*reverse=*/true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001709 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001710 code_ += " builder.finish()";
1711 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001712 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001713 // Generate Object API Packer function.
1714 if (parser_.opts.generate_object_based_api) {
1715 // TODO(cneo): Replace more for loops with ForAllX stuff.
1716 // TODO(cneo): Manage indentation with IncrementIdentLevel?
Austin Schuh2dd86a92022-09-14 21:19:23 -07001717 code_.SetValue("STRUCT_OTY", namer_.ObjectType(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001718 code_ += " pub fn unpack(&self) -> {{STRUCT_OTY}} {";
1719 ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
1720 const Type &type = field.value.type;
1721 switch (GetFullType(type)) {
1722 case ftInteger:
1723 case ftBool:
1724 case ftFloat:
1725 case ftEnumKey: {
1726 code_ += " let {{FIELD}} = self.{{FIELD}}();";
1727 return;
1728 }
1729 case ftUnionKey: return;
1730 case ftUnionValue: {
1731 const auto &enum_def = *type.enum_def;
1732 code_.SetValue("ENUM_TY", WrapInNameSpace(enum_def));
1733 code_.SetValue("NATIVE_ENUM_NAME", NamespacedNativeName(enum_def));
1734 code_ += " let {{FIELD}} = match self.{{FIELD}}_type() {";
1735 code_ += " {{ENUM_TY}}::NONE => {{NATIVE_ENUM_NAME}}::NONE,";
1736 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
1737 code_ +=
1738 " {{ENUM_TY}}::{{VARIANT_NAME}} => "
1739 "{{NATIVE_ENUM_NAME}}::{{NATIVE_VARIANT}}(Box::new(";
1740 code_ += " self.{{FIELD}}_as_{{U_ELEMENT_NAME}}()";
1741 code_ +=
1742 " .expect(\"Invalid union table, "
1743 "expected `{{ENUM_TY}}::{{VARIANT_NAME}}`.\")";
1744 code_ += " .unpack()";
1745 code_ += " )),";
1746 });
1747 // Maybe we shouldn't throw away unknown discriminants?
1748 code_ += " _ => {{NATIVE_ENUM_NAME}}::NONE,";
1749 code_ += " };";
1750 return;
1751 }
1752 // The rest of the types need special handling based on if the field
1753 // is optional or not.
1754 case ftString: {
1755 code_.SetValue("EXPR", "x.to_string()");
1756 break;
1757 }
1758 case ftStruct: {
1759 code_.SetValue("EXPR", "x.unpack()");
1760 break;
1761 }
1762 case ftTable: {
1763 code_.SetValue("EXPR", "Box::new(x.unpack())");
1764 break;
1765 }
1766 case ftVectorOfInteger:
1767 case ftVectorOfBool: {
1768 if (IsOneByte(type.VectorType().base_type)) {
1769 // 1 byte stuff is viewed w/ slice instead of flatbuffer::Vector
1770 // and thus needs to be cloned out of the slice.
1771 code_.SetValue("EXPR", "x.to_vec()");
1772 break;
1773 }
1774 code_.SetValue("EXPR", "x.into_iter().collect()");
1775 break;
1776 }
1777 case ftVectorOfFloat:
1778 case ftVectorOfEnumKey: {
1779 code_.SetValue("EXPR", "x.into_iter().collect()");
1780 break;
1781 }
1782 case ftVectorOfString: {
1783 code_.SetValue("EXPR", "x.iter().map(|s| s.to_string()).collect()");
1784 break;
1785 }
1786 case ftVectorOfStruct:
1787 case ftVectorOfTable: {
1788 code_.SetValue("EXPR", "x.iter().map(|t| t.unpack()).collect()");
1789 break;
1790 }
1791 case ftVectorOfUnionValue: {
1792 FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
1793 return;
1794 }
1795 case ftArrayOfEnum:
1796 case ftArrayOfStruct:
1797 case ftArrayOfBuiltin: {
1798 FLATBUFFERS_ASSERT(false &&
1799 "arrays are not supported within tables");
1800 return;
1801 }
1802 }
1803 if (field.IsOptional()) {
1804 code_ += " let {{FIELD}} = self.{{FIELD}}().map(|x| {";
1805 code_ += " {{EXPR}}";
1806 code_ += " });";
1807 } else {
1808 code_ += " let {{FIELD}} = {";
1809 code_ += " let x = self.{{FIELD}}();";
1810 code_ += " {{EXPR}}";
1811 code_ += " };";
1812 }
1813 });
1814 code_ += " {{STRUCT_OTY}} {";
1815 ForAllObjectTableFields(struct_def, [&](const FieldDef &field) {
1816 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
1817 code_ += " {{FIELD}},";
1818 });
1819 code_ += " }";
1820 code_ += " }";
1821 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001822
Austin Schuh272c6132020-11-14 16:37:52 -08001823 if (struct_def.fields.vec.size() > 0) code_ += "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001824
1825 // Generate the accessors. Each has one of two forms:
1826 //
1827 // If a value can be None:
1828 // pub fn name(&'a self) -> Option<user_facing_type> {
1829 // self._tab.get::<internal_type>(offset, defaultval)
1830 // }
1831 //
1832 // If a value is always Some:
1833 // pub fn name(&'a self) -> user_facing_type {
1834 // self._tab.get::<internal_type>(offset, defaultval).unwrap()
1835 // }
Austin Schuh272c6132020-11-14 16:37:52 -08001836 ForAllTableFields(struct_def, [&](const FieldDef &field) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001837 code_.SetValue("RETURN_TYPE",
1838 GenTableAccessorFuncReturnType(field, "'a"));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001839
James Kuszmaul8e62b022022-03-22 09:33:25 -07001840 this->GenComment(field.doc_comment);
1841 code_ += "#[inline]";
1842 code_ += "pub fn {{FIELD}}(&self) -> {{RETURN_TYPE}} {";
1843 code_ += " " + GenTableAccessorFuncBody(field, "'a");
1844 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001845
1846 // Generate a comparison function for this field if it is a key.
Austin Schuh272c6132020-11-14 16:37:52 -08001847 if (field.key) { GenKeyFieldMethods(field); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001848
1849 // Generate a nested flatbuffer field, if applicable.
1850 auto nested = field.attributes.Lookup("nested_flatbuffer");
1851 if (nested) {
1852 std::string qualified_name = nested->constant;
1853 auto nested_root = parser_.LookupStruct(nested->constant);
1854 if (nested_root == nullptr) {
1855 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1856 nested->constant);
1857 nested_root = parser_.LookupStruct(qualified_name);
1858 }
1859 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001860
Austin Schuh272c6132020-11-14 16:37:52 -08001861 code_.SetValue("NESTED", WrapInNameSpace(*nested_root));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001862 code_ += "pub fn {{FIELD}}_nested_flatbuffer(&'a self) -> \\";
1863 if (field.IsRequired()) {
Austin Schuh272c6132020-11-14 16:37:52 -08001864 code_ += "{{NESTED}}<'a> {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001865 code_ += " let data = self.{{FIELD}}();";
1866 code_ += " use flatbuffers::Follow;";
1867 code_ +=
1868 " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1869 "::follow(data, 0)";
Austin Schuh272c6132020-11-14 16:37:52 -08001870 } else {
1871 code_ += "Option<{{NESTED}}<'a>> {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001872 code_ += " self.{{FIELD}}().map(|data| {";
1873 code_ += " use flatbuffers::Follow;";
1874 code_ +=
1875 " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1876 "::follow(data, 0)";
1877 code_ += " })";
Austin Schuh272c6132020-11-14 16:37:52 -08001878 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001879 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001880 }
Austin Schuh272c6132020-11-14 16:37:52 -08001881 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001882
1883 // Explicit specializations for union accessors
Austin Schuh272c6132020-11-14 16:37:52 -08001884 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1885 if (field.value.type.base_type != BASE_TYPE_UNION) return;
Austin Schuh272c6132020-11-14 16:37:52 -08001886 ForAllUnionVariantsBesidesNone(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001887 *field.value.type.enum_def, [&](const EnumVal &unused) {
1888 (void)unused;
1889 code_ += "#[inline]";
1890 code_ += "#[allow(non_snake_case)]";
1891 code_ +=
1892 "pub fn {{FIELD}}_as_{{U_ELEMENT_NAME}}(&self) -> "
1893 "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
1894 // If the user defined schemas name a field that clashes with a
1895 // language reserved word, flatc will try to escape the field name
1896 // by appending an underscore. This works well for most cases,
1897 // except one. When generating union accessors (and referring to
1898 // them internally within the code generated here), an extra
1899 // underscore will be appended to the name, causing build failures.
1900 //
1901 // This only happens when unions have members that overlap with
1902 // language reserved words.
1903 //
1904 // To avoid this problem the type field name is used unescaped here:
1905 code_ +=
1906 " if self.{{DISCRIMINANT}}() == {{U_ELEMENT_ENUM_TYPE}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08001907
James Kuszmaul8e62b022022-03-22 09:33:25 -07001908 // The following logic is not tested in the integration test,
1909 // as of April 10, 2020
1910 if (field.IsRequired()) {
1911 code_ += " let u = self.{{FIELD}}();";
1912 code_ += " Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
1913 } else {
1914 code_ +=
1915 " self.{{FIELD}}().map("
1916 "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)";
1917 }
1918 code_ += " } else {";
1919 code_ += " None";
1920 code_ += " }";
1921 code_ += "}";
1922 code_ += "";
1923 });
Austin Schuh272c6132020-11-14 16:37:52 -08001924 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001925 code_ += "}"; // End of table impl.
1926 code_ += "";
1927
James Kuszmaul8e62b022022-03-22 09:33:25 -07001928 // Generate Verifier;
1929 code_ += "impl flatbuffers::Verifiable for {{STRUCT_TY}}<'_> {";
1930 code_ += " #[inline]";
1931 code_ += " fn run_verifier(";
1932 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
1933 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
1934 code_ += " use self::flatbuffers::Verifiable;";
1935 code_ += " v.visit_table(pos)?\\";
1936 // Escape newline and insert it onthe next line so we can end the builder
1937 // with a nice semicolon.
1938 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1939 if (GetFullType(field.value.type) == ftUnionKey) return;
1940
1941 code_.SetValue("IS_REQ", field.IsRequired() ? "true" : "false");
1942 if (GetFullType(field.value.type) != ftUnionValue) {
1943 // All types besides unions.
1944 code_.SetValue("TY", FollowType(field.value.type, "'_"));
1945 code_ +=
1946 "\n .visit_field::<{{TY}}>(\"{{FIELD}}\", "
1947 "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\";
1948 return;
1949 }
1950 // Unions.
1951 const EnumDef &union_def = *field.value.type.enum_def;
1952 code_.SetValue("UNION_TYPE", WrapInNameSpace(union_def));
1953 code_.SetValue("UNION_TYPE_OFFSET_NAME",
Austin Schuh2dd86a92022-09-14 21:19:23 -07001954 namer_.LegacyRustFieldOffsetName(field) + "_TYPE");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001955 code_ +=
1956 "\n .visit_union::<{{UNION_TYPE}}, _>("
1957 "\"{{FIELD}}_type\", Self::{{UNION_TYPE_OFFSET_NAME}}, "
1958 "\"{{FIELD}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, "
1959 "|key, v, pos| {";
1960 code_ += " match key {";
1961 ForAllUnionVariantsBesidesNone(union_def, [&](const EnumVal &unused) {
1962 (void)unused;
1963 code_ +=
1964 " {{U_ELEMENT_ENUM_TYPE}} => v.verify_union_variant::"
1965 "<flatbuffers::ForwardsUOffset<{{U_ELEMENT_TABLE_TYPE}}>>("
1966 "\"{{U_ELEMENT_ENUM_TYPE}}\", pos),";
1967 });
1968 code_ += " _ => Ok(()),";
1969 code_ += " }";
1970 code_ += " })?\\";
1971 });
1972 code_ += "\n .finish();";
1973 code_ += " Ok(())";
1974 code_ += " }";
1975 code_ += "}";
1976
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001977 // Generate an args struct:
1978 code_.SetValue("MAYBE_LT",
Austin Schuh272c6132020-11-14 16:37:52 -08001979 TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
Austin Schuh2dd86a92022-09-14 21:19:23 -07001980 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}Args{{MAYBE_LT}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08001981 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1982 code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001983 code_ += " pub {{FIELD}}: {{PARAM_TYPE}},";
Austin Schuh272c6132020-11-14 16:37:52 -08001984 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001985 code_ += "}";
1986
1987 // Generate an impl of Default for the *Args type:
James Kuszmaul8e62b022022-03-22 09:33:25 -07001988 code_ += "impl<'a> Default for {{STRUCT_TY}}Args{{MAYBE_LT}} {";
1989 code_ += " #[inline]";
1990 code_ += " fn default() -> Self {";
1991 code_ += " {{STRUCT_TY}}Args {";
Austin Schuh272c6132020-11-14 16:37:52 -08001992 ForAllTableFields(struct_def, [&](const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001993 code_ += " {{FIELD}}: {{BLDR_DEF_VAL}},\\";
1994 code_ += field.IsRequired() ? " // required field" : "";
Austin Schuh272c6132020-11-14 16:37:52 -08001995 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001996 code_ += " }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001997 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001998 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001999 code_ += "";
2000
2001 // Implement serde::Serialize
2002 if (parser_.opts.rust_serialize) {
2003 const auto numFields = struct_def.fields.vec.size();
2004 code_.SetValue("NUM_FIELDS", NumToString(numFields));
2005 code_ += "impl Serialize for {{STRUCT_TY}}<'_> {";
2006 code_ +=
2007 " fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
2008 code_ += " where";
2009 code_ += " S: Serializer,";
2010 code_ += " {";
2011 if (numFields == 0) {
2012 code_ +=
2013 " let s = serializer.serialize_struct(\"{{STRUCT_TY}}\", 0)?;";
2014 } else {
2015 code_ +=
2016 " let mut s = serializer.serialize_struct(\"{{STRUCT_TY}}\", "
2017 "{{NUM_FIELDS}})?;";
2018 }
2019 ForAllTableFields(struct_def, [&](const FieldDef &field) {
2020 const Type &type = field.value.type;
2021 if (IsUnion(type)) {
2022 if (type.base_type == BASE_TYPE_UNION) {
2023 const auto &enum_def = *type.enum_def;
2024 code_.SetValue("ENUM_TY", WrapInNameSpace(enum_def));
Austin Schuh2dd86a92022-09-14 21:19:23 -07002025 code_.SetValue("FIELD", namer_.Field(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002026
2027 code_ += " match self.{{FIELD}}_type() {";
2028 code_ += " {{ENUM_TY}}::NONE => (),";
2029 ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
Austin Schuh2dd86a92022-09-14 21:19:23 -07002030 code_.SetValue("FIELD", namer_.Field(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002031 code_ += " {{ENUM_TY}}::{{VARIANT_NAME}} => {";
2032 code_ +=
2033 " let f = "
2034 "self.{{FIELD}}_as_{{U_ELEMENT_NAME}}()";
2035 code_ +=
2036 " .expect(\"Invalid union table, expected "
2037 "`{{ENUM_TY}}::{{VARIANT_NAME}}`.\");";
2038 code_ += " s.serialize_field(\"{{FIELD}}\", &f)?;";
2039 code_ += " }";
2040 });
2041 code_ += " _ => unimplemented!(),";
2042 code_ += " }";
2043 } else {
2044 code_ +=
2045 " s.serialize_field(\"{{FIELD}}\", "
2046 "&self.{{FIELD}}())?;";
2047 }
2048 } else {
2049 if (field.IsOptional()) {
2050 code_ += " if let Some(f) = self.{{FIELD}}() {";
2051 code_ += " s.serialize_field(\"{{FIELD}}\", &f)?;";
2052 code_ += " } else {";
2053 code_ += " s.skip_field(\"{{FIELD}}\")?;";
2054 code_ += " }";
2055 } else {
2056 code_ +=
2057 " s.serialize_field(\"{{FIELD}}\", "
2058 "&self.{{FIELD}}())?;";
2059 }
2060 }
2061 });
2062 code_ += " s.end()";
2063 code_ += " }";
2064 code_ += "}";
2065 code_ += "";
2066 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002067
2068 // Generate a builder struct:
Austin Schuh2dd86a92022-09-14 21:19:23 -07002069 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}Builder<'a: 'b, 'b> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002070 code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
Austin Schuh272c6132020-11-14 16:37:52 -08002071 code_ +=
2072 " start_: flatbuffers::WIPOffset<"
2073 "flatbuffers::TableUnfinishedWIPOffset>,";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002074 code_ += "}";
2075
2076 // Generate builder functions:
James Kuszmaul8e62b022022-03-22 09:33:25 -07002077 code_ += "impl<'a: 'b, 'b> {{STRUCT_TY}}Builder<'a, 'b> {";
Austin Schuh272c6132020-11-14 16:37:52 -08002078 ForAllTableFields(struct_def, [&](const FieldDef &field) {
2079 const bool is_scalar = IsScalar(field.value.type.base_type);
Austin Schuh2dd86a92022-09-14 21:19:23 -07002080 std::string offset = namer_.LegacyRustFieldOffsetName(field);
Austin Schuh272c6132020-11-14 16:37:52 -08002081 // Generate functions to add data, which take one of two forms.
2082 //
2083 // If a value has a default:
2084 // fn add_x(x_: type) {
2085 // fbb_.push_slot::<type>(offset, x_, Some(default));
2086 // }
2087 //
2088 // If a value does not have a default:
2089 // fn add_x(x_: type) {
2090 // fbb_.push_slot_always::<type>(offset, x_);
2091 // }
Austin Schuh2dd86a92022-09-14 21:19:23 -07002092 code_.SetValue("FIELD_OFFSET", namer_.Type(struct_def) + "::" + offset);
Austin Schuh272c6132020-11-14 16:37:52 -08002093 code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
2094 code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002095 code_ += "#[inline]";
2096 code_ +=
2097 "pub fn add_{{FIELD}}(&mut self, {{FIELD}}: "
2098 "{{FIELD_TYPE}}) {";
2099 if (is_scalar && !field.IsOptional()) {
Austin Schuh272c6132020-11-14 16:37:52 -08002100 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002101 " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD}}, "
2102 "{{BLDR_DEF_VAL}});";
Austin Schuh272c6132020-11-14 16:37:52 -08002103 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002104 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD}});";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002105 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07002106 code_ += "}";
Austin Schuh272c6132020-11-14 16:37:52 -08002107 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002108
2109 // Struct initializer (all fields required);
2110 code_ += " #[inline]";
2111 code_ +=
2112 " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002113 "{{STRUCT_TY}}Builder<'a, 'b> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002114 code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
2115 code_ += " let start = _fbb.start_table();";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002116 code_ += " {{STRUCT_TY}}Builder {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002117 code_ += " fbb_: _fbb,";
2118 code_ += " start_: start,";
2119 code_ += " }";
2120 code_ += " }";
2121
2122 // finish() function.
2123 code_ += " #[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002124 code_ +=
2125 " pub fn finish(self) -> "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002126 "flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002127 code_ += " let o = self.fbb_.end_table(self.start_);";
2128
Austin Schuh272c6132020-11-14 16:37:52 -08002129 ForAllTableFields(struct_def, [&](const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002130 if (!field.IsRequired()) return;
Austin Schuh272c6132020-11-14 16:37:52 -08002131 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002132 " self.fbb_.required(o, {{STRUCT_TY}}::{{OFFSET_NAME}},"
2133 "\"{{FIELD}}\");";
Austin Schuh272c6132020-11-14 16:37:52 -08002134 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002135 code_ += " flatbuffers::WIPOffset::new(o.value())";
2136 code_ += " }";
2137 code_ += "}";
2138 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08002139
Austin Schuh2dd86a92022-09-14 21:19:23 -07002140 code_ += "impl core::fmt::Debug for {{STRUCT_TY}}<'_> {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002141 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07002142 " fn fmt(&self, f: &mut core::fmt::Formatter<'_>"
2143 ") -> core::fmt::Result {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002144 code_ += " let mut ds = f.debug_struct(\"{{STRUCT_TY}}\");";
Austin Schuh272c6132020-11-14 16:37:52 -08002145 ForAllTableFields(struct_def, [&](const FieldDef &field) {
2146 if (GetFullType(field.value.type) == ftUnionValue) {
2147 // Generate a match statement to handle unions properly.
2148 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002149 code_.SetValue("UNION_ERR",
2150 "&\"InvalidFlatbuffer: Union discriminant"
2151 " does not match value.\"");
Austin Schuh272c6132020-11-14 16:37:52 -08002152
James Kuszmaul8e62b022022-03-22 09:33:25 -07002153 code_ += " match self.{{DISCRIMINANT}}() {";
2154 ForAllUnionVariantsBesidesNone(
2155 *field.value.type.enum_def, [&](const EnumVal &unused) {
2156 (void)unused;
2157 code_ += " {{U_ELEMENT_ENUM_TYPE}} => {";
2158 code_ +=
2159 " if let Some(x) = "
2160 "self.{{FIELD}}_as_"
2161 "{{U_ELEMENT_NAME}}() {";
2162 code_ += " ds.field(\"{{FIELD}}\", &x)";
2163 code_ += " } else {";
2164 code_ += " ds.field(\"{{FIELD}}\", {{UNION_ERR}})";
2165 code_ += " }";
2166 code_ += " },";
2167 });
2168 code_ += " _ => {";
2169 code_ += " let x: Option<()> = None;";
2170 code_ += " ds.field(\"{{FIELD}}\", &x)";
2171 code_ += " },";
2172 code_ += " };";
Austin Schuh272c6132020-11-14 16:37:52 -08002173 } else {
2174 // Most fields.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002175 code_ += " ds.field(\"{{FIELD}}\", &self.{{FIELD}}());";
Austin Schuh272c6132020-11-14 16:37:52 -08002176 }
2177 });
2178 code_ += " ds.finish()";
2179 code_ += " }";
2180 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002181 }
2182
James Kuszmaul8e62b022022-03-22 09:33:25 -07002183 void GenTableObject(const StructDef &table) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07002184 code_.SetValue("STRUCT_OTY", namer_.ObjectType(table));
2185 code_.SetValue("STRUCT_TY", namer_.Type(table));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002186
2187 // Generate the native object.
2188 code_ += "#[non_exhaustive]";
2189 code_ += "#[derive(Debug, Clone, PartialEq)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -07002190 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_OTY}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002191 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2192 // Union objects combine both the union discriminant and value, so we
2193 // skip making a field for the discriminant.
2194 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
2195 code_ += "pub {{FIELD}}: {{FIELD_OTY}},";
2196 });
2197 code_ += "}";
2198
2199 code_ += "impl Default for {{STRUCT_OTY}} {";
2200 code_ += " fn default() -> Self {";
2201 code_ += " Self {";
2202 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2203 if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
2204 std::string default_value = GetDefaultValue(field, kObject);
2205 code_ += " {{FIELD}}: " + default_value + ",";
2206 });
2207 code_ += " }";
2208 code_ += " }";
2209 code_ += "}";
2210
2211 // TODO(cneo): Generate defaults for Native tables. However, since structs
2212 // may be required, they, and therefore enums need defaults.
2213
2214 // Generate pack function.
2215 code_ += "impl {{STRUCT_OTY}} {";
2216 code_ += " pub fn pack<'b>(";
2217 code_ += " &self,";
2218 code_ += " _fbb: &mut flatbuffers::FlatBufferBuilder<'b>";
2219 code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_TY}}<'b>> {";
2220 // First we generate variables for each field and then later assemble them
2221 // using "StructArgs" to more easily manage ownership of the builder.
2222 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2223 const Type &type = field.value.type;
2224 switch (GetFullType(type)) {
2225 case ftInteger:
2226 case ftBool:
2227 case ftFloat:
2228 case ftEnumKey: {
2229 code_ += " let {{FIELD}} = self.{{FIELD}};";
2230 return;
2231 }
2232 case ftUnionKey: return; // Generate union type with union value.
2233 case ftUnionValue: {
2234 code_.SetValue("ENUM_METHOD",
Austin Schuh2dd86a92022-09-14 21:19:23 -07002235 namer_.Method(*field.value.type.enum_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002236 code_ +=
2237 " let {{FIELD}}_type = "
2238 "self.{{FIELD}}.{{ENUM_METHOD}}_type();";
2239 code_ += " let {{FIELD}} = self.{{FIELD}}.pack(_fbb);";
2240 return;
2241 }
2242 // The rest of the types require special casing around optionalness
2243 // due to "required" annotation.
2244 case ftString: {
2245 MapNativeTableField(field, "_fbb.create_string(x)");
2246 return;
2247 }
2248 case ftStruct: {
2249 // Hold the struct in a variable so we can reference it.
2250 if (field.IsRequired()) {
2251 code_ += " let {{FIELD}}_tmp = Some(self.{{FIELD}}.pack());";
2252 } else {
2253 code_ +=
2254 " let {{FIELD}}_tmp = self.{{FIELD}}"
2255 ".as_ref().map(|x| x.pack());";
2256 }
2257 code_ += " let {{FIELD}} = {{FIELD}}_tmp.as_ref();";
2258
2259 return;
2260 }
2261 case ftTable: {
2262 MapNativeTableField(field, "x.pack(_fbb)");
2263 return;
2264 }
2265 case ftVectorOfEnumKey:
2266 case ftVectorOfInteger:
2267 case ftVectorOfBool:
2268 case ftVectorOfFloat: {
2269 MapNativeTableField(field, "_fbb.create_vector(x)");
2270 return;
2271 }
2272 case ftVectorOfStruct: {
2273 MapNativeTableField(
2274 field,
2275 "let w: Vec<_> = x.iter().map(|t| t.pack()).collect();"
2276 "_fbb.create_vector(&w)");
2277 return;
2278 }
2279 case ftVectorOfString: {
2280 // TODO(cneo): create_vector* should be more generic to avoid
2281 // allocations.
2282
2283 MapNativeTableField(
2284 field,
2285 "let w: Vec<_> = x.iter().map(|s| s.as_ref()).collect();"
2286 "_fbb.create_vector_of_strings(&w)");
2287 return;
2288 }
2289 case ftVectorOfTable: {
2290 MapNativeTableField(
2291 field,
2292 "let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();"
2293 "_fbb.create_vector(&w)");
2294 return;
2295 }
2296 case ftVectorOfUnionValue: {
2297 FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
2298 return;
2299 }
2300 case ftArrayOfEnum:
2301 case ftArrayOfStruct:
2302 case ftArrayOfBuiltin: {
2303 FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
2304 return;
2305 }
2306 }
2307 });
2308 code_ += " {{STRUCT_TY}}::create(_fbb, &{{STRUCT_TY}}Args{";
2309 ForAllObjectTableFields(table, [&](const FieldDef &field) {
2310 (void)field; // Unused.
2311 code_ += " {{FIELD}},";
2312 });
2313 code_ += " })";
2314 code_ += " }";
2315 code_ += "}";
2316 }
2317 void ForAllObjectTableFields(const StructDef &table,
2318 std::function<void(const FieldDef &)> cb) {
2319 const std::vector<FieldDef *> &v = table.fields.vec;
2320 for (auto it = v.begin(); it != v.end(); it++) {
2321 const FieldDef &field = **it;
2322 if (field.deprecated) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -07002323 code_.SetValue("FIELD", namer_.Field(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002324 code_.SetValue("FIELD_OTY", ObjectFieldType(field, true));
2325 code_.IncrementIdentLevel();
2326 cb(field);
2327 code_.DecrementIdentLevel();
2328 }
2329 }
2330 void MapNativeTableField(const FieldDef &field, const std::string &expr) {
2331 if (field.IsOptional()) {
2332 code_ += " let {{FIELD}} = self.{{FIELD}}.as_ref().map(|x|{";
2333 code_ += " " + expr;
2334 code_ += " });";
2335 } else {
2336 // For some reason Args has optional types for required fields.
2337 // TODO(cneo): Fix this... but its a breaking change?
2338 code_ += " let {{FIELD}} = Some({";
2339 code_ += " let x = &self.{{FIELD}};";
2340 code_ += " " + expr;
2341 code_ += " });";
2342 }
2343 }
2344
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002345 // Generate functions to compare tables and structs by key. This function
2346 // must only be called if the field key is defined.
2347 void GenKeyFieldMethods(const FieldDef &field) {
2348 FLATBUFFERS_ASSERT(field.key);
2349
2350 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002351 code_.SetValue("REF", IsString(field.value.type) ? "" : "&");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002352
James Kuszmaul8e62b022022-03-22 09:33:25 -07002353 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002354 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002355 "pub fn key_compare_less_than(&self, o: &{{STRUCT_TY}}) -> "
2356 "bool {";
2357 code_ += " self.{{FIELD}}() < o.{{FIELD}}()";
2358 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002359 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002360 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002361 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002362 "pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
Austin Schuh2dd86a92022-09-14 21:19:23 -07002363 "::core::cmp::Ordering {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002364 code_ += " let key = self.{{FIELD}}();";
2365 code_ += " key.cmp({{REF}}val)";
2366 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002367 }
2368
2369 // Generate functions for accessing the root table object. This function
2370 // must only be called if the root table is defined.
2371 void GenRootTableFuncs(const StructDef &struct_def) {
2372 FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
Austin Schuh2dd86a92022-09-14 21:19:23 -07002373 code_.SetValue("STRUCT_TY", namer_.Type(struct_def));
2374 code_.SetValue("STRUCT_FN", namer_.Function(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002375 code_.SetValue("STRUCT_CONST", namer_.Constant(struct_def.name));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002376
2377 // The root datatype accessors:
2378 code_ += "#[inline]";
2379 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002380 "#[deprecated(since=\"2.0.0\", "
2381 "note=\"Deprecated in favor of `root_as...` methods.\")]";
2382 code_ +=
2383 "pub fn get_root_as_{{STRUCT_FN}}<'a>(buf: &'a [u8])"
2384 " -> {{STRUCT_TY}}<'a> {";
2385 code_ +=
2386 " unsafe { flatbuffers::root_unchecked::<{{STRUCT_TY}}"
2387 "<'a>>(buf) }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002388 code_ += "}";
2389 code_ += "";
2390
2391 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002392 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002393 "#[deprecated(since=\"2.0.0\", "
2394 "note=\"Deprecated in favor of `root_as...` methods.\")]";
Austin Schuh272c6132020-11-14 16:37:52 -08002395 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002396 "pub fn get_size_prefixed_root_as_{{STRUCT_FN}}"
2397 "<'a>(buf: &'a [u8]) -> {{STRUCT_TY}}<'a> {";
2398 code_ +=
2399 " unsafe { flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_TY}}"
2400 "<'a>>(buf) }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002401 code_ += "}";
2402 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002403 // Default verifier root fns.
2404 code_ += "#[inline]";
2405 code_ += "/// Verifies that a buffer of bytes contains a `{{STRUCT_TY}}`";
2406 code_ += "/// and returns it.";
2407 code_ += "/// Note that verification is still experimental and may not";
2408 code_ += "/// catch every error, or be maximally performant. For the";
2409 code_ += "/// previous, unchecked, behavior use";
2410 code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
2411 code_ +=
2412 "pub fn root_as_{{STRUCT_FN}}(buf: &[u8]) "
2413 "-> Result<{{STRUCT_TY}}, flatbuffers::InvalidFlatbuffer> {";
2414 code_ += " flatbuffers::root::<{{STRUCT_TY}}>(buf)";
2415 code_ += "}";
2416 code_ += "#[inline]";
2417 code_ += "/// Verifies that a buffer of bytes contains a size prefixed";
2418 code_ += "/// `{{STRUCT_TY}}` and returns it.";
2419 code_ += "/// Note that verification is still experimental and may not";
2420 code_ += "/// catch every error, or be maximally performant. For the";
2421 code_ += "/// previous, unchecked, behavior use";
2422 code_ += "/// `size_prefixed_root_as_{{STRUCT_FN}}_unchecked`.";
2423 code_ +=
2424 "pub fn size_prefixed_root_as_{{STRUCT_FN}}"
2425 "(buf: &[u8]) -> Result<{{STRUCT_TY}}, "
2426 "flatbuffers::InvalidFlatbuffer> {";
2427 code_ += " flatbuffers::size_prefixed_root::<{{STRUCT_TY}}>(buf)";
2428 code_ += "}";
2429 // Verifier with options root fns.
2430 code_ += "#[inline]";
2431 code_ += "/// Verifies, with the given options, that a buffer of bytes";
2432 code_ += "/// contains a `{{STRUCT_TY}}` and returns it.";
2433 code_ += "/// Note that verification is still experimental and may not";
2434 code_ += "/// catch every error, or be maximally performant. For the";
2435 code_ += "/// previous, unchecked, behavior use";
2436 code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
2437 code_ += "pub fn root_as_{{STRUCT_FN}}_with_opts<'b, 'o>(";
2438 code_ += " opts: &'o flatbuffers::VerifierOptions,";
2439 code_ += " buf: &'b [u8],";
2440 code_ +=
2441 ") -> Result<{{STRUCT_TY}}<'b>, flatbuffers::InvalidFlatbuffer>"
2442 " {";
2443 code_ += " flatbuffers::root_with_opts::<{{STRUCT_TY}}<'b>>(opts, buf)";
2444 code_ += "}";
2445 code_ += "#[inline]";
2446 code_ += "/// Verifies, with the given verifier options, that a buffer of";
2447 code_ += "/// bytes contains a size prefixed `{{STRUCT_TY}}` and returns";
2448 code_ += "/// it. Note that verification is still experimental and may not";
2449 code_ += "/// catch every error, or be maximally performant. For the";
2450 code_ += "/// previous, unchecked, behavior use";
2451 code_ += "/// `root_as_{{STRUCT_FN}}_unchecked`.";
2452 code_ +=
2453 "pub fn size_prefixed_root_as_{{STRUCT_FN}}_with_opts"
2454 "<'b, 'o>(";
2455 code_ += " opts: &'o flatbuffers::VerifierOptions,";
2456 code_ += " buf: &'b [u8],";
2457 code_ +=
2458 ") -> Result<{{STRUCT_TY}}<'b>, flatbuffers::InvalidFlatbuffer>"
2459 " {";
2460 code_ +=
2461 " flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_TY}}"
2462 "<'b>>(opts, buf)";
2463 code_ += "}";
2464 // Unchecked root fns.
2465 code_ += "#[inline]";
2466 code_ +=
2467 "/// Assumes, without verification, that a buffer of bytes "
2468 "contains a {{STRUCT_TY}} and returns it.";
2469 code_ += "/// # Safety";
2470 code_ +=
2471 "/// Callers must trust the given bytes do indeed contain a valid"
2472 " `{{STRUCT_TY}}`.";
2473 code_ +=
2474 "pub unsafe fn root_as_{{STRUCT_FN}}_unchecked"
2475 "(buf: &[u8]) -> {{STRUCT_TY}} {";
2476 code_ += " flatbuffers::root_unchecked::<{{STRUCT_TY}}>(buf)";
2477 code_ += "}";
2478 code_ += "#[inline]";
2479 code_ +=
2480 "/// Assumes, without verification, that a buffer of bytes "
2481 "contains a size prefixed {{STRUCT_TY}} and returns it.";
2482 code_ += "/// # Safety";
2483 code_ +=
2484 "/// Callers must trust the given bytes do indeed contain a valid"
2485 " size prefixed `{{STRUCT_TY}}`.";
2486 code_ +=
2487 "pub unsafe fn size_prefixed_root_as_{{STRUCT_FN}}"
2488 "_unchecked(buf: &[u8]) -> {{STRUCT_TY}} {";
2489 code_ +=
2490 " flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_TY}}>"
2491 "(buf)";
2492 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002493
2494 if (parser_.file_identifier_.length()) {
2495 // Declare the identifier
Austin Schuh272c6132020-11-14 16:37:52 -08002496 // (no lifetime needed as constants have static lifetimes by default)
James Kuszmaul8e62b022022-03-22 09:33:25 -07002497 code_ += "pub const {{STRUCT_CONST}}_IDENTIFIER: &str\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002498 code_ += " = \"" + parser_.file_identifier_ + "\";";
2499 code_ += "";
2500
2501 // Check if a buffer has the identifier.
2502 code_ += "#[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002503 code_ += "pub fn {{STRUCT_FN}}_buffer_has_identifier\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002504 code_ += "(buf: &[u8]) -> bool {";
Austin Schuh272c6132020-11-14 16:37:52 -08002505 code_ += " flatbuffers::buffer_has_identifier(buf, \\";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002506 code_ += "{{STRUCT_CONST}}_IDENTIFIER, false)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002507 code_ += "}";
2508 code_ += "";
2509 code_ += "#[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002510 code_ += "pub fn {{STRUCT_FN}}_size_prefixed\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002511 code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
Austin Schuh272c6132020-11-14 16:37:52 -08002512 code_ += " flatbuffers::buffer_has_identifier(buf, \\";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002513 code_ += "{{STRUCT_CONST}}_IDENTIFIER, true)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002514 code_ += "}";
2515 code_ += "";
2516 }
2517
2518 if (parser_.file_extension_.length()) {
2519 // Return the extension
James Kuszmaul8e62b022022-03-22 09:33:25 -07002520 code_ += "pub const {{STRUCT_CONST}}_EXTENSION: &str = \\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002521 code_ += "\"" + parser_.file_extension_ + "\";";
2522 code_ += "";
2523 }
2524
2525 // Finish a buffer with a given root object:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002526 code_ += "#[inline]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002527 code_ += "pub fn finish_{{STRUCT_FN}}_buffer<'a, 'b>(";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002528 code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002529 code_ += " root: flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>>) {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002530 if (parser_.file_identifier_.length()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002531 code_ += " fbb.finish(root, Some({{STRUCT_CONST}}_IDENTIFIER));";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002532 } else {
2533 code_ += " fbb.finish(root, None);";
2534 }
2535 code_ += "}";
2536 code_ += "";
2537 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08002538 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002539 "pub fn finish_size_prefixed_{{STRUCT_FN}}_buffer"
Austin Schuh272c6132020-11-14 16:37:52 -08002540 "<'a, 'b>("
2541 "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002542 "root: flatbuffers::WIPOffset<{{STRUCT_TY}}<'a>>) {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002543 if (parser_.file_identifier_.length()) {
Austin Schuh272c6132020-11-14 16:37:52 -08002544 code_ +=
2545 " fbb.finish_size_prefixed(root, "
James Kuszmaul8e62b022022-03-22 09:33:25 -07002546 "Some({{STRUCT_CONST}}_IDENTIFIER));";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002547 } else {
2548 code_ += " fbb.finish_size_prefixed(root, None);";
2549 }
2550 code_ += "}";
2551 }
2552
2553 static void GenPadding(
2554 const FieldDef &field, std::string *code_ptr, int *id,
2555 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
2556 if (field.padding) {
2557 for (int i = 0; i < 4; i++) {
2558 if (static_cast<int>(field.padding) & (1 << i)) {
2559 f((1 << i) * 8, code_ptr, id);
2560 }
2561 }
2562 assert(!(field.padding & ~0xF));
2563 }
2564 }
2565
2566 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
Austin Schuh272c6132020-11-14 16:37:52 -08002567 *code_ptr +=
2568 " padding" + NumToString((*id)++) + "__: u" + NumToString(bits) + ",";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002569 }
2570
2571 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
2572 (void)bits;
2573 *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
2574 }
2575
James Kuszmaul8e62b022022-03-22 09:33:25 -07002576 void ForAllStructFields(const StructDef &struct_def,
2577 std::function<void(const FieldDef &field)> cb) {
2578 size_t offset_to_field = 0;
Austin Schuh272c6132020-11-14 16:37:52 -08002579 for (auto it = struct_def.fields.vec.begin();
2580 it != struct_def.fields.vec.end(); ++it) {
2581 const auto &field = **it;
2582 code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002583 code_.SetValue("FIELD_OTY", ObjectFieldType(field, false));
Austin Schuh2dd86a92022-09-14 21:19:23 -07002584 code_.SetValue("FIELD", namer_.Field(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002585 code_.SetValue("FIELD_OFFSET", NumToString(offset_to_field));
2586 code_.SetValue(
2587 "REF",
2588 IsStruct(field.value.type) || IsArray(field.value.type) ? "&" : "");
2589 code_.IncrementIdentLevel();
Austin Schuh272c6132020-11-14 16:37:52 -08002590 cb(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07002591 code_.DecrementIdentLevel();
2592 const size_t size = InlineSize(field.value.type);
2593 offset_to_field += size + field.padding;
Austin Schuh272c6132020-11-14 16:37:52 -08002594 }
2595 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002596 // Generate an accessor struct with constructor for a flatbuffers struct.
2597 void GenStruct(const StructDef &struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07002598 const bool is_private = parser_.opts.no_leak_private_annotations &&
2599 (struct_def.attributes.Lookup("private") != nullptr);
2600 code_.SetValue("ACCESS_TYPE", is_private ? "pub(crate)" : "pub");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002601 // Generates manual padding and alignment.
2602 // Variables are private because they contain little endian data on all
2603 // platforms.
2604 GenComment(struct_def.doc_comment);
2605 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
Austin Schuh2dd86a92022-09-14 21:19:23 -07002606 code_.SetValue("STRUCT_TY", namer_.Type(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002607 code_.SetValue("STRUCT_SIZE", NumToString(struct_def.bytesize));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002608
James Kuszmaul8e62b022022-03-22 09:33:25 -07002609 // We represent Flatbuffers-structs in Rust-u8-arrays since the data may be
2610 // of the wrong endianness and alignment 1.
2611 //
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002612 // PartialEq is useful to derive because we can correctly compare structs
2613 // for equality by just comparing their underlying byte data. This doesn't
2614 // hold for PartialOrd/Ord.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002615 code_ += "// struct {{STRUCT_TY}}, aligned to {{ALIGN}}";
2616 code_ += "#[repr(transparent)]";
Austin Schuh272c6132020-11-14 16:37:52 -08002617 code_ += "#[derive(Clone, Copy, PartialEq)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -07002618 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_TY}}(pub [u8; {{STRUCT_SIZE}}]);";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002619 code_ += "impl Default for {{STRUCT_TY}} { ";
2620 code_ += " fn default() -> Self { ";
2621 code_ += " Self([0; {{STRUCT_SIZE}}])";
2622 code_ += " }";
2623 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002624
Austin Schuh272c6132020-11-14 16:37:52 -08002625 // Debug for structs.
Austin Schuh2dd86a92022-09-14 21:19:23 -07002626 code_ += "impl core::fmt::Debug for {{STRUCT_TY}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002627 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07002628 " fn fmt(&self, f: &mut core::fmt::Formatter"
2629 ") -> core::fmt::Result {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002630 code_ += " f.debug_struct(\"{{STRUCT_TY}}\")";
Austin Schuh272c6132020-11-14 16:37:52 -08002631 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002632 (void)unused;
2633 code_ += " .field(\"{{FIELD}}\", &self.{{FIELD}}())";
Austin Schuh272c6132020-11-14 16:37:52 -08002634 });
2635 code_ += " .finish()";
2636 code_ += " }";
2637 code_ += "}";
2638 code_ += "";
2639
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002640 // Generate impls for SafeSliceAccess (because all structs are endian-safe),
2641 // Follow for the value type, Follow for the reference type, Push for the
2642 // value type, and Push for the reference type.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002643 code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{STRUCT_TY}} {}";
2644 code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_TY}} {}";
2645 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_TY}} {";
2646 code_ += " type Inner = &'a {{STRUCT_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002647 code_ += " #[inline]";
2648 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002649 code_ += " <&'a {{STRUCT_TY}}>::follow(buf, loc)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002650 code_ += " }";
2651 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002652 code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_TY}} {";
2653 code_ += " type Inner = &'a {{STRUCT_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002654 code_ += " #[inline]";
2655 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002656 code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_TY}}>(buf, loc)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002657 code_ += " }";
2658 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002659 code_ += "impl<'b> flatbuffers::Push for {{STRUCT_TY}} {";
2660 code_ += " type Output = {{STRUCT_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002661 code_ += " #[inline]";
2662 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
2663 code_ += " let src = unsafe {";
Austin Schuh272c6132020-11-14 16:37:52 -08002664 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07002665 " ::core::slice::from_raw_parts("
James Kuszmaul8e62b022022-03-22 09:33:25 -07002666 "self as *const {{STRUCT_TY}} as *const u8, Self::size())";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002667 code_ += " };";
2668 code_ += " dst.copy_from_slice(src);";
2669 code_ += " }";
2670 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002671 code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_TY}} {";
2672 code_ += " type Output = {{STRUCT_TY}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002673 code_ += "";
2674 code_ += " #[inline]";
2675 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
2676 code_ += " let src = unsafe {";
Austin Schuh272c6132020-11-14 16:37:52 -08002677 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07002678 " ::core::slice::from_raw_parts("
James Kuszmaul8e62b022022-03-22 09:33:25 -07002679 "*self as *const {{STRUCT_TY}} as *const u8, Self::size())";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002680 code_ += " };";
2681 code_ += " dst.copy_from_slice(src);";
2682 code_ += " }";
2683 code_ += "}";
2684 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002685
2686 // Generate verifier: Structs are simple so presence and alignment are
2687 // all that need to be checked.
2688 code_ += "impl<'a> flatbuffers::Verifiable for {{STRUCT_TY}} {";
2689 code_ += " #[inline]";
2690 code_ += " fn run_verifier(";
2691 code_ += " v: &mut flatbuffers::Verifier, pos: usize";
2692 code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
2693 code_ += " use self::flatbuffers::Verifiable;";
2694 code_ += " v.in_buffer::<Self>(pos)";
2695 code_ += " }";
2696 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002697 code_ += "";
2698
James Kuszmaul8e62b022022-03-22 09:33:25 -07002699 // Implement serde::Serialize
2700 if (parser_.opts.rust_serialize) {
2701 const auto numFields = struct_def.fields.vec.size();
2702 code_.SetValue("NUM_FIELDS", NumToString(numFields));
2703 code_ += "impl Serialize for {{STRUCT_TY}} {";
2704 code_ +=
2705 " fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
2706 code_ += " where";
2707 code_ += " S: Serializer,";
2708 code_ += " {";
2709 if (numFields == 0) {
2710 code_ +=
2711 " let s = serializer.serialize_struct(\"{{STRUCT_TY}}\", 0)?;";
2712 } else {
2713 code_ +=
2714 " let mut s = serializer.serialize_struct(\"{{STRUCT_TY}}\", "
2715 "{{NUM_FIELDS}})?;";
2716 }
2717 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2718 (void)unused;
2719 code_ +=
2720 " s.serialize_field(\"{{FIELD}}\", "
2721 "&self.{{FIELD}}())?;";
2722 });
2723 code_ += " s.end()";
2724 code_ += " }";
2725 code_ += "}";
2726 code_ += "";
2727 }
2728
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002729 // Generate a constructor that takes all fields as arguments.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002730 code_ += "impl<'a> {{STRUCT_TY}} {";
2731 code_ += " #[allow(clippy::too_many_arguments)]";
2732 code_ += " pub fn new(";
2733 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2734 (void)unused;
2735 code_ += " {{FIELD}}: {{REF}}{{FIELD_TYPE}},";
Austin Schuh272c6132020-11-14 16:37:52 -08002736 });
James Kuszmaul8e62b022022-03-22 09:33:25 -07002737 code_ += " ) -> Self {";
2738 code_ += " let mut s = Self([0; {{STRUCT_SIZE}}]);";
2739 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
2740 (void)unused;
2741 code_ += " s.set_{{FIELD}}({{FIELD}});";
Austin Schuh272c6132020-11-14 16:37:52 -08002742 });
James Kuszmaul8e62b022022-03-22 09:33:25 -07002743 code_ += " s";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002744 code_ += " }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002745 code_ += "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002746
Austin Schuh272c6132020-11-14 16:37:52 -08002747 if (parser_.opts.generate_name_strings) {
2748 GenFullyQualifiedNameGetter(struct_def, struct_def.name);
2749 }
2750
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002751 // Generate accessor methods for the struct.
Austin Schuh272c6132020-11-14 16:37:52 -08002752 ForAllStructFields(struct_def, [&](const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002753 this->GenComment(field.doc_comment);
2754 // Getter.
2755 if (IsStruct(field.value.type)) {
2756 code_ += "pub fn {{FIELD}}(&self) -> &{{FIELD_TYPE}} {";
2757 code_ +=
2758 " unsafe {"
2759 " &*(self.0[{{FIELD_OFFSET}}..].as_ptr() as *const"
2760 " {{FIELD_TYPE}}) }";
2761 } else if (IsArray(field.value.type)) {
2762 code_.SetValue("ARRAY_SIZE",
2763 NumToString(field.value.type.fixed_length));
2764 code_.SetValue("ARRAY_ITEM", GetTypeGet(field.value.type.VectorType()));
2765 code_ +=
2766 "pub fn {{FIELD}}(&'a self) -> "
2767 "flatbuffers::Array<'a, {{ARRAY_ITEM}}, {{ARRAY_SIZE}}> {";
2768 code_ += " flatbuffers::Array::follow(&self.0, {{FIELD_OFFSET}})";
2769 } else {
2770 code_ += "pub fn {{FIELD}}(&self) -> {{FIELD_TYPE}} {";
2771 code_ +=
2772 " let mut mem = core::mem::MaybeUninit::"
2773 "<{{FIELD_TYPE}}>::uninit();";
2774 code_ += " unsafe {";
2775 code_ += " core::ptr::copy_nonoverlapping(";
2776 code_ += " self.0[{{FIELD_OFFSET}}..].as_ptr(),";
2777 code_ += " mem.as_mut_ptr() as *mut u8,";
2778 code_ += " core::mem::size_of::<{{FIELD_TYPE}}>(),";
2779 code_ += " );";
2780 code_ += " mem.assume_init()";
2781 code_ += " }.from_little_endian()";
2782 }
2783 code_ += "}\n";
2784 // Setter.
2785 if (IsStruct(field.value.type)) {
2786 code_.SetValue("FIELD_SIZE", NumToString(InlineSize(field.value.type)));
2787 code_ += "#[allow(clippy::identity_op)]"; // If FIELD_OFFSET=0.
2788 code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {";
2789 code_ +=
2790 " self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}} + {{FIELD_SIZE}}]"
2791 ".copy_from_slice(&x.0)";
2792 } else if (IsArray(field.value.type)) {
2793 if (GetFullType(field.value.type) == ftArrayOfBuiltin) {
2794 code_.SetValue("ARRAY_ITEM",
2795 GetTypeGet(field.value.type.VectorType()));
2796 code_.SetValue(
2797 "ARRAY_ITEM_SIZE",
2798 NumToString(InlineSize(field.value.type.VectorType())));
2799 code_ +=
2800 "pub fn set_{{FIELD}}(&mut self, items: &{{FIELD_TYPE}}) "
2801 "{";
2802 code_ +=
2803 " flatbuffers::emplace_scalar_array(&mut self.0, "
2804 "{{FIELD_OFFSET}}, items);";
2805 } else {
2806 code_.SetValue("FIELD_SIZE",
2807 NumToString(InlineSize(field.value.type)));
2808 code_ += "pub fn set_{{FIELD}}(&mut self, x: &{{FIELD_TYPE}}) {";
2809 code_ += " unsafe {";
Austin Schuh2dd86a92022-09-14 21:19:23 -07002810 code_ += " core::ptr::copy(";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002811 code_ += " x.as_ptr() as *const u8,";
2812 code_ += " self.0.as_mut_ptr().add({{FIELD_OFFSET}}),";
2813 code_ += " {{FIELD_SIZE}},";
2814 code_ += " );";
2815 code_ += " }";
2816 }
2817 } else {
2818 code_ += "pub fn set_{{FIELD}}(&mut self, x: {{FIELD_TYPE}}) {";
2819 code_ += " let x_le = x.to_little_endian();";
2820 code_ += " unsafe {";
2821 code_ += " core::ptr::copy_nonoverlapping(";
2822 code_ += " &x_le as *const {{FIELD_TYPE}} as *const u8,";
2823 code_ += " self.0[{{FIELD_OFFSET}}..].as_mut_ptr(),";
2824 code_ += " core::mem::size_of::<{{FIELD_TYPE}}>(),";
2825 code_ += " );";
2826 code_ += " }";
2827 }
2828 code_ += "}\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002829
2830 // Generate a comparison function for this field if it is a key.
Austin Schuh272c6132020-11-14 16:37:52 -08002831 if (field.key) { GenKeyFieldMethods(field); }
2832 });
James Kuszmaul8e62b022022-03-22 09:33:25 -07002833
2834 // Generate Object API unpack method.
2835 if (parser_.opts.generate_object_based_api) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07002836 code_.SetValue("STRUCT_OTY", namer_.ObjectType(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002837 code_ += " pub fn unpack(&self) -> {{STRUCT_OTY}} {";
2838 code_ += " {{STRUCT_OTY}} {";
2839 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2840 if (IsArray(field.value.type)) {
2841 if (GetFullType(field.value.type) == ftArrayOfStruct) {
2842 code_ +=
2843 " {{FIELD}}: { let {{FIELD}} = "
2844 "self.{{FIELD}}(); flatbuffers::array_init(|i| "
2845 "{{FIELD}}.get(i).unpack()) },";
2846 } else {
2847 code_ += " {{FIELD}}: self.{{FIELD}}().into(),";
2848 }
2849 } else {
2850 std::string unpack = IsStruct(field.value.type) ? ".unpack()" : "";
2851 code_ += " {{FIELD}}: self.{{FIELD}}()" + unpack + ",";
2852 }
2853 });
2854 code_ += " }";
2855 code_ += " }";
2856 }
2857
2858 code_ += "}"; // End impl Struct methods.
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002859 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002860
2861 // Generate Struct Object.
2862 if (parser_.opts.generate_object_based_api) {
2863 // Struct declaration
2864 code_ += "#[derive(Debug, Clone, PartialEq, Default)]";
Austin Schuh2dd86a92022-09-14 21:19:23 -07002865 code_ += "{{ACCESS_TYPE}} struct {{STRUCT_OTY}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002866 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2867 (void)field; // unused.
2868 code_ += "pub {{FIELD}}: {{FIELD_OTY}},";
2869 });
2870 code_ += "}";
2871 // The `pack` method that turns the native struct into its Flatbuffers
2872 // counterpart.
2873 code_ += "impl {{STRUCT_OTY}} {";
2874 code_ += " pub fn pack(&self) -> {{STRUCT_TY}} {";
2875 code_ += " {{STRUCT_TY}}::new(";
2876 ForAllStructFields(struct_def, [&](const FieldDef &field) {
2877 if (IsStruct(field.value.type)) {
2878 code_ += " &self.{{FIELD}}.pack(),";
2879 } else if (IsArray(field.value.type)) {
2880 if (GetFullType(field.value.type) == ftArrayOfStruct) {
2881 code_ +=
2882 " &flatbuffers::array_init(|i| "
2883 "self.{{FIELD}}[i].pack()),";
2884 } else {
2885 code_ += " &self.{{FIELD}},";
2886 }
2887 } else {
2888 code_ += " self.{{FIELD}},";
2889 }
2890 });
2891 code_ += " )";
2892 code_ += " }";
2893 code_ += "}";
2894 code_ += "";
2895 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002896 }
2897
2898 void GenNamespaceImports(const int white_spaces) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002899 // DO not use global attributes (i.e. #![...]) since it interferes
2900 // with users who include! generated files.
2901 // See: https://github.com/google/flatbuffers/issues/6261
Austin Schuh272c6132020-11-14 16:37:52 -08002902 std::string indent = std::string(white_spaces, ' ');
2903 code_ += "";
2904 if (!parser_.opts.generate_all) {
2905 for (auto it = parser_.included_files_.begin();
2906 it != parser_.included_files_.end(); ++it) {
2907 if (it->second.empty()) continue;
2908 auto noext = flatbuffers::StripExtension(it->second);
2909 auto basename = flatbuffers::StripPath(noext);
2910
James Kuszmaul8e62b022022-03-22 09:33:25 -07002911 if (parser_.opts.include_prefix.empty()) {
2912 code_ += indent + "use crate::" + basename +
2913 parser_.opts.filename_suffix + "::*;";
2914 } else {
2915 auto prefix = parser_.opts.include_prefix;
2916 prefix.pop_back();
2917
2918 code_ += indent + "use crate::" + prefix + "::" + basename +
2919 parser_.opts.filename_suffix + "::*;";
2920 }
Austin Schuh272c6132020-11-14 16:37:52 -08002921 }
2922 }
Austin Schuh2dd86a92022-09-14 21:19:23 -07002923 code_ += indent + "use core::mem;";
2924 code_ += indent + "use core::cmp::Ordering;";
Austin Schuh272c6132020-11-14 16:37:52 -08002925 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002926 if (parser_.opts.rust_serialize) {
2927 code_ += indent + "extern crate serde;";
2928 code_ +=
2929 indent +
2930 "use self::serde::ser::{Serialize, Serializer, SerializeStruct};";
2931 code_ += "";
2932 }
Austin Schuh272c6132020-11-14 16:37:52 -08002933 code_ += indent + "extern crate flatbuffers;";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002934 code_ += indent + "use self::flatbuffers::{EndianScalar, Follow};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002935 }
2936
2937 // Set up the correct namespace. This opens a namespace if the current
2938 // namespace is different from the target namespace. This function
2939 // closes and opens the namespaces only as necessary.
2940 //
2941 // The file must start and end with an empty (or null) namespace so that
2942 // namespaces are properly opened and closed.
2943 void SetNameSpace(const Namespace *ns) {
2944 if (cur_name_space_ == ns) { return; }
2945
2946 // Compute the size of the longest common namespace prefix.
2947 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
2948 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
2949 // and common_prefix_size = 2
2950 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
2951 size_t new_size = ns ? ns->components.size() : 0;
2952
2953 size_t common_prefix_size = 0;
2954 while (common_prefix_size < old_size && common_prefix_size < new_size &&
2955 ns->components[common_prefix_size] ==
2956 cur_name_space_->components[common_prefix_size]) {
2957 common_prefix_size++;
2958 }
2959
2960 // Close cur_name_space in reverse order to reach the common prefix.
2961 // In the previous example, D then C are closed.
2962 for (size_t j = old_size; j > common_prefix_size; --j) {
2963 code_ += "} // pub mod " + cur_name_space_->components[j - 1];
2964 }
2965 if (old_size != common_prefix_size) { code_ += ""; }
2966
2967 // open namespace parts to reach the ns namespace
2968 // in the previous example, E, then F, then G are opened
2969 for (auto j = common_prefix_size; j != new_size; ++j) {
2970 code_ += "#[allow(unused_imports, dead_code)]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002971 code_ += "pub mod " + namer_.Namespace(ns->components[j]) + " {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002972 // Generate local namespace imports.
2973 GenNamespaceImports(2);
2974 }
2975 if (new_size != common_prefix_size) { code_ += ""; }
2976
2977 cur_name_space_ = ns;
2978 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07002979
2980 private:
Austin Schuh2dd86a92022-09-14 21:19:23 -07002981 IdlNamer namer_;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002982};
2983
2984} // namespace rust
2985
2986bool GenerateRust(const Parser &parser, const std::string &path,
2987 const std::string &file_name) {
2988 rust::RustGenerator generator(parser, path, file_name);
2989 return generator.generate();
2990}
2991
2992std::string RustMakeRule(const Parser &parser, const std::string &path,
2993 const std::string &file_name) {
2994 std::string filebase =
2995 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
Austin Schuh272c6132020-11-14 16:37:52 -08002996 rust::RustGenerator generator(parser, path, file_name);
2997 std::string make_rule =
2998 generator.GeneratedFileName(path, filebase, parser.opts) + ": ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002999
3000 auto included_files = parser.GetIncludedFilesRecursive(file_name);
3001 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
3002 make_rule += " " + *it;
3003 }
3004 return make_rule;
3005}
3006
3007} // namespace flatbuffers
3008
3009// TODO(rw): Generated code should import other generated files.
3010// TODO(rw): Generated code should refer to namespaces in included files in a
3011// way that makes them referrable.
3012// TODO(rw): Generated code should indent according to nesting level.
3013// TODO(rw): Generated code should generate endian-safe Debug impls.
3014// TODO(rw): Generated code could use a Rust-only enum type to access unions,
3015// instead of making the user use _type() to manually switch.
Austin Schuh272c6132020-11-14 16:37:52 -08003016// TODO(maxburke): There should be test schemas added that use language
3017// keywords as fields of structs, tables, unions, enums, to make sure
3018// that internal code generated references escaped names correctly.
3019// TODO(maxburke): We should see if there is a more flexible way of resolving
3020// module paths for use declarations. Right now if schemas refer to
3021// other flatbuffer files, the include paths in emitted Rust bindings
3022// are crate-relative which may undesirable.