Refactor idl_gen_rust (#6206)

* Refactor idl_gen_rust to a ForAllX continuation pattern.
* Updated rust sample code

Co-authored-by: Casper Neo <cneo@google.com>
This commit is contained in:
Casper
2020-10-24 15:46:55 -07:00
committed by GitHub
parent 84809be7e7
commit e68e8d7de9
2 changed files with 195 additions and 268 deletions

View File

@@ -26,37 +26,50 @@ pub mod sample {
extern crate flatbuffers; extern crate flatbuffers;
use self::flatbuffers::EndianScalar; use self::flatbuffers::EndianScalar;
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_COLOR: i8 = 0;
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MAX_COLOR: i8 = 2;
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
#[allow(non_camel_case_types)]
pub const ENUM_VALUES_COLOR: [Color; 3] = [
Color::Red,
Color::Green,
Color::Blue,
];
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Color(pub i8); pub struct Color(pub i8);
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
impl Color { impl Color {
pub const ENUM_MIN: i8 = 0;
pub const ENUM_MAX: i8 = 2;
pub const Red: Self = Self(0); pub const Red: Self = Self(0);
pub const Green: Self = Self(1); pub const Green: Self = Self(1);
pub const Blue: Self = Self(2); pub const Blue: Self = Self(2);
pub const ENUM_MIN: i8 = 0;
pub const ENUM_MAX: i8 = 2;
pub const ENUM_VALUES: &'static [Self] = &[ pub const ENUM_VALUES: &'static [Self] = &[
Self::Red, Self::Red,
Self::Green, Self::Green,
Self::Blue, Self::Blue,
]; ];
/// Returns the variant's name or "" if unknown. /// Returns the variant's name or "" if unknown.
pub fn variant_name(self) -> &'static str { pub fn variant_name(self) -> Option<&'static str> {
match self { match self {
Self::Red => "Red", Self::Red => Some("Red"),
Self::Green => "Green", Self::Green => Some("Green"),
Self::Blue => "Blue", Self::Blue => Some("Blue"),
_ => "", _ => None,
} }
} }
} }
impl std::fmt::Debug for Color { impl std::fmt::Debug for Color {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let name = self.variant_name(); if let Some(name) = self.variant_name() {
if name.is_empty() {
f.write_fmt(format_args!("<UNKNOWN {:?}>", self.0))
} else {
f.write_str(name) f.write_str(name)
} else {
f.write_fmt(format_args!("<UNKNOWN {:?}>", self.0))
} }
} }
} }
@@ -87,41 +100,46 @@ impl flatbuffers::EndianScalar for Color {
} }
} }
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_EQUIPMENT: u8 = 0;
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MAX_EQUIPMENT: u8 = 1;
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub const ENUM_VALUES_COLOR: [Color; 3] = [ pub const ENUM_VALUES_EQUIPMENT: [Equipment; 2] = [
Color::Red, Equipment::NONE,
Color::Green, Equipment::Weapon,
Color::Blue
]; ];
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Equipment(pub u8); pub struct Equipment(pub u8);
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
impl Equipment { impl Equipment {
pub const ENUM_MIN: u8 = 0;
pub const ENUM_MAX: u8 = 1;
pub const NONE: Self = Self(0); pub const NONE: Self = Self(0);
pub const Weapon: Self = Self(1); pub const Weapon: Self = Self(1);
pub const ENUM_MIN: u8 = 0;
pub const ENUM_MAX: u8 = 1;
pub const ENUM_VALUES: &'static [Self] = &[ pub const ENUM_VALUES: &'static [Self] = &[
Self::NONE, Self::NONE,
Self::Weapon, Self::Weapon,
]; ];
/// Returns the variant's name or "" if unknown. /// Returns the variant's name or "" if unknown.
pub fn variant_name(self) -> &'static str { pub fn variant_name(self) -> Option<&'static str> {
match self { match self {
Self::NONE => "NONE", Self::NONE => Some("NONE"),
Self::Weapon => "Weapon", Self::Weapon => Some("Weapon"),
_ => "", _ => None,
} }
} }
} }
impl std::fmt::Debug for Equipment { impl std::fmt::Debug for Equipment {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let name = self.variant_name(); if let Some(name) = self.variant_name() {
if name.is_empty() {
f.write_fmt(format_args!("<UNKNOWN {:?}>", self.0))
} else {
f.write_str(name) f.write_str(name)
} else {
f.write_fmt(format_args!("<UNKNOWN {:?}>", self.0))
} }
} }
} }
@@ -152,12 +170,6 @@ impl flatbuffers::EndianScalar for Equipment {
} }
} }
#[allow(non_camel_case_types)]
pub const ENUM_VALUES_EQUIPMENT: [Equipment; 2] = [
Equipment::NONE,
Equipment::Weapon
];
pub struct EquipmentUnionTableOffset {} pub struct EquipmentUnionTableOffset {}
// struct Vec3, aligned to 4 // struct Vec3, aligned to 4
#[repr(C, align(4))] #[repr(C, align(4))]

