[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:
Eddie Linder
2021-04-16 18:15:59 +03:00
committed by GitHub
parent 151900ba96
commit da3bb64ef6
25 changed files with 1442 additions and 77 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "flatbuffers"
version = "0.8.3"
version = "0.8.4"
edition = "2018"
authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
license = "Apache-2.0"

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2021 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::follow::Follow;
use crate::{
vector::{SafeSliceAccess, VectorIter},
EndianScalar,
};
use std::fmt::{Debug, Formatter, Result};
use std::marker::PhantomData;
use std::mem::size_of;
use std::slice::from_raw_parts;
#[derive(Copy, Clone)]
pub struct Array<'a, T: 'a, const N: usize>(&'a [u8], PhantomData<T>);
impl<'a, T: 'a, const N: usize> Debug for Array<'a, T, N>
where
T: 'a + Follow<'a>,
<T as Follow<'a>>::Inner: Debug,
{
fn fmt(&self, f: &mut Formatter) -> Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<'a, T: 'a, const N: usize> Array<'a, T, N> {
#[inline(always)]
pub fn new(buf: &'a [u8]) -> Self {
debug_assert!(size_of::<T>() * N == buf.len());
Array {
0: buf,
1: PhantomData,
}
}
#[inline(always)]
pub fn len(&self) -> usize {
N
}
}
impl<'a, T: Follow<'a> + 'a, const N: usize> Array<'a, T, N> {
#[inline(always)]
pub fn get(&self, idx: usize) -> T::Inner {
debug_assert!(idx < N);
let sz = size_of::<T>();
T::follow(self.0, sz * idx)
}
#[inline(always)]
pub fn iter(&self) -> VectorIter<'a, T> {
VectorIter::from_slice(self.0, self.len())
}
}
impl<'a, T: Follow<'a> + Debug, const N: usize> Into<[T::Inner; N]> for Array<'a, T, N> {
#[inline(always)]
fn into(self) -> [T::Inner; N] {
array_init(|i| self.get(i))
}
}
impl<'a, T: SafeSliceAccess + 'a, const N: usize> Array<'a, T, N> {
pub fn safe_slice(self) -> &'a [T] {
let sz = size_of::<T>();
debug_assert!(sz > 0);
let ptr = self.0.as_ptr() as *const T;
unsafe { from_raw_parts(ptr, N) }
}
}
/// Implement Follow for all possible Arrays that have Follow-able elements.
impl<'a, T: Follow<'a> + 'a, const N: usize> Follow<'a> for Array<'a, T, N> {
type Inner = Array<'a, T, N>;
#[inline(always)]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Array::new(&buf[loc..loc + N * size_of::<T>()])
}
}
pub fn emplace_scalar_array<T: EndianScalar, const N: usize>(
buf: &mut [u8],
loc: usize,
src: &[T; N],
) {
let mut buf_ptr = buf[loc..].as_mut_ptr() as *mut T;
for item in src.iter() {
let item_le = item.to_little_endian();
unsafe {
buf_ptr.write(item_le);
buf_ptr = buf_ptr.add(1);
}
}
}
impl<'a, T: Follow<'a> + 'a, const N: usize> IntoIterator for Array<'a, T, N> {
type Item = T::Inner;
type IntoIter = VectorIter<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[inline]
pub fn array_init<F, T, const N: usize>(mut initializer: F) -> [T; N]
where
F: FnMut(usize) -> T,
{
let mut array: core::mem::MaybeUninit<[T; N]> = core::mem::MaybeUninit::uninit();
let mut ptr_i = array.as_mut_ptr() as *mut T;
unsafe {
for i in 0..N {
let value_i = initializer(i);
ptr_i.write(value_i);
ptr_i = ptr_i.add(1);
}
array.assume_init()
}
}

View File

@@ -253,12 +253,9 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
// Gets The pointer to the size of the string
let str_memory = &buf[buf.len() - ptr..];
// Gets the size of the written string from buffer
let size = u32::from_le_bytes([
str_memory[0],
str_memory[1],
str_memory[2],
str_memory[3],
]) as usize;
let size =
u32::from_le_bytes([str_memory[0], str_memory[1], str_memory[2], str_memory[3]])
as usize;
// Size of the string size
let string_size: usize = 4;
// Fetches actual string bytes from index of string after string size
@@ -728,23 +725,21 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
// could be empty (e.g. for empty tables, or for all-default values).
debug_assert!(
self.nested,
format!(
"incorrect FlatBufferBuilder usage: {} must be called while in a nested state",
fn_name
)
"incorrect FlatBufferBuilder usage: {} must be called while in a nested state",
fn_name
);
}
#[inline]
fn assert_not_nested(&self, msg: &'static str) {
debug_assert!(!self.nested, msg);
debug_assert!(!self.nested, "{}", msg);
}
#[inline]
fn assert_finished(&self, msg: &'static str) {
debug_assert!(self.finished, msg);
debug_assert!(self.finished, "{}", msg);
}
#[inline]
fn assert_not_finished(&self, msg: &'static str) {
debug_assert!(!self.finished, msg);
debug_assert!(!self.finished, "{}", msg);
}
}

View File

