mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-05 13:08:58 +00:00
[Rust] Add support for fixed size arrays (#6548)
* Add support for fixed size arrays * clang-format * Update rust image to 1.51 to support const generics * Handle correctly big endian * Add fuzz tests and clean code * Add struct fuzz test and optimize struct arrays for api * Bump flatbuffers crate version
This commit is contained in:
@@ -81,6 +81,10 @@ enum FullType {
|
||||
ftVectorOfTable = 14,
|
||||
ftVectorOfString = 15,
|
||||
ftVectorOfUnionValue = 16,
|
||||
|
||||
ftArrayOfBuiltin = 17,
|
||||
ftArrayOfEnum = 18,
|
||||
ftArrayOfStruct = 19,
|
||||
};
|
||||
|
||||
// Convert a Type to a FullType (exhaustive).
|
||||
@@ -127,6 +131,23 @@ FullType GetFullType(const Type &type) {
|
||||
FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
|
||||
}
|
||||
}
|
||||
} else if (IsArray(type)) {
|
||||
switch (GetFullType(type.VectorType())) {
|
||||
case ftInteger:
|
||||
case ftFloat:
|
||||
case ftBool: {
|
||||
return ftArrayOfBuiltin;
|
||||
}
|
||||
case ftStruct: {
|
||||
return ftArrayOfStruct;
|
||||
}
|
||||
case ftEnumKey: {
|
||||
return ftArrayOfEnum;
|
||||
}
|
||||
default: {
|
||||
FLATBUFFERS_ASSERT(false && "Unsupported type for fixed array");
|
||||
}
|
||||
}
|
||||
} else if (type.enum_def != nullptr) {
|
||||
if (type.enum_def->is_union) {
|
||||
if (type.base_type == BASE_TYPE_UNION) {
|
||||
@@ -567,6 +588,12 @@ class RustGenerator : public BaseGenerator {
|
||||
case ftUnionKey: {
|
||||
return GetTypeBasic(type);
|
||||
}
|
||||
case ftArrayOfBuiltin:
|
||||
case ftArrayOfEnum:
|
||||
case ftArrayOfStruct: {
|
||||
return "[" + GetTypeGet(type.VectorType()) + "; " +
|
||||
NumToString(type.fixed_length) + "]";
|
||||
}
|
||||
case ftTable: {
|
||||
return WrapInNameSpace(type.struct_def->defined_namespace,
|
||||
type.struct_def->name) +
|
||||
@@ -937,6 +964,9 @@ class RustGenerator : public BaseGenerator {
|
||||
return "INVALID_CODE_GENERATION";
|
||||
}
|
||||
|
||||
case ftArrayOfStruct:
|
||||
case ftArrayOfEnum:
|
||||
case ftArrayOfBuiltin:
|
||||
case ftVectorOfBool:
|
||||
case ftVectorOfFloat:
|
||||
case ftVectorOfInteger:
|
||||
@@ -1035,6 +1065,12 @@ class RustGenerator : public BaseGenerator {
|
||||
case ftVectorOfUnionValue: {
|
||||
return WrapUOffsetsVector("flatbuffers::Table<" + lifetime + ">");
|
||||
}
|
||||
case ftArrayOfEnum:
|
||||
case ftArrayOfStruct:
|
||||
case ftArrayOfBuiltin: {
|
||||
FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
|
||||
return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
|
||||
}
|
||||
}
|
||||
return "INVALID_CODE_GENERATION"; // for return analysis
|
||||
}
|
||||
@@ -1101,6 +1137,21 @@ class RustGenerator : public BaseGenerator {
|
||||
FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
|
||||
return "INVALID_CODE_GENERATION"; // OH NO!
|
||||
}
|
||||
case ftArrayOfEnum: {
|
||||
ty = "[" + WrapInNameSpace(*type.VectorType().enum_def) + "; " +
|
||||
NumToString(type.fixed_length) + "]";
|
||||
break;
|
||||
}
|
||||
case ftArrayOfStruct: {
|
||||
ty = "[" + NamespacedNativeName(*type.VectorType().struct_def) + "; " +
|
||||
NumToString(type.fixed_length) + "]";
|
||||
break;
|
||||
}
|
||||
case ftArrayOfBuiltin: {
|
||||
ty = "[" + GetTypeBasic(type.VectorType()) + "; " +
|
||||
NumToString(type.fixed_length) + "]";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (in_a_table && !IsUnion(type) && field.IsOptional()) {
|
||||
return "Option<" + ty + ">";
|
||||
@@ -1170,6 +1221,21 @@ class RustGenerator : public BaseGenerator {
|
||||
case ftUnionValue: {
|
||||
return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
|
||||
}
|
||||
case ftArrayOfBuiltin: {
|
||||
const auto typname = GetTypeBasic(type.VectorType());
|
||||
return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
|
||||
NumToString(type.fixed_length) + ">";
|
||||
}
|
||||
case ftArrayOfEnum: {
|
||||
const auto typname = WrapInNameSpace(*type.enum_def);
|
||||
return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
|
||||
NumToString(type.fixed_length) + ">";
|
||||
}
|
||||
case ftArrayOfStruct: {
|
||||
const auto typname = WrapInNameSpace(*type.struct_def);
|
||||
return "flatbuffers::Array<" + lifetime + ", " + typname + ", " +
|
||||
NumToString(type.fixed_length) + ">";
|
||||
}
|
||||
}
|
||||
|
||||
return "INVALID_CODE_GENERATION"; // for return analysis
|
||||
@@ -1217,6 +1283,12 @@ class RustGenerator : public BaseGenerator {
|
||||
case ftVectorOfUnionValue: {
|
||||
return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
|
||||
}
|
||||
case ftArrayOfEnum:
|
||||
case ftArrayOfStruct:
|
||||
case ftArrayOfBuiltin: {
|
||||
FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
|
||||
return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
|
||||
}
|
||||
}
|
||||
return "INVALID_CODE_GENERATION"; // for return analysis
|
||||
}
|
||||
@@ -1289,6 +1361,12 @@ class RustGenerator : public BaseGenerator {
|
||||
// Into trait to convert tables to typesafe union values.
|
||||
return "INVALID_CODE_GENERATION"; // for return analysis
|
||||
}
|
||||
case ftArrayOfEnum:
|
||||
case ftArrayOfStruct:
|
||||
case ftArrayOfBuiltin: {
|
||||
FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
|
||||
return "ARRAYS_NOT_SUPPORTED_IN_TABLES";
|
||||
}
|
||||
}
|
||||
return "INVALID_CODE_GENERATION"; // for return analysis
|
||||
}
|
||||
@@ -1302,6 +1380,10 @@ class RustGenerator : public BaseGenerator {
|
||||
const auto WrapVector = [&](std::string ty) -> std::string {
|
||||
return "flatbuffers::Vector<" + lifetime + ", " + ty + ">";
|
||||
};
|
||||
const auto WrapArray = [&](std::string ty, uint16_t length) -> std::string {
|
||||
return "flatbuffers::Array<" + lifetime + ", " + ty + ", " +
|
||||
NumToString(length) + ">";
|
||||
};
|
||||
switch (GetFullType(type)) {
|
||||
case ftInteger:
|
||||
case ftFloat:
|
||||
@@ -1351,6 +1433,18 @@ class RustGenerator : public BaseGenerator {
|
||||
FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
|
||||
return "INVALID_CODE_GENERATION"; // for return analysis
|
||||
}
|
||||
case ftArrayOfEnum: {
|
||||
const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
|
||||
return WrapArray(typname, type.fixed_length);
|
||||
}
|
||||
case ftArrayOfStruct: {
|
||||
const auto typname = WrapInNameSpace(*type.struct_def);
|
||||
return WrapArray(typname, type.fixed_length);
|
||||
}
|
||||
case ftArrayOfBuiltin: {
|
||||
const auto typname = GetTypeBasic(type.VectorType());
|
||||
return WrapArray(typname, type.fixed_length);
|
||||
}
|
||||
}
|
||||
return "INVALID_CODE_GENERATION"; // for return analysis
|
||||
}
|
||||
@@ -1595,6 +1689,13 @@ class RustGenerator : public BaseGenerator {
|
||||
FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
|
||||
return;
|
||||
}
|
||||
case ftArrayOfEnum:
|
||||
case ftArrayOfStruct:
|
||||
case ftArrayOfBuiltin: {
|
||||
FLATBUFFERS_ASSERT(false &&
|
||||
"arrays are not supported within tables");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (field.IsOptional()) {
|
||||
code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}().map(|x| {";
|
||||
@@ -2037,6 +2138,12 @@ class RustGenerator : public BaseGenerator {
|
||||
FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported");
|
||||
return;
|
||||
}
|
||||
case ftArrayOfEnum:
|
||||
case ftArrayOfStruct:
|
||||
case ftArrayOfBuiltin: {
|
||||
FLATBUFFERS_ASSERT(false && "arrays are not supported within tables");
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
code_ += " {{STRUCT_NAME}}::create(_fbb, &{{STRUCT_NAME}}Args{";
|
||||
@@ -2317,11 +2424,11 @@ class RustGenerator : public BaseGenerator {
|
||||
code_.SetValue("FIELD_OBJECT_TYPE", ObjectFieldType(field, false));
|
||||
code_.SetValue("FIELD_NAME", Name(field));
|
||||
code_.SetValue("FIELD_OFFSET", NumToString(offset_to_field));
|
||||
code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
|
||||
code_.SetValue(
|
||||
"REF",
|
||||
IsStruct(field.value.type) || IsArray(field.value.type) ? "&" : "");
|
||||
cb(field);
|
||||
const size_t size = IsStruct(field.value.type)
|
||||
? field.value.type.struct_def->bytesize
|
||||
: SizeOf(field.value.type.base_type);
|
||||
const size_t size = InlineSize(field.value.type);
|
||||
offset_to_field += size + field.padding;
|
||||
}
|
||||
}
|
||||
@@ -2425,7 +2532,7 @@ class RustGenerator : public BaseGenerator {
|
||||
code_ += "}";
|
||||
|
||||
// Generate a constructor that takes all fields as arguments.
|
||||
code_ += "impl {{STRUCT_NAME}} {";
|
||||
code_ += "impl<'a> {{STRUCT_NAME}} {";
|
||||
code_ += " #[allow(clippy::too_many_arguments)]";
|
||||
code_ += " pub fn new(";
|
||||
ForAllStructFields(struct_def, [&](const FieldDef &unused) {
|
||||
@@ -2456,6 +2563,14 @@ class RustGenerator : public BaseGenerator {
|
||||
" unsafe {"
|
||||
" &*(self.0[{{FIELD_OFFSET}}..].as_ptr() as *const"
|
||||
" {{FIELD_TYPE}}) }";
|
||||
} else if (IsArray(field.value.type)) {
|
||||
code_.SetValue("ARRAY_SIZE",
|
||||
NumToString(field.value.type.fixed_length));
|
||||
code_.SetValue("ARRAY_ITEM", GetTypeGet(field.value.type.VectorType()));
|
||||
code_ +=
|
||||
" pub fn {{FIELD_NAME}}(&'a self) -> "
|
||||
"flatbuffers::Array<'a, {{ARRAY_ITEM}}, {{ARRAY_SIZE}}> {";
|
||||
code_ += " flatbuffers::Array::follow(&self.0, {{FIELD_OFFSET}})";
|
||||
} else {
|
||||
code_ += " pub fn {{FIELD_NAME}}(&self) -> {{FIELD_TYPE}} {";
|
||||
code_ +=
|
||||
@@ -2473,12 +2588,37 @@ class RustGenerator : public BaseGenerator {
|
||||
code_ += " }\n";
|
||||
// Setter.
|
||||
if (IsStruct(field.value.type)) {
|
||||
code_.SetValue("FIELD_SIZE",
|
||||
NumToString(field.value.type.struct_def->bytesize));
|
||||
code_.SetValue("FIELD_SIZE", NumToString(InlineSize(field.value.type)));
|
||||
code_ += " pub fn set_{{FIELD_NAME}}(&mut self, x: &{{FIELD_TYPE}}) {";
|
||||
code_ +=
|
||||
" self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}}+{{FIELD_SIZE}}]"
|
||||
".copy_from_slice(&x.0)";
|
||||
} else if (IsArray(field.value.type)) {
|
||||
if (GetFullType(field.value.type) == ftArrayOfBuiltin) {
|
||||
code_.SetValue("ARRAY_ITEM",
|
||||
GetTypeGet(field.value.type.VectorType()));
|
||||
code_.SetValue(
|
||||
"ARRAY_ITEM_SIZE",
|
||||
NumToString(InlineSize(field.value.type.VectorType())));
|
||||
code_ +=
|
||||
" pub fn set_{{FIELD_NAME}}(&mut self, items: &{{FIELD_TYPE}}) "
|
||||
"{";
|
||||
code_ +=
|
||||
" flatbuffers::emplace_scalar_array(&mut self.0, "
|
||||
"{{FIELD_OFFSET}}, items);";
|
||||
} else {
|
||||
code_.SetValue("FIELD_SIZE",
|
||||
NumToString(InlineSize(field.value.type)));
|
||||
code_ +=
|
||||
" pub fn set_{{FIELD_NAME}}(&mut self, x: &{{FIELD_TYPE}}) {";
|
||||
code_ += " unsafe {";
|
||||
code_ += " std::ptr::copy(";
|
||||
code_ += " x.as_ptr() as *const u8,";
|
||||
code_ += " self.0.as_mut_ptr().add({{FIELD_OFFSET}}),";
|
||||
code_ += " {{FIELD_SIZE}},";
|
||||
code_ += " );";
|
||||
code_ += " }";
|
||||
}
|
||||
} else {
|
||||
code_ += " pub fn set_{{FIELD_NAME}}(&mut self, x: {{FIELD_TYPE}}) {";
|
||||
code_ += " let x_le = x.to_little_endian();";
|
||||
@@ -2502,8 +2642,19 @@ class RustGenerator : public BaseGenerator {
|
||||
code_ += " pub fn unpack(&self) -> {{NATIVE_STRUCT_NAME}} {";
|
||||
code_ += " {{NATIVE_STRUCT_NAME}} {";
|
||||
ForAllStructFields(struct_def, [&](const FieldDef &field) {
|
||||
std::string unpack = IsStruct(field.value.type) ? ".unpack()" : "";
|
||||
code_ += " {{FIELD_NAME}}: self.{{FIELD_NAME}}()" + unpack + ",";
|
||||
if (IsArray(field.value.type)) {
|
||||
if (GetFullType(field.value.type) == ftArrayOfStruct) {
|
||||
code_ +=
|
||||
" {{FIELD_NAME}}: { let {{FIELD_NAME}} = "
|
||||
"self.{{FIELD_NAME}}(); flatbuffers::array_init(|i| "
|
||||
"{{FIELD_NAME}}.get(i).unpack()) },";
|
||||
} else {
|
||||
code_ += " {{FIELD_NAME}}: self.{{FIELD_NAME}}().into(),";
|
||||
}
|
||||
} else {
|
||||
std::string unpack = IsStruct(field.value.type) ? ".unpack()" : "";
|
||||
code_ += " {{FIELD_NAME}}: self.{{FIELD_NAME}}()" + unpack + ",";
|
||||
}
|
||||
});
|
||||
code_ += " }";
|
||||
code_ += " }";
|
||||
@@ -2530,6 +2681,14 @@ class RustGenerator : public BaseGenerator {
|
||||
ForAllStructFields(struct_def, [&](const FieldDef &field) {
|
||||
if (IsStruct(field.value.type)) {
|
||||
code_ += " &self.{{FIELD_NAME}}.pack(),";
|
||||
} else if (IsArray(field.value.type)) {
|
||||
if (GetFullType(field.value.type) == ftArrayOfStruct) {
|
||||
code_ +=
|
||||
" &flatbuffers::array_init(|i| "
|
||||
"self.{{FIELD_NAME}}[i].pack()),";
|
||||
} else {
|
||||
code_ += " &self.{{FIELD_NAME}},";
|
||||
}
|
||||
} else {
|
||||
code_ += " self.{{FIELD_NAME}},";
|
||||
}
|
||||
@@ -2570,7 +2729,7 @@ class RustGenerator : public BaseGenerator {
|
||||
code_ += indent + "use std::cmp::Ordering;";
|
||||
code_ += "";
|
||||
code_ += indent + "extern crate flatbuffers;";
|
||||
code_ += indent + "use self::flatbuffers::EndianScalar;";
|
||||
code_ += indent + "use self::flatbuffers::{EndianScalar, Follow};";
|
||||
}
|
||||
|
||||
// Set up the correct namespace. This opens a namespace if the current
|
||||
|
||||
Reference in New Issue
Block a user