blob: 3995a7f2e4cbf4282ce788237ad2ca8f18f38a6d [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"
23
24namespace flatbuffers {
25
Austin Schuhe89fa2d2019-08-14 20:24:23 -070026// Convert a camelCaseIdentifier or CamelCaseIdentifier to a
27// snake_case_indentifier.
28std::string MakeSnakeCase(const std::string &in) {
29 std::string s;
30 for (size_t i = 0; i < in.length(); i++) {
31 if (i == 0) {
Austin Schuh272c6132020-11-14 16:37:52 -080032 s += CharToLower(in[0]);
Austin Schuhe89fa2d2019-08-14 20:24:23 -070033 } else if (in[i] == '_') {
34 s += '_';
35 } else if (!islower(in[i])) {
36 // Prevent duplicate underscores for Upper_Snake_Case strings
37 // and UPPERCASE strings.
Austin Schuh272c6132020-11-14 16:37:52 -080038 if (islower(in[i - 1])) { s += '_'; }
39 s += CharToLower(in[i]);
Austin Schuhe89fa2d2019-08-14 20:24:23 -070040 } else {
41 s += in[i];
42 }
43 }
44 return s;
45}
46
47// Convert a string to all uppercase.
48std::string MakeUpper(const std::string &in) {
49 std::string s;
Austin Schuh272c6132020-11-14 16:37:52 -080050 for (size_t i = 0; i < in.length(); i++) { s += CharToUpper(in[i]); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -070051 return s;
52}
53
54// Encapsulate all logical field types in this enum. This allows us to write
55// field logic based on type switches, instead of branches on the properties
56// set on the Type.
57// TODO(rw): for backwards compatibility, we can't use a strict `enum class`
58// declaration here. could we use the `-Wswitch-enum` warning to
59// achieve the same effect?
60enum FullType {
61 ftInteger = 0,
62 ftFloat = 1,
63 ftBool = 2,
64
65 ftStruct = 3,
66 ftTable = 4,
67
68 ftEnumKey = 5,
69 ftUnionKey = 6,
70
71 ftUnionValue = 7,
72
73 // TODO(rw): bytestring?
74 ftString = 8,
75
76 ftVectorOfInteger = 9,
77 ftVectorOfFloat = 10,
78 ftVectorOfBool = 11,
79 ftVectorOfEnumKey = 12,
80 ftVectorOfStruct = 13,
81 ftVectorOfTable = 14,
82 ftVectorOfString = 15,
83 ftVectorOfUnionValue = 16,
84};
85
86// Convert a Type to a FullType (exhaustive).
87FullType GetFullType(const Type &type) {
88 // N.B. The order of these conditionals matters for some types.
89
Austin Schuh272c6132020-11-14 16:37:52 -080090 if (IsString(type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070091 return ftString;
92 } else if (type.base_type == BASE_TYPE_STRUCT) {
93 if (type.struct_def->fixed) {
94 return ftStruct;
95 } else {
96 return ftTable;
97 }
Austin Schuh272c6132020-11-14 16:37:52 -080098 } else if (IsVector(type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070099 switch (GetFullType(type.VectorType())) {
100 case ftInteger: {
101 return ftVectorOfInteger;
102 }
103 case ftFloat: {
104 return ftVectorOfFloat;
105 }
106 case ftBool: {
107 return ftVectorOfBool;
108 }
109 case ftStruct: {
110 return ftVectorOfStruct;
111 }
112 case ftTable: {
113 return ftVectorOfTable;
114 }
115 case ftString: {
116 return ftVectorOfString;
117 }
118 case ftEnumKey: {
119 return ftVectorOfEnumKey;
120 }
121 case ftUnionKey:
122 case ftUnionValue: {
123 FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
124 break;
125 }
126 default: {
127 FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
128 }
129 }
130 } else if (type.enum_def != nullptr) {
131 if (type.enum_def->is_union) {
132 if (type.base_type == BASE_TYPE_UNION) {
133 return ftUnionValue;
134 } else if (IsInteger(type.base_type)) {
135 return ftUnionKey;
136 } else {
137 FLATBUFFERS_ASSERT(false && "unknown union field type");
138 }
139 } else {
140 return ftEnumKey;
141 }
142 } else if (IsScalar(type.base_type)) {
143 if (IsBool(type.base_type)) {
144 return ftBool;
145 } else if (IsInteger(type.base_type)) {
146 return ftInteger;
147 } else if (IsFloat(type.base_type)) {
148 return ftFloat;
149 } else {
150 FLATBUFFERS_ASSERT(false && "unknown number type");
151 }
152 }
153
154 FLATBUFFERS_ASSERT(false && "completely unknown type");
155
156 // this is only to satisfy the compiler's return analysis.
157 return ftBool;
158}
159
160// If the second parameter is false then wrap the first with Option<...>
161std::string WrapInOptionIfNotRequired(std::string s, bool required) {
162 if (required) {
163 return s;
164 } else {
165 return "Option<" + s + ">";
166 }
167}
168
169// If the second parameter is false then add .unwrap()
170std::string AddUnwrapIfRequired(std::string s, bool required) {
171 if (required) {
172 return s + ".unwrap()";
173 } else {
174 return s;
175 }
176}
177
Austin Schuh272c6132020-11-14 16:37:52 -0800178bool IsBitFlagsEnum(const EnumDef &enum_def) {
179 return enum_def.attributes.Lookup("bit_flags") != nullptr;
180}
181bool IsBitFlagsEnum(const FieldDef &field) {
182 EnumDef* ed = field.value.type.enum_def;
183 return ed && IsBitFlagsEnum(*ed);
184}
185
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700186namespace rust {
187
188class RustGenerator : public BaseGenerator {
189 public:
190 RustGenerator(const Parser &parser, const std::string &path,
191 const std::string &file_name)
Austin Schuh272c6132020-11-14 16:37:52 -0800192 : BaseGenerator(parser, path, file_name, "", "::", "rs"),
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700193 cur_name_space_(nullptr) {
194 const char *keywords[] = {
195 // list taken from:
196 // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
197 //
198 // we write keywords one per line so that we can easily compare them with
199 // changes to that webpage in the future.
200
201 // currently-used keywords
Austin Schuh272c6132020-11-14 16:37:52 -0800202 "as", "break", "const", "continue", "crate", "else", "enum", "extern",
203 "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod",
204 "move", "mut", "pub", "ref", "return", "Self", "self", "static", "struct",
205 "super", "trait", "true", "type", "unsafe", "use", "where", "while",
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700206
207 // future possible keywords
Austin Schuh272c6132020-11-14 16:37:52 -0800208 "abstract", "alignof", "become", "box", "do", "final", "macro",
209 "offsetof", "override", "priv", "proc", "pure", "sizeof", "typeof",
210 "unsized", "virtual", "yield",
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700211
212 // other rust terms we should not use
Austin Schuh272c6132020-11-14 16:37:52 -0800213 "std", "usize", "isize", "u8", "i8", "u16", "i16", "u32", "i32", "u64",
214 "i64", "u128", "i128", "f32", "f64",
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700215
216 // These are terms the code generator can implement on types.
217 //
218 // In Rust, the trait resolution rules (as described at
219 // https://github.com/rust-lang/rust/issues/26007) mean that, as long
220 // as we impl table accessors as inherent methods, we'll never create
221 // conflicts with these keywords. However, that's a fairly nuanced
222 // implementation detail, and how we implement methods could change in
223 // the future. as a result, we proactively block these out as reserved
224 // words.
Austin Schuh272c6132020-11-14 16:37:52 -0800225 "follow", "push", "size", "alignment", "to_little_endian",
226 "from_little_endian", nullptr,
227
228 // used by Enum constants
229 "ENUM_MAX", "ENUM_MIN", "ENUM_VALUES",
230 };
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700231 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
232 }
233
234 // Iterate through all definitions we haven't generated code for (enums,
235 // structs, and tables) and output them to a single file.
236 bool generate() {
237 code_.Clear();
238 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
239
240 assert(!cur_name_space_);
241
242 // Generate imports for the global scope in case no namespace is used
243 // in the schema file.
244 GenNamespaceImports(0);
245 code_ += "";
246
247 // Generate all code in their namespaces, once, because Rust does not
248 // permit re-opening modules.
249 //
250 // TODO(rw): Use a set data structure to reduce namespace evaluations from
251 // O(n**2) to O(n).
252 for (auto ns_it = parser_.namespaces_.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800253 ns_it != parser_.namespaces_.end(); ++ns_it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700254 const auto &ns = *ns_it;
255
256 // Generate code for all the enum declarations.
257 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
258 ++it) {
259 const auto &enum_def = **it;
260 if (enum_def.defined_namespace != ns) { continue; }
261 if (!enum_def.generated) {
262 SetNameSpace(enum_def.defined_namespace);
263 GenEnum(enum_def);
264 }
265 }
266
267 // Generate code for all structs.
268 for (auto it = parser_.structs_.vec.begin();
269 it != parser_.structs_.vec.end(); ++it) {
270 const auto &struct_def = **it;
271 if (struct_def.defined_namespace != ns) { continue; }
272 if (struct_def.fixed && !struct_def.generated) {
273 SetNameSpace(struct_def.defined_namespace);
274 GenStruct(struct_def);
275 }
276 }
277
278 // Generate code for all tables.
279 for (auto it = parser_.structs_.vec.begin();
280 it != parser_.structs_.vec.end(); ++it) {
281 const auto &struct_def = **it;
282 if (struct_def.defined_namespace != ns) { continue; }
283 if (!struct_def.fixed && !struct_def.generated) {
284 SetNameSpace(struct_def.defined_namespace);
285 GenTable(struct_def);
286 }
287 }
288
289 // Generate global helper functions.
290 if (parser_.root_struct_def_) {
291 auto &struct_def = *parser_.root_struct_def_;
292 if (struct_def.defined_namespace != ns) { continue; }
293 SetNameSpace(struct_def.defined_namespace);
294 GenRootTableFuncs(struct_def);
295 }
296 }
297 if (cur_name_space_) SetNameSpace(nullptr);
298
Austin Schuh272c6132020-11-14 16:37:52 -0800299 const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700300 const auto final_code = code_.ToString();
301 return SaveFile(file_path.c_str(), final_code, false);
302 }
303
304 private:
305 CodeWriter code_;
306
307 std::set<std::string> keywords_;
308
309 // This tracks the current namespace so we can insert namespace declarations.
310 const Namespace *cur_name_space_;
311
312 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
313
314 // Determine if a Type needs a lifetime template parameter when used in the
315 // Rust builder args.
316 bool TableBuilderTypeNeedsLifetime(const Type &type) const {
317 switch (GetFullType(type)) {
318 case ftInteger:
319 case ftFloat:
320 case ftBool:
321 case ftEnumKey:
322 case ftUnionKey:
Austin Schuh272c6132020-11-14 16:37:52 -0800323 case ftUnionValue: {
324 return false;
325 }
326 default: {
327 return true;
328 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700329 }
330 }
331
332 // Determine if a table args rust type needs a lifetime template parameter.
333 bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
334 FLATBUFFERS_ASSERT(!struct_def.fixed);
335
336 for (auto it = struct_def.fields.vec.begin();
337 it != struct_def.fields.vec.end(); ++it) {
338 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -0800339 if (field.deprecated) { continue; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700340
Austin Schuh272c6132020-11-14 16:37:52 -0800341 if (TableBuilderTypeNeedsLifetime(field.value.type)) { return true; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700342 }
343
344 return false;
345 }
346
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700347 std::string EscapeKeyword(const std::string &name) const {
348 return keywords_.find(name) == keywords_.end() ? name : name + "_";
349 }
350
351 std::string Name(const Definition &def) const {
352 return EscapeKeyword(def.name);
353 }
354
355 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
356
357 std::string WrapInNameSpace(const Definition &def) const {
358 return WrapInNameSpace(def.defined_namespace, Name(def));
359 }
360 std::string WrapInNameSpace(const Namespace *ns,
361 const std::string &name) const {
362 if (CurrentNameSpace() == ns) return name;
363 std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
364 return prefix + name;
365 }
366
367 // Determine the namespace traversal needed from the Rust crate root.
368 // This may be useful in the future for referring to included files, but is
369 // currently unused.
370 std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const {
371 std::stringstream stream;
372
373 stream << "::";
374 for (auto d = dst->components.begin(); d != dst->components.end(); ++d) {
375 stream << MakeSnakeCase(*d) + "::";
376 }
377 return stream.str();
378 }
379
380 // Determine the relative namespace traversal needed to reference one
381 // namespace from another namespace. This is useful because it does not force
382 // the user to have a particular file layout. (If we output absolute
383 // namespace paths, that may require users to organize their Rust crates in a
384 // particular way.)
385 std::string GetRelativeNamespaceTraversal(const Namespace *src,
386 const Namespace *dst) const {
387 // calculate the path needed to reference dst from src.
388 // example: f(A::B::C, A::B::C) -> (none)
389 // example: f(A::B::C, A::B) -> super::
390 // example: f(A::B::C, A::B::D) -> super::D
391 // example: f(A::B::C, A) -> super::super::
392 // example: f(A::B::C, D) -> super::super::super::D
393 // example: f(A::B::C, D::E) -> super::super::super::D::E
394 // example: f(A, D::E) -> super::D::E
395 // does not include leaf object (typically a struct type).
396
397 size_t i = 0;
398 std::stringstream stream;
399
400 auto s = src->components.begin();
401 auto d = dst->components.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800402 for (;;) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700403 if (s == src->components.end()) { break; }
404 if (d == dst->components.end()) { break; }
405 if (*s != *d) { break; }
406 ++s;
407 ++d;
408 ++i;
409 }
410
Austin Schuh272c6132020-11-14 16:37:52 -0800411 for (; s != src->components.end(); ++s) { stream << "super::"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700412 for (; d != dst->components.end(); ++d) {
413 stream << MakeSnakeCase(*d) + "::";
414 }
415 return stream.str();
416 }
417
418 // Generate a comment from the schema.
419 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
420 std::string text;
421 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
422 code_ += text + "\\";
423 }
424
425 // Return a Rust type from the table in idl.h.
426 std::string GetTypeBasic(const Type &type) const {
427 switch (GetFullType(type)) {
428 case ftInteger:
429 case ftFloat:
430 case ftBool:
431 case ftEnumKey:
Austin Schuh272c6132020-11-14 16:37:52 -0800432 case ftUnionKey: {
433 break;
434 }
435 default: {
436 FLATBUFFERS_ASSERT(false && "incorrect type given");
437 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700438 }
439
440 // clang-format off
441 static const char * const ctypename[] = {
442 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -0800443 RTYPE, ...) \
444 #RTYPE,
445 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700446 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700447 };
Austin Schuh272c6132020-11-14 16:37:52 -0800448 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700449
450 if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
451 return ctypename[type.base_type];
452 }
453
454 // Look up the native type for an enum. This will always be an integer like
455 // u8, i32, etc.
456 std::string GetEnumTypeForDecl(const Type &type) {
457 const auto ft = GetFullType(type);
458 if (!(ft == ftEnumKey || ft == ftUnionKey)) {
459 FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
460 }
461
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700462 // clang-format off
Austin Schuh272c6132020-11-14 16:37:52 -0800463 static const char *ctypename[] = {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700464 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -0800465 RTYPE, ...) \
466 #RTYPE,
467 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700468 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700469 };
Austin Schuh272c6132020-11-14 16:37:52 -0800470 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700471
472 // Enums can be bools, but their Rust representation must be a u8, as used
473 // in the repr attribute (#[repr(bool)] is an invalid attribute).
474 if (type.base_type == BASE_TYPE_BOOL) return "u8";
475 return ctypename[type.base_type];
476 }
477
478 // Return a Rust type for any type (scalar, table, struct) specifically for
479 // using a FlatBuffer.
480 std::string GetTypeGet(const Type &type) const {
481 switch (GetFullType(type)) {
482 case ftInteger:
483 case ftFloat:
484 case ftBool:
485 case ftEnumKey:
486 case ftUnionKey: {
Austin Schuh272c6132020-11-14 16:37:52 -0800487 return GetTypeBasic(type);
488 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700489 case ftTable: {
490 return WrapInNameSpace(type.struct_def->defined_namespace,
Austin Schuh272c6132020-11-14 16:37:52 -0800491 type.struct_def->name) +
492 "<'a>";
493 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700494 default: {
495 return WrapInNameSpace(type.struct_def->defined_namespace,
Austin Schuh272c6132020-11-14 16:37:52 -0800496 type.struct_def->name);
497 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700498 }
499 }
500
Austin Schuh272c6132020-11-14 16:37:52 -0800501 std::string GetEnumValue(const EnumDef &enum_def,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700502 const EnumVal &enum_val) const {
503 return Name(enum_def) + "::" + Name(enum_val);
504 }
505
Austin Schuh272c6132020-11-14 16:37:52 -0800506 // 1 suffix since old C++ can't figure out the overload.
507 void ForAllEnumValues1(const EnumDef &enum_def,
508 std::function<void(const EnumVal&)> cb) {
509 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
510 const auto &ev = **it;
511 code_.SetValue("VARIANT", Name(ev));
512 code_.SetValue("VALUE", enum_def.ToString(ev));
513 cb(ev);
514 }
515 }
516 void ForAllEnumValues(const EnumDef &enum_def, std::function<void()> cb) {
517 std::function<void(const EnumVal&)> wrapped = [&](const EnumVal& unused) {
518 (void) unused;
519 cb();
520 };
521 ForAllEnumValues1(enum_def, wrapped);
522 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700523 // Generate an enum declaration,
524 // an enum string lookup table,
525 // an enum match function,
526 // and an enum array of values
527 void GenEnum(const EnumDef &enum_def) {
528 code_.SetValue("ENUM_NAME", Name(enum_def));
529 code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
Austin Schuh272c6132020-11-14 16:37:52 -0800530 code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
531 code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700532 const EnumVal *minv = enum_def.MinValue();
533 const EnumVal *maxv = enum_def.MaxValue();
534 FLATBUFFERS_ASSERT(minv && maxv);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700535 code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
536 code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
537
Austin Schuh272c6132020-11-14 16:37:52 -0800538 if (IsBitFlagsEnum(enum_def)) {
539 // Defer to the convenient and canonical bitflags crate. We declare it in a
540 // module to #allow camel case constants in a smaller scope. This matches
541 // Flatbuffers c-modeled enums where variants are associated constants but
542 // in camel case.
543 code_ += "#[allow(non_upper_case_globals)]";
544 code_ += "mod bitflags_{{ENUM_NAME_SNAKE}} {";
545 code_ += " flatbuffers::bitflags::bitflags! {";
546 GenComment(enum_def.doc_comment, " ");
547 code_ += " pub struct {{ENUM_NAME}}: {{BASE_TYPE}} {";
548 ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
549 this->GenComment(ev.doc_comment, " ");
550 code_ += " const {{VARIANT}} = {{VALUE}};";
551 });
552 code_ += " }";
553 code_ += " }";
554 code_ += "}";
555 code_ += "pub use self::bitflags_{{ENUM_NAME_SNAKE}}::{{ENUM_NAME}};";
556 code_ += "";
557
558 // Generate Follow and Push so we can serialize and stuff.
559 code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
560 code_ += " type Inner = Self;";
561 code_ += " #[inline]";
562 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
563 code_ += " let bits = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc);";
564 code_ += " unsafe { Self::from_bits_unchecked(bits) }";
565 code_ += " }";
566 code_ += "}";
567 code_ += "";
568 code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
569 code_ += " type Output = {{ENUM_NAME}};";
570 code_ += " #[inline]";
571 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
572 code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
573 "(dst, self.bits());";
574 code_ += " }";
575 code_ += "}";
576 code_ += "";
577 code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
578 code_ += " #[inline]";
579 code_ += " fn to_little_endian(self) -> Self {";
580 code_ += " let bits = {{BASE_TYPE}}::to_le(self.bits());";
581 code_ += " unsafe { Self::from_bits_unchecked(bits) }";
582 code_ += " }";
583 code_ += " #[inline]";
584 code_ += " fn from_little_endian(self) -> Self {";
585 code_ += " let bits = {{BASE_TYPE}}::from_le(self.bits());";
586 code_ += " unsafe { Self::from_bits_unchecked(bits) }";
587 code_ += " }";
588 code_ += "}";
589 code_ += "";
590 return;
591 }
592
593 // Deprecated associated constants;
594 code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
595 " instead. This will no longer be generated in 2021.\")]";
596 code_ += "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
597 " = {{ENUM_MIN_BASE_VALUE}};";
598 code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
599 " instead. This will no longer be generated in 2021.\")]";
600 code_ += "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
601 " = {{ENUM_MAX_BASE_VALUE}};";
602 auto num_fields = NumToString(enum_def.size());
603 code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
604 " instead. This will no longer be generated in 2021.\")]";
605 code_ += "#[allow(non_camel_case_types)]";
606 code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " +
607 num_fields + "] = [";
608 ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
609 code_ += " " + GetEnumValue(enum_def, ev) + ",";
610 });
611 code_ += "];";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700612 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -0800613
614 GenComment(enum_def.doc_comment);
615 code_ +=
616 "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]";
617 code_ += "#[repr(transparent)]";
618 code_ += "pub struct {{ENUM_NAME}}(pub {{BASE_TYPE}});";
619 code_ += "#[allow(non_upper_case_globals)]";
620 code_ += "impl {{ENUM_NAME}} {";
621 ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
622 this->GenComment(ev.doc_comment, " ");
623 code_ += " pub const {{VARIANT}}: Self = Self({{VALUE}});";
624 });
625 code_ += "";
626 // Generate Associated constants
627 code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};";
628 code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};";
629 code_ += " pub const ENUM_VALUES: &'static [Self] = &[";
630 ForAllEnumValues(enum_def, [&](){
631 code_ += " Self::{{VARIANT}},";
632 });
633 code_ += " ];";
634 code_ += " /// Returns the variant's name or \"\" if unknown.";
635 code_ += " pub fn variant_name(self) -> Option<&'static str> {";
636 code_ += " match self {";
637 ForAllEnumValues(enum_def, [&](){
638 code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),";
639 });
640 code_ += " _ => None,";
641 code_ += " }";
642 code_ += " }";
643 code_ += "}";
644
645 // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>".
646 code_ += "impl std::fmt::Debug for {{ENUM_NAME}} {";
647 code_ += " fn fmt(&self, f: &mut std::fmt::Formatter) ->"
648 " std::fmt::Result {";
649 code_ += " if let Some(name) = self.variant_name() {";
650 code_ += " f.write_str(name)";
651 code_ += " } else {";
652 code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))";
653 code_ += " }";
654 code_ += " }";
655 code_ += "}";
656
657 // Generate Follow and Push so we can serialize and stuff.
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700658 code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
659 code_ += " type Inner = Self;";
660 code_ += " #[inline]";
661 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
Austin Schuh272c6132020-11-14 16:37:52 -0800662 code_ += " Self(flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc))";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700663 code_ += " }";
664 code_ += "}";
665 code_ += "";
666 code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
667 code_ += " type Output = {{ENUM_NAME}};";
668 code_ += " #[inline]";
669 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
Austin Schuh272c6132020-11-14 16:37:52 -0800670 code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
671 "(dst, self.0);";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700672 code_ += " }";
673 code_ += "}";
674 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -0800675 code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
676 code_ += " #[inline]";
677 code_ += " fn to_little_endian(self) -> Self {";
678 code_ += " Self({{BASE_TYPE}}::to_le(self.0))";
679 code_ += " }";
680 code_ += " #[inline]";
681 code_ += " fn from_little_endian(self) -> Self {";
682 code_ += " Self({{BASE_TYPE}}::from_le(self.0))";
683 code_ += " }";
684 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700685 code_ += "";
686
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700687 if (enum_def.is_union) {
688 // Generate tyoesafe offset(s) for unions
689 code_.SetValue("NAME", Name(enum_def));
690 code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
691 code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
692 }
693 }
694
695 std::string GetFieldOffsetName(const FieldDef &field) {
696 return "VT_" + MakeUpper(Name(field));
697 }
698
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700699 std::string GetDefaultScalarValue(const FieldDef &field) {
700 switch (GetFullType(field.value.type)) {
Austin Schuh272c6132020-11-14 16:37:52 -0800701 case ftInteger:
702 case ftFloat: {
703 return field.optional ? "None" : field.value.constant;
704 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700705 case ftBool: {
Austin Schuh272c6132020-11-14 16:37:52 -0800706 return field.optional ? "None"
707 : field.value.constant == "0" ? "false" : "true";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700708 }
709 case ftUnionKey:
710 case ftEnumKey: {
Austin Schuh272c6132020-11-14 16:37:52 -0800711 if (field.optional) {
712 return "None";
713 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700714 auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
715 assert(ev);
716 return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
Austin Schuh272c6132020-11-14 16:37:52 -0800717 GetEnumValue(*field.value.type.enum_def, *ev));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700718 }
719
720 // All pointer-ish types have a default value of None, because they are
721 // wrapped in Option.
Austin Schuh272c6132020-11-14 16:37:52 -0800722 default: {
723 return "None";
724 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700725 }
726 }
727
728 // Create the return type for fields in the *BuilderArgs structs that are
729 // used to create Tables.
730 //
731 // Note: we could make all inputs to the BuilderArgs be an Option, as well
732 // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
733 // know if the value is default or not, because there are three ways to
734 // return a default value:
735 // 1) return a stored value that happens to be the default,
736 // 2) return a hardcoded value because the relevant vtable field is not in
737 // the vtable, or
738 // 3) return a hardcoded value because the vtable field value is set to zero.
739 std::string TableBuilderArgsDefnType(const FieldDef &field,
740 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -0800741 const Type &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700742
743 switch (GetFullType(type)) {
744 case ftInteger:
745 case ftFloat:
746 case ftBool: {
747 const auto typname = GetTypeBasic(type);
Austin Schuh272c6132020-11-14 16:37:52 -0800748 return field.optional ? "Option<" + typname + ">" : typname;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700749 }
750 case ftStruct: {
751 const auto typname = WrapInNameSpace(*type.struct_def);
752 return "Option<&" + lifetime + " " + typname + ">";
753 }
754 case ftTable: {
755 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800756 return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700757 ">>>";
758 }
759 case ftString: {
760 return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
761 }
762 case ftEnumKey:
763 case ftUnionKey: {
764 const auto typname = WrapInNameSpace(*type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800765 return field.optional ? "Option<" + typname + ">" : typname;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700766 }
767 case ftUnionValue: {
768 return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
769 }
770
771 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -0800772 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700773 case ftVectorOfFloat: {
774 const auto typname = GetTypeBasic(type.VectorType());
Austin Schuh272c6132020-11-14 16:37:52 -0800775 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
776 ", " + typname + ">>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700777 }
778 case ftVectorOfEnumKey: {
779 const auto typname = WrapInNameSpace(*type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800780 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
781 ", " + typname + ">>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700782 }
783 case ftVectorOfStruct: {
784 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800785 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
786 ", " + typname + ">>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700787 }
788 case ftVectorOfTable: {
789 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800790 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
791 ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
792 ">>>>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700793 }
794 case ftVectorOfString: {
Austin Schuh272c6132020-11-14 16:37:52 -0800795 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
796 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700797 }
798 case ftVectorOfUnionValue: {
Austin Schuh272c6132020-11-14 16:37:52 -0800799 const auto typname =
800 WrapInNameSpace(*type.enum_def) + "UnionTableOffset";
801 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
802 ", flatbuffers::ForwardsUOffset<"
803 "flatbuffers::Table<" +
804 lifetime + ">>>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700805 }
806 }
Austin Schuh272c6132020-11-14 16:37:52 -0800807 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700808 }
809
810 std::string TableBuilderArgsAddFuncType(const FieldDef &field,
811 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -0800812 const Type &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700813
814 switch (GetFullType(field.value.type)) {
815 case ftVectorOfStruct: {
816 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800817 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
818 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700819 }
820 case ftVectorOfTable: {
821 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800822 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
823 ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
824 ">>>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700825 }
826 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -0800827 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700828 case ftVectorOfFloat: {
829 const auto typname = GetTypeBasic(type.VectorType());
Austin Schuh272c6132020-11-14 16:37:52 -0800830 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
831 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700832 }
833 case ftVectorOfString: {
Austin Schuh272c6132020-11-14 16:37:52 -0800834 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700835 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
836 }
837 case ftVectorOfEnumKey: {
838 const auto typname = WrapInNameSpace(*type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800839 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " +
840 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700841 }
842 case ftVectorOfUnionValue: {
Austin Schuh272c6132020-11-14 16:37:52 -0800843 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
844 ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + lifetime +
845 ">>>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700846 }
847 case ftEnumKey: {
848 const auto typname = WrapInNameSpace(*type.enum_def);
849 return typname;
850 }
851 case ftStruct: {
852 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800853 return "&" + typname + "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700854 }
855 case ftTable: {
856 const auto typname = WrapInNameSpace(*type.struct_def);
857 return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
858 }
859 case ftInteger:
Austin Schuh272c6132020-11-14 16:37:52 -0800860 case ftBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700861 case ftFloat: {
Austin Schuh272c6132020-11-14 16:37:52 -0800862 return GetTypeBasic(type);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700863 }
864 case ftString: {
865 return "flatbuffers::WIPOffset<&" + lifetime + " str>";
866 }
867 case ftUnionKey: {
868 const auto typname = WrapInNameSpace(*type.enum_def);
869 return typname;
870 }
871 case ftUnionValue: {
872 return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
873 }
874 }
875
Austin Schuh272c6132020-11-14 16:37:52 -0800876 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700877 }
878
879 std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
Austin Schuh272c6132020-11-14 16:37:52 -0800880 const Type &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700881
882 switch (GetFullType(field.value.type)) {
883 case ftInteger:
Austin Schuh272c6132020-11-14 16:37:52 -0800884 case ftBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700885 case ftFloat: {
886 const auto typname = GetTypeBasic(field.value.type);
Austin Schuh272c6132020-11-14 16:37:52 -0800887 return (field.optional ? "self.fbb_.push_slot_always::<"
888 : "self.fbb_.push_slot::<") +
889 typname + ">";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700890 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700891 case ftEnumKey:
892 case ftUnionKey: {
893 const auto underlying_typname = GetTypeBasic(type);
Austin Schuh272c6132020-11-14 16:37:52 -0800894 return (field.optional ?
895 "self.fbb_.push_slot_always::<" :
896 "self.fbb_.push_slot::<") + underlying_typname + ">";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700897 }
898
899 case ftStruct: {
900 const std::string typname = WrapInNameSpace(*type.struct_def);
901 return "self.fbb_.push_slot_always::<&" + typname + ">";
902 }
903 case ftTable: {
904 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800905 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" +
906 typname + ">>";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700907 }
908
909 case ftUnionValue:
910 case ftString:
911 case ftVectorOfInteger:
912 case ftVectorOfFloat:
913 case ftVectorOfBool:
914 case ftVectorOfEnumKey:
915 case ftVectorOfStruct:
916 case ftVectorOfTable:
917 case ftVectorOfString:
918 case ftVectorOfUnionValue: {
919 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
920 }
921 }
Austin Schuh272c6132020-11-14 16:37:52 -0800922 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700923 }
924
925 std::string GenTableAccessorFuncReturnType(const FieldDef &field,
926 const std::string &lifetime) {
Austin Schuh272c6132020-11-14 16:37:52 -0800927 const Type &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700928
929 switch (GetFullType(field.value.type)) {
930 case ftInteger:
931 case ftFloat:
932 case ftBool: {
933 const auto typname = GetTypeBasic(type);
Austin Schuh272c6132020-11-14 16:37:52 -0800934 return field.optional ? "Option<" + typname + ">" : typname;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700935 }
936 case ftStruct: {
937 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800938 return WrapInOptionIfNotRequired("&" + lifetime + " " + typname,
939 field.required);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700940 }
941 case ftTable: {
942 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800943 return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">",
944 field.required);
945 }
946 case ftEnumKey:
947 case ftUnionKey: {
948 const auto typname = WrapInNameSpace(*type.enum_def);
949 return field.optional ? "Option<" + typname + ">" : typname;
950 }
951
952 case ftUnionValue: {
953 return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">",
954 field.required);
955 }
956 case ftString: {
957 return WrapInOptionIfNotRequired("&" + lifetime + " str",
958 field.required);
959 }
960 case ftVectorOfInteger:
961 case ftVectorOfBool:
962 case ftVectorOfFloat: {
963 const auto typname = GetTypeBasic(type.VectorType());
964 if (IsOneByte(type.VectorType().base_type)) {
965 return WrapInOptionIfNotRequired(
966 "&" + lifetime + " [" + typname + "]", field.required);
967 }
968 return WrapInOptionIfNotRequired(
969 "flatbuffers::Vector<" + lifetime + ", " + typname + ">",
970 field.required);
971 }
972 case ftVectorOfEnumKey: {
973 const auto typname = WrapInNameSpace(*type.enum_def);
974 return WrapInOptionIfNotRequired(
975 "flatbuffers::Vector<" + lifetime + ", " + typname + ">",
976 field.required);
977 }
978 case ftVectorOfStruct: {
979 const auto typname = WrapInNameSpace(*type.struct_def);
980 return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]",
981 field.required);
982 }
983 case ftVectorOfTable: {
984 const auto typname = WrapInNameSpace(*type.struct_def);
985 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime +
986 ", flatbuffers::ForwardsUOffset<" +
987 typname + "<" + lifetime + ">>>",
988 field.required);
989 }
990 case ftVectorOfString: {
991 return WrapInOptionIfNotRequired(
992 "flatbuffers::Vector<" + lifetime +
993 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>",
994 field.required);
995 }
996 case ftVectorOfUnionValue: {
997 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
998 // TODO(rw): when we do support these, we should consider using the
999 // Into trait to convert tables to typesafe union values.
1000 return "INVALID_CODE_GENERATION"; // for return analysis
1001 }
1002 }
1003 return "INVALID_CODE_GENERATION"; // for return analysis
1004 }
1005
1006 std::string GenTableAccessorFuncBody(const FieldDef &field,
1007 const std::string &lifetime,
1008 const std::string &offset_prefix) {
1009 const std::string offset_name =
1010 offset_prefix + "::" + GetFieldOffsetName(field);
1011 const Type &type = field.value.type;
1012
1013 switch (GetFullType(field.value.type)) {
1014 case ftInteger:
1015 case ftFloat:
1016 case ftBool: {
1017 const auto typname = GetTypeBasic(type);
1018 if (field.optional) {
1019 return "self._tab.get::<" + typname + ">(" + offset_name + ", None)";
1020 } else {
1021 const auto default_value = GetDefaultScalarValue(field);
1022 return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" +
1023 default_value + ")).unwrap()";
1024 }
1025 }
1026 case ftStruct: {
1027 const auto typname = WrapInNameSpace(*type.struct_def);
1028 return AddUnwrapIfRequired(
1029 "self._tab.get::<" + typname + ">(" + offset_name + ", None)",
1030 field.required);
1031 }
1032 case ftTable: {
1033 const auto typname = WrapInNameSpace(*type.struct_def);
1034 return AddUnwrapIfRequired(
1035 "self._tab.get::<flatbuffers::ForwardsUOffset<" + typname + "<" +
1036 lifetime + ">>>(" + offset_name + ", None)",
1037 field.required);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001038 }
1039 case ftUnionValue: {
Austin Schuh272c6132020-11-14 16:37:52 -08001040 return AddUnwrapIfRequired(
1041 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1042 "flatbuffers::Table<" +
1043 lifetime + ">>>(" + offset_name + ", None)",
1044 field.required);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001045 }
1046 case ftUnionKey:
1047 case ftEnumKey: {
Austin Schuh272c6132020-11-14 16:37:52 -08001048 const std::string typname = WrapInNameSpace(*type.enum_def);
1049 const std::string default_value = GetDefaultScalarValue(field);
1050 if (field.optional) {
1051 return "self._tab.get::<" + typname + ">(" + offset_name + ", None)";
1052 } else {
1053 return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" +
1054 default_value + ")).unwrap()";
1055 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001056 }
1057 case ftString: {
Austin Schuh272c6132020-11-14 16:37:52 -08001058 return AddUnwrapIfRequired(
1059 "self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" +
1060 offset_name + ", None)",
1061 field.required);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001062 }
1063
1064 case ftVectorOfInteger:
Austin Schuh272c6132020-11-14 16:37:52 -08001065 case ftVectorOfBool:
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001066 case ftVectorOfFloat: {
1067 const auto typname = GetTypeBasic(type.VectorType());
Austin Schuh272c6132020-11-14 16:37:52 -08001068 std::string s =
1069 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1070 "flatbuffers::Vector<" +
1071 lifetime + ", " + typname + ">>>(" + offset_name + ", None)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001072 // single-byte values are safe to slice
1073 if (IsOneByte(type.VectorType().base_type)) {
1074 s += ".map(|v| v.safe_slice())";
1075 }
1076 return AddUnwrapIfRequired(s, field.required);
1077 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001078 case ftVectorOfEnumKey: {
1079 const auto typname = WrapInNameSpace(*type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001080 return AddUnwrapIfRequired(
1081 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1082 "flatbuffers::Vector<" +
1083 lifetime + ", " + typname + ">>>(" + offset_name + ", None)",
1084 field.required);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001085 }
1086 case ftVectorOfStruct: {
1087 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001088 return AddUnwrapIfRequired(
1089 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1090 "flatbuffers::Vector<" +
1091 typname + ">>>(" + offset_name +
1092 ", None).map(|v| v.safe_slice() )",
1093 field.required);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001094 }
1095 case ftVectorOfTable: {
1096 const auto typname = WrapInNameSpace(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001097 return AddUnwrapIfRequired(
1098 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1099 "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" +
1100 typname + "<" + lifetime + ">>>>>(" + offset_name + ", None)",
1101 field.required);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001102 }
1103 case ftVectorOfString: {
Austin Schuh272c6132020-11-14 16:37:52 -08001104 return AddUnwrapIfRequired(
1105 "self._tab.get::<flatbuffers::ForwardsUOffset<"
1106 "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" +
1107 lifetime + " str>>>>(" + offset_name + ", None)",
1108 field.required);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001109 }
1110 case ftVectorOfUnionValue: {
1111 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
Austin Schuh272c6132020-11-14 16:37:52 -08001112 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001113 }
1114 }
Austin Schuh272c6132020-11-14 16:37:52 -08001115 return "INVALID_CODE_GENERATION"; // for return analysis
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001116 }
1117
Austin Schuh272c6132020-11-14 16:37:52 -08001118 bool TableFieldReturnsOption(const FieldDef &field) {
1119 if (field.optional) return true;
1120 switch (GetFullType(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001121 case ftInteger:
1122 case ftFloat:
1123 case ftBool:
1124 case ftEnumKey:
Austin Schuh272c6132020-11-14 16:37:52 -08001125 case ftUnionKey: return false;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001126 default: return true;
1127 }
1128 }
1129
Austin Schuh272c6132020-11-14 16:37:52 -08001130 // Generates a fully-qualified name getter for use with --gen-name-strings
1131 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1132 const std::string &name) {
1133 code_ += " pub const fn get_fully_qualified_name() -> &'static str {";
1134 code_ += " \"" +
1135 struct_def.defined_namespace->GetFullyQualifiedName(name) + "\"";
1136 code_ += " }";
1137 code_ += "";
1138 }
1139
1140 void ForAllUnionVariantsBesidesNone(
1141 const EnumDef &def,
1142 std::function<void(const EnumVal &ev)> cb
1143 ) {
1144 FLATBUFFERS_ASSERT(def.is_union);
1145
1146 for (auto it = def.Vals().begin(); it != def.Vals().end(); ++it) {
1147 const EnumVal & ev = **it;
1148 // TODO(cneo): Can variants be deprecated, should we skip them?
1149 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1150 code_.SetValue(
1151 "U_ELEMENT_ENUM_TYPE",
1152 WrapInNameSpace(def.defined_namespace, GetEnumValue(def, ev)));
1153 code_.SetValue("U_ELEMENT_TABLE_TYPE",
1154 WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
1155 ev.union_type.struct_def->name));
1156 code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
1157 cb(ev);
1158 }
1159 }
1160
1161 void ForAllTableFields(
1162 const StructDef &struct_def,
1163 std::function<void(const FieldDef&)> cb, bool reversed=false) {
1164 // TODO(cneo): Remove `reversed` overload. It's only here to minimize the
1165 // diff when refactoring to the `ForAllX` helper functions.
1166 auto go = [&](const FieldDef& field) {
1167 if (field.deprecated) return;
1168 code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1169 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
1170 code_.SetValue("FIELD_NAME", Name(field));
1171 code_.SetValue("DEFAULT_VALUE", GetDefaultScalarValue(field));
1172 cb(field);
1173 };
1174 const auto &fields = struct_def.fields.vec;
1175 if (reversed) {
1176 for (auto it = fields.rbegin(); it != fields.rend(); ++it) go(**it);
1177 } else {
1178 for (auto it = fields.begin(); it != fields.end(); ++it) go(**it);
1179 }
1180 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001181 // Generate an accessor struct, builder struct, and create function for a
1182 // table.
1183 void GenTable(const StructDef &struct_def) {
1184 code_.SetValue("STRUCT_NAME", Name(struct_def));
1185 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1186 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
1187
1188 // Generate an offset type, the base type, the Follow impl, and the
1189 // init_from_table impl.
1190 code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
Austin Schuh272c6132020-11-14 16:37:52 -08001191 code_ += "#[derive(Copy, Clone, PartialEq)]";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001192 code_ += "";
1193
1194 GenComment(struct_def.doc_comment);
1195
1196 code_ += "pub struct {{STRUCT_NAME}}<'a> {";
1197 code_ += " pub _tab: flatbuffers::Table<'a>,";
1198 code_ += "}";
1199 code_ += "";
1200 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
1201 code_ += " type Inner = {{STRUCT_NAME}}<'a>;";
1202 code_ += " #[inline]";
1203 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
Austin Schuh272c6132020-11-14 16:37:52 -08001204 code_ += " Self { _tab: flatbuffers::Table { buf, loc } }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001205 code_ += " }";
1206 code_ += "}";
1207 code_ += "";
1208 code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
Austin Schuh272c6132020-11-14 16:37:52 -08001209
1210 if (parser_.opts.generate_name_strings) {
1211 GenFullyQualifiedNameGetter(struct_def, struct_def.name);
1212 }
1213
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001214 code_ += " #[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08001215 code_ +=
1216 " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
1217 "Self {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001218 code_ += " {{STRUCT_NAME}} {";
1219 code_ += " _tab: table,";
1220 code_ += " }";
1221 code_ += " }";
1222
1223 // Generate a convenient create* function that uses the above builder
1224 // to create a table in one function call.
Austin Schuh272c6132020-11-14 16:37:52 -08001225 code_.SetValue("MAYBE_US", struct_def.fields.vec.size() == 0 ? "_" : "");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001226 code_.SetValue("MAYBE_LT",
Austin Schuh272c6132020-11-14 16:37:52 -08001227 TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001228 code_ += " #[allow(unused_mut)]";
1229 code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
Austin Schuh272c6132020-11-14 16:37:52 -08001230 code_ +=
1231 " _fbb: "
1232 "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1233 code_ +=
1234 " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
1235 " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001236
1237 code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
1238 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1239 size; size /= 2) {
Austin Schuh272c6132020-11-14 16:37:52 -08001240 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1241 if (struct_def.sortbysize && size != SizeOf(field.value.type.base_type))
1242 return;
1243 if (TableFieldReturnsOption(field)) {
1244 code_ +=
1245 " if let Some(x) = args.{{FIELD_NAME}} "
1246 "{ builder.add_{{FIELD_NAME}}(x); }";
1247 } else {
1248 code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001249 }
Austin Schuh272c6132020-11-14 16:37:52 -08001250 }, /*reverse=*/true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001251 }
1252 code_ += " builder.finish()";
1253 code_ += " }";
1254 code_ += "";
1255
1256 // Generate field id constants.
Austin Schuh272c6132020-11-14 16:37:52 -08001257 ForAllTableFields(struct_def, [&](const FieldDef &unused){
1258 (void) unused;
1259 code_ += " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1260 "{{OFFSET_VALUE}};";
1261 });
1262 if (struct_def.fields.vec.size() > 0) code_ += "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001263
1264 // Generate the accessors. Each has one of two forms:
1265 //
1266 // If a value can be None:
1267 // pub fn name(&'a self) -> Option<user_facing_type> {
1268 // self._tab.get::<internal_type>(offset, defaultval)
1269 // }
1270 //
1271 // If a value is always Some:
1272 // pub fn name(&'a self) -> user_facing_type {
1273 // self._tab.get::<internal_type>(offset, defaultval).unwrap()
1274 // }
1275 const auto offset_prefix = Name(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001276 ForAllTableFields(struct_def, [&](const FieldDef &field) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001277 code_.SetValue("RETURN_TYPE",
1278 GenTableAccessorFuncReturnType(field, "'a"));
1279 code_.SetValue("FUNC_BODY",
1280 GenTableAccessorFuncBody(field, "'a", offset_prefix));
1281
Austin Schuh272c6132020-11-14 16:37:52 -08001282 this->GenComment(field.doc_comment, " ");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001283 code_ += " #[inline]";
1284 code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
1285 code_ += " {{FUNC_BODY}}";
1286 code_ += " }";
1287
1288 // Generate a comparison function for this field if it is a key.
Austin Schuh272c6132020-11-14 16:37:52 -08001289 if (field.key) { GenKeyFieldMethods(field); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001290
1291 // Generate a nested flatbuffer field, if applicable.
1292 auto nested = field.attributes.Lookup("nested_flatbuffer");
1293 if (nested) {
1294 std::string qualified_name = nested->constant;
1295 auto nested_root = parser_.LookupStruct(nested->constant);
1296 if (nested_root == nullptr) {
1297 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1298 nested->constant);
1299 nested_root = parser_.LookupStruct(qualified_name);
1300 }
1301 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001302
Austin Schuh272c6132020-11-14 16:37:52 -08001303 code_.SetValue("NESTED", WrapInNameSpace(*nested_root));
1304 code_ +=
1305 " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> \\";
1306 if (field.required) {
1307 code_ += "{{NESTED}}<'a> {";
1308 code_ += " let data = self.{{FIELD_NAME}}();";
1309 code_ += " use flatbuffers::Follow;";
1310 code_ += " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1311 "::follow(data, 0)";
1312 } else {
1313 code_ += "Option<{{NESTED}}<'a>> {";
1314 code_ += " self.{{FIELD_NAME}}().map(|data| {";
1315 code_ += " use flatbuffers::Follow;";
1316 code_ += " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>"
1317 "::follow(data, 0)";
1318 code_ += " })";
1319 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001320 code_ += " }";
1321 }
Austin Schuh272c6132020-11-14 16:37:52 -08001322 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001323
1324 // Explicit specializations for union accessors
Austin Schuh272c6132020-11-14 16:37:52 -08001325 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1326 if (field.value.type.base_type != BASE_TYPE_UNION) return;
1327 code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
1328 ForAllUnionVariantsBesidesNone(
1329 *field.value.type.enum_def, [&](const EnumVal &unused){
1330 (void) unused;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001331 code_ += " #[inline]";
1332 code_ += " #[allow(non_snake_case)]";
Austin Schuh272c6132020-11-14 16:37:52 -08001333 code_ +=
1334 " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
1335 "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
1336 // If the user defined schemas name a field that clashes with a
1337 // language reserved word, flatc will try to escape the field name by
1338 // appending an underscore. This works well for most cases, except
1339 // one. When generating union accessors (and referring to them
1340 // internally within the code generated here), an extra underscore
1341 // will be appended to the name, causing build failures.
1342 //
1343 // This only happens when unions have members that overlap with
1344 // language reserved words.
1345 //
1346 // To avoid this problem the type field name is used unescaped here:
1347 code_ +=
1348 " if self.{{FIELD_TYPE_FIELD_NAME}}_type() == "
1349 "{{U_ELEMENT_ENUM_TYPE}} {";
1350
1351 // The following logic is not tested in the integration test,
1352 // as of April 10, 2020
1353 if (field.required) {
1354 code_ += " let u = self.{{FIELD_NAME}}();";
1355 code_ += " Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
1356 } else {
1357 code_ +=
1358 " self.{{FIELD_NAME}}().map("
1359 "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)";
1360 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001361 code_ += " } else {";
1362 code_ += " None";
1363 code_ += " }";
1364 code_ += " }";
1365 code_ += "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001366
Austin Schuh272c6132020-11-14 16:37:52 -08001367 });
1368 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001369 code_ += "}"; // End of table impl.
1370 code_ += "";
1371
1372 // Generate an args struct:
1373 code_.SetValue("MAYBE_LT",
Austin Schuh272c6132020-11-14 16:37:52 -08001374 TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001375 code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08001376 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1377 code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
1378 code_ += " pub {{FIELD_NAME}}: {{PARAM_TYPE}},";
1379 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001380 code_ += "}";
1381
1382 // Generate an impl of Default for the *Args type:
1383 code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1384 code_ += " #[inline]";
1385 code_ += " fn default() -> Self {";
1386 code_ += " {{STRUCT_NAME}}Args {";
Austin Schuh272c6132020-11-14 16:37:52 -08001387 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1388 code_ += " {{FIELD_NAME}}: {{DEFAULT_VALUE}},\\";
1389 code_ += field.required ? " // required field" : "";
1390 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001391 code_ += " }";
1392 code_ += " }";
1393 code_ += "}";
1394
1395 // Generate a builder struct:
1396 code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
1397 code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
Austin Schuh272c6132020-11-14 16:37:52 -08001398 code_ +=
1399 " start_: flatbuffers::WIPOffset<"
1400 "flatbuffers::TableUnfinishedWIPOffset>,";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001401 code_ += "}";
1402
1403 // Generate builder functions:
1404 code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
Austin Schuh272c6132020-11-14 16:37:52 -08001405 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1406 const bool is_scalar = IsScalar(field.value.type.base_type);
1407 std::string offset = GetFieldOffsetName(field);
1408 // Generate functions to add data, which take one of two forms.
1409 //
1410 // If a value has a default:
1411 // fn add_x(x_: type) {
1412 // fbb_.push_slot::<type>(offset, x_, Some(default));
1413 // }
1414 //
1415 // If a value does not have a default:
1416 // fn add_x(x_: type) {
1417 // fbb_.push_slot_always::<type>(offset, x_);
1418 // }
1419 code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
1420 code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
1421 code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
1422 code_ += " #[inline]";
1423 code_ += " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
1424 "{{FIELD_TYPE}}) {";
1425 if (is_scalar && !field.optional) {
1426 code_ +=
1427 " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
1428 "{{DEFAULT_VALUE}});";
1429 } else {
1430 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001431 }
Austin Schuh272c6132020-11-14 16:37:52 -08001432 code_ += " }";
1433 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001434
1435 // Struct initializer (all fields required);
1436 code_ += " #[inline]";
1437 code_ +=
1438 " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
1439 "{{STRUCT_NAME}}Builder<'a, 'b> {";
1440 code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
1441 code_ += " let start = _fbb.start_table();";
1442 code_ += " {{STRUCT_NAME}}Builder {";
1443 code_ += " fbb_: _fbb,";
1444 code_ += " start_: start,";
1445 code_ += " }";
1446 code_ += " }";
1447
1448 // finish() function.
1449 code_ += " #[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08001450 code_ +=
1451 " pub fn finish(self) -> "
1452 "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001453 code_ += " let o = self.fbb_.end_table(self.start_);";
1454
Austin Schuh272c6132020-11-14 16:37:52 -08001455 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1456 if (!field.required) return;
1457 code_ +=
1458 " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
1459 "\"{{FIELD_NAME}}\");";
1460 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001461 code_ += " flatbuffers::WIPOffset::new(o.value())";
1462 code_ += " }";
1463 code_ += "}";
1464 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08001465
1466 code_ += "impl std::fmt::Debug for {{STRUCT_NAME}}<'_> {";
1467 code_ += " fn fmt(&self, f: &mut std::fmt::Formatter<'_>"
1468 ") -> std::fmt::Result {";
1469 code_ += " let mut ds = f.debug_struct(\"{{STRUCT_NAME}}\");";
1470 ForAllTableFields(struct_def, [&](const FieldDef &field) {
1471 if (GetFullType(field.value.type) == ftUnionValue) {
1472 // Generate a match statement to handle unions properly.
1473 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
1474 code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
1475 code_.SetValue("UNION_ERR", "&\"InvalidFlatbuffer: Union discriminant"
1476 " does not match value.\"");
1477
1478 code_ += " match self.{{FIELD_NAME}}_type() {";
1479 ForAllUnionVariantsBesidesNone(*field.value.type.enum_def,
1480 [&](const EnumVal &unused){
1481 (void) unused;
1482 code_ += " {{U_ELEMENT_ENUM_TYPE}} => {";
1483 code_ += " if let Some(x) = self.{{FIELD_TYPE_FIELD_NAME}}_as_"
1484 "{{U_ELEMENT_NAME}}() {";
1485 code_ += " ds.field(\"{{FIELD_NAME}}\", &x)";
1486 code_ += " } else {";
1487 code_ += " ds.field(\"{{FIELD_NAME}}\", {{UNION_ERR}})";
1488 code_ += " }";
1489 code_ += " },";
1490 });
1491 code_ += " _ => { ";
1492 code_ += " let x: Option<()> = None;";
1493 code_ += " ds.field(\"{{FIELD_NAME}}\", &x)";
1494 code_ += " },";
1495 code_ += " };";
1496 } else {
1497 // Most fields.
1498 code_ += " ds.field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}());";
1499 }
1500 });
1501 code_ += " ds.finish()";
1502 code_ += " }";
1503 code_ += "}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001504 }
1505
1506 // Generate functions to compare tables and structs by key. This function
1507 // must only be called if the field key is defined.
1508 void GenKeyFieldMethods(const FieldDef &field) {
1509 FLATBUFFERS_ASSERT(field.key);
1510
1511 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
1512
1513 code_ += " #[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08001514 code_ +=
1515 " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
1516 " bool {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001517 code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
1518 code_ += " }";
1519 code_ += "";
1520 code_ += " #[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08001521 code_ +=
1522 " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
1523 " ::std::cmp::Ordering {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001524 code_ += " let key = self.{{FIELD_NAME}}();";
1525 code_ += " key.cmp(&val)";
1526 code_ += " }";
1527 }
1528
1529 // Generate functions for accessing the root table object. This function
1530 // must only be called if the root table is defined.
1531 void GenRootTableFuncs(const StructDef &struct_def) {
1532 FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
1533 auto name = Name(struct_def);
1534
1535 code_.SetValue("STRUCT_NAME", name);
1536 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
1537 code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
1538
1539 // The root datatype accessors:
1540 code_ += "#[inline]";
1541 code_ +=
1542 "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
1543 " -> {{STRUCT_NAME}}<'a> {";
1544 code_ += " flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)";
1545 code_ += "}";
1546 code_ += "";
1547
1548 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08001549 code_ +=
1550 "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
1551 "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
1552 code_ +=
1553 " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
1554 "(buf)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001555 code_ += "}";
1556 code_ += "";
1557
1558 if (parser_.file_identifier_.length()) {
1559 // Declare the identifier
Austin Schuh272c6132020-11-14 16:37:52 -08001560 // (no lifetime needed as constants have static lifetimes by default)
1561 code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &str\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001562 code_ += " = \"" + parser_.file_identifier_ + "\";";
1563 code_ += "";
1564
1565 // Check if a buffer has the identifier.
1566 code_ += "#[inline]";
1567 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
1568 code_ += "(buf: &[u8]) -> bool {";
Austin Schuh272c6132020-11-14 16:37:52 -08001569 code_ += " flatbuffers::buffer_has_identifier(buf, \\";
1570 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001571 code_ += "}";
1572 code_ += "";
1573 code_ += "#[inline]";
1574 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
1575 code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
Austin Schuh272c6132020-11-14 16:37:52 -08001576 code_ += " flatbuffers::buffer_has_identifier(buf, \\";
1577 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001578 code_ += "}";
1579 code_ += "";
1580 }
1581
1582 if (parser_.file_extension_.length()) {
1583 // Return the extension
Austin Schuh272c6132020-11-14 16:37:52 -08001584 code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &str = \\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001585 code_ += "\"" + parser_.file_extension_ + "\";";
1586 code_ += "";
1587 }
1588
1589 // Finish a buffer with a given root object:
1590 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1591 code_ += "#[inline]";
1592 code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
1593 code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1594 code_ += " root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1595 if (parser_.file_identifier_.length()) {
1596 code_ += " fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1597 } else {
1598 code_ += " fbb.finish(root, None);";
1599 }
1600 code_ += "}";
1601 code_ += "";
1602 code_ += "#[inline]";
Austin Schuh272c6132020-11-14 16:37:52 -08001603 code_ +=
1604 "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
1605 "<'a, 'b>("
1606 "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
1607 "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001608 if (parser_.file_identifier_.length()) {
Austin Schuh272c6132020-11-14 16:37:52 -08001609 code_ +=
1610 " fbb.finish_size_prefixed(root, "
1611 "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001612 } else {
1613 code_ += " fbb.finish_size_prefixed(root, None);";
1614 }
1615 code_ += "}";
1616 }
1617
1618 static void GenPadding(
1619 const FieldDef &field, std::string *code_ptr, int *id,
1620 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
1621 if (field.padding) {
1622 for (int i = 0; i < 4; i++) {
1623 if (static_cast<int>(field.padding) & (1 << i)) {
1624 f((1 << i) * 8, code_ptr, id);
1625 }
1626 }
1627 assert(!(field.padding & ~0xF));
1628 }
1629 }
1630
1631 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
Austin Schuh272c6132020-11-14 16:37:52 -08001632 *code_ptr +=
1633 " padding" + NumToString((*id)++) + "__: u" + NumToString(bits) + ",";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001634 }
1635
1636 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
1637 (void)bits;
1638 *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
1639 }
1640
Austin Schuh272c6132020-11-14 16:37:52 -08001641 void ForAllStructFields(
1642 const StructDef &struct_def,
1643 std::function<void(const FieldDef &field)> cb
1644 ) {
1645 for (auto it = struct_def.fields.vec.begin();
1646 it != struct_def.fields.vec.end(); ++it) {
1647 const auto &field = **it;
1648 code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
1649 code_.SetValue("FIELD_NAME", Name(field));
1650 cb(field);
1651 }
1652 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001653 // Generate an accessor struct with constructor for a flatbuffers struct.
1654 void GenStruct(const StructDef &struct_def) {
1655 // Generates manual padding and alignment.
1656 // Variables are private because they contain little endian data on all
1657 // platforms.
1658 GenComment(struct_def.doc_comment);
1659 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
1660 code_.SetValue("STRUCT_NAME", Name(struct_def));
1661
1662 code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
1663 code_ += "#[repr(C, align({{ALIGN}}))]";
1664
1665 // PartialEq is useful to derive because we can correctly compare structs
1666 // for equality by just comparing their underlying byte data. This doesn't
1667 // hold for PartialOrd/Ord.
Austin Schuh272c6132020-11-14 16:37:52 -08001668 code_ += "#[derive(Clone, Copy, PartialEq)]";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001669 code_ += "pub struct {{STRUCT_NAME}} {";
1670
1671 int padding_id = 0;
Austin Schuh272c6132020-11-14 16:37:52 -08001672 ForAllStructFields(struct_def, [&](const FieldDef &field) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001673 code_ += " {{FIELD_NAME}}_: {{FIELD_TYPE}},";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001674 if (field.padding) {
1675 std::string padding;
1676 GenPadding(field, &padding, &padding_id, PaddingDefinition);
1677 code_ += padding;
1678 }
Austin Schuh272c6132020-11-14 16:37:52 -08001679 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001680 code_ += "} // pub struct {{STRUCT_NAME}}";
1681
Austin Schuh272c6132020-11-14 16:37:52 -08001682 // Debug for structs.
1683 code_ += "impl std::fmt::Debug for {{STRUCT_NAME}} {";
1684 code_ += " fn fmt(&self, f: &mut std::fmt::Formatter"
1685 ") -> std::fmt::Result {";
1686 code_ += " f.debug_struct(\"{{STRUCT_NAME}}\")";
1687 ForAllStructFields(struct_def, [&](const FieldDef &unused) {
1688 (void) unused;
1689 code_ += " .field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}())";
1690 });
1691 code_ += " .finish()";
1692 code_ += " }";
1693 code_ += "}";
1694 code_ += "";
1695
1696
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001697 // Generate impls for SafeSliceAccess (because all structs are endian-safe),
1698 // Follow for the value type, Follow for the reference type, Push for the
1699 // value type, and Push for the reference type.
1700 code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
1701 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
1702 code_ += " type Inner = &'a {{STRUCT_NAME}};";
1703 code_ += " #[inline]";
1704 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1705 code_ += " <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
1706 code_ += " }";
1707 code_ += "}";
1708 code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
1709 code_ += " type Inner = &'a {{STRUCT_NAME}};";
1710 code_ += " #[inline]";
1711 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1712 code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
1713 code_ += " }";
1714 code_ += "}";
1715 code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
1716 code_ += " type Output = {{STRUCT_NAME}};";
1717 code_ += " #[inline]";
1718 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1719 code_ += " let src = unsafe {";
Austin Schuh272c6132020-11-14 16:37:52 -08001720 code_ +=
1721 " ::std::slice::from_raw_parts("
1722 "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001723 code_ += " };";
1724 code_ += " dst.copy_from_slice(src);";
1725 code_ += " }";
1726 code_ += "}";
1727 code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
1728 code_ += " type Output = {{STRUCT_NAME}};";
1729 code_ += "";
1730 code_ += " #[inline]";
1731 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1732 code_ += " let src = unsafe {";
Austin Schuh272c6132020-11-14 16:37:52 -08001733 code_ +=
1734 " ::std::slice::from_raw_parts("
1735 "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001736 code_ += " };";
1737 code_ += " dst.copy_from_slice(src);";
1738 code_ += " }";
1739 code_ += "}";
1740 code_ += "";
1741 code_ += "";
1742
1743 // Generate a constructor that takes all fields as arguments.
1744 code_ += "impl {{STRUCT_NAME}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08001745 // TODO(cneo): Stop generating args on one line. Make it simpler.
1746 bool first_arg = true;
1747 code_ += " pub fn new(\\";
1748 ForAllStructFields(struct_def, [&](const FieldDef &field) {
1749 if (first_arg) first_arg = false; else code_ += ", \\";
1750 code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
1751 code_ += "_{{FIELD_NAME}}: {{REF}}{{FIELD_TYPE}}\\";
1752 });
1753 code_ += ") -> Self {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001754 code_ += " {{STRUCT_NAME}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08001755
1756 ForAllStructFields(struct_def, [&](const FieldDef &field) {
1757 const bool is_struct = IsStruct(field.value.type);
1758 code_.SetValue("DEREF", is_struct ? "*" : "");
1759 code_.SetValue("TO_LE", is_struct ? "" : ".to_little_endian()");
1760 code_ += " {{FIELD_NAME}}_: {{DEREF}}_{{FIELD_NAME}}{{TO_LE}},";
1761 });
1762 code_ += "";
1763
1764 // TODO(cneo): Does this padding even work? Why after all the fields?
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001765 padding_id = 0;
Austin Schuh272c6132020-11-14 16:37:52 -08001766 ForAllStructFields(struct_def, [&](const FieldDef &field) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001767 if (field.padding) {
1768 std::string padding;
1769 GenPadding(field, &padding, &padding_id, PaddingInitializer);
1770 code_ += " " + padding;
1771 }
Austin Schuh272c6132020-11-14 16:37:52 -08001772 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001773 code_ += " }";
1774 code_ += " }";
1775
Austin Schuh272c6132020-11-14 16:37:52 -08001776 if (parser_.opts.generate_name_strings) {
1777 GenFullyQualifiedNameGetter(struct_def, struct_def.name);
1778 }
1779
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001780 // Generate accessor methods for the struct.
Austin Schuh272c6132020-11-14 16:37:52 -08001781 ForAllStructFields(struct_def, [&](const FieldDef &field) {
1782 const bool is_struct = IsStruct(field.value.type);
1783 code_.SetValue("REF", is_struct ? "&" : "");
1784 code_.SetValue("FROM_LE", is_struct ? "" : ".from_little_endian()");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001785
Austin Schuh272c6132020-11-14 16:37:52 -08001786 this->GenComment(field.doc_comment, " ");
1787 code_ += " pub fn {{FIELD_NAME}}(&self) -> {{REF}}{{FIELD_TYPE}} {";
1788 code_ += " {{REF}}self.{{FIELD_NAME}}_{{FROM_LE}}";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001789 code_ += " }";
1790
1791 // Generate a comparison function for this field if it is a key.
Austin Schuh272c6132020-11-14 16:37:52 -08001792 if (field.key) { GenKeyFieldMethods(field); }
1793 });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001794 code_ += "}";
1795 code_ += "";
1796 }
1797
1798 void GenNamespaceImports(const int white_spaces) {
Austin Schuh272c6132020-11-14 16:37:52 -08001799 if (white_spaces == 0) {
1800 code_ += "#![allow(unused_imports, dead_code)]";
1801 }
1802 std::string indent = std::string(white_spaces, ' ');
1803 code_ += "";
1804 if (!parser_.opts.generate_all) {
1805 for (auto it = parser_.included_files_.begin();
1806 it != parser_.included_files_.end(); ++it) {
1807 if (it->second.empty()) continue;
1808 auto noext = flatbuffers::StripExtension(it->second);
1809 auto basename = flatbuffers::StripPath(noext);
1810
1811 code_ += indent + "use crate::" + basename + "_generated::*;";
1812 }
1813 }
1814
1815 code_ += indent + "use std::mem;";
1816 code_ += indent + "use std::cmp::Ordering;";
1817 code_ += "";
1818 code_ += indent + "extern crate flatbuffers;";
1819 code_ += indent + "use self::flatbuffers::EndianScalar;";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001820 }
1821
1822 // Set up the correct namespace. This opens a namespace if the current
1823 // namespace is different from the target namespace. This function
1824 // closes and opens the namespaces only as necessary.
1825 //
1826 // The file must start and end with an empty (or null) namespace so that
1827 // namespaces are properly opened and closed.
1828 void SetNameSpace(const Namespace *ns) {
1829 if (cur_name_space_ == ns) { return; }
1830
1831 // Compute the size of the longest common namespace prefix.
1832 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
1833 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
1834 // and common_prefix_size = 2
1835 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
1836 size_t new_size = ns ? ns->components.size() : 0;
1837
1838 size_t common_prefix_size = 0;
1839 while (common_prefix_size < old_size && common_prefix_size < new_size &&
1840 ns->components[common_prefix_size] ==
1841 cur_name_space_->components[common_prefix_size]) {
1842 common_prefix_size++;
1843 }
1844
1845 // Close cur_name_space in reverse order to reach the common prefix.
1846 // In the previous example, D then C are closed.
1847 for (size_t j = old_size; j > common_prefix_size; --j) {
1848 code_ += "} // pub mod " + cur_name_space_->components[j - 1];
1849 }
1850 if (old_size != common_prefix_size) { code_ += ""; }
1851
1852 // open namespace parts to reach the ns namespace
1853 // in the previous example, E, then F, then G are opened
1854 for (auto j = common_prefix_size; j != new_size; ++j) {
1855 code_ += "#[allow(unused_imports, dead_code)]";
1856 code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
1857 // Generate local namespace imports.
1858 GenNamespaceImports(2);
1859 }
1860 if (new_size != common_prefix_size) { code_ += ""; }
1861
1862 cur_name_space_ = ns;
1863 }
1864};
1865
1866} // namespace rust
1867
1868bool GenerateRust(const Parser &parser, const std::string &path,
1869 const std::string &file_name) {
1870 rust::RustGenerator generator(parser, path, file_name);
1871 return generator.generate();
1872}
1873
1874std::string RustMakeRule(const Parser &parser, const std::string &path,
1875 const std::string &file_name) {
1876 std::string filebase =
1877 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
Austin Schuh272c6132020-11-14 16:37:52 -08001878 rust::RustGenerator generator(parser, path, file_name);
1879 std::string make_rule =
1880 generator.GeneratedFileName(path, filebase, parser.opts) + ": ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001881
1882 auto included_files = parser.GetIncludedFilesRecursive(file_name);
1883 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1884 make_rule += " " + *it;
1885 }
1886 return make_rule;
1887}
1888
1889} // namespace flatbuffers
1890
1891// TODO(rw): Generated code should import other generated files.
1892// TODO(rw): Generated code should refer to namespaces in included files in a
1893// way that makes them referrable.
1894// TODO(rw): Generated code should indent according to nesting level.
1895// TODO(rw): Generated code should generate endian-safe Debug impls.
1896// TODO(rw): Generated code could use a Rust-only enum type to access unions,
1897// instead of making the user use _type() to manually switch.
Austin Schuh272c6132020-11-14 16:37:52 -08001898// TODO(maxburke): There should be test schemas added that use language
1899// keywords as fields of structs, tables, unions, enums, to make sure
1900// that internal code generated references escaped names correctly.
1901// TODO(maxburke): We should see if there is a more flexible way of resolving
1902// module paths for use declarations. Right now if schemas refer to
1903// other flatbuffer files, the include paths in emitted Rust bindings
1904// are crate-relative which may undesirable.