@@ -155,7 +155,7 @@ pub fn emplace_scalar<T: EndianScalar>(s: &mut [u8], x: T) {
core::ptr::copy_nonoverlapping(
&x_le as *const T as *const u8,
s.as_mut_ptr() as *mut u8,
size_of::<T>()
size_of::<T>(),
);
}
}
@@ -174,11 +174,7 @@ pub fn read_scalar<T: EndianScalar>(s: &[u8]) -> T {
let mut mem = core::mem::MaybeUninit::<T>::uninit();
// Since [u8] has alignment 1, we copy it into T which may have higher alignment.
let x = unsafe {
core::ptr::copy_nonoverlapping(
s.as_ptr(),
mem.as_mut_ptr() as *mut u8,
size_of::<T>()
);
core::ptr::copy_nonoverlapping(s.as_ptr(), mem.as_mut_ptr() as *mut u8, size_of::<T>());
mem.assume_init()
};
x.from_little_endian()

View File

@@ -28,6 +28,7 @@
//! At this time, to generate Rust code, you will need the latest `master` version of `flatc`, available from here: <https://github.com/google/flatbuffers>
//! (On OSX, you can install FlatBuffers from `HEAD` with the Homebrew package manager.)
mod array;
mod builder;
mod endian_scalar;
mod follow;
@@ -40,6 +41,7 @@ mod verifier;
mod vtable;
mod vtable_writer;
pub use crate::array::{array_init, emplace_scalar_array, Array};
pub use crate::builder::FlatBufferBuilder;
pub use crate::endian_scalar::{
byte_swap_f32, byte_swap_f64, emplace_scalar, read_scalar, read_scalar_at, EndianScalar,

View File

@@ -29,11 +29,15 @@ use crate::primitives::*;
pub struct Vector<'a, T: 'a>(&'a [u8], usize, PhantomData<T>);
impl<'a, T:'a> Default for Vector<'a, T> {
impl<'a, T: 'a> Default for Vector<'a, T> {
fn default() -> Self {
// Static, length 0 vector.
// Note that derived default causes UB due to issues in read_scalar_at /facepalm.
Self(&[0; core::mem::size_of::<UOffsetT>()], 0, Default::default())
Self(
&[0; core::mem::size_of::<UOffsetT>()],
0,
Default::default(),
)
}
}
@@ -88,7 +92,7 @@ impl<'a, T: Follow<'a> + 'a> Vector<'a, T> {
#[inline(always)]
pub fn iter(&self) -> VectorIter<'a, T> {
VectorIter::new(*self)
VectorIter::from_vector(*self)
}
}
@@ -185,7 +189,7 @@ pub struct VectorIter<'a, T: 'a> {
impl<'a, T: 'a> VectorIter<'a, T> {
#[inline]
pub fn new(inner: Vector<'a, T>) -> Self {
pub fn from_vector(inner: Vector<'a, T>) -> Self {
VectorIter {
buf: inner.0,
// inner.1 is the location of the data for the vector.
@@ -196,6 +200,16 @@ impl<'a, T: 'a> VectorIter<'a, T> {
phantom: PhantomData,
}
}
#[inline]
pub fn from_slice(buf: &'a [u8], items_num: usize) -> Self {
VectorIter {
buf,
loc: 0,
remaining: items_num,
phantom: PhantomData,
}
}
}
impl<'a, T: Follow<'a> + 'a> Clone for VectorIter<'a, T> {

View File

@@ -39,8 +39,10 @@ pub enum InvalidFlatbuffer {
required: &'static str,
error_trace: ErrorTrace,
},
#[error("Union exactly one of union discriminant (`{field_type}`) and value \
(`{field}`) are present.\n{error_trace}")]
#[error(
"Union exactly one of union discriminant (`{field_type}`) and value \
(`{field}`) are present.\n{error_trace}"
)]
InconsistentUnion {
field: &'static str,
field_type: &'static str,
@@ -70,8 +72,10 @@ pub enum InvalidFlatbuffer {
range: Range<usize>,
error_trace: ErrorTrace,
},
#[error("Signed offset at position {position} has value {soffset} which points out of bounds.\
\n{error_trace}")]
#[error(
"Signed offset at position {position} has value {soffset} which points out of bounds.\
\n{error_trace}"
)]
SignedOffsetOutOfBounds {
soffset: SOffsetT,
position: usize,

View File

@@ -6,7 +6,7 @@ use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod my_game {
@@ -15,7 +15,7 @@ pub mod my_game {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod sample {
@@ -23,7 +23,7 @@ pub mod sample {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_COLOR: i8 = 0;
@@ -313,7 +313,7 @@ impl<'a> flatbuffers::Verifiable for Vec3 {
v.in_buffer::<Self>(pos)
}
}
impl Vec3 {
impl<'a> Vec3 {
#[allow(clippy::too_many_arguments)]
pub fn new(
x: f32,

View File

@@ -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

View File

@@ -2467,7 +2467,7 @@ bool Parser::SupportsAdvancedArrayFeatures() const {
return (opts.lang_to_generate &
~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava |
IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson |
IDLOptions::kBinary)) == 0;
IDLOptions::kBinary | IDLOptions::kRust)) == 0;
}
Namespace *Parser::UniqueNamespace(Namespace *ns) {

View File

@@ -0,0 +1,725 @@
// automatically generated by the FlatBuffers compiler, do not modify
use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod my_game {
use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod example {
use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::{EndianScalar, Follow};
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_TEST_ENUM: i8 = 0;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MAX_TEST_ENUM: i8 = 2;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
#[allow(non_camel_case_types)]
pub const ENUM_VALUES_TEST_ENUM: [TestEnum; 3] = [
TestEnum::A,
TestEnum::B,
TestEnum::C,
];
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(transparent)]
pub struct TestEnum(pub i8);
#[allow(non_upper_case_globals)]
impl TestEnum {
pub const A: Self = Self(0);
pub const B: Self = Self(1);
pub const C: Self = Self(2);
pub const ENUM_MIN: i8 = 0;
pub const ENUM_MAX: i8 = 2;
pub const ENUM_VALUES: &'static [Self] = &[
Self::A,
Self::B,
Self::C,
];
/// Returns the variant's name or "" if unknown.
pub fn variant_name(self) -> Option<&'static str> {
match self {
Self::A => Some("A"),
Self::B => Some("B"),
Self::C => Some("C"),
_ => None,
}
}
}
impl std::fmt::Debug for TestEnum {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if let Some(name) = self.variant_name() {
f.write_str(name)
} else {
f.write_fmt(format_args!("<UNKNOWN {:?}>", self.0))
}
}
}
impl<'a> flatbuffers::Follow<'a> for TestEnum {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
let b = flatbuffers::read_scalar_at::<i8>(buf, loc);
Self(b)
}
}
impl flatbuffers::Push for TestEnum {
type Output = TestEnum;
#[inline]
fn push(&self, dst: &mut [u8], _rest: &[u8]) {
flatbuffers::emplace_scalar::<i8>(dst, self.0);
}
}
impl flatbuffers::EndianScalar for TestEnum {
#[inline]
fn to_little_endian(self) -> Self {
let b = i8::to_le(self.0);
Self(b)
}
#[inline]
#[allow(clippy::wrong_self_convention)]
fn from_little_endian(self) -> Self {
let b = i8::from_le(self.0);
Self(b)
}
}
impl<'a> flatbuffers::Verifiable for TestEnum {
#[inline]
fn run_verifier(
v: &mut flatbuffers::Verifier, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
i8::run_verifier(v, pos)
}
}
impl flatbuffers::SimpleToVerifyInSlice for TestEnum {}
// struct NestedStruct, aligned to 8
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq)]
pub struct NestedStruct(pub [u8; 32]);
impl Default for NestedStruct {
fn default() -> Self {
Self([0; 32])
}
}
impl std::fmt::Debug for NestedStruct {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("NestedStruct")
.field("a", &self.a())
.field("b", &self.b())
.field("c", &self.c())
.field("d", &self.d())
.finish()
}
}
impl flatbuffers::SimpleToVerifyInSlice for NestedStruct {}
impl flatbuffers::SafeSliceAccess for NestedStruct {}
impl<'a> flatbuffers::Follow<'a> for NestedStruct {
type Inner = &'a NestedStruct;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
<&'a NestedStruct>::follow(buf, loc)
}
}
impl<'a> flatbuffers::Follow<'a> for &'a NestedStruct {
type Inner = &'a NestedStruct;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
flatbuffers::follow_cast_ref::<NestedStruct>(buf, loc)
}
}
impl<'b> flatbuffers::Push for NestedStruct {
type Output = NestedStruct;
#[inline]
fn push(&self, dst: &mut [u8], _rest: &[u8]) {
let src = unsafe {
::std::slice::from_raw_parts(self as *const NestedStruct as *const u8, Self::size())
};
dst.copy_from_slice(src);
}
}
impl<'b> flatbuffers::Push for &'b NestedStruct {
type Output = NestedStruct;
#[inline]
fn push(&self, dst: &mut [u8], _rest: &[u8]) {
let src = unsafe {
::std::slice::from_raw_parts(*self as *const NestedStruct as *const u8, Self::size())
};
dst.copy_from_slice(src);
}
}
impl<'a> flatbuffers::Verifiable for NestedStruct {
#[inline]
fn run_verifier(
v: &mut flatbuffers::Verifier, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
v.in_buffer::<Self>(pos)
}
}
impl<'a> NestedStruct {
#[allow(clippy::too_many_arguments)]
pub fn new(
a: &[i32; 2],
b: TestEnum,
c: &[TestEnum; 2],
d: &[i64; 2],
) -> Self {
let mut s = Self([0; 32]);
s.set_a(&a);
s.set_b(b);
s.set_c(&c);
s.set_d(&d);
s
}
pub fn a(&'a self) -> flatbuffers::Array<'a, i32, 2> {
flatbuffers::Array::follow(&self.0, 0)
}
pub fn set_a(&mut self, items: &[i32; 2]) {
flatbuffers::emplace_scalar_array(&mut self.0, 0, items);
}
pub fn b(&self) -> TestEnum {
let mut mem = core::mem::MaybeUninit::<TestEnum>::uninit();
unsafe {
core::ptr::copy_nonoverlapping(
self.0[8..].as_ptr(),
mem.as_mut_ptr() as *mut u8,
core::mem::size_of::<TestEnum>(),
);
mem.assume_init()
}.from_little_endian()
}
pub fn set_b(&mut self, x: TestEnum) {
let x_le = x.to_little_endian();
unsafe {
core::ptr::copy_nonoverlapping(
&x_le as *const TestEnum as *const u8,
self.0[8..].as_mut_ptr(),
core::mem::size_of::<TestEnum>(),
);
}
}
pub fn c(&'a self) -> flatbuffers::Array<'a, TestEnum, 2> {
flatbuffers::Array::follow(&self.0, 9)
}
pub fn set_c(&mut self, x: &[TestEnum; 2]) {
unsafe {
std::ptr::copy(
x.as_ptr() as *const u8,
self.0.as_mut_ptr().add(9),
2,
);
}
}
pub fn d(&'a self) -> flatbuffers::Array<'a, i64, 2> {
flatbuffers::Array::follow(&self.0, 16)
}
pub fn set_d(&mut self, items: &[i64; 2]) {
flatbuffers::emplace_scalar_array(&mut self.0, 16, items);
}
pub fn unpack(&self) -> NestedStructT {
NestedStructT {
a: self.a().into(),
b: self.b(),
c: self.c().into(),
d: self.d().into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct NestedStructT {
pub a: [i32; 2],
pub b: TestEnum,
pub c: [TestEnum; 2],
pub d: [i64; 2],
}
impl NestedStructT {
pub fn pack(&self) -> NestedStruct {
NestedStruct::new(
&self.a,
self.b,
&self.c,
&self.d,
)
}
}
// struct ArrayStruct, aligned to 8
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq)]
pub struct ArrayStruct(pub [u8; 160]);
impl Default for ArrayStruct {
fn default() -> Self {
Self([0; 160])
}
}
impl std::fmt::Debug for ArrayStruct {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("ArrayStruct")
.field("a", &self.a())
.field("b", &self.b())
.field("c", &self.c())
.field("d", &self.d())
.field("e", &self.e())
.field("f", &self.f())
.finish()
}
}
impl flatbuffers::SimpleToVerifyInSlice for ArrayStruct {}
impl flatbuffers::SafeSliceAccess for ArrayStruct {}
impl<'a> flatbuffers::Follow<'a> for ArrayStruct {
type Inner = &'a ArrayStruct;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
<&'a ArrayStruct>::follow(buf, loc)
}
}
impl<'a> flatbuffers::Follow<'a> for &'a ArrayStruct {
type Inner = &'a ArrayStruct;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
flatbuffers::follow_cast_ref::<ArrayStruct>(buf, loc)
}
}
impl<'b> flatbuffers::Push for ArrayStruct {
type Output = ArrayStruct;
#[inline]
fn push(&self, dst: &mut [u8], _rest: &[u8]) {
let src = unsafe {
::std::slice::from_raw_parts(self as *const ArrayStruct as *const u8, Self::size())
};
dst.copy_from_slice(src);
}
}
impl<'b> flatbuffers::Push for &'b ArrayStruct {
type Output = ArrayStruct;
#[inline]
fn push(&self, dst: &mut [u8], _rest: &[u8]) {
let src = unsafe {
::std::slice::from_raw_parts(*self as *const ArrayStruct as *const u8, Self::size())
};
dst.copy_from_slice(src);
}
}
impl<'a> flatbuffers::Verifiable for ArrayStruct {
#[inline]
fn run_verifier(
v: &mut flatbuffers::Verifier, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
v.in_buffer::<Self>(pos)
}
}
impl<'a> ArrayStruct {
#[allow(clippy::too_many_arguments)]
pub fn new(
a: f32,
b: &[i32; 15],
c: i8,
d: &[NestedStruct; 2],
e: i32,
f: &[i64; 2],
) -> Self {
let mut s = Self([0; 160]);
s.set_a(a);
s.set_b(&b);
s.set_c(c);
s.set_d(&d);
s.set_e(e);
s.set_f(&f);
s
}
pub fn a(&self) -> f32 {
let mut mem = core::mem::MaybeUninit::<f32>::uninit();
unsafe {
core::ptr::copy_nonoverlapping(
self.0[0..].as_ptr(),
mem.as_mut_ptr() as *mut u8,
core::mem::size_of::<f32>(),
);
mem.assume_init()
}.from_little_endian()
}
pub fn set_a(&mut self, x: f32) {
let x_le = x.to_little_endian();
unsafe {
core::ptr::copy_nonoverlapping(
&x_le as *const f32 as *const u8,
self.0[0..].as_mut_ptr(),
core::mem::size_of::<f32>(),
);
}
}
pub fn b(&'a self) -> flatbuffers::Array<'a, i32, 15> {
flatbuffers::Array::follow(&self.0, 4)
}
pub fn set_b(&mut self, items: &[i32; 15]) {
flatbuffers::emplace_scalar_array(&mut self.0, 4, items);
}
pub fn c(&self) -> i8 {
let mut mem = core::mem::MaybeUninit::<i8>::uninit();
unsafe {
core::ptr::copy_nonoverlapping(
self.0[64..].as_ptr(),
mem.as_mut_ptr() as *mut u8,
core::mem::size_of::<i8>(),
);
mem.assume_init()
}.from_little_endian()
}
pub fn set_c(&mut self, x: i8) {
let x_le = x.to_little_endian();
unsafe {
core::ptr::copy_nonoverlapping(
&x_le as *const i8 as *const u8,
self.0[64..].as_mut_ptr(),
core::mem::size_of::<i8>(),
);
}
}
pub fn d(&'a self) -> flatbuffers::Array<'a, NestedStruct, 2> {
flatbuffers::Array::follow(&self.0, 72)
}
pub fn set_d(&mut self, x: &[NestedStruct; 2]) {
unsafe {
std::ptr::copy(
x.as_ptr() as *const u8,
self.0.as_mut_ptr().add(72),
64,
);
}
}
pub fn e(&self) -> i32 {
let mut mem = core::mem::MaybeUninit::<i32>::uninit();
unsafe {
core::ptr::copy_nonoverlapping(
self.0[136..].as_ptr(),
mem.as_mut_ptr() as *mut u8,
core::mem::size_of::<i32>(),
);
mem.assume_init()
}.from_little_endian()
}
pub fn set_e(&mut self, x: i32) {
let x_le = x.to_little_endian();
unsafe {
core::ptr::copy_nonoverlapping(
&x_le as *const i32 as *const u8,
self.0[136..].as_mut_ptr(),
core::mem::size_of::<i32>(),
);
}
}
pub fn f(&'a self) -> flatbuffers::Array<'a, i64, 2> {
flatbuffers::Array::follow(&self.0, 144)
}
pub fn set_f(&mut self, items: &[i64; 2]) {
flatbuffers::emplace_scalar_array(&mut self.0, 144, items);
}
pub fn unpack(&self) -> ArrayStructT {
ArrayStructT {
a: self.a(),
b: self.b().into(),
c: self.c(),
d: { let d = self.d(); flatbuffers::array_init(|i| d.get(i).unpack()) },
e: self.e(),
f: self.f().into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct ArrayStructT {
pub a: f32,
pub b: [i32; 15],
pub c: i8,
pub d: [NestedStructT; 2],
pub e: i32,
pub f: [i64; 2],
}
impl ArrayStructT {
pub fn pack(&self) -> ArrayStruct {
ArrayStruct::new(
self.a,
&self.b,
self.c,
&flatbuffers::array_init(|i| self.d[i].pack()),
self.e,
&self.f,
)
}
}
pub enum ArrayTableOffset {}
#[derive(Copy, Clone, PartialEq)]
pub struct ArrayTable<'a> {
pub _tab: flatbuffers::Table<'a>,
}
impl<'a> flatbuffers::Follow<'a> for ArrayTable<'a> {
type Inner = ArrayTable<'a>;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: flatbuffers::Table { buf, loc } }
}
}
impl<'a> ArrayTable<'a> {
#[inline]
pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
ArrayTable { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
_fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
args: &'args ArrayTableArgs<'args>) -> flatbuffers::WIPOffset<ArrayTable<'bldr>> {
let mut builder = ArrayTableBuilder::new(_fbb);
if let Some(x) = args.a { builder.add_a(x); }
builder.finish()
}
pub fn unpack(&self) -> ArrayTableT {
let a = self.a().map(|x| {
x.unpack()
});
ArrayTableT {
a,
}
}
pub const VT_A: flatbuffers::VOffsetT = 4;
#[inline]
pub fn a(&self) -> Option<&'a ArrayStruct> {
self._tab.get::<ArrayStruct>(ArrayTable::VT_A, None)
}
}
impl flatbuffers::Verifiable for ArrayTable<'_> {
#[inline]
fn run_verifier(
v: &mut flatbuffers::Verifier, pos: usize
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
use self::flatbuffers::Verifiable;
v.visit_table(pos)?
.visit_field::<ArrayStruct>(&"a", Self::VT_A, false)?
.finish();
Ok(())
}
}
pub struct ArrayTableArgs<'a> {
pub a: Option<&'a ArrayStruct>,
}
impl<'a> Default for ArrayTableArgs<'a> {
#[inline]
fn default() -> Self {
ArrayTableArgs {
a: None,
}
}
}
pub struct ArrayTableBuilder<'a: 'b, 'b> {
fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b> ArrayTableBuilder<'a, 'b> {
#[inline]
pub fn add_a(&mut self, a: &ArrayStruct) {
self.fbb_.push_slot_always::<&ArrayStruct>(ArrayTable::VT_A, a);
}
#[inline]
pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ArrayTableBuilder<'a, 'b> {
let start = _fbb.start_table();
ArrayTableBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn finish(self) -> flatbuffers::WIPOffset<ArrayTable<'a>> {
let o = self.fbb_.end_table(self.start_);
flatbuffers::WIPOffset::new(o.value())
}
}
impl std::fmt::Debug for ArrayTable<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut ds = f.debug_struct("ArrayTable");
ds.field("a", &self.a());
ds.finish()
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub struct ArrayTableT {
pub a: Option<ArrayStructT>,
}
impl Default for ArrayTableT {
fn default() -> Self {
Self {
a: None,
}
}
}
impl ArrayTableT {
pub fn pack<'b>(
&self,
_fbb: &mut flatbuffers::FlatBufferBuilder<'b>
) -> flatbuffers::WIPOffset<ArrayTable<'b>> {
let a_tmp = self.a.as_ref().map(|x| x.pack());
let a = a_tmp.as_ref();
ArrayTable::create(_fbb, &ArrayTableArgs{
a,
})
}
}
#[inline]
#[deprecated(since="2.0.0", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_root_as_array_table<'a>(buf: &'a [u8]) -> ArrayTable<'a> {
unsafe { flatbuffers::root_unchecked::<ArrayTable<'a>>(buf) }
}
#[inline]
#[deprecated(since="2.0.0", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_size_prefixed_root_as_array_table<'a>(buf: &'a [u8]) -> ArrayTable<'a> {
unsafe { flatbuffers::size_prefixed_root_unchecked::<ArrayTable<'a>>(buf) }
}
#[inline]
/// Verifies that a buffer of bytes contains a `ArrayTable`
/// and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_array_table_unchecked`.
pub fn root_as_array_table(buf: &[u8]) -> Result<ArrayTable, flatbuffers::InvalidFlatbuffer> {
flatbuffers::root::<ArrayTable>(buf)
}
#[inline]
/// Verifies that a buffer of bytes contains a size prefixed
/// `ArrayTable` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `size_prefixed_root_as_array_table_unchecked`.
pub fn size_prefixed_root_as_array_table(buf: &[u8]) -> Result<ArrayTable, flatbuffers::InvalidFlatbuffer> {
flatbuffers::size_prefixed_root::<ArrayTable>(buf)
}
#[inline]
/// Verifies, with the given options, that a buffer of bytes
/// contains a `ArrayTable` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_array_table_unchecked`.
pub fn root_as_array_table_with_opts<'b, 'o>(
opts: &'o flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<ArrayTable<'b>, flatbuffers::InvalidFlatbuffer> {
flatbuffers::root_with_opts::<ArrayTable<'b>>(opts, buf)
}
#[inline]
/// Verifies, with the given verifier options, that a buffer of
/// bytes contains a size prefixed `ArrayTable` and returns
/// it. Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_array_table_unchecked`.
pub fn size_prefixed_root_as_array_table_with_opts<'b, 'o>(
opts: &'o flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<ArrayTable<'b>, flatbuffers::InvalidFlatbuffer> {
flatbuffers::size_prefixed_root_with_opts::<ArrayTable<'b>>(opts, buf)
}
#[inline]
/// Assumes, without verification, that a buffer of bytes contains a ArrayTable and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid `ArrayTable`.
pub unsafe fn root_as_array_table_unchecked(buf: &[u8]) -> ArrayTable {
flatbuffers::root_unchecked::<ArrayTable>(buf)
}
#[inline]
/// Assumes, without verification, that a buffer of bytes contains a size prefixed ArrayTable and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid size prefixed `ArrayTable`.
pub unsafe fn size_prefixed_root_as_array_table_unchecked(buf: &[u8]) -> ArrayTable {
flatbuffers::size_prefixed_root_unchecked::<ArrayTable>(buf)
}
pub const ARRAY_TABLE_IDENTIFIER: &str = "ARRT";
#[inline]
pub fn array_table_buffer_has_identifier(buf: &[u8]) -> bool {
flatbuffers::buffer_has_identifier(buf, ARRAY_TABLE_IDENTIFIER, false)
}
#[inline]
pub fn array_table_size_prefixed_buffer_has_identifier(buf: &[u8]) -> bool {
flatbuffers::buffer_has_identifier(buf, ARRAY_TABLE_IDENTIFIER, true)
}
pub const ARRAY_TABLE_EXTENSION: &str = "mon";
#[inline]
pub fn finish_array_table_buffer<'a, 'b>(
fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,
root: flatbuffers::WIPOffset<ArrayTable<'a>>) {
fbb.finish(root, Some(ARRAY_TABLE_IDENTIFIER));
}
#[inline]
pub fn finish_size_prefixed_array_table_buffer<'a, 'b>(fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, root: flatbuffers::WIPOffset<ArrayTable<'a>>) {
fbb.finish_size_prefixed(root, Some(ARRAY_TABLE_IDENTIFIER));
}
} // pub mod Example
} // pub mod MyGame

