1 /*
2 * Copyright 2018 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // independent from idl_parser, since this code is not needed for most clients
18
19 #include "flatbuffers/code_generators.h"
20 #include "flatbuffers/flatbuffers.h"
21 #include "flatbuffers/idl.h"
22 #include "flatbuffers/util.h"
23
24 namespace flatbuffers {
25
GeneratedFileName(const std::string & path,const std::string & file_name)26 static std::string GeneratedFileName(const std::string &path,
27 const std::string &file_name) {
28 return path + file_name + "_generated.rs";
29 }
30
31 // Convert a camelCaseIdentifier or CamelCaseIdentifier to a
32 // snake_case_indentifier.
MakeSnakeCase(const std::string & in)33 std::string MakeSnakeCase(const std::string &in) {
34 std::string s;
35 for (size_t i = 0; i < in.length(); i++) {
36 if (i == 0) {
37 s += static_cast<char>(tolower(in[0]));
38 } else if (in[i] == '_') {
39 s += '_';
40 } else if (!islower(in[i])) {
41 // Prevent duplicate underscores for Upper_Snake_Case strings
42 // and UPPERCASE strings.
43 if (islower(in[i - 1])) {
44 s += '_';
45 }
46 s += static_cast<char>(tolower(in[i]));
47 } else {
48 s += in[i];
49 }
50 }
51 return s;
52 }
53
54 // Convert a string to all uppercase.
MakeUpper(const std::string & in)55 std::string MakeUpper(const std::string &in) {
56 std::string s;
57 for (size_t i = 0; i < in.length(); i++) {
58 s += static_cast<char>(toupper(in[i]));
59 }
60 return s;
61 }
62
63 // Encapsulate all logical field types in this enum. This allows us to write
64 // field logic based on type switches, instead of branches on the properties
65 // set on the Type.
66 // TODO(rw): for backwards compatibility, we can't use a strict `enum class`
67 // declaration here. could we use the `-Wswitch-enum` warning to
68 // achieve the same effect?
69 enum FullType {
70 ftInteger = 0,
71 ftFloat = 1,
72 ftBool = 2,
73
74 ftStruct = 3,
75 ftTable = 4,
76
77 ftEnumKey = 5,
78 ftUnionKey = 6,
79
80 ftUnionValue = 7,
81
82 // TODO(rw): bytestring?
83 ftString = 8,
84
85 ftVectorOfInteger = 9,
86 ftVectorOfFloat = 10,
87 ftVectorOfBool = 11,
88 ftVectorOfEnumKey = 12,
89 ftVectorOfStruct = 13,
90 ftVectorOfTable = 14,
91 ftVectorOfString = 15,
92 ftVectorOfUnionValue = 16,
93 };
94
95 // Convert a Type to a FullType (exhaustive).
GetFullType(const Type & type)96 FullType GetFullType(const Type &type) {
97 // N.B. The order of these conditionals matters for some types.
98
99 if (type.base_type == BASE_TYPE_STRING) {
100 return ftString;
101 } else if (type.base_type == BASE_TYPE_STRUCT) {
102 if (type.struct_def->fixed) {
103 return ftStruct;
104 } else {
105 return ftTable;
106 }
107 } else if (type.base_type == BASE_TYPE_VECTOR) {
108 switch (GetFullType(type.VectorType())) {
109 case ftInteger: {
110 return ftVectorOfInteger;
111 }
112 case ftFloat: {
113 return ftVectorOfFloat;
114 }
115 case ftBool: {
116 return ftVectorOfBool;
117 }
118 case ftStruct: {
119 return ftVectorOfStruct;
120 }
121 case ftTable: {
122 return ftVectorOfTable;
123 }
124 case ftString: {
125 return ftVectorOfString;
126 }
127 case ftEnumKey: {
128 return ftVectorOfEnumKey;
129 }
130 case ftUnionKey:
131 case ftUnionValue: {
132 FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
133 }
134 default: {
135 FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
136 }
137 }
138 } else if (type.enum_def != nullptr) {
139 if (type.enum_def->is_union) {
140 if (type.base_type == BASE_TYPE_UNION) {
141 return ftUnionValue;
142 } else if (IsInteger(type.base_type)) {
143 return ftUnionKey;
144 } else {
145 FLATBUFFERS_ASSERT(false && "unknown union field type");
146 }
147 } else {
148 return ftEnumKey;
149 }
150 } else if (IsScalar(type.base_type)) {
151 if (IsBool(type.base_type)) {
152 return ftBool;
153 } else if (IsInteger(type.base_type)) {
154 return ftInteger;
155 } else if (IsFloat(type.base_type)) {
156 return ftFloat;
157 } else {
158 FLATBUFFERS_ASSERT(false && "unknown number type");
159 }
160 }
161
162 FLATBUFFERS_ASSERT(false && "completely unknown type");
163
164 // this is only to satisfy the compiler's return analysis.
165 return ftBool;
166 }
167
168 // If the second parameter is false then wrap the first with Option<...>
WrapInOptionIfNotRequired(std::string s,bool required)169 std::string WrapInOptionIfNotRequired(std::string s, bool required) {
170 if (required) {
171 return s;
172 } else {
173 return "Option<" + s + ">";
174 }
175 }
176
177 // If the second parameter is false then add .unwrap()
AddUnwrapIfRequired(std::string s,bool required)178 std::string AddUnwrapIfRequired(std::string s, bool required) {
179 if (required) {
180 return s + ".unwrap()";
181 } else {
182 return s;
183 }
184 }
185
186 namespace rust {
187
188 class RustGenerator : public BaseGenerator {
189 public:
RustGenerator(const Parser & parser,const std::string & path,const std::string & file_name)190 RustGenerator(const Parser &parser, const std::string &path,
191 const std::string &file_name)
192 : BaseGenerator(parser, path, file_name, "", "::"),
193 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
202 "as",
203 "break",
204 "const",
205 "continue",
206 "crate",
207 "else",
208 "enum",
209 "extern",
210 "false",
211 "fn",
212 "for",
213 "if",
214 "impl",
215 "in",
216 "let",
217 "loop",
218 "match",
219 "mod",
220 "move",
221 "mut",
222 "pub",
223 "ref",
224 "return",
225 "Self",
226 "self",
227 "static",
228 "struct",
229 "super",
230 "trait",
231 "true",
232 "type",
233 "unsafe",
234 "use",
235 "where",
236 "while",
237
238 // future possible keywords
239 "abstract",
240 "alignof",
241 "become",
242 "box",
243 "do",
244 "final",
245 "macro",
246 "offsetof",
247 "override",
248 "priv",
249 "proc",
250 "pure",
251 "sizeof",
252 "typeof",
253 "unsized",
254 "virtual",
255 "yield",
256
257 // other rust terms we should not use
258 "std",
259 "usize",
260 "isize",
261 "u8",
262 "i8",
263 "u16",
264 "i16",
265 "u32",
266 "i32",
267 "u64",
268 "i64",
269 "u128",
270 "i128",
271 "f32",
272 "f64",
273
274 // These are terms the code generator can implement on types.
275 //
276 // In Rust, the trait resolution rules (as described at
277 // https://github.com/rust-lang/rust/issues/26007) mean that, as long
278 // as we impl table accessors as inherent methods, we'll never create
279 // conflicts with these keywords. However, that's a fairly nuanced
280 // implementation detail, and how we implement methods could change in
281 // the future. as a result, we proactively block these out as reserved
282 // words.
283 "follow",
284 "push",
285 "size",
286 "alignment",
287 "to_little_endian",
288 "from_little_endian",
289 nullptr };
290 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
291 }
292
293 // Iterate through all definitions we haven't generated code for (enums,
294 // structs, and tables) and output them to a single file.
generate()295 bool generate() {
296 code_.Clear();
297 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
298
299 assert(!cur_name_space_);
300
301 // Generate all code in their namespaces, once, because Rust does not
302 // permit re-opening modules.
303 //
304 // TODO(rw): Use a set data structure to reduce namespace evaluations from
305 // O(n**2) to O(n).
306 for (auto ns_it = parser_.namespaces_.begin();
307 ns_it != parser_.namespaces_.end();
308 ++ns_it) {
309 const auto &ns = *ns_it;
310
311 // Generate code for all the enum declarations.
312 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
313 ++it) {
314 const auto &enum_def = **it;
315 if (enum_def.defined_namespace != ns) { continue; }
316 if (!enum_def.generated) {
317 SetNameSpace(enum_def.defined_namespace);
318 GenEnum(enum_def);
319 }
320 }
321
322 // Generate code for all structs.
323 for (auto it = parser_.structs_.vec.begin();
324 it != parser_.structs_.vec.end(); ++it) {
325 const auto &struct_def = **it;
326 if (struct_def.defined_namespace != ns) { continue; }
327 if (struct_def.fixed && !struct_def.generated) {
328 SetNameSpace(struct_def.defined_namespace);
329 GenStruct(struct_def);
330 }
331 }
332
333 // Generate code for all tables.
334 for (auto it = parser_.structs_.vec.begin();
335 it != parser_.structs_.vec.end(); ++it) {
336 const auto &struct_def = **it;
337 if (struct_def.defined_namespace != ns) { continue; }
338 if (!struct_def.fixed && !struct_def.generated) {
339 SetNameSpace(struct_def.defined_namespace);
340 GenTable(struct_def);
341 }
342 }
343
344 // Generate global helper functions.
345 if (parser_.root_struct_def_) {
346 auto &struct_def = *parser_.root_struct_def_;
347 if (struct_def.defined_namespace != ns) { continue; }
348 SetNameSpace(struct_def.defined_namespace);
349 GenRootTableFuncs(struct_def);
350 }
351 }
352 if (cur_name_space_) SetNameSpace(nullptr);
353
354 const auto file_path = GeneratedFileName(path_, file_name_);
355 const auto final_code = code_.ToString();
356 return SaveFile(file_path.c_str(), final_code, false);
357 }
358
359 private:
360 CodeWriter code_;
361
362 std::set<std::string> keywords_;
363
364 // This tracks the current namespace so we can insert namespace declarations.
365 const Namespace *cur_name_space_;
366
CurrentNameSpace() const367 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
368
369 // Determine if a Type needs a lifetime template parameter when used in the
370 // Rust builder args.
TableBuilderTypeNeedsLifetime(const Type & type) const371 bool TableBuilderTypeNeedsLifetime(const Type &type) const {
372 switch (GetFullType(type)) {
373 case ftInteger:
374 case ftFloat:
375 case ftBool:
376 case ftEnumKey:
377 case ftUnionKey:
378 case ftUnionValue: { return false; }
379 default: { return true; }
380 }
381 }
382
383 // Determine if a table args rust type needs a lifetime template parameter.
TableBuilderArgsNeedsLifetime(const StructDef & struct_def) const384 bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
385 FLATBUFFERS_ASSERT(!struct_def.fixed);
386
387 for (auto it = struct_def.fields.vec.begin();
388 it != struct_def.fields.vec.end(); ++it) {
389 const auto &field = **it;
390 if (field.deprecated) {
391 continue;
392 }
393
394 if (TableBuilderTypeNeedsLifetime(field.value.type)) {
395 return true;
396 }
397 }
398
399 return false;
400 }
401
402 // Determine if a Type needs to be copied (for endian safety) when used in a
403 // Struct.
StructMemberAccessNeedsCopy(const Type & type) const404 bool StructMemberAccessNeedsCopy(const Type &type) const {
405 switch (GetFullType(type)) {
406 case ftInteger: // requires endian swap
407 case ftFloat: // requires endian swap
408 case ftBool: // no endian-swap, but do the copy for UX consistency
409 case ftEnumKey: { return true; } // requires endian swap
410 case ftStruct: { return false; } // no endian swap
411 default: {
412 // logic error: no other types can be struct members.
413 FLATBUFFERS_ASSERT(false && "invalid struct member type");
414 return false; // only to satisfy compiler's return analysis
415 }
416 }
417 }
418
EscapeKeyword(const std::string & name) const419 std::string EscapeKeyword(const std::string &name) const {
420 return keywords_.find(name) == keywords_.end() ? name : name + "_";
421 }
422
Name(const Definition & def) const423 std::string Name(const Definition &def) const {
424 return EscapeKeyword(def.name);
425 }
426
Name(const EnumVal & ev) const427 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
428
WrapInNameSpace(const Definition & def) const429 std::string WrapInNameSpace(const Definition &def) const {
430 return WrapInNameSpace(def.defined_namespace, Name(def));
431 }
WrapInNameSpace(const Namespace * ns,const std::string & name) const432 std::string WrapInNameSpace(const Namespace *ns,
433 const std::string &name) const {
434 if (CurrentNameSpace() == ns) return name;
435 std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
436 return prefix + name;
437 }
438
439 // Determine the namespace traversal needed from the Rust crate root.
440 // This may be useful in the future for referring to included files, but is
441 // currently unused.
GetAbsoluteNamespaceTraversal(const Namespace * dst) const442 std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const {
443 std::stringstream stream;
444
445 stream << "::";
446 for (auto d = dst->components.begin(); d != dst->components.end(); d++) {
447 stream << MakeSnakeCase(*d) + "::";
448 }
449 return stream.str();
450 }
451
452 // Determine the relative namespace traversal needed to reference one
453 // namespace from another namespace. This is useful because it does not force
454 // the user to have a particular file layout. (If we output absolute
455 // namespace paths, that may require users to organize their Rust crates in a
456 // particular way.)
GetRelativeNamespaceTraversal(const Namespace * src,const Namespace * dst) const457 std::string GetRelativeNamespaceTraversal(const Namespace *src,
458 const Namespace *dst) const {
459 // calculate the path needed to reference dst from src.
460 // example: f(A::B::C, A::B::C) -> (none)
461 // example: f(A::B::C, A::B) -> super::
462 // example: f(A::B::C, A::B::D) -> super::D
463 // example: f(A::B::C, A) -> super::super::
464 // example: f(A::B::C, D) -> super::super::super::D
465 // example: f(A::B::C, D::E) -> super::super::super::D::E
466 // example: f(A, D::E) -> super::D::E
467 // does not include leaf object (typically a struct type).
468
469 size_t i = 0;
470 std::stringstream stream;
471
472 auto s = src->components.begin();
473 auto d = dst->components.begin();
474 for(;;) {
475 if (s == src->components.end()) { break; }
476 if (d == dst->components.end()) { break; }
477 if (*s != *d) { break; }
478 s++;
479 d++;
480 i++;
481 }
482
483 for (; s != src->components.end(); s++) {
484 stream << "super::";
485 }
486 for (; d != dst->components.end(); d++) {
487 stream << MakeSnakeCase(*d) + "::";
488 }
489 return stream.str();
490 }
491
492 // Generate a comment from the schema.
GenComment(const std::vector<std::string> & dc,const char * prefix="")493 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
494 std::string text;
495 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
496 code_ += text + "\\";
497 }
498
499 // Return a Rust type from the table in idl.h.
GetTypeBasic(const Type & type) const500 std::string GetTypeBasic(const Type &type) const {
501 switch (GetFullType(type)) {
502 case ftInteger:
503 case ftFloat:
504 case ftBool:
505 case ftEnumKey:
506 case ftUnionKey: { break; }
507 default: { FLATBUFFERS_ASSERT(false && "incorrect type given");}
508 }
509
510 // clang-format off
511 static const char * const ctypename[] = {
512 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
513 RTYPE) \
514 #RTYPE,
515 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
516 #undef FLATBUFFERS_TD
517 // clang-format on
518 };
519
520 if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
521 return ctypename[type.base_type];
522 }
523
524 // Look up the native type for an enum. This will always be an integer like
525 // u8, i32, etc.
GetEnumTypeForDecl(const Type & type)526 std::string GetEnumTypeForDecl(const Type &type) {
527 const auto ft = GetFullType(type);
528 if (!(ft == ftEnumKey || ft == ftUnionKey)) {
529 FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
530 }
531
532 static const char *ctypename[] = {
533 // clang-format off
534 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
535 RTYPE) \
536 #RTYPE,
537 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
538 #undef FLATBUFFERS_TD
539 // clang-format on
540 };
541
542 // Enums can be bools, but their Rust representation must be a u8, as used
543 // in the repr attribute (#[repr(bool)] is an invalid attribute).
544 if (type.base_type == BASE_TYPE_BOOL) return "u8";
545 return ctypename[type.base_type];
546 }
547
548 // Return a Rust type for any type (scalar, table, struct) specifically for
549 // using a FlatBuffer.
GetTypeGet(const Type & type) const550 std::string GetTypeGet(const Type &type) const {
551 switch (GetFullType(type)) {
552 case ftInteger:
553 case ftFloat:
554 case ftBool:
555 case ftEnumKey:
556 case ftUnionKey: {
557 return GetTypeBasic(type); }
558 case ftTable: {
559 return WrapInNameSpace(type.struct_def->defined_namespace,
560 type.struct_def->name) + "<'a>"; }
561 default: {
562 return WrapInNameSpace(type.struct_def->defined_namespace,
563 type.struct_def->name); }
564 }
565 }
566
GetEnumValUse(const EnumDef & enum_def,const EnumVal & enum_val) const567 std::string GetEnumValUse(const EnumDef &enum_def,
568 const EnumVal &enum_val) const {
569 return Name(enum_def) + "::" + Name(enum_val);
570 }
571
572 // Generate an enum declaration,
573 // an enum string lookup table,
574 // an enum match function,
575 // and an enum array of values
GenEnum(const EnumDef & enum_def)576 void GenEnum(const EnumDef &enum_def) {
577 code_.SetValue("ENUM_NAME", Name(enum_def));
578 code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
579
580 GenComment(enum_def.doc_comment);
581 code_ += "#[allow(non_camel_case_types)]";
582 code_ += "#[repr({{BASE_TYPE}})]";
583 code_ += "#[derive(Clone, Copy, PartialEq, Debug)]";
584 code_ += "pub enum " + Name(enum_def) + " {";
585
586 int64_t anyv = 0;
587 const EnumVal *minv = nullptr, *maxv = nullptr;
588 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
589 ++it) {
590 const auto &ev = **it;
591
592 GenComment(ev.doc_comment, " ");
593 code_.SetValue("KEY", Name(ev));
594 code_.SetValue("VALUE", NumToString(ev.value));
595 code_ += " {{KEY}} = {{VALUE}},";
596
597 minv = !minv || minv->value > ev.value ? &ev : minv;
598 maxv = !maxv || maxv->value < ev.value ? &ev : maxv;
599 anyv |= ev.value;
600 }
601
602 code_ += "";
603 code_ += "}";
604 code_ += "";
605
606 code_.SetValue("ENUM_NAME", Name(enum_def));
607 code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
608 code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
609 code_.SetValue("ENUM_MIN_BASE_VALUE", NumToString(minv->value));
610 code_.SetValue("ENUM_MAX_BASE_VALUE", NumToString(maxv->value));
611
612 // Generate enum constants, and impls for Follow, EndianScalar, and Push.
613 code_ += "const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
614 code_ += "{{ENUM_MIN_BASE_VALUE}};";
615 code_ += "const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
616 code_ += "{{ENUM_MAX_BASE_VALUE}};";
617 code_ += "";
618 code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
619 code_ += " type Inner = Self;";
620 code_ += " #[inline]";
621 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
622 code_ += " flatbuffers::read_scalar_at::<Self>(buf, loc)";
623 code_ += " }";
624 code_ += "}";
625 code_ += "";
626 code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
627 code_ += " #[inline]";
628 code_ += " fn to_little_endian(self) -> Self {";
629 code_ += " let n = {{BASE_TYPE}}::to_le(self as {{BASE_TYPE}});";
630 code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
631 code_ += " unsafe { *p }";
632 code_ += " }";
633 code_ += " #[inline]";
634 code_ += " fn from_little_endian(self) -> Self {";
635 code_ += " let n = {{BASE_TYPE}}::from_le(self as {{BASE_TYPE}});";
636 code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
637 code_ += " unsafe { *p }";
638 code_ += " }";
639 code_ += "}";
640 code_ += "";
641 code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
642 code_ += " type Output = {{ENUM_NAME}};";
643 code_ += " #[inline]";
644 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
645 code_ += " flatbuffers::emplace_scalar::<{{ENUM_NAME}}>"
646 "(dst, *self);";
647 code_ += " }";
648 code_ += "}";
649 code_ += "";
650
651 // Generate an array of all enumeration values.
652 auto num_fields = NumToString(enum_def.vals.vec.size());
653 code_ += "#[allow(non_camel_case_types)]";
654 code_ += "const ENUM_VALUES_{{ENUM_NAME_CAPS}}:[{{ENUM_NAME}}; " +
655 num_fields + "] = [";
656 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
657 ++it) {
658 const auto &ev = **it;
659 auto value = GetEnumValUse(enum_def, ev);
660 auto suffix = *it != enum_def.vals.vec.back() ? "," : "";
661 code_ += " " + value + suffix;
662 }
663 code_ += "];";
664 code_ += "";
665
666 // Generate a string table for enum values.
667 // Problem is, if values are very sparse that could generate really big
668 // tables. Ideally in that case we generate a map lookup instead, but for
669 // the moment we simply don't output a table at all.
670 auto range =
671 enum_def.vals.vec.back()->value - enum_def.vals.vec.front()->value + 1;
672 // Average distance between values above which we consider a table
673 // "too sparse". Change at will.
674 static const int kMaxSparseness = 5;
675 if (range / static_cast<int64_t>(enum_def.vals.vec.size()) <
676 kMaxSparseness) {
677 code_ += "#[allow(non_camel_case_types)]";
678 code_ += "const ENUM_NAMES_{{ENUM_NAME_CAPS}}:[&'static str; " +
679 NumToString(range) + "] = [";
680
681 auto val = enum_def.vals.vec.front()->value;
682 for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
683 ++it) {
684 const auto &ev = **it;
685 while (val++ != ev.value) { code_ += " \"\","; }
686 auto suffix = *it != enum_def.vals.vec.back() ? "," : "";
687 code_ += " \"" + Name(ev) + "\"" + suffix;
688 }
689 code_ += "];";
690 code_ += "";
691
692 code_ += "pub fn enum_name_{{ENUM_NAME_SNAKE}}(e: {{ENUM_NAME}}) -> "
693 "&'static str {";
694
695 code_ += " let index: usize = e as usize\\";
696 if (enum_def.vals.vec.front()->value) {
697 auto vals = GetEnumValUse(enum_def, *enum_def.vals.vec.front());
698 code_ += " - " + vals + " as usize\\";
699 }
700 code_ += ";";
701
702 code_ += " ENUM_NAMES_{{ENUM_NAME_CAPS}}[index]";
703 code_ += "}";
704 code_ += "";
705 }
706
707 if (enum_def.is_union) {
708 // Generate tyoesafe offset(s) for unions
709 code_.SetValue("NAME", Name(enum_def));
710 code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
711 code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
712 }
713 }
714
GetFieldOffsetName(const FieldDef & field)715 std::string GetFieldOffsetName(const FieldDef &field) {
716 return "VT_" + MakeUpper(Name(field));
717 }
718
GetDefaultConstant(const FieldDef & field)719 std::string GetDefaultConstant(const FieldDef &field) {
720 return field.value.type.base_type == BASE_TYPE_FLOAT
721 ? field.value.constant + ""
722 : field.value.constant;
723 }
724
GetDefaultScalarValue(const FieldDef & field)725 std::string GetDefaultScalarValue(const FieldDef &field) {
726 switch (GetFullType(field.value.type)) {
727 case ftInteger: { return GetDefaultConstant(field); }
728 case ftFloat: { return GetDefaultConstant(field); }
729 case ftBool: {
730 return field.value.constant == "0" ? "false" : "true";
731 }
732 case ftUnionKey:
733 case ftEnumKey: {
734 auto ev = field.value.type.enum_def->ReverseLookup(
735 StringToInt(field.value.constant.c_str()), false);
736 assert(ev);
737 return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
738 GetEnumValUse(*field.value.type.enum_def, *ev));
739 }
740
741 // All pointer-ish types have a default value of None, because they are
742 // wrapped in Option.
743 default: { return "None"; }
744 }
745 }
746
747 // Create the return type for fields in the *BuilderArgs structs that are
748 // used to create Tables.
749 //
750 // Note: we could make all inputs to the BuilderArgs be an Option, as well
751 // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
752 // know if the value is default or not, because there are three ways to
753 // return a default value:
754 // 1) return a stored value that happens to be the default,
755 // 2) return a hardcoded value because the relevant vtable field is not in
756 // the vtable, or
757 // 3) return a hardcoded value because the vtable field value is set to zero.
TableBuilderArgsDefnType(const FieldDef & field,const std::string lifetime)758 std::string TableBuilderArgsDefnType(const FieldDef &field,
759 const std::string lifetime) {
760 const Type& type = field.value.type;
761
762 switch (GetFullType(type)) {
763 case ftInteger:
764 case ftFloat:
765 case ftBool: {
766 const auto typname = GetTypeBasic(type);
767 return typname;
768 }
769 case ftStruct: {
770 const auto typname = WrapInNameSpace(*type.struct_def);
771 return "Option<&" + lifetime + " " + typname + ">";
772 }
773 case ftTable: {
774 const auto typname = WrapInNameSpace(*type.struct_def);
775 return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime + \
776 ">>>";
777 }
778 case ftString: {
779 return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
780 }
781 case ftEnumKey:
782 case ftUnionKey: {
783 const auto typname = WrapInNameSpace(*type.enum_def);
784 return typname;
785 }
786 case ftUnionValue: {
787 const auto typname = WrapInNameSpace(*type.enum_def);
788 return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
789 }
790
791 case ftVectorOfInteger:
792 case ftVectorOfFloat: {
793 const auto typname = GetTypeBasic(type.VectorType());
794 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
795 lifetime + ", " + typname + ">>>";
796 }
797 case ftVectorOfBool: {
798 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
799 lifetime + ", bool>>>";
800 }
801 case ftVectorOfEnumKey: {
802 const auto typname = WrapInNameSpace(*type.enum_def);
803 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
804 lifetime + ", " + typname + ">>>";
805 }
806 case ftVectorOfStruct: {
807 const auto typname = WrapInNameSpace(*type.struct_def);
808 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
809 lifetime + ", " + typname + ">>>";
810 }
811 case ftVectorOfTable: {
812 const auto typname = WrapInNameSpace(*type.struct_def);
813 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
814 lifetime + ", flatbuffers::ForwardsUOffset<" + typname + \
815 "<" + lifetime + ">>>>>";
816 }
817 case ftVectorOfString: {
818 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
819 lifetime + ", flatbuffers::ForwardsUOffset<&" + lifetime + \
820 " str>>>>";
821 }
822 case ftVectorOfUnionValue: {
823 const auto typname = WrapInNameSpace(*type.enum_def) + \
824 "UnionTableOffset";
825 return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
826 lifetime + ", flatbuffers::ForwardsUOffset<"
827 "flatbuffers::Table<" + lifetime + ">>>>";
828 }
829 }
830 return "INVALID_CODE_GENERATION"; // for return analysis
831 }
832
TableBuilderArgsDefaultValue(const FieldDef & field)833 std::string TableBuilderArgsDefaultValue(const FieldDef &field) {
834 return GetDefaultScalarValue(field);
835 }
TableBuilderAddFuncDefaultValue(const FieldDef & field)836 std::string TableBuilderAddFuncDefaultValue(const FieldDef &field) {
837 switch (GetFullType(field.value.type)) {
838 case ftUnionKey:
839 case ftEnumKey: {
840 const std::string basetype = GetTypeBasic(field.value.type);
841 return GetDefaultScalarValue(field);
842 }
843
844 default: { return GetDefaultScalarValue(field); }
845 }
846 }
847
TableBuilderArgsAddFuncType(const FieldDef & field,const std::string lifetime)848 std::string TableBuilderArgsAddFuncType(const FieldDef &field,
849 const std::string lifetime) {
850 const Type& type = field.value.type;
851
852 switch (GetFullType(field.value.type)) {
853 case ftVectorOfStruct: {
854 const auto typname = WrapInNameSpace(*type.struct_def);
855 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
856 ", " + typname + ">>";
857 }
858 case ftVectorOfTable: {
859 const auto typname = WrapInNameSpace(*type.struct_def);
860 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
861 ", flatbuffers::ForwardsUOffset<" + typname + \
862 "<" + lifetime + ">>>>";
863 }
864 case ftVectorOfInteger:
865 case ftVectorOfFloat: {
866 const auto typname = GetTypeBasic(type.VectorType());
867 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
868 ", " + typname + ">>";
869 }
870 case ftVectorOfBool: {
871 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
872 ", bool>>";
873 }
874 case ftVectorOfString: {
875 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
876 ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
877 }
878 case ftVectorOfEnumKey: {
879 const auto typname = WrapInNameSpace(*type.enum_def);
880 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
881 ", " + typname + ">>";
882 }
883 case ftVectorOfUnionValue: {
884 const auto typname = WrapInNameSpace(*type.enum_def);
885 return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
886 ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + \
887 lifetime + ">>>";
888 }
889 case ftEnumKey: {
890 const auto typname = WrapInNameSpace(*type.enum_def);
891 return typname;
892 }
893 case ftStruct: {
894 const auto typname = WrapInNameSpace(*type.struct_def);
895 return "&" + lifetime + " " + typname + "";
896 }
897 case ftTable: {
898 const auto typname = WrapInNameSpace(*type.struct_def);
899 return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
900 }
901 case ftInteger:
902 case ftFloat: {
903 const auto typname = GetTypeBasic(type);
904 return typname;
905 }
906 case ftBool: {
907 return "bool";
908 }
909 case ftString: {
910 return "flatbuffers::WIPOffset<&" + lifetime + " str>";
911 }
912 case ftUnionKey: {
913 const auto typname = WrapInNameSpace(*type.enum_def);
914 return typname;
915 }
916 case ftUnionValue: {
917 const auto typname = WrapInNameSpace(*type.enum_def);
918 return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
919 }
920 }
921
922 return "INVALID_CODE_GENERATION"; // for return analysis
923 }
924
TableBuilderArgsAddFuncBody(const FieldDef & field)925 std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
926 const Type& type = field.value.type;
927
928 switch (GetFullType(field.value.type)) {
929 case ftInteger:
930 case ftFloat: {
931 const auto typname = GetTypeBasic(field.value.type);
932 return "self.fbb_.push_slot::<" + typname + ">";
933 }
934 case ftBool: {
935 return "self.fbb_.push_slot::<bool>";
936 }
937
938 case ftEnumKey:
939 case ftUnionKey: {
940 const auto underlying_typname = GetTypeBasic(type);
941 return "self.fbb_.push_slot::<" + underlying_typname + ">";
942 }
943
944 case ftStruct: {
945 const std::string typname = WrapInNameSpace(*type.struct_def);
946 return "self.fbb_.push_slot_always::<&" + typname + ">";
947 }
948 case ftTable: {
949 const auto typname = WrapInNameSpace(*type.struct_def);
950 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" + \
951 typname + ">>";
952 }
953
954 case ftUnionValue:
955 case ftString:
956 case ftVectorOfInteger:
957 case ftVectorOfFloat:
958 case ftVectorOfBool:
959 case ftVectorOfEnumKey:
960 case ftVectorOfStruct:
961 case ftVectorOfTable:
962 case ftVectorOfString:
963 case ftVectorOfUnionValue: {
964 return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
965 }
966 }
967 return "INVALID_CODE_GENERATION"; // for return analysis
968 }
969
GenTableAccessorFuncReturnType(const FieldDef & field,const std::string lifetime)970 std::string GenTableAccessorFuncReturnType(const FieldDef &field,
971 const std::string lifetime) {
972 const Type& type = field.value.type;
973
974 switch (GetFullType(field.value.type)) {
975 case ftInteger:
976 case ftFloat: {
977 const auto typname = GetTypeBasic(type);
978 return typname;
979 }
980 case ftBool: {
981 return "bool";
982 }
983 case ftStruct: {
984 const auto typname = WrapInNameSpace(*type.struct_def);
985 return WrapInOptionIfNotRequired("&" + lifetime + " " + typname, field.required);
986 }
987 case ftTable: {
988 const auto typname = WrapInNameSpace(*type.struct_def);
989 return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">", field.required);
990 }
991 case ftEnumKey:
992 case ftUnionKey: {
993 const auto typname = WrapInNameSpace(*type.enum_def);
994 return typname;
995 }
996
997 case ftUnionValue: {
998 return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">", field.required);
999 }
1000 case ftString: {
1001 return WrapInOptionIfNotRequired("&" + lifetime + " str", field.required);
1002 }
1003 case ftVectorOfInteger:
1004 case ftVectorOfFloat: {
1005 const auto typname = GetTypeBasic(type.VectorType());
1006 if (IsOneByte(type.VectorType().base_type)) {
1007 return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
1008 }
1009 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
1010 }
1011 case ftVectorOfBool: {
1012 return WrapInOptionIfNotRequired("&" + lifetime + " [bool]", field.required);
1013 }
1014 case ftVectorOfEnumKey: {
1015 const auto typname = WrapInNameSpace(*type.enum_def);
1016 return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
1017 }
1018 case ftVectorOfStruct: {
1019 const auto typname = WrapInNameSpace(*type.struct_def);
1020 return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
1021 }
1022 case ftVectorOfTable: {
1023 const auto typname = WrapInNameSpace(*type.struct_def);
1024 return WrapInOptionIfNotRequired("flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + \
1025 typname + "<" + lifetime + ">>>", field.required);
1026 }
1027 case ftVectorOfString: {
1028 return WrapInOptionIfNotRequired("flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \
1029 lifetime + " str>>", field.required);
1030 }
1031 case ftVectorOfUnionValue: {
1032 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1033 // TODO(rw): when we do support these, we should consider using the
1034 // Into trait to convert tables to typesafe union values.
1035 return "INVALID_CODE_GENERATION"; // for return analysis
1036 }
1037 }
1038 return "INVALID_CODE_GENERATION"; // for return analysis
1039 }
1040
GenTableAccessorFuncBody(const FieldDef & field,const std::string lifetime,const std::string offset_prefix)1041 std::string GenTableAccessorFuncBody(const FieldDef &field,
1042 const std::string lifetime,
1043 const std::string offset_prefix) {
1044 const std::string offset_name = offset_prefix + "::" + \
1045 GetFieldOffsetName(field);
1046 const Type& type = field.value.type;
1047
1048 switch (GetFullType(field.value.type)) {
1049 case ftInteger:
1050 case ftFloat:
1051 case ftBool: {
1052 const auto typname = GetTypeBasic(type);
1053 const auto default_value = GetDefaultScalarValue(field);
1054 return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + \
1055 default_value + ")).unwrap()";
1056 }
1057 case ftStruct: {
1058 const auto typname = WrapInNameSpace(*type.struct_def);
1059 return AddUnwrapIfRequired("self._tab.get::<" + typname + ">(" + offset_name + ", None)", field.required);
1060 }
1061 case ftTable: {
1062 const auto typname = WrapInNameSpace(*type.struct_def);
1063 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + \
1064 typname + "<" + lifetime + ">>>(" + offset_name + ", None)", field.required);
1065 }
1066 case ftUnionValue: {
1067 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1068 "flatbuffers::Table<" + lifetime + ">>>(" + offset_name + \
1069 ", None)", field.required);
1070 }
1071 case ftUnionKey:
1072 case ftEnumKey: {
1073 const auto underlying_typname = GetTypeBasic(type);
1074 const auto typname = WrapInNameSpace(*type.enum_def);
1075 const auto default_value = GetDefaultScalarValue(field);
1076 return "self._tab.get::<" + typname + ">(" + offset_name + \
1077 ", Some(" + default_value + ")).unwrap()";
1078 }
1079 case ftString: {
1080 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" + \
1081 offset_name + ", None)", field.required);
1082 }
1083
1084 case ftVectorOfInteger:
1085 case ftVectorOfFloat: {
1086 const auto typname = GetTypeBasic(type.VectorType());
1087 std::string s = "self._tab.get::<flatbuffers::ForwardsUOffset<"
1088 "flatbuffers::Vector<" + lifetime + ", " + typname + \
1089 ">>>(" + offset_name + ", None)";
1090 // single-byte values are safe to slice
1091 if (IsOneByte(type.VectorType().base_type)) {
1092 s += ".map(|v| v.safe_slice())";
1093 }
1094 return AddUnwrapIfRequired(s, field.required);
1095 }
1096 case ftVectorOfBool: {
1097 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1098 "flatbuffers::Vector<" + lifetime + ", bool>>>(" + \
1099 offset_name + ", None).map(|v| v.safe_slice())", field.required);
1100 }
1101 case ftVectorOfEnumKey: {
1102 const auto typname = WrapInNameSpace(*type.enum_def);
1103 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1104 "flatbuffers::Vector<" + lifetime + ", " + typname + ">>>(" + \
1105 offset_name + ", None)", field.required);
1106 }
1107 case ftVectorOfStruct: {
1108 const auto typname = WrapInNameSpace(*type.struct_def);
1109 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1110 "flatbuffers::Vector<" + typname + ">>>(" + \
1111 offset_name + ", None).map(|v| v.safe_slice() )", field.required);
1112 }
1113 case ftVectorOfTable: {
1114 const auto typname = WrapInNameSpace(*type.struct_def);
1115 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1116 "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + typname + \
1117 "<" + lifetime + ">>>>>(" + offset_name + ", None)", field.required);
1118 }
1119 case ftVectorOfString: {
1120 return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
1121 "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \
1122 lifetime + " str>>>>(" + offset_name + ", None)", field.required);
1123 }
1124 case ftVectorOfUnionValue: {
1125 FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
1126 return "INVALID_CODE_GENERATION"; // for return analysis
1127 }
1128 }
1129 return "INVALID_CODE_GENERATION"; // for return analysis
1130 }
1131
TableFieldReturnsOption(const Type & type)1132 bool TableFieldReturnsOption(const Type& type) {
1133 switch (GetFullType(type)) {
1134 case ftInteger:
1135 case ftFloat:
1136 case ftBool:
1137 case ftEnumKey:
1138 case ftUnionKey:
1139 return false;
1140 default: return true;
1141 }
1142 }
1143
1144 // Generate an accessor struct, builder struct, and create function for a
1145 // table.
GenTable(const StructDef & struct_def)1146 void GenTable(const StructDef &struct_def) {
1147 GenComment(struct_def.doc_comment);
1148
1149 code_.SetValue("STRUCT_NAME", Name(struct_def));
1150 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1151 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
1152
1153 // Generate an offset type, the base type, the Follow impl, and the
1154 // init_from_table impl.
1155 code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
1156 code_ += "#[derive(Copy, Clone, Debug, PartialEq)]";
1157 code_ += "";
1158 code_ += "pub struct {{STRUCT_NAME}}<'a> {";
1159 code_ += " pub _tab: flatbuffers::Table<'a>,";
1160 code_ += "}";
1161 code_ += "";
1162 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
1163 code_ += " type Inner = {{STRUCT_NAME}}<'a>;";
1164 code_ += " #[inline]";
1165 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1166 code_ += " Self {";
1167 code_ += " _tab: flatbuffers::Table { buf: buf, loc: loc },";
1168 code_ += " }";
1169 code_ += " }";
1170 code_ += "}";
1171 code_ += "";
1172 code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
1173 code_ += " #[inline]";
1174 code_ += " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
1175 "Self {";
1176 code_ += " {{STRUCT_NAME}} {";
1177 code_ += " _tab: table,";
1178 code_ += " }";
1179 code_ += " }";
1180
1181 // Generate a convenient create* function that uses the above builder
1182 // to create a table in one function call.
1183 code_.SetValue("MAYBE_US",
1184 struct_def.fields.vec.size() == 0 ? "_" : "");
1185 code_.SetValue("MAYBE_LT",
1186 TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
1187 code_ += " #[allow(unused_mut)]";
1188 code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
1189 code_ += " _fbb: "
1190 "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
1191 code_ += " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
1192 " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
1193
1194 code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
1195 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1196 size; size /= 2) {
1197 for (auto it = struct_def.fields.vec.rbegin();
1198 it != struct_def.fields.vec.rend(); ++it) {
1199 const auto &field = **it;
1200 // TODO(rw): fully understand this sortbysize usage
1201 if (!field.deprecated && (!struct_def.sortbysize ||
1202 size == SizeOf(field.value.type.base_type))) {
1203 code_.SetValue("FIELD_NAME", Name(field));
1204 if (TableFieldReturnsOption(field.value.type)) {
1205 code_ += " if let Some(x) = args.{{FIELD_NAME}} "
1206 "{ builder.add_{{FIELD_NAME}}(x); }";
1207 } else {
1208 code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
1209 }
1210 }
1211 }
1212 }
1213 code_ += " builder.finish()";
1214 code_ += " }";
1215 code_ += "";
1216
1217 // Generate field id constants.
1218 if (struct_def.fields.vec.size() > 0) {
1219 for (auto it = struct_def.fields.vec.begin();
1220 it != struct_def.fields.vec.end(); ++it) {
1221 const auto &field = **it;
1222 if (field.deprecated) {
1223 // Deprecated fields won't be accessible.
1224 continue;
1225 }
1226
1227 code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1228 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
1229 code_ += " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
1230 "{{OFFSET_VALUE}};";
1231 }
1232 code_ += "";
1233 }
1234
1235 // Generate the accessors. Each has one of two forms:
1236 //
1237 // If a value can be None:
1238 // pub fn name(&'a self) -> Option<user_facing_type> {
1239 // self._tab.get::<internal_type>(offset, defaultval)
1240 // }
1241 //
1242 // If a value is always Some:
1243 // pub fn name(&'a self) -> user_facing_type {
1244 // self._tab.get::<internal_type>(offset, defaultval).unwrap()
1245 // }
1246 const auto offset_prefix = Name(struct_def);
1247 for (auto it = struct_def.fields.vec.begin();
1248 it != struct_def.fields.vec.end(); ++it) {
1249 const auto &field = **it;
1250 if (field.deprecated) {
1251 // Deprecated fields won't be accessible.
1252 continue;
1253 }
1254
1255 code_.SetValue("FIELD_NAME", Name(field));
1256 code_.SetValue("RETURN_TYPE",
1257 GenTableAccessorFuncReturnType(field, "'a"));
1258 code_.SetValue("FUNC_BODY",
1259 GenTableAccessorFuncBody(field, "'a", offset_prefix));
1260
1261 GenComment(field.doc_comment, " ");
1262 code_ += " #[inline]";
1263 code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
1264 code_ += " {{FUNC_BODY}}";
1265 code_ += " }";
1266
1267 // Generate a comparison function for this field if it is a key.
1268 if (field.key) {
1269 GenKeyFieldMethods(field);
1270 }
1271
1272 // Generate a nested flatbuffer field, if applicable.
1273 auto nested = field.attributes.Lookup("nested_flatbuffer");
1274 if (nested) {
1275 std::string qualified_name = nested->constant;
1276 auto nested_root = parser_.LookupStruct(nested->constant);
1277 if (nested_root == nullptr) {
1278 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
1279 nested->constant);
1280 nested_root = parser_.LookupStruct(qualified_name);
1281 }
1282 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
1283 (void)nested_root;
1284
1285 code_.SetValue("OFFSET_NAME",
1286 offset_prefix + "::" + GetFieldOffsetName(field));
1287 code_ += " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> "
1288 " Option<{{STRUCT_NAME}}<'a>> {";
1289 code_ += " match self.{{FIELD_NAME}}() {";
1290 code_ += " None => { None }";
1291 code_ += " Some(data) => {";
1292 code_ += " use self::flatbuffers::Follow;";
1293 code_ += " Some(<flatbuffers::ForwardsUOffset"
1294 "<{{STRUCT_NAME}}<'a>>>::follow(data, 0))";
1295 code_ += " },";
1296 code_ += " }";
1297 code_ += " }";
1298 }
1299 }
1300
1301 // Explicit specializations for union accessors
1302 for (auto it = struct_def.fields.vec.begin();
1303 it != struct_def.fields.vec.end(); ++it) {
1304 const auto &field = **it;
1305 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
1306 continue;
1307 }
1308
1309 auto u = field.value.type.enum_def;
1310
1311 code_.SetValue("FIELD_NAME", Name(field));
1312
1313 for (auto u_it = u->vals.vec.begin(); u_it != u->vals.vec.end(); ++u_it) {
1314 auto &ev = **u_it;
1315 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1316
1317 auto table_init_type = WrapInNameSpace(
1318 ev.union_type.struct_def->defined_namespace,
1319 ev.union_type.struct_def->name);
1320
1321 code_.SetValue("U_ELEMENT_ENUM_TYPE",
1322 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
1323 code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type);
1324 code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
1325
1326 code_ += " #[inline]";
1327 code_ += " #[allow(non_snake_case)]";
1328 code_ += " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&'a self) -> "
1329 "Option<{{U_ELEMENT_TABLE_TYPE}}> {";
1330 code_ += " if self.{{FIELD_NAME}}_type() == {{U_ELEMENT_ENUM_TYPE}} {";
1331 code_ += " self.{{FIELD_NAME}}().map(|u| "
1332 "{{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
1333 code_ += " } else {";
1334 code_ += " None";
1335 code_ += " }";
1336 code_ += " }";
1337 code_ += "";
1338 }
1339 }
1340
1341 code_ += "}"; // End of table impl.
1342 code_ += "";
1343
1344 // Generate an args struct:
1345 code_.SetValue("MAYBE_LT",
1346 TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
1347 code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1348 for (auto it = struct_def.fields.vec.begin();
1349 it != struct_def.fields.vec.end(); ++it) {
1350 const auto &field = **it;
1351 if (!field.deprecated) {
1352 code_.SetValue("PARAM_NAME", Name(field));
1353 code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a "));
1354 code_ += " pub {{PARAM_NAME}}: {{PARAM_TYPE}},";
1355 }
1356 }
1357 code_ += "}";
1358
1359 // Generate an impl of Default for the *Args type:
1360 code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
1361 code_ += " #[inline]";
1362 code_ += " fn default() -> Self {";
1363 code_ += " {{STRUCT_NAME}}Args {";
1364 for (auto it = struct_def.fields.vec.begin();
1365 it != struct_def.fields.vec.end(); ++it) {
1366 const auto &field = **it;
1367 if (!field.deprecated) {
1368 code_.SetValue("PARAM_VALUE", TableBuilderArgsDefaultValue(field));
1369 code_.SetValue("REQ", field.required ? " // required field" : "");
1370 code_.SetValue("PARAM_NAME", Name(field));
1371 code_ += " {{PARAM_NAME}}: {{PARAM_VALUE}},{{REQ}}";
1372 }
1373 }
1374 code_ += " }";
1375 code_ += " }";
1376 code_ += "}";
1377
1378 // Generate a builder struct:
1379 code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
1380 code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1381 code_ += " start_: flatbuffers::WIPOffset<"
1382 "flatbuffers::TableUnfinishedWIPOffset>,";
1383 code_ += "}";
1384
1385 // Generate builder functions:
1386 code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
1387 for (auto it = struct_def.fields.vec.begin();
1388 it != struct_def.fields.vec.end(); ++it) {
1389 const auto &field = **it;
1390 if (!field.deprecated) {
1391 const bool is_scalar = IsScalar(field.value.type.base_type);
1392
1393 std::string offset = GetFieldOffsetName(field);
1394 std::string name = Name(field);
1395 std::string value = GetDefaultScalarValue(field);
1396
1397 // Generate functions to add data, which take one of two forms.
1398 //
1399 // If a value has a default:
1400 // fn add_x(x_: type) {
1401 // fbb_.push_slot::<type>(offset, x_, Some(default));
1402 // }
1403 //
1404 // If a value does not have a default:
1405 // fn add_x(x_: type) {
1406 // fbb_.push_slot_always::<type>(offset, x_);
1407 // }
1408 code_.SetValue("FIELD_NAME", Name(field));
1409 code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
1410 code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
1411 code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
1412 code_ += " #[inline]";
1413 code_ += " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
1414 "{{FIELD_TYPE}}) {";
1415 if (is_scalar) {
1416 code_.SetValue("FIELD_DEFAULT_VALUE",
1417 TableBuilderAddFuncDefaultValue(field));
1418 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
1419 "{{FIELD_DEFAULT_VALUE}});";
1420 } else {
1421 code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
1422 }
1423 code_ += " }";
1424 }
1425 }
1426
1427 // Struct initializer (all fields required);
1428 code_ += " #[inline]";
1429 code_ +=
1430 " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
1431 "{{STRUCT_NAME}}Builder<'a, 'b> {";
1432 code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
1433 code_ += " let start = _fbb.start_table();";
1434 code_ += " {{STRUCT_NAME}}Builder {";
1435 code_ += " fbb_: _fbb,";
1436 code_ += " start_: start,";
1437 code_ += " }";
1438 code_ += " }";
1439
1440 // finish() function.
1441 code_ += " #[inline]";
1442 code_ += " pub fn finish(self) -> "
1443 "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
1444 code_ += " let o = self.fbb_.end_table(self.start_);";
1445
1446 for (auto it = struct_def.fields.vec.begin();
1447 it != struct_def.fields.vec.end(); ++it) {
1448 const auto &field = **it;
1449 if (!field.deprecated && field.required) {
1450 code_.SetValue("FIELD_NAME", MakeSnakeCase(Name(field)));
1451 code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
1452 code_ += " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
1453 "\"{{FIELD_NAME}}\");";
1454 }
1455 }
1456 code_ += " flatbuffers::WIPOffset::new(o.value())";
1457 code_ += " }";
1458 code_ += "}";
1459 code_ += "";
1460 }
1461
1462 // Generate functions to compare tables and structs by key. This function
1463 // must only be called if the field key is defined.
GenKeyFieldMethods(const FieldDef & field)1464 void GenKeyFieldMethods(const FieldDef &field) {
1465 FLATBUFFERS_ASSERT(field.key);
1466
1467 code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
1468
1469 code_ += " #[inline]";
1470 code_ += " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
1471 " bool {";
1472 code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
1473 code_ += " }";
1474 code_ += "";
1475 code_ += " #[inline]";
1476 code_ += " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
1477 " ::std::cmp::Ordering {";
1478 code_ += " let key = self.{{FIELD_NAME}}();";
1479 code_ += " key.cmp(&val)";
1480 code_ += " }";
1481 }
1482
1483 // Generate functions for accessing the root table object. This function
1484 // must only be called if the root table is defined.
GenRootTableFuncs(const StructDef & struct_def)1485 void GenRootTableFuncs(const StructDef &struct_def) {
1486 FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
1487 auto name = Name(struct_def);
1488
1489 code_.SetValue("STRUCT_NAME", name);
1490 code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
1491 code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
1492
1493 // The root datatype accessors:
1494 code_ += "#[inline]";
1495 code_ +=
1496 "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
1497 " -> {{STRUCT_NAME}}<'a> {";
1498 code_ += " flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)";
1499 code_ += "}";
1500 code_ += "";
1501
1502 code_ += "#[inline]";
1503 code_ += "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
1504 "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
1505 code_ += " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
1506 "(buf)";
1507 code_ += "}";
1508 code_ += "";
1509
1510 if (parser_.file_identifier_.length()) {
1511 // Declare the identifier
1512 code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &'static str\\";
1513 code_ += " = \"" + parser_.file_identifier_ + "\";";
1514 code_ += "";
1515
1516 // Check if a buffer has the identifier.
1517 code_ += "#[inline]";
1518 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
1519 code_ += "(buf: &[u8]) -> bool {";
1520 code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
1521 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false);";
1522 code_ += "}";
1523 code_ += "";
1524 code_ += "#[inline]";
1525 code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
1526 code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
1527 code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
1528 code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true);";
1529 code_ += "}";
1530 code_ += "";
1531 }
1532
1533 if (parser_.file_extension_.length()) {
1534 // Return the extension
1535 code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &'static str = \\";
1536 code_ += "\"" + parser_.file_extension_ + "\";";
1537 code_ += "";
1538 }
1539
1540 // Finish a buffer with a given root object:
1541 code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
1542 code_ += "#[inline]";
1543 code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
1544 code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
1545 code_ += " root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1546 if (parser_.file_identifier_.length()) {
1547 code_ += " fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1548 } else {
1549 code_ += " fbb.finish(root, None);";
1550 }
1551 code_ += "}";
1552 code_ += "";
1553 code_ += "#[inline]";
1554 code_ += "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
1555 "<'a, 'b>("
1556 "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
1557 "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
1558 if (parser_.file_identifier_.length()) {
1559 code_ += " fbb.finish_size_prefixed(root, "
1560 "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
1561 } else {
1562 code_ += " fbb.finish_size_prefixed(root, None);";
1563 }
1564 code_ += "}";
1565 }
1566
GenPadding(const FieldDef & field,std::string * code_ptr,int * id,const std::function<void (int bits,std::string * code_ptr,int * id)> & f)1567 static void GenPadding(
1568 const FieldDef &field, std::string *code_ptr, int *id,
1569 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
1570 if (field.padding) {
1571 for (int i = 0; i < 4; i++) {
1572 if (static_cast<int>(field.padding) & (1 << i)) {
1573 f((1 << i) * 8, code_ptr, id);
1574 }
1575 }
1576 assert(!(field.padding & ~0xF));
1577 }
1578 }
1579
PaddingDefinition(int bits,std::string * code_ptr,int * id)1580 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
1581 *code_ptr += " padding" + NumToString((*id)++) + "__: u" + \
1582 NumToString(bits) + ",";
1583 }
1584
PaddingInitializer(int bits,std::string * code_ptr,int * id)1585 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
1586 (void)bits;
1587 *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
1588 }
1589
1590 // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def)1591 void GenStruct(const StructDef &struct_def) {
1592 // Generates manual padding and alignment.
1593 // Variables are private because they contain little endian data on all
1594 // platforms.
1595 GenComment(struct_def.doc_comment);
1596 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
1597 code_.SetValue("STRUCT_NAME", Name(struct_def));
1598
1599 code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
1600 code_ += "#[repr(C, align({{ALIGN}}))]";
1601
1602 // PartialEq is useful to derive because we can correctly compare structs
1603 // for equality by just comparing their underlying byte data. This doesn't
1604 // hold for PartialOrd/Ord.
1605 code_ += "#[derive(Clone, Copy, Debug, PartialEq)]";
1606 code_ += "pub struct {{STRUCT_NAME}} {";
1607
1608 int padding_id = 0;
1609 for (auto it = struct_def.fields.vec.begin();
1610 it != struct_def.fields.vec.end(); ++it) {
1611 const auto &field = **it;
1612 code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
1613 code_.SetValue("FIELD_NAME", Name(field));
1614 code_ += " {{FIELD_NAME}}_: {{FIELD_TYPE}},";
1615
1616 if (field.padding) {
1617 std::string padding;
1618 GenPadding(field, &padding, &padding_id, PaddingDefinition);
1619 code_ += padding;
1620 }
1621 }
1622
1623 code_ += "} // pub struct {{STRUCT_NAME}}";
1624
1625 // Generate impls for SafeSliceAccess (because all structs are endian-safe),
1626 // Follow for the value type, Follow for the reference type, Push for the
1627 // value type, and Push for the reference type.
1628 code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
1629 code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
1630 code_ += " type Inner = &'a {{STRUCT_NAME}};";
1631 code_ += " #[inline]";
1632 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1633 code_ += " <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
1634 code_ += " }";
1635 code_ += "}";
1636 code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
1637 code_ += " type Inner = &'a {{STRUCT_NAME}};";
1638 code_ += " #[inline]";
1639 code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
1640 code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
1641 code_ += " }";
1642 code_ += "}";
1643 code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
1644 code_ += " type Output = {{STRUCT_NAME}};";
1645 code_ += " #[inline]";
1646 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1647 code_ += " let src = unsafe {";
1648 code_ += " ::std::slice::from_raw_parts("
1649 "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1650 code_ += " };";
1651 code_ += " dst.copy_from_slice(src);";
1652 code_ += " }";
1653 code_ += "}";
1654 code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
1655 code_ += " type Output = {{STRUCT_NAME}};";
1656 code_ += "";
1657 code_ += " #[inline]";
1658 code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
1659 code_ += " let src = unsafe {";
1660 code_ += " ::std::slice::from_raw_parts("
1661 "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
1662 code_ += " };";
1663 code_ += " dst.copy_from_slice(src);";
1664 code_ += " }";
1665 code_ += "}";
1666 code_ += "";
1667 code_ += "";
1668
1669 // Generate a constructor that takes all fields as arguments.
1670 code_ += "impl {{STRUCT_NAME}} {";
1671 std::string arg_list;
1672 std::string init_list;
1673 padding_id = 0;
1674 for (auto it = struct_def.fields.vec.begin();
1675 it != struct_def.fields.vec.end(); ++it) {
1676 const auto &field = **it;
1677 const auto member_name = Name(field) + "_";
1678 const auto reference = StructMemberAccessNeedsCopy(field.value.type)
1679 ? "" : "&'a ";
1680 const auto arg_name = "_" + Name(field);
1681 const auto arg_type = reference + GetTypeGet(field.value.type);
1682
1683 if (it != struct_def.fields.vec.begin()) {
1684 arg_list += ", ";
1685 }
1686 arg_list += arg_name + ": ";
1687 arg_list += arg_type;
1688 init_list += " " + member_name;
1689 if (StructMemberAccessNeedsCopy(field.value.type)) {
1690 init_list += ": " + arg_name + ".to_little_endian(),\n";
1691 } else {
1692 init_list += ": *" + arg_name + ",\n";
1693 }
1694 }
1695
1696 code_.SetValue("ARG_LIST", arg_list);
1697 code_.SetValue("INIT_LIST", init_list);
1698 code_ += " pub fn new<'a>({{ARG_LIST}}) -> Self {";
1699 code_ += " {{STRUCT_NAME}} {";
1700 code_ += "{{INIT_LIST}}";
1701 padding_id = 0;
1702 for (auto it = struct_def.fields.vec.begin();
1703 it != struct_def.fields.vec.end(); ++it) {
1704 const auto &field = **it;
1705 if (field.padding) {
1706 std::string padding;
1707 GenPadding(field, &padding, &padding_id, PaddingInitializer);
1708 code_ += " " + padding;
1709 }
1710 }
1711 code_ += " }";
1712 code_ += " }";
1713
1714 // Generate accessor methods for the struct.
1715 for (auto it = struct_def.fields.vec.begin();
1716 it != struct_def.fields.vec.end(); ++it) {
1717 const auto &field = **it;
1718
1719 auto field_type = TableBuilderArgsAddFuncType(field, "'a");
1720 auto member = "self." + Name(field) + "_";
1721 auto value = StructMemberAccessNeedsCopy(field.value.type) ?
1722 member + ".from_little_endian()" : member;
1723
1724 code_.SetValue("FIELD_NAME", Name(field));
1725 code_.SetValue("FIELD_TYPE", field_type);
1726 code_.SetValue("FIELD_VALUE", value);
1727 code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
1728
1729 GenComment(field.doc_comment, " ");
1730 code_ += " pub fn {{FIELD_NAME}}<'a>(&'a self) -> {{FIELD_TYPE}} {";
1731 code_ += " {{REF}}{{FIELD_VALUE}}";
1732 code_ += " }";
1733
1734 // Generate a comparison function for this field if it is a key.
1735 if (field.key) {
1736 GenKeyFieldMethods(field);
1737 }
1738 }
1739 code_ += "}";
1740 code_ += "";
1741 }
1742
1743 // Set up the correct namespace. This opens a namespace if the current
1744 // namespace is different from the target namespace. This function
1745 // closes and opens the namespaces only as necessary.
1746 //
1747 // The file must start and end with an empty (or null) namespace so that
1748 // namespaces are properly opened and closed.
SetNameSpace(const Namespace * ns)1749 void SetNameSpace(const Namespace *ns) {
1750 if (cur_name_space_ == ns) { return; }
1751
1752 // Compute the size of the longest common namespace prefix.
1753 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
1754 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
1755 // and common_prefix_size = 2
1756 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
1757 size_t new_size = ns ? ns->components.size() : 0;
1758
1759 size_t common_prefix_size = 0;
1760 while (common_prefix_size < old_size && common_prefix_size < new_size &&
1761 ns->components[common_prefix_size] ==
1762 cur_name_space_->components[common_prefix_size]) {
1763 common_prefix_size++;
1764 }
1765
1766 // Close cur_name_space in reverse order to reach the common prefix.
1767 // In the previous example, D then C are closed.
1768 for (size_t j = old_size; j > common_prefix_size; --j) {
1769 code_ += "} // pub mod " + cur_name_space_->components[j - 1];
1770 }
1771 if (old_size != common_prefix_size) { code_ += ""; }
1772
1773 // open namespace parts to reach the ns namespace
1774 // in the previous example, E, then F, then G are opened
1775 for (auto j = common_prefix_size; j != new_size; ++j) {
1776 code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
1777 code_ += " #![allow(dead_code)]";
1778 code_ += " #![allow(unused_imports)]";
1779 code_ += "";
1780 code_ += " use std::mem;";
1781 code_ += " use std::cmp::Ordering;";
1782 code_ += "";
1783 code_ += " extern crate flatbuffers;";
1784 code_ += " use self::flatbuffers::EndianScalar;";
1785 }
1786 if (new_size != common_prefix_size) { code_ += ""; }
1787
1788 cur_name_space_ = ns;
1789 }
1790 };
1791
1792 } // namespace rust
1793
GenerateRust(const Parser & parser,const std::string & path,const std::string & file_name)1794 bool GenerateRust(const Parser &parser, const std::string &path,
1795 const std::string &file_name) {
1796 rust::RustGenerator generator(parser, path, file_name);
1797 return generator.generate();
1798 }
1799
RustMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)1800 std::string RustMakeRule(const Parser &parser, const std::string &path,
1801 const std::string &file_name) {
1802 std::string filebase =
1803 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
1804 std::string make_rule = GeneratedFileName(path, filebase) + ": ";
1805
1806 auto included_files = parser.GetIncludedFilesRecursive(file_name);
1807 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1808 make_rule += " " + *it;
1809 }
1810 return make_rule;
1811 }
1812
1813 } // namespace flatbuffers
1814
1815 // TODO(rw): Generated code should import other generated files.
1816 // TODO(rw): Generated code should refer to namespaces in included files in a
1817 // way that makes them referrable.
1818 // TODO(rw): Generated code should indent according to nesting level.
1819 // TODO(rw): Generated code should generate endian-safe Debug impls.
1820 // TODO(rw): Generated code could use a Rust-only enum type to access unions,
1821 // instead of making the user use _type() to manually switch.
1822