View File

@@ -344,27 +344,6 @@ class RustGenerator : public BaseGenerator {
return false; return false;
} }
// Determine if a Type needs to be copied (for endian safety) when used in a
// Struct.
bool StructMemberAccessNeedsCopy(const Type &type) const {
switch (GetFullType(type)) {
case ftInteger: // requires endian swap
case ftFloat: // requires endian swap
case ftBool: // no endian-swap, but do the copy for UX consistency
case ftEnumKey: {
return true;
} // requires endian swap
case ftStruct: {
return false;
} // no endian swap
default: {
// logic error: no other types can be struct members.
FLATBUFFERS_ASSERT(false && "invalid struct member type");
return false; // only to satisfy compiler's return analysis
}
}
}
std::string EscapeKeyword(const std::string &name) const { std::string EscapeKeyword(const std::string &name) const {
return keywords_.find(name) == keywords_.end() ? name : name + "_"; return keywords_.find(name) == keywords_.end() ? name : name + "_";
} }
@@ -828,25 +807,6 @@ class RustGenerator : public BaseGenerator {
return "INVALID_CODE_GENERATION"; // for return analysis return "INVALID_CODE_GENERATION"; // for return analysis
} }
std::string TableBuilderArgsDefaultValue(const FieldDef &field) {
return GetDefaultScalarValue(field);
}
std::string TableBuilderAddFuncDefaultValue(const FieldDef &field) {
// All branches of switch do the same action!
switch (GetFullType(field.value.type)) {
case ftUnionKey:
case ftEnumKey: {
const std::string basetype =
GetTypeBasic(field.value.type); //<- never used
return GetDefaultScalarValue(field);
}
default: {
return GetDefaultScalarValue(field);
}
}
}
std::string TableBuilderArgsAddFuncType(const FieldDef &field, std::string TableBuilderArgsAddFuncType(const FieldDef &field,
const std::string &lifetime) { const std::string &lifetime) {
const Type &type = field.value.type; const Type &type = field.value.type;
@@ -1177,6 +1137,47 @@ class RustGenerator : public BaseGenerator {
code_ += ""; code_ += "";
} }
void ForAllUnionVariantsBesidesNone(
const EnumDef &def,
std::function<void(const EnumVal &ev)> cb
) {
FLATBUFFERS_ASSERT(def.is_union);
for (auto it = def.Vals().begin(); it != def.Vals().end(); ++it) {
const EnumVal & ev = **it;
// TODO(cneo): Can variants be deprecated, should we skip them?
if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
code_.SetValue(
"U_ELEMENT_ENUM_TYPE",
WrapInNameSpace(def.defined_namespace, GetEnumValue(def, ev)));
code_.SetValue("U_ELEMENT_TABLE_TYPE",
WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
ev.union_type.struct_def->name));
code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
cb(ev);
}
}
void ForAllTableFields(
const StructDef &struct_def,
std::function<void(const FieldDef&)> cb, bool reversed=false) {
// TODO(cneo): Remove `reversed` overload. It's only here to minimize the
// diff when refactoring to the `ForAllX` helper functions.
auto go = [&](const FieldDef& field) {
if (field.deprecated) return;
code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
code_.SetValue("FIELD_NAME", Name(field));
code_.SetValue("DEFAULT_VALUE", GetDefaultScalarValue(field));
cb(field);
};
const auto &fields = struct_def.fields.vec;
if (reversed) {
for (auto it = fields.rbegin(); it != fields.rend(); ++it) go(**it);
} else {
for (auto it = fields.begin(); it != fields.end(); ++it) go(**it);
}
}
// Generate an accessor struct, builder struct, and create function for a // Generate an accessor struct, builder struct, and create function for a
// table. // table.
void GenTable(const StructDef &struct_def) { void GenTable(const StructDef &struct_def) {
@@ -1236,45 +1237,29 @@ class RustGenerator : public BaseGenerator {
code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);"; code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
size; size /= 2) { size; size /= 2) {
for (auto it = struct_def.fields.vec.rbegin(); ForAllTableFields(struct_def, [&](const FieldDef &field) {
it != struct_def.fields.vec.rend(); ++it) { if (struct_def.sortbysize && size != SizeOf(field.value.type.base_type))
const auto &field = **it; return;
// TODO(rw): fully understand this sortbysize usage if (TableFieldReturnsOption(field)) {
if (!field.deprecated && (!struct_def.sortbysize || code_ +=
size == SizeOf(field.value.type.base_type))) { " if let Some(x) = args.{{FIELD_NAME}} "
code_.SetValue("FIELD_NAME", Name(field)); "{ builder.add_{{FIELD_NAME}}(x); }";
if (TableFieldReturnsOption(field)) { } else {
code_ += code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
" if let Some(x) = args.{{FIELD_NAME}} "
"{ builder.add_{{FIELD_NAME}}(x); }";
} else {
code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
}
} }
} }, /*reverse=*/true);
} }
code_ += " builder.finish()"; code_ += " builder.finish()";
code_ += " }"; code_ += " }";
code_ += ""; code_ += "";
// Generate field id constants. // Generate field id constants.
if (struct_def.fields.vec.size() > 0) { ForAllTableFields(struct_def, [&](const FieldDef &unused){
for (auto it = struct_def.fields.vec.begin(); (void) unused;
it != struct_def.fields.vec.end(); ++it) { code_ += " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
const auto &field = **it; "{{OFFSET_VALUE}};";
if (field.deprecated) { });
// Deprecated fields won't be accessible. if (struct_def.fields.vec.size() > 0) code_ += "";
continue;
}
code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
code_ +=
" pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
"{{OFFSET_VALUE}};";
}
code_ += "";
}
// Generate the accessors. Each has one of two forms: // Generate the accessors. Each has one of two forms:
// //
@@ -1288,21 +1273,13 @@ class RustGenerator : public BaseGenerator {
// self._tab.get::<internal_type>(offset, defaultval).unwrap() // self._tab.get::<internal_type>(offset, defaultval).unwrap()
// } // }
const auto offset_prefix = Name(struct_def); const auto offset_prefix = Name(struct_def);
for (auto it = struct_def.fields.vec.begin(); ForAllTableFields(struct_def, [&](const FieldDef &field) {
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
if (field.deprecated) {
// Deprecated fields won't be accessible.
continue;
}
code_.SetValue("FIELD_NAME", Name(field));
code_.SetValue("RETURN_TYPE", code_.SetValue("RETURN_TYPE",
GenTableAccessorFuncReturnType(field, "'a")); GenTableAccessorFuncReturnType(field, "'a"));
code_.SetValue("FUNC_BODY", code_.SetValue("FUNC_BODY",
GenTableAccessorFuncBody(field, "'a", offset_prefix)); GenTableAccessorFuncBody(field, "'a", offset_prefix));
GenComment(field.doc_comment, " "); this->GenComment(field.doc_comment, " ");
code_ += " #[inline]"; code_ += " #[inline]";
code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {"; code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
code_ += " {{FUNC_BODY}}"; code_ += " {{FUNC_BODY}}";
@@ -1334,35 +1311,15 @@ class RustGenerator : public BaseGenerator {
code_ += " })"; code_ += " })";
code_ += " }"; code_ += " }";
} }
} });
// Explicit specializations for union accessors // Explicit specializations for union accessors
for (auto it = struct_def.fields.vec.begin(); ForAllTableFields(struct_def, [&](const FieldDef &field) {
it != struct_def.fields.vec.end(); ++it) { if (field.value.type.base_type != BASE_TYPE_UNION) return;
const auto &field = **it;
if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
continue;
}
auto u = field.value.type.enum_def;
code_.SetValue("FIELD_NAME", Name(field));
code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name); code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
ForAllUnionVariantsBesidesNone(
for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) { *field.value.type.enum_def, [&](const EnumVal &unused){
auto &ev = **u_it; (void) unused;
if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
auto table_init_type =
WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
ev.union_type.struct_def->name);
code_.SetValue(
"U_ELEMENT_ENUM_TYPE",
WrapInNameSpace(u->defined_namespace, GetEnumValue(*u, ev)));
code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type);
code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
code_ += " #[inline]"; code_ += " #[inline]";
code_ += " #[allow(non_snake_case)]"; code_ += " #[allow(non_snake_case)]";
code_ += code_ +=
@@ -1398,9 +1355,9 @@ class RustGenerator : public BaseGenerator {
code_ += " }"; code_ += " }";
code_ += " }"; code_ += " }";
code_ += ""; code_ += "";
}
}
});
});
code_ += "}"; // End of table impl. code_ += "}"; // End of table impl.
code_ += ""; code_ += "";
@@ -1408,15 +1365,10 @@ class RustGenerator : public BaseGenerator {
code_.SetValue("MAYBE_LT", code_.SetValue("MAYBE_LT",
TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : ""); TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {"; code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
for (auto it = struct_def.fields.vec.begin(); ForAllTableFields(struct_def, [&](const FieldDef &field) {
it != struct_def.fields.vec.end(); ++it) { code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
const auto &field = **it; code_ += " pub {{FIELD_NAME}}: {{PARAM_TYPE}},";
if (!field.deprecated) { });
code_.SetValue("PARAM_NAME", Name(field));
code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a"));
code_ += " pub {{PARAM_NAME}}: {{PARAM_TYPE}},";
}
}
code_ += "}"; code_ += "}";
// Generate an impl of Default for the *Args type: // Generate an impl of Default for the *Args type:
@@ -1424,16 +1376,10 @@ class RustGenerator : public BaseGenerator {
code_ += " #[inline]"; code_ += " #[inline]";
code_ += " fn default() -> Self {"; code_ += " fn default() -> Self {";
code_ += " {{STRUCT_NAME}}Args {"; code_ += " {{STRUCT_NAME}}Args {";
for (auto it = struct_def.fields.vec.begin(); ForAllTableFields(struct_def, [&](const FieldDef &field) {
it != struct_def.fields.vec.end(); ++it) { code_ += " {{FIELD_NAME}}: {{DEFAULT_VALUE}},\\";
const auto &field = **it; code_ += field.required ? " // required field" : "";
if (!field.deprecated) { });
code_.SetValue("PARAM_VALUE", TableBuilderArgsDefaultValue(field));
code_.SetValue("REQ", field.required ? " // required field" : "");
code_.SetValue("PARAM_NAME", Name(field));
code_ += " {{PARAM_NAME}}: {{PARAM_VALUE}},{{REQ}}";
}
}
code_ += " }"; code_ += " }";
code_ += " }"; code_ += " }";
code_ += "}"; code_ += "}";
@@ -1448,44 +1394,35 @@ class RustGenerator : public BaseGenerator {
// Generate builder functions: // Generate builder functions:
code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {"; code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
for (auto it = struct_def.fields.vec.begin(); ForAllTableFields(struct_def, [&](const FieldDef &field) {
it != struct_def.fields.vec.end(); ++it) { const bool is_scalar = IsScalar(field.value.type.base_type);
const auto &field = **it; std::string offset = GetFieldOffsetName(field);
if (!field.deprecated) { // Generate functions to add data, which take one of two forms.
const bool is_scalar = IsScalar(field.value.type.base_type); //
std::string offset = GetFieldOffsetName(field); // If a value has a default:
// fn add_x(x_: type) {
// Generate functions to add data, which take one of two forms. // fbb_.push_slot::<type>(offset, x_, Some(default));
// // }
// If a value has a default: //
// fn add_x(x_: type) { // If a value does not have a default:
// fbb_.push_slot::<type>(offset, x_, Some(default)); // fn add_x(x_: type) {
// } // fbb_.push_slot_always::<type>(offset, x_);
// // }
// If a value does not have a default: code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
// fn add_x(x_: type) { code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
// fbb_.push_slot_always::<type>(offset, x_); code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
// } code_ += " #[inline]";
code_.SetValue("FIELD_NAME", Name(field)); code_ += " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset); "{{FIELD_TYPE}}) {";
code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b ")); if (is_scalar && !field.optional) {
code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
code_ += " #[inline]";
code_ += code_ +=
" pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: " " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
"{{FIELD_TYPE}}) {"; "{{DEFAULT_VALUE}});";
if (is_scalar && !field.optional) { } else {
code_.SetValue("FIELD_DEFAULT_VALUE", code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
TableBuilderAddFuncDefaultValue(field));
code_ +=
" {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
"{{FIELD_DEFAULT_VALUE}});";
} else {
code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
}
code_ += " }";
} }
} code_ += " }";
});
// Struct initializer (all fields required); // Struct initializer (all fields required);
code_ += " #[inline]"; code_ += " #[inline]";
@@ -1507,17 +1444,12 @@ class RustGenerator : public BaseGenerator {
"flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {"; "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
code_ += " let o = self.fbb_.end_table(self.start_);"; code_ += " let o = self.fbb_.end_table(self.start_);";
for (auto it = struct_def.fields.vec.begin(); ForAllTableFields(struct_def, [&](const FieldDef &field) {
it != struct_def.fields.vec.end(); ++it) { if (!field.required) return;
const auto &field = **it; code_ +=
if (!field.deprecated && field.required) { " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
code_.SetValue("FIELD_NAME", MakeSnakeCase(Name(field))); "\"{{FIELD_NAME}}\");";
code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field)); });
code_ +=
" self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
"\"{{FIELD_NAME}}\");";
}
}
code_ += " flatbuffers::WIPOffset::new(o.value())"; code_ += " flatbuffers::WIPOffset::new(o.value())";
code_ += " }"; code_ += " }";
code_ += "}"; code_ += "}";
@@ -1659,6 +1591,18 @@ class RustGenerator : public BaseGenerator {
*code_ptr += "padding" + NumToString((*id)++) + "__: 0,"; *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
} }
void ForAllStructFields(
const StructDef &struct_def,
std::function<void(const FieldDef &field)> cb
) {
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
code_.SetValue("FIELD_NAME", Name(field));
cb(field);
}
}
// Generate an accessor struct with constructor for a flatbuffers struct. // Generate an accessor struct with constructor for a flatbuffers struct.
void GenStruct(const StructDef &struct_def) { void GenStruct(const StructDef &struct_def) {
// Generates manual padding and alignment. // Generates manual padding and alignment.
@@ -1678,19 +1622,14 @@ class RustGenerator : public BaseGenerator {
code_ += "pub struct {{STRUCT_NAME}} {"; code_ += "pub struct {{STRUCT_NAME}} {";
int padding_id = 0; int padding_id = 0;
for (auto it = struct_def.fields.vec.begin(); ForAllStructFields(struct_def, [&](const FieldDef &field) {
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
code_.SetValue("FIELD_NAME", Name(field));
code_ += " {{FIELD_NAME}}_: {{FIELD_TYPE}},"; code_ += " {{FIELD_NAME}}_: {{FIELD_TYPE}},";
if (field.padding) { if (field.padding) {
std::string padding; std::string padding;
GenPadding(field, &padding, &padding_id, PaddingDefinition); GenPadding(field, &padding, &padding_id, PaddingDefinition);
code_ += padding; code_ += padding;
} }
} });
code_ += "} // pub struct {{STRUCT_NAME}}"; code_ += "} // pub struct {{STRUCT_NAME}}";
@@ -1742,44 +1681,34 @@ class RustGenerator : public BaseGenerator {
// Generate a constructor that takes all fields as arguments. // Generate a constructor that takes all fields as arguments.
code_ += "impl {{STRUCT_NAME}} {"; code_ += "impl {{STRUCT_NAME}} {";
std::string arg_list; // TODO(cneo): Stop generating args on one line. Make it simpler.
std::string init_list; bool first_arg = true;
padding_id = 0; code_ += " pub fn new(\\";
for (auto it = struct_def.fields.vec.begin(); ForAllStructFields(struct_def, [&](const FieldDef &field) {
it != struct_def.fields.vec.end(); ++it) { if (first_arg) first_arg = false; else code_ += ", \\";
const auto &field = **it; code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
const auto member_name = Name(field) + "_"; code_ += "_{{FIELD_NAME}}: {{REF}}{{FIELD_TYPE}}\\";
const auto reference = });
StructMemberAccessNeedsCopy(field.value.type) ? "" : "&"; code_ += ") -> Self {";
const auto arg_name = "_" + Name(field);
const auto arg_type = reference + GetTypeGet(field.value.type);
if (it != struct_def.fields.vec.begin()) { arg_list += ", "; }
arg_list += arg_name + ": ";
arg_list += arg_type;
init_list += " " + member_name;
if (StructMemberAccessNeedsCopy(field.value.type)) {
init_list += ": " + arg_name + ".to_little_endian(),\n";
} else {
init_list += ": *" + arg_name + ",\n";
}
}
code_.SetValue("ARG_LIST", arg_list);
code_.SetValue("INIT_LIST", init_list);
code_ += " pub fn new({{ARG_LIST}}) -> Self {";
code_ += " {{STRUCT_NAME}} {"; code_ += " {{STRUCT_NAME}} {";
code_ += "{{INIT_LIST}}";
ForAllStructFields(struct_def, [&](const FieldDef &field) {
const bool is_struct = IsStruct(field.value.type);
code_.SetValue("DEREF", is_struct ? "*" : "");
code_.SetValue("TO_LE", is_struct ? "" : ".to_little_endian()");
code_ += " {{FIELD_NAME}}_: {{DEREF}}_{{FIELD_NAME}}{{TO_LE}},";
});
code_ += "";
// TODO(cneo): Does this padding even work? Why after all the fields?
padding_id = 0; padding_id = 0;
for (auto it = struct_def.fields.vec.begin(); ForAllStructFields(struct_def, [&](const FieldDef &field) {
it != struct_def.fields.vec.end(); ++it) {
const auto &field = **it;
if (field.padding) { if (field.padding) {
std::string padding; std::string padding;
GenPadding(field, &padding, &padding_id, PaddingInitializer); GenPadding(field, &padding, &padding_id, PaddingInitializer);
code_ += " " + padding; code_ += " " + padding;
} }
} });
code_ += " }"; code_ += " }";
code_ += " }"; code_ += " }";
@@ -1788,33 +1717,19 @@ class RustGenerator : public BaseGenerator {
} }
// Generate accessor methods for the struct. // Generate accessor methods for the struct.
for (auto it = struct_def.fields.vec.begin(); ForAllStructFields(struct_def, [&](const FieldDef &field) {
it != struct_def.fields.vec.end(); ++it) { const bool is_struct = IsStruct(field.value.type);
const auto &field = **it; code_.SetValue("REF", is_struct ? "&" : "");
code_.SetValue("FROM_LE", is_struct ? "" : ".from_little_endian()");
auto field_type = TableBuilderArgsAddFuncType(field, "'a"); this->GenComment(field.doc_comment, " ");
auto member = "self." + Name(field) + "_"; code_ += " pub fn {{FIELD_NAME}}(&self) -> {{REF}}{{FIELD_TYPE}} {";
auto value = StructMemberAccessNeedsCopy(field.value.type) code_ += " {{REF}}self.{{FIELD_NAME}}_{{FROM_LE}}";
? member + ".from_little_endian()" code_ += " }";
: member;
code_.SetValue("FIELD_NAME", Name(field));
code_.SetValue("FIELD_TYPE", field_type);
code_.SetValue("FIELD_VALUE", value);
GenComment(field.doc_comment, " ");
if (IsStruct(field.value.type)) {
code_ += " pub fn {{FIELD_NAME}}(&self) -> {{FIELD_TYPE}} {";
code_ += " &{{FIELD_VALUE}}";
code_ += " }";
} else {
code_ += " pub fn {{FIELD_NAME}}(&self) -> {{FIELD_TYPE}} {";
code_ += " {{FIELD_VALUE}}";
code_ += " }";
}
// Generate a comparison function for this field if it is a key. // Generate a comparison function for this field if it is a key.
if (field.key) { GenKeyFieldMethods(field); } if (field.key) { GenKeyFieldMethods(field); }
} });
code_ += "}"; code_ += "}";
code_ += ""; code_ += "";
} }