View File

@@ -1,4 +1,4 @@
FROM rust:1.40.0-slim-stretch as base
FROM rust:1.51.0-slim as base
WORKDIR /code
ADD . .
RUN cp flatc_debian_stretch flatc

View File

@@ -1,4 +1,4 @@
FROM rust:1.40.0-slim-stretch as base
FROM rust:1.51.0-slim as base
RUN apt -qq update -y && apt -qq install -y \
gcc-mips-linux-gnu \
libexpat1 \

View File

@@ -57,7 +57,7 @@ set TEST_NOINCL_FLAGS=%TEST_BASE_FLAGS% --no-includes
..\%buildtype%\flatc.exe --cpp --bfbs-comments --bfbs-builtins --bfbs-gen-embed %TEST_NOINCL_FLAGS% %TEST_CPP_FLAGS% -I include_test monster_test.fbs || goto FAIL
..\%buildtype%\flatc.exe -b --schema --bfbs-comments --bfbs-builtins -I include_test arrays_test.fbs || goto FAIL
..\%buildtype%\flatc.exe --jsonschema --schema -I include_test monster_test.fbs || goto FAIL
..\%buildtype%\flatc.exe --cpp --java --csharp --jsonschema %TEST_NOINCL_FLAGS% %TEST_CPP_FLAGS% %TEST_CS_FLAGS% --scoped-enums arrays_test.fbs || goto FAIL
..\%buildtype%\flatc.exe --cpp --java --csharp --jsonschema --rust %TEST_NOINCL_FLAGS% %TEST_CPP_FLAGS% %TEST_CS_FLAGS% --scoped-enums arrays_test.fbs || goto FAIL
..\%buildtype%\flatc.exe --python %TEST_BASE_FLAGS% arrays_test.fbs || goto FAIL
..\%buildtype%\flatc.exe --cpp %TEST_BASE_FLAGS% --cpp-ptr-type flatbuffers::unique_ptr native_type_test.fbs || goto FAIL

View File

@@ -55,7 +55,7 @@ $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS $TEST_TS_FLAGS -o namespace_te
../flatc -b --schema --bfbs-comments --bfbs-builtins -I include_test arrays_test.fbs
../flatc --jsonschema --schema -I include_test monster_test.fbs
../flatc --cpp --java --kotlin --csharp --python $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS monster_extra.fbs monsterdata_extra.json
../flatc --cpp --java --csharp --jsonschema $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS --scoped-enums arrays_test.fbs
../flatc --cpp --java --csharp --jsonschema --rust $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS --scoped-enums arrays_test.fbs
../flatc --python $TEST_BASE_FLAGS arrays_test.fbs
../flatc --dart monster_extra.fbs

View File

@@ -7,7 +7,7 @@ use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
pub enum TableAOffset {}
#[derive(Copy, Clone, PartialEq)]

View File

@@ -7,7 +7,7 @@ use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod my_game {
@@ -17,7 +17,7 @@ pub mod my_game {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod other_name_space {
@@ -26,7 +26,7 @@ pub mod other_name_space {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_FROM_INCLUDE: i64 = 0;
@@ -173,7 +173,7 @@ impl<'a> flatbuffers::Verifiable for Unused {
v.in_buffer::<Self>(pos)
}
}
impl Unused {
impl<'a> Unused {
#[allow(clippy::too_many_arguments)]
pub fn new(
a: i32,

View File

@@ -8,7 +8,7 @@ use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod my_game {
@@ -19,7 +19,7 @@ pub mod my_game {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
pub enum InParentNamespaceOffset {}
#[derive(Copy, Clone, PartialEq)]
@@ -133,7 +133,7 @@ pub mod example_2 {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
pub enum MonsterOffset {}
#[derive(Copy, Clone, PartialEq)]
@@ -249,7 +249,7 @@ pub mod example {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(non_upper_case_globals)]
mod bitflags_color {
@@ -1035,7 +1035,7 @@ impl<'a> flatbuffers::Verifiable for Test {
v.in_buffer::<Self>(pos)
}
}
impl Test {
impl<'a> Test {
#[allow(clippy::too_many_arguments)]
pub fn new(
a: i16,
@@ -1188,7 +1188,7 @@ impl<'a> flatbuffers::Verifiable for Vec3 {
v.in_buffer::<Self>(pos)
}
}
impl Vec3 {
impl<'a> Vec3 {
#[allow(clippy::too_many_arguments)]
pub fn new(
x: f32,
@@ -1434,7 +1434,7 @@ impl<'a> flatbuffers::Verifiable for Ability {
v.in_buffer::<Self>(pos)
}
}
impl Ability {
impl<'a> Ability {
#[allow(clippy::too_many_arguments)]
pub fn new(
id: u32,
@@ -1594,7 +1594,7 @@ impl<'a> flatbuffers::Verifiable for StructOfStructs {
v.in_buffer::<Self>(pos)
}
}
impl StructOfStructs {
impl<'a> StructOfStructs {
#[allow(clippy::too_many_arguments)]
pub fn new(
a: &Ability,

View File

@@ -6,7 +6,7 @@ use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_ABC: i32 = 0;

View File

@@ -6,7 +6,7 @@ use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod namespace_a {
@@ -15,7 +15,7 @@ pub mod namespace_a {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod namespace_b {
@@ -23,7 +23,7 @@ pub mod namespace_b {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_UNION_IN_NESTED_NS: u8 = 0;
@@ -312,7 +312,7 @@ impl<'a> flatbuffers::Verifiable for StructInNestedNS {
v.in_buffer::<Self>(pos)
}
}
impl StructInNestedNS {
impl<'a> StructInNestedNS {
#[allow(clippy::too_many_arguments)]
pub fn new(
a: i32,

View File

@@ -6,7 +6,7 @@ use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod namespace_a {
@@ -15,7 +15,7 @@ pub mod namespace_a {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod namespace_b {
@@ -23,7 +23,7 @@ pub mod namespace_b {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_UNION_IN_NESTED_NS: u8 = 0;
@@ -312,7 +312,7 @@ impl<'a> flatbuffers::Verifiable for StructInNestedNS {
v.in_buffer::<Self>(pos)
}
}
impl StructInNestedNS {
impl<'a> StructInNestedNS {
#[allow(clippy::too_many_arguments)]
pub fn new(
a: i32,
@@ -900,7 +900,7 @@ pub mod namespace_c {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
pub enum TableInCOffset {}
#[derive(Copy, Clone, PartialEq)]

View File

@@ -6,7 +6,7 @@ use std::mem;
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[allow(unused_imports, dead_code)]
pub mod optional_scalars {
@@ -15,7 +15,7 @@ pub mod optional_scalars {
use std::cmp::Ordering;
extern crate flatbuffers;
use self::flatbuffers::EndianScalar;
use self::flatbuffers::{EndianScalar, Follow};
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_OPTIONAL_BYTE: i8 = 0;

View File

@@ -43,6 +43,7 @@ bencher = "0.1.5"
static_assertions = "1.0.0"
rand = "*"
quickcheck_derive = "*"
array-init = "2.0"
[[bench]]
# setup for bencher

View File

@@ -0,0 +1,330 @@
extern crate array_init;
#[allow(dead_code, unused_imports)]
#[path = "../../arrays_test_generated.rs"]
mod arrays_test_generated;
use std::fmt::Debug;
use crate::arrays_test_generated::my_game::example::*;
extern crate quickcheck;
use array_init::array_init;
use std::mem::size_of;
use quickcheck::{Arbitrary, Gen};
fn create_serialized_example_with_generated_code(builder: &mut flatbuffers::FlatBufferBuilder) {
let nested_struct1 = NestedStruct::new(
&[-1, 2],
TestEnum::A,
&[TestEnum::C, TestEnum::B],
&[0x1122334455667788, -0x1122334455667788],
);
let nested_struct2 = NestedStruct::new(
&[3, -4],
TestEnum::B,
&[TestEnum::B, TestEnum::A],
&[-0x1122334455667788, 0x1122334455667788],
);
let array_struct = ArrayStruct::new(
12.34,
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF],
-127,
&[nested_struct1, nested_struct2],
1,
&[-0x8000000000000000, 0x7FFFFFFFFFFFFFFF],
);
// Test five makes sense when specified.
let ss = ArrayTable::create(
builder,
&ArrayTableArgs {
a: Some(&array_struct),
},
);
finish_array_table_buffer(builder, ss);
}
fn serialized_example_is_accessible_and_correct(
bytes: &[u8],
identifier_required: bool,
size_prefixed: bool,
) {
if identifier_required {
let correct = if size_prefixed {
array_table_size_prefixed_buffer_has_identifier(bytes)
} else {
array_table_buffer_has_identifier(bytes)
};
assert_eq!(correct, true);
}
let array_table = if size_prefixed {
size_prefixed_root_as_array_table(bytes).unwrap()
} else {
root_as_array_table(bytes).unwrap()
};
let array_struct = array_table.a().unwrap();
assert_eq!(array_struct.a(), 12.34);
assert_eq!(array_struct.b().len(), 0xF);
assert_eq!(array_struct.b().iter().sum::<i32>(), 120);
assert_eq!(array_struct.c(), -127);
assert_eq!(array_struct.d().len(), 2);
let nested_struct1 = array_struct.d().get(0);
assert_eq!(nested_struct1.a().len(), 2);
assert_eq!(nested_struct1.a().iter().sum::<i32>(), 1);
assert_eq!(nested_struct1.b(), TestEnum::A);
assert_eq!(nested_struct1.c().len(), 2);
assert_eq!(nested_struct1.c().get(0), TestEnum::C);
assert_eq!(nested_struct1.c().get(1), TestEnum::B);
assert_eq!(nested_struct1.d().len(), 2);
assert_eq!(
[nested_struct1.d().get(0), nested_struct1.d().get(1)],
[0x1122334455667788, -0x1122334455667788]
);
let nested_struct2 = array_struct.d().get(1);
assert_eq!(nested_struct2.a().len(), 2);
assert_eq!(nested_struct2.a().iter().sum::<i32>(), -1);
assert_eq!(nested_struct2.b(), TestEnum::B);
assert_eq!(nested_struct2.c().len(), 2);
assert_eq!(nested_struct2.c().get(0), TestEnum::B);
assert_eq!(nested_struct2.c().get(1), TestEnum::A);
assert_eq!(nested_struct2.d().len(), 2);
let arr: [i64; 2] = nested_struct2.d().into();
assert_eq!(
arr,
[-0x1122334455667788, 0x1122334455667788]
);
assert_eq!(array_struct.e(), 1);
assert_eq!(array_struct.f().len(), 2);
assert_eq!(array_struct.f().get(0), -0x8000000000000000);
assert_eq!(array_struct.f().get(1), 0x7FFFFFFFFFFFFFFF);
}
#[test]
fn generated_code_creates_correct_example() {
let mut b = flatbuffers::FlatBufferBuilder::new();
create_serialized_example_with_generated_code(&mut b);
let buf = b.finished_data();
serialized_example_is_accessible_and_correct(&buf[..], true, false);
}
#[test]
fn struct_netsted_struct_is_32_bytes() {
assert_eq!(32, ::std::mem::size_of::<NestedStruct>());
}
#[test]
fn struct_array_struct_is_160_bytes() {
assert_eq!(160, ::std::mem::size_of::<ArrayStruct>());
}
#[test]
fn test_object_api_reads_correctly() {
let mut b = flatbuffers::FlatBufferBuilder::new();
create_serialized_example_with_generated_code(&mut b);
let array_table = root_as_array_table(b.finished_data()).unwrap().unpack();
let array_struct = array_table.a.unwrap();
assert_eq!(array_struct.a, 12.34);
assert_eq!(array_struct.b.len(), 0xF);
assert_eq!(array_struct.b.iter().sum::<i32>(), 120);
assert_eq!(array_struct.c, -127);
assert_eq!(array_struct.d.len(), 2);
let nested_struct1 = &array_struct.d[0];
assert_eq!(nested_struct1.a.len(), 2);
assert_eq!(nested_struct1.a.iter().sum::<i32>(), 1);
assert_eq!(nested_struct1.b, TestEnum::A);
assert_eq!(nested_struct1.c.len(), 2);
assert_eq!(nested_struct1.c[0], TestEnum::C);
assert_eq!(nested_struct1.c[1], TestEnum::B);
assert_eq!(nested_struct1.d.len(), 2);
assert_eq!(nested_struct1.d, [0x1122334455667788, -0x1122334455667788]);
let nested_struct2 = &array_struct.d[1];
assert_eq!(nested_struct2.a.len(), 2);
assert_eq!(nested_struct2.a.iter().sum::<i32>(), -1);
assert_eq!(nested_struct2.b, TestEnum::B);
assert_eq!(nested_struct2.c.len(), 2);
assert_eq!(nested_struct2.c[0], TestEnum::B);
assert_eq!(nested_struct2.c[1], TestEnum::A);
assert_eq!(nested_struct2.d.len(), 2);
assert_eq!(nested_struct2.d, [-0x1122334455667788, 0x1122334455667788]);
assert_eq!(array_struct.e, 1);
assert_eq!(array_struct.f.len(), 2);
assert_eq!(array_struct.f[0], -0x8000000000000000);
assert_eq!(array_struct.f[1], 0x7FFFFFFFFFFFFFFF);
}
#[test]
fn object_api_defaults() {
use arrays_test_generated::my_game::example::*;
assert_eq!(
NestedStructT::default(),
NestedStructT {
a: [0, 0],
b: TestEnum::default(),
c: [TestEnum::default(), TestEnum::default()],
d: [0, 0]
}
);
assert_eq!(
ArrayStructT::default(),
ArrayStructT {
a: 0.0,
b: [0; 0xF],
c: 0,
d: [NestedStructT::default(), NestedStructT::default()],
e: 0,
f: [0, 0]
}
);
}
#[test]
fn generated_code_debug_prints_correctly() {
let b = &mut flatbuffers::FlatBufferBuilder::new();
create_serialized_example_with_generated_code(b);
let buf = b.finished_data();
let array_table = root_as_array_table(buf).unwrap();
assert_eq!(
format!("{:.5?}", &array_table),
"ArrayTable { a: Some(ArrayStruct { a: 12.34000, \
b: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], \
c: -127, d: [NestedStruct { a: [-1, 2], b: A, c: [C, B], \
d: [1234605616436508552, -1234605616436508552] }, \
NestedStruct { a: [3, -4], b: B, c: [B, A], d: [-1234605616436508552, 1234605616436508552] }], \
e: 1, f: [-9223372036854775808, 9223372036854775807] }) }"
);
}
#[test]
#[should_panic]
fn assert_on_too_small_array_buf() {
let a = [0u8; 19];
flatbuffers::Array::<i32, 5>::new(&a);
}
#[test]
#[should_panic]
fn assert_on_too_big_array_buf() {
let a = [0u8; 21];
flatbuffers::Array::<i32, 5>::new(&a);
}
#[test]
#[cfg(target_endian = "little")]
fn verify_struct_array_alignment() {
let mut b = flatbuffers::FlatBufferBuilder::new();
create_serialized_example_with_generated_code(&mut b);
let buf = b.finished_data();
let array_table = root_as_array_table(buf).unwrap();
let array_struct = array_table.a().unwrap();
let struct_start_ptr = array_struct.0.as_ptr() as usize;
let b_start_ptr = array_struct.b().safe_slice().as_ptr() as usize;
let d_start_ptr = array_struct.d().safe_slice().as_ptr() as usize;
// The T type of b
let b_aln = ::std::mem::align_of::<i32>();
assert_eq!((b_start_ptr - struct_start_ptr) % b_aln, 0);
assert_eq!((d_start_ptr - b_start_ptr) % b_aln, 0);
assert_eq!((d_start_ptr - struct_start_ptr) % 8, 0);
}
#[derive(Clone, Debug)]
struct FakeArray<T, const N: usize>([T; N]);
impl<T: Arbitrary + Debug + PartialEq, const N: usize> Arbitrary for FakeArray<T, N> {
fn arbitrary<G: Gen>(g: &mut G) -> FakeArray<T, N> {
let x: [T; N] = array_init(|_| {
loop {
let generated_scalar = T::arbitrary(g);
// Verify that generated scalar is not Nan, which is not equals to itself,
// therefore we can't use it to validate input == output
if generated_scalar == generated_scalar { return generated_scalar }
}
});
FakeArray{0: x}
}
}
#[cfg(test)]
mod array_fuzz {
#[cfg(not(miri))] // slow.
extern crate quickcheck;
extern crate flatbuffers;
use self::flatbuffers::{Follow, Push};
use super::*;
const MAX_TESTS: u64 = 20;
const ARRAY_SIZE: usize = 29;
// This uses a macro because lifetimes for the trait-bounded function get too
// complicated.
macro_rules! impl_prop {
($test_name:ident, $fn_name:ident, $ty:ident) => (
fn $fn_name(xs: FakeArray<$ty, ARRAY_SIZE>) {
let mut test_buf = [0 as u8; 1024];
flatbuffers::emplace_scalar_array(&mut test_buf, 0, &xs.0);
let arr: flatbuffers::Array<$ty, ARRAY_SIZE> = flatbuffers::Array::follow(&test_buf, 0);
let got: [$ty; ARRAY_SIZE] = arr.into();
assert_eq!(got, xs.0);
#[cfg(target_endian = "little")]
assert_eq!(arr.safe_slice(), xs.0);
}
#[test]
fn $test_name() {
quickcheck::QuickCheck::new().max_tests(MAX_TESTS).quickcheck($fn_name as fn(FakeArray<$ty, ARRAY_SIZE>));
}
)
}
impl_prop!(test_bool, prop_bool, bool);
impl_prop!(test_u8, prop_u8, u8);
impl_prop!(test_i8, prop_i8, i8);
impl_prop!(test_u16, prop_u16, u16);
impl_prop!(test_u32, prop_u32, u32);
impl_prop!(test_u64, prop_u64, u64);
impl_prop!(test_i16, prop_i16, i16);
impl_prop!(test_i32, prop_i32, i32);
impl_prop!(test_i64, prop_i64, i64);
impl_prop!(test_f32, prop_f32, f32);
impl_prop!(test_f64, prop_f64, f64);
const NESTED_STRUCT_SIZE: usize = size_of::<NestedStruct>();
#[derive(Clone, Debug, PartialEq)]
struct NestedStructWrapper(NestedStruct);
impl Arbitrary for NestedStructWrapper {
fn arbitrary<G: Gen>(g: &mut G) -> NestedStructWrapper {
let mut x = NestedStruct::default();
x.0 = FakeArray::<u8, NESTED_STRUCT_SIZE>::arbitrary(g).0;
NestedStructWrapper{0: x}
}
}
fn prop_struct(xs: FakeArray<NestedStructWrapper, ARRAY_SIZE>) {
let mut test_buf = [0 as u8; 1024];
let native_struct_array: [&NestedStruct; ARRAY_SIZE] = array_init::from_iter(xs.0.iter().map(|x| &x.0)).unwrap();
for i in 0..ARRAY_SIZE {
let offset = i * NESTED_STRUCT_SIZE;
native_struct_array[i].push(&mut test_buf[offset..offset + NESTED_STRUCT_SIZE], &[]);
}
let arr: flatbuffers::Array<NestedStruct, ARRAY_SIZE> = flatbuffers::Array::follow(&test_buf, 0);
let got: [&NestedStruct; ARRAY_SIZE] = arr.into();
assert_eq!(got, native_struct_array);
let arr_slice = arr.safe_slice();
for i in 0..ARRAY_SIZE {
assert_eq!(arr_slice[i], *native_struct_array[i]);
}
}
#[test]
fn test_struct() {
quickcheck::QuickCheck::new().max_tests(MAX_TESTS).quickcheck(prop_struct as fn(FakeArray<NestedStructWrapper, ARRAY_SIZE>));
}
}

View File

@@ -16,7 +16,7 @@
*/
#[macro_use]
#[cfg(not(miri))] // slow.
#[cfg(not(miri))] // slow.
extern crate quickcheck;
extern crate flatbuffers;
extern crate flexbuffers;
@@ -24,13 +24,13 @@ extern crate rand;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[cfg(not(miri))] // slow.
#[cfg(not(miri))] // slow.
#[macro_use]
extern crate quickcheck_derive;
mod flexbuffers_tests;
mod optional_scalars_test;
mod more_defaults_test;
mod optional_scalars_test;
#[allow(dead_code, unused_imports)]
#[path = "../../include_test/include_test1_generated.rs"]
@@ -57,6 +57,10 @@ pub use monster_test_generated::my_game;
#[path = "../../optional_scalars_generated.rs"]
mod optional_scalars_generated;
#[allow(dead_code, unused_imports)]
#[path = "../../arrays_test_generated.rs"]
mod arrays_test_generated;
#[rustfmt::skip] // TODO: Use standard rust formatting and remove dead code.
#[allow(dead_code)]
mod flatbuffers_tests {
@@ -1509,8 +1513,7 @@ mod roundtrip_table {
assert!(values_generated > 0);
assert!(min_tests_per_choice > 0);
for i in 0..test_value_types_max as u64 {
assert!(stats[&i] >= min_tests_per_choice,
format!("inadequately-tested fuzz case: {}", i));
assert!(stats[&i] >= min_tests_per_choice, "inadequately-tested fuzz case: {}", i);
}
}