summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rust/flatbuffers/Cargo.toml1
-rw-r--r--rust/flatbuffers/src/builder.rs2
-rw-r--r--rust/flatbuffers/src/follow.rs11
-rw-r--r--rust/flatbuffers/src/get_root.rs107
-rw-r--r--rust/flatbuffers/src/lib.rs15
-rw-r--r--rust/flatbuffers/src/table.rs8
-rw-r--r--rust/flatbuffers/src/vector.rs7
-rw-r--r--rust/flatbuffers/src/verifier.rs559
-rw-r--r--samples/monster_generated.rs161
-rw-r--r--samples/sample_binary.rs5
-rw-r--r--src/idl_gen_rust.cpp469
-rw-r--r--tests/include_test/include_test1_generated.rs14
-rw-r--r--tests/include_test/sub/include_test2_generated.rs45
-rw-r--r--tests/monster_test_generated.rs391
-rw-r--r--tests/namespace_test/namespace_test1_generated.rs43
-rw-r--r--tests/namespace_test/namespace_test2_generated.rs47
-rw-r--r--tests/optional_scalars_generated.rs133
-rw-r--r--tests/rust_usage_test/bin/flatbuffers_alloc_check.rs2
-rw-r--r--tests/rust_usage_test/bin/monster_example.rs2
-rw-r--r--tests/rust_usage_test/tests/integration_test.rs132
-rw-r--r--tests/rust_usage_test/tests/optional_scalars_test.rs4
21 files changed, 1857 insertions, 301 deletions
diff --git a/rust/flatbuffers/Cargo.toml b/rust/flatbuffers/Cargo.toml
index 460c5522..ad95e673 100644
--- a/rust/flatbuffers/Cargo.toml
+++ b/rust/flatbuffers/Cargo.toml
@@ -13,3 +13,4 @@ categories = ["encoding", "data-structures", "memory-management"]
[dependencies]
smallvec = "1.0"
bitflags = "1.2"
+thiserror = "1.0"
diff --git a/rust/flatbuffers/src/builder.rs b/rust/flatbuffers/src/builder.rs
index a3c15f26..f3bfcf2d 100644
--- a/rust/flatbuffers/src/builder.rs
+++ b/rust/flatbuffers/src/builder.rs
@@ -435,7 +435,7 @@ impl<'fbb> FlatBufferBuilder<'fbb> {
// Write the vtable offset, which is the start of any Table.
// We fill its value later.
let object_revloc_to_vtable: WIPOffset<VTableWIPOffset> =
- WIPOffset::new(self.push::<UOffsetT>(0xF0F0_F0F0 as UOffsetT).value());
+ WIPOffset::new(self.push::<UOffsetT>(0xF0F0_F0F0).value());
// Layout of the data this function will create when a new vtable is
// needed.
diff --git a/rust/flatbuffers/src/follow.rs b/rust/flatbuffers/src/follow.rs
index 8dd70da0..a09003d7 100644
--- a/rust/flatbuffers/src/follow.rs
+++ b/rust/flatbuffers/src/follow.rs
@@ -27,16 +27,9 @@ use std::marker::PhantomData;
/// Writing a new Follow implementation primarily involves deciding whether
/// you want to return data (of the type Self::Inner) or do you want to
/// continue traversing the FlatBuffer.
-pub trait Follow<'a> {
+pub trait Follow<'buf> {
type Inner;
- fn follow(buf: &'a [u8], loc: usize) -> Self::Inner;
-}
-
-/// Execute a follow as a top-level function.
-#[allow(dead_code)]
-#[inline]
-pub fn lifted_follow<'a, T: Follow<'a>>(buf: &'a [u8], loc: usize) -> T::Inner {
- T::follow(buf, loc)
+ fn follow(buf: &'buf [u8], loc: usize) -> Self::Inner;
}
/// FollowStart wraps a Follow impl in a struct type. This can make certain
diff --git a/rust/flatbuffers/src/get_root.rs b/rust/flatbuffers/src/get_root.rs
new file mode 100644
index 00000000..2a01cf87
--- /dev/null
+++ b/rust/flatbuffers/src/get_root.rs
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2020 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, ForwardsUOffset, InvalidFlatbuffer, SkipSizePrefix, Verifiable, Verifier,
+ VerifierOptions,
+};
+
+/// Gets the root of the Flatbuffer, verifying it first with default options.
+/// Note that verification is an experimental feature and may not be maximally performant or
+/// catch every error (though that is the goal). See the `_unchecked` variants for previous
+/// behavior.
+pub fn root<'buf, T>(data: &'buf [u8]) -> Result<T::Inner, InvalidFlatbuffer>
+where
+ T: 'buf + Follow<'buf> + Verifiable,
+{
+ let opts = VerifierOptions::default();
+ root_with_opts::<T>(&opts, data)
+}
+
+#[inline]
+/// Gets the root of the Flatbuffer, verifying it first with given options.
+/// Note that verification is an experimental feature and may not be maximally performant or
+/// catch every error (though that is the goal). See the `_unchecked` variants for previous
+/// behavior.
+pub fn root_with_opts<'opts, 'buf, T>(
+ opts: &'opts VerifierOptions,
+ data: &'buf [u8],
+) -> Result<T::Inner, InvalidFlatbuffer>
+where
+ T: 'buf + Follow<'buf> + Verifiable,
+{
+ let mut v = Verifier::new(&opts, data);
+ <ForwardsUOffset<T>>::run_verifier(&mut v, 0)?;
+ Ok(unsafe { root_unchecked::<T>(data) })
+}
+
+#[inline]
+/// Gets the root of a size prefixed Flatbuffer, verifying it first with default options.
+/// Note that verification is an experimental feature and may not be maximally performant or
+/// catch every error (though that is the goal). See the `_unchecked` variants for previous
+/// behavior.
+pub fn size_prefixed_root<'buf, T>(data: &'buf [u8]) -> Result<T::Inner, InvalidFlatbuffer>
+where
+ T: 'buf + Follow<'buf> + Verifiable,
+{
+ let opts = VerifierOptions::default();
+ size_prefixed_root_with_opts::<T>(&opts, data)
+}
+
+#[inline]
+/// Gets the root of a size prefixed Flatbuffer, verifying it first with given options.
+/// Note that verification is an experimental feature and may not be maximally performant or
+/// catch every error (though that is the goal). See the `_unchecked` variants for previous
+/// behavior.
+pub fn size_prefixed_root_with_opts<'opts, 'buf, T>(
+ opts: &'opts VerifierOptions,
+ data: &'buf [u8],
+) -> Result<T::Inner, InvalidFlatbuffer>
+where
+ T: 'buf + Follow<'buf> + Verifiable,
+{
+ let mut v = Verifier::new(&opts, data);
+ <SkipSizePrefix<ForwardsUOffset<T>>>::run_verifier(&mut v, 0)?;
+ Ok(unsafe { size_prefixed_root_unchecked::<T>(data) })
+}
+
+#[inline]
+/// Gets root for a trusted Flatbuffer.
+/// # Safety
+/// Flatbuffers accessors do not perform validation checks before accessing. Unlike the other
+/// `root` functions, this does not validate the flatbuffer before returning the accessor. Users
+/// must trust `data` contains a valid flatbuffer (e.g. b/c it was built by your software). Reading
+/// unchecked buffers may cause panics or even UB.
+pub unsafe fn root_unchecked<'buf, T>(data: &'buf [u8]) -> T::Inner
+where
+ T: Follow<'buf> + 'buf,
+{
+ <ForwardsUOffset<T>>::follow(data, 0)
+}
+
+#[inline]
+/// Gets root for a trusted, size prefixed, Flatbuffer.
+/// # Safety
+/// Flatbuffers accessors do not perform validation checks before accessing. Unlike the other
+/// `root` functions, this does not validate the flatbuffer before returning the accessor. Users
+/// must trust `data` contains a valid flatbuffer (e.g. b/c it was built by your software). Reading
+/// unchecked buffers may cause panics or even UB.
+pub unsafe fn size_prefixed_root_unchecked<'buf, T>(data: &'buf [u8]) -> T::Inner
+where
+ T: Follow<'buf> + 'buf,
+{
+ <SkipSizePrefix<ForwardsUOffset<T>>>::follow(data, 0)
+}
diff --git a/rust/flatbuffers/src/lib.rs b/rust/flatbuffers/src/lib.rs
index 3abd33b4..77d51f82 100644
--- a/rust/flatbuffers/src/lib.rs
+++ b/rust/flatbuffers/src/lib.rs
@@ -19,26 +19,27 @@
//! A library for memory-efficient serialization of data.
//!
//! This crate provides runtime support for the FlatBuffers format in the Rust programming language.
-//! To use this crate, first generate code with the `flatc` compiler, as described here: https://google.github.io/flatbuffers/
+//! To use this crate, first generate code with the `flatc` compiler, as described here: <https://google.github.io/flatbuffers/>
//! Then, include that code into your project.
//! Finally, add this crate to your `Cargo.toml`.
//!
//! At this time, Rust support is experimental, and APIs may change between minor versions.
//!
-//! At this time, to generate Rust code, you will need the latest `master` version of `flatc`, available from here: https://github.com/google/flatbuffers
+//! 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 builder;
mod endian_scalar;
mod follow;
+mod get_root;
mod primitives;
mod push;
mod table;
mod vector;
+mod verifier;
mod vtable;
mod vtable_writer;
-pub use bitflags;
pub use crate::builder::FlatBufferBuilder;
pub use crate::endian_scalar::{
byte_swap_f32, byte_swap_f64, emplace_scalar, read_scalar, read_scalar_at, EndianScalar,
@@ -46,9 +47,15 @@ pub use crate::endian_scalar::{
pub use crate::follow::{Follow, FollowStart};
pub use crate::primitives::*;
pub use crate::push::Push;
-pub use crate::table::{buffer_has_identifier, get_root, get_size_prefixed_root, Table};
+pub use crate::table::{buffer_has_identifier, Table};
pub use crate::vector::{follow_cast_ref, SafeSliceAccess, Vector, VectorIter};
+pub use crate::verifier::{
+ ErrorTraceDetail, InvalidFlatbuffer, SimpleToVerifyInSlice, Verifiable, Verifier,
+ VerifierOptions,
+};
pub use crate::vtable::field_index_to_field_offset;
+pub use bitflags;
+pub use get_root::*;
// TODO(rw): Unify `create_vector` and `create_vector_direct` by using
// `Into<Vector<...>>`.
diff --git a/rust/flatbuffers/src/table.rs b/rust/flatbuffers/src/table.rs
index 46728cda..cfb85590 100644
--- a/rust/flatbuffers/src/table.rs
+++ b/rust/flatbuffers/src/table.rs
@@ -56,14 +56,6 @@ impl<'a> Follow<'a> for Table<'a> {
}
#[inline]
-pub fn get_root<'a, T: Follow<'a> + 'a>(data: &'a [u8]) -> T::Inner {
- <ForwardsUOffset<T>>::follow(data, 0)
-}
-#[inline]
-pub fn get_size_prefixed_root<'a, T: Follow<'a> + 'a>(data: &'a [u8]) -> T::Inner {
- <SkipSizePrefix<ForwardsUOffset<T>>>::follow(data, 0)
-}
-#[inline]
pub fn buffer_has_identifier(data: &[u8], ident: &str, size_prefixed: bool) -> bool {
assert_eq!(ident.len(), FILE_IDENTIFIER_LENGTH);
diff --git a/rust/flatbuffers/src/vector.rs b/rust/flatbuffers/src/vector.rs
index 5236ea16..c53a878c 100644
--- a/rust/flatbuffers/src/vector.rs
+++ b/rust/flatbuffers/src/vector.rs
@@ -14,12 +14,12 @@
* limitations under the License.
*/
+use std::fmt::{Debug, Formatter, Result};
use std::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator};
use std::marker::PhantomData;
use std::mem::size_of;
use std::slice::from_raw_parts;
use std::str::from_utf8_unchecked;
-use std::fmt::{Debug, Result, Formatter};
use crate::endian_scalar::read_scalar_at;
#[cfg(target_endian = "little")]
@@ -32,14 +32,13 @@ pub struct Vector<'a, T: 'a>(&'a [u8], usize, PhantomData<T>);
impl<'a, T> Debug for Vector<'a, T>
where
T: 'a + Follow<'a>,
- <T as Follow<'a>>::Inner : Debug
+ <T as Follow<'a>>::Inner: Debug,
{
fn fmt(&self, f: &mut Formatter) -> Result {
f.debug_list().entries(self.iter()).finish()
}
}
-
// We cannot use derive for these two impls, as it would only implement Copy
// and Clone for `T: Copy` and `T: Clone` respectively. However `Vector<'a, T>`
// can always be copied, no matter that `T` you have.
@@ -104,6 +103,8 @@ impl SafeSliceAccess for u8 {}
impl SafeSliceAccess for i8 {}
impl SafeSliceAccess for bool {}
+// TODO(caspern): Get rid of this. Conditional compliation is unnecessary complexity.
+// Vectors of primitives just don't work on big endian machines!!!
#[cfg(target_endian = "little")]
mod le_safe_slice_impls {
impl super::SafeSliceAccess for u16 {}
diff --git a/rust/flatbuffers/src/verifier.rs b/rust/flatbuffers/src/verifier.rs
new file mode 100644
index 00000000..f33bf922
--- /dev/null
+++ b/rust/flatbuffers/src/verifier.rs
@@ -0,0 +1,559 @@
+use crate::follow::Follow;
+use crate::{ForwardsUOffset, SOffsetT, SkipSizePrefix, UOffsetT, VOffsetT, Vector, SIZE_UOFFSET};
+use std::ops::Range;
+use thiserror::Error;
+
+/// Traces the location of data errors. Not populated for Dos detecting errors.
+/// Useful for MissingRequiredField and Utf8Error in particular, though
+/// the other errors should not be producible by correct flatbuffers implementations.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum ErrorTraceDetail {
+ VectorElement {
+ index: usize,
+ position: usize,
+ },
+ TableField {
+ field_name: &'static str,
+ position: usize,
+ },
+ UnionVariant {
+ variant: &'static str,
+ position: usize,
+ },
+}
+#[derive(PartialEq, Eq, Default, Debug, Clone)]
+pub struct ErrorTrace(Vec<ErrorTraceDetail>);
+impl std::convert::AsRef<[ErrorTraceDetail]> for ErrorTrace {
+ #[inline]
+ fn as_ref(&self) -> &[ErrorTraceDetail] {
+ &self.0
+ }
+}
+
+/// Describes how a flatuffer is invalid and, for data errors, roughly where. No extra tracing
+/// information is given for DoS detecting errors since it will probably be a lot.
+#[derive(Clone, Error, Debug, PartialEq, Eq)]
+pub enum InvalidFlatbuffer {
+ #[error("Missing required field `{required}`.\n{error_trace}")]
+ MissingRequiredField {
+ required: &'static str,
+ error_trace: ErrorTrace,
+ },
+ #[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,
+ error_trace: ErrorTrace,
+ },
+ #[error("Utf8 error for string in {range:?}: {error}\n{error_trace}")]
+ Utf8Error {
+ #[source]
+ error: std::str::Utf8Error,
+ range: Range<usize>,
+ error_trace: ErrorTrace,
+ },
+ #[error("String in range [{}, {}) is missing its null terminator.\n{error_trace}",
+ range.start, range.end)]
+ MissingNullTerminator {
+ range: Range<usize>,
+ error_trace: ErrorTrace,
+ },
+ #[error("Type `{unaligned_type}` at position {position} is unaligned.\n{error_trace}")]
+ Unaligned {
+ position: usize,
+ unaligned_type: &'static str,
+ error_trace: ErrorTrace,
+ },
+ #[error("Range [{}, {}) is out of bounds.\n{error_trace}", range.start, range.end)]
+ RangeOutOfBounds {
+ range: Range<usize>,
+ error_trace: ErrorTrace,
+ },
+ #[error("Signed offset at position {position} has value {soffset} which points out of bounds.\
+ \n{error_trace}")]
+ SignedOffsetOutOfBounds {
+ soffset: SOffsetT,
+ position: usize,
+ error_trace: ErrorTrace,
+ },
+ // Dos detecting errors. These do not get error traces since it will probably be very large.
+ #[error("Too many tables.")]
+ TooManyTables,
+ #[error("Apparent size too large.")]
+ ApparentSizeTooLarge,
+ #[error("Nested table depth limit reached.")]
+ DepthLimitReached,
+}
+
+impl std::fmt::Display for ErrorTrace {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ use ErrorTraceDetail::*;
+ for e in self.0.iter() {
+ match e {
+ VectorElement { index, position } => {
+ writeln!(
+ f,
+ "\twhile verifying vector element {:?} at position {:?}",
+ index, position
+ )?;
+ }
+ TableField {
+ field_name,
+ position,
+ } => {
+ writeln!(
+ f,
+ "\twhile verifying table field `{}` at position {:?}",
+ field_name, position
+ )?;
+ }
+ UnionVariant { variant, position } => {
+ writeln!(
+ f,
+ "\t while verifying union variant `{}` at position {:?}",
+ variant, position
+ )?;
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+pub type Result<T> = std::prelude::v1::Result<T, InvalidFlatbuffer>;
+
+impl InvalidFlatbuffer {
+ fn new_range_oob<T>(start: usize, end: usize) -> Result<T> {
+ Err(Self::RangeOutOfBounds {
+ range: Range { start, end },
+ error_trace: Default::default(),
+ })
+ }
+ fn new_inconsistent_union<T>(field: &'static str, field_type: &'static str) -> Result<T> {
+ Err(Self::InconsistentUnion {
+ field,
+ field_type,
+ error_trace: Default::default(),
+ })
+ }
+ fn new_missing_required<T>(required: &'static str) -> Result<T> {
+ Err(Self::MissingRequiredField {
+ required,
+ error_trace: Default::default(),
+ })
+ }
+}
+
+/// Records the path to the verifier detail if the error is a data error and not a DoS error.
+fn append_trace<T>(mut res: Result<T>, d: ErrorTraceDetail) -> Result<T> {
+ if let Err(e) = res.as_mut() {
+ use InvalidFlatbuffer::*;
+ if let MissingRequiredField { error_trace, .. }
+ | Unaligned { error_trace, .. }
+ | RangeOutOfBounds { error_trace, .. }
+ | InconsistentUnion { error_trace, .. }
+ | Utf8Error { error_trace, .. }
+ | MissingNullTerminator { error_trace, .. }
+ | SignedOffsetOutOfBounds { error_trace, .. } = e
+ {
+ error_trace.0.push(d)
+ }
+ }
+ res
+}
+
+/// Adds a TableField trace detail if `res` is a data error.
+fn trace_field<T>(res: Result<T>, field_name: &'static str, position: usize) -> Result<T> {
+ append_trace(
+ res,
+ ErrorTraceDetail::TableField {
+ field_name,
+ position,
+ },
+ )
+}
+/// Adds a TableField trace detail if `res` is a data error.
+fn trace_elem<T>(res: Result<T>, index: usize, position: usize) -> Result<T> {
+ append_trace(res, ErrorTraceDetail::VectorElement { index, position })
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct VerifierOptions {
+ /// Maximum depth of nested tables allowed in a valid flatbuffer.
+ pub max_depth: usize,
+ /// Maximum number of tables allowed in a valid flatbuffer.
+ pub max_tables: usize,
+ /// Maximum "apparent" size of the message if the Flatbuffer object DAG is expanded into a
+ /// tree.
+ pub max_apparent_size: usize,
+ /// Ignore errors where a string is missing its null terminator.
+ /// This is mostly a problem if the message will be sent to a client using old c-strings.
+ pub ignore_missing_null_terminator: bool,
+ // probably want an option to ignore utf8 errors since strings come from c++
+ // options to error un-recognized enums and unions? possible footgun.
+ // Ignore nested flatbuffers, etc?
+}
+impl Default for VerifierOptions {
+ fn default() -> Self {
+ Self {
+ max_depth: 64,
+ max_tables: 1_000_000,
+ // size_ might do something different.
+ max_apparent_size: 1 << 31,
+ ignore_missing_null_terminator: false,
+ }
+ }
+}
+
+/// Carries the verification state. Should not be reused between tables.
+#[derive(Debug)]
+pub struct Verifier<'opts, 'buf> {
+ buffer: &'buf [u8],
+ opts: &'opts VerifierOptions,
+ depth: usize,
+ num_tables: usize,
+ apparent_size: usize,
+}
+impl<'opts, 'buf> Verifier<'opts, 'buf> {
+ pub fn new(opts: &'opts VerifierOptions, buffer: &'buf [u8]) -> Self {
+ Self {
+ opts,
+ buffer,
+ depth: 0,
+ num_tables: 0,
+ apparent_size: 0,
+ }
+ }
+ /// Resets verifier internal state.
+ #[inline]
+ pub fn reset(&mut self) {
+ self.depth = 0;
+ self.num_tables = 0;
+ self.num_tables = 0;
+ }
+ /// Check that there really is a T in there.
+ #[inline]
+ fn is_aligned<T>(&self, pos: usize) -> Result<()> {
+ // Safe because we're not dereferencing.
+ let p = unsafe { self.buffer.as_ptr().add(pos) };
+ if (p as usize) % std::mem::align_of::<T>() == 0 {
+ Ok(())
+ } else {
+ Err(InvalidFlatbuffer::Unaligned {
+ unaligned_type: std::any::type_name::<T>(),
+ position: pos,
+ error_trace: Default::default(),
+ })
+ }
+ }
+ #[inline]
+ fn range_in_buffer(&mut self, pos: usize, size: usize) -> Result<()> {
+ let end = pos.saturating_add(size);
+ if end > self.buffer.len() {
+ return InvalidFlatbuffer::new_range_oob(pos, end);
+ }
+ self.apparent_size += size;
+ if self.apparent_size > self.opts.max_apparent_size {
+ return Err(InvalidFlatbuffer::ApparentSizeTooLarge);
+ }
+ Ok(())
+ }
+ #[inline]
+ pub fn in_buffer<T>(&mut self, pos: usize) -> Result<()> {
+ self.is_aligned::<T>(pos)?;
+ self.range_in_buffer(pos, std::mem::size_of::<T>())
+ }
+ #[inline]
+ fn get_u16(&mut self, pos: usize) -> Result<u16> {
+ self.in_buffer::<u16>(pos)?;
+ Ok(u16::from_le_bytes([self.buffer[pos], self.buffer[pos + 1]]))
+ }
+ #[inline]
+ fn get_uoffset(&mut self, pos: usize) -> Result<UOffsetT> {
+ self.in_buffer::<u32>(pos)?;
+ Ok(u32::from_le_bytes([
+ self.buffer[pos],
+ self.buffer[pos + 1],
+ self.buffer[pos + 2],
+ self.buffer[pos + 3],
+ ]))
+ }
+ #[inline]
+ fn deref_soffset(&mut self, pos: usize) -> Result<usize> {
+ self.in_buffer::<SOffsetT>(pos)?;
+ let offset = SOffsetT::from_le_bytes([
+ self.buffer[pos],
+ self.buffer[pos + 1],
+ self.buffer[pos + 2],
+ self.buffer[pos + 3],
+ ]);
+
+ // signed offsets are subtracted.
+ let derefed = if offset > 0 {
+ pos.checked_sub(offset.abs() as usize)
+ } else {
+ pos.checked_add(offset.abs() as usize)
+ };
+ if let Some(x) = derefed {
+ if x < self.buffer.len() {
+ return Ok(x);
+ }
+ }
+ Err(InvalidFlatbuffer::SignedOffsetOutOfBounds {
+ soffset: offset,
+ position: pos,
+ error_trace: Default::default(),
+ })
+ }
+ #[inline]
+ pub fn visit_table<'ver>(
+ &'ver mut self,
+ table_pos: usize,
+ ) -> Result<TableVerifier<'ver, 'opts, 'buf>> {
+ let vtable_pos = self.deref_soffset(table_pos)?;
+ let vtable_len = self.get_u16(vtable_pos)? as usize;
+ self.is_aligned::<VOffsetT>(vtable_pos.saturating_add(vtable_len))?; // i.e. vtable_len is even.
+ self.range_in_buffer(vtable_pos, vtable_len)?;
+ // Check bounds.
+ self.num_tables += 1;
+ if self.num_tables > self.opts.max_tables {
+ return Err(InvalidFlatbuffer::TooManyTables);
+ }
+ self.depth += 1;
+ if self.depth > self.opts.max_depth {
+ return Err(InvalidFlatbuffer::DepthLimitReached);
+ }
+ Ok(TableVerifier {
+ pos: table_pos,
+ vtable: vtable_pos,
+ vtable_len,
+ verifier: self,
+ })
+ }
+
+ /// Runs the union variant's type's verifier assuming the variant is at the given position,
+ /// tracing the error.
+ pub fn verify_union_variant<T: Verifiable>(
+ &mut self,
+ variant: &'static str,
+ position: usize,
+ ) -> Result<()> {
+ let res = T::run_verifier(self, position);
+ append_trace(res, ErrorTraceDetail::UnionVariant { variant, position })
+ }
+}
+
+// Cache table metadata in usize so we don't have to cast types or jump around so much.
+// We will visit every field anyway.
+pub struct TableVerifier<'ver, 'opts, 'buf> {
+ // Absolute position of table in buffer
+ pos: usize,
+ // Absolute position of vtable in buffer.
+ vtable: usize,
+ // Length of vtable.
+ vtable_len: usize,
+ // Verifier struct which holds the surrounding state and options.
+ verifier: &'ver mut Verifier<'opts, 'buf>,
+}
+impl<'ver, 'opts, 'buf> TableVerifier<'ver, 'opts, 'buf> {
+ fn deref(&mut self, field: VOffsetT) -> Result<Option<usize>> {
+ let field = field as usize;
+ if field < self.vtable_len {
+ let field_offset = self.verifier.get_u16(self.vtable.saturating_add(field))?;
+ if field_offset > 0 {
+ // Field is present.
+ let field_pos = self.pos.saturating_add(field_offset as usize);
+ return Ok(Some(field_pos));
+ }
+ }
+ Ok(None)
+ }
+
+ #[inline]
+ pub fn visit_field<T: Verifiable>(
+ mut self,
+ field_name: &'static str,
+ field: VOffsetT,
+ required: bool,
+ ) -> Result<Self> {
+ if let Some(field_pos) = self.deref(field)? {
+ trace_field(
+ T::run_verifier(self.verifier, field_pos),
+ field_name,
+ field_pos,
+ )?;
+ return Ok(self);
+ }
+ if required {
+ InvalidFlatbuffer::new_missing_required(field_name)
+ } else {
+ Ok(self)
+ }
+ }
+ #[inline]
+ /// Union verification is complicated. The schemas passes this function the metadata of the
+ /// union's key (discriminant) and value fields, and a callback. The function verifies and
+ /// reads the key, then invokes the callback to perform data-dependent verification.
+ pub fn visit_union<Key, UnionVerifier>(
+ mut self,
+ key_field_name: &'static str,
+ key_field_voff: VOffsetT,
+ val_field_name: &'static str,
+ val_field_voff: VOffsetT,
+ required: bool,
+ verify_union: UnionVerifier,
+ ) -> Result<Self>
+ where
+ Key: Follow<'buf> + Verifiable,
+ UnionVerifier:
+ (std::ops::FnOnce(<Key as Follow<'buf>>::Inner, &mut Verifier, usize) -> Result<()>),
+ // NOTE: <Key as Follow<'buf>>::Inner == Key
+ {
+ // TODO(caspern): how to trace vtable errors?
+ let val_pos = self.deref(val_field_voff)?;
+ let key_pos = self.deref(key_field_voff)?;
+ match (key_pos, val_pos) {
+ (None, None) => {
+ if required {
+ InvalidFlatbuffer::new_missing_required(val_field_name)
+ } else {
+ Ok(self)
+ }
+ }
+ (Some(k), Some(v)) => {
+ trace_field(Key::run_verifier(self.verifier, k), key_field_name, k)?;
+ let discriminant = Key::follow(self.verifier.buffer, k);
+ trace_field(
+ verify_union(discriminant, self.verifier, v),
+ val_field_name,
+ v,
+ )?;
+ Ok(self)
+ }
+ _ => InvalidFlatbuffer::new_inconsistent_union(key_field_name, val_field_name),
+ }
+ }
+ pub fn finish(self) -> &'ver mut Verifier<'opts, 'buf> {
+ self.verifier.depth -= 1;
+ self.verifier
+ }
+}
+
+// Needs to be implemented for Tables and maybe structs.
+// Unions need some special treatment.
+pub trait Verifiable {
+ /// Runs the verifier for this type, assuming its at position `pos` in the verifier's buffer.
+ /// Should not need to be called directly.
+ fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()>;
+}
+
+// Verify the uoffset and then pass verifier to the type being pointed to.
+impl<T: Verifiable> Verifiable for ForwardsUOffset<T> {
+ #[inline]
+ fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
+ let offset = v.get_uoffset(pos)? as usize;
+ let next_pos = offset.saturating_add(pos);
+ T::run_verifier(v, next_pos)
+ }
+}
+
+/// Checks and returns the range containing the flatbuffers vector.
+fn verify_vector_range<T>(v: &mut Verifier, pos: usize) -> Result<std::ops::Range<usize>> {
+ let len = v.get_uoffset(pos)? as usize;
+ let start = pos.saturating_add(SIZE_UOFFSET);
+ v.is_aligned::<T>(start)?;
+ let size = len.saturating_mul(std::mem::size_of::<T>());
+ let end = start.saturating_add(size);
+ v.range_in_buffer(start, size)?;
+ Ok(std::ops::Range { start, end })
+}
+
+pub trait SimpleToVerifyInSlice {}
+impl SimpleToVerifyInSlice for bool {}
+impl SimpleToVerifyInSlice for i8 {}
+impl SimpleToVerifyInSlice for u8 {}
+impl SimpleToVerifyInSlice for i16 {}
+impl SimpleToVerifyInSlice for u16 {}
+impl SimpleToVerifyInSlice for i32 {}
+impl SimpleToVerifyInSlice for u32 {}
+impl SimpleToVerifyInSlice for f32 {}
+impl SimpleToVerifyInSlice for i64 {}
+impl SimpleToVerifyInSlice for u64 {}
+impl SimpleToVerifyInSlice for f64 {}
+
+impl<T: SimpleToVerifyInSlice> Verifiable for Vector<'_, T> {
+ fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
+ verify_vector_range::<T>(v, pos)?;
+ Ok(())
+ }
+}
+
+impl<T: Verifiable> Verifiable for SkipSizePrefix<T> {
+ #[inline]
+ fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
+ T::run_verifier(v, pos.saturating_add(crate::SIZE_SIZEPREFIX))
+ }
+}
+
+impl<T: Verifiable> Verifiable for Vector<'_, ForwardsUOffset<T>> {
+ #[inline]
+ fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
+ let range = verify_vector_range::<ForwardsUOffset<T>>(v, pos)?;
+ let size = std::mem::size_of::<ForwardsUOffset<T>>();
+ for (i, element_pos) in range.step_by(size).enumerate() {
+ trace_elem(
+ <ForwardsUOffset<T>>::run_verifier(v, element_pos),
+ i,
+ element_pos,
+ )?;
+ }
+ Ok(())
+ }
+}
+
+impl<'a> Verifiable for &'a str {
+ #[inline]
+ fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
+ let range = verify_vector_range::<u8>(v, pos)?;
+ let has_null_terminator = v.buffer.get(range.end).map(|&b| b == 0).unwrap_or(false);
+ let s = std::str::from_utf8(&v.buffer[range.clone()]);
+ if let Err(error) = s {
+ return Err(InvalidFlatbuffer::Utf8Error {
+ error,
+ range,
+ error_trace: Default::default(),
+ });
+ }
+ if !v.opts.ignore_missing_null_terminator && !has_null_terminator {
+ return Err(InvalidFlatbuffer::MissingNullTerminator {
+ range,
+ error_trace: Default::default(),
+ });
+ }
+ Ok(())
+ }
+}
+
+// Verify VectorOfTables, Unions, Arrays, Structs...
+macro_rules! impl_verifiable_for {
+ ($T: ty) => {
+ impl Verifiable for $T {
+ #[inline]
+ fn run_verifier<'opts, 'buf>(v: &mut Verifier<'opts, 'buf>, pos: usize) -> Result<()> {
+ v.in_buffer::<$T>(pos)
+ }
+ }
+ };
+}
+impl_verifiable_for!(bool);
+impl_verifiable_for!(u8);
+impl_verifiable_for!(i8);
+impl_verifiable_for!(u16);
+impl_verifiable_for!(i16);
+impl_verifiable_for!(u32);
+impl_verifiable_for!(i32);
+impl_verifiable_for!(f32);
+impl_verifiable_for!(u64);
+impl_verifiable_for!(i64);
+impl_verifiable_for!(f64);
diff --git a/samples/monster_generated.rs b/samples/monster_generated.rs
index e352b758..53070c0d 100644
--- a/samples/monster_generated.rs
+++ b/samples/monster_generated.rs
@@ -77,7 +77,8 @@ impl<'a> flatbuffers::Follow<'a> for Color {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
- Self(flatbuffers::read_scalar_at::<i8>(buf, loc))
+ let b = flatbuffers::read_scalar_at::<i8>(buf, loc);
+ Self(b)
}
}
@@ -92,14 +93,27 @@ impl flatbuffers::Push for Color {
impl flatbuffers::EndianScalar for Color {
#[inline]
fn to_little_endian(self) -> Self {
- Self(i8::to_le(self.0))
+ let b = i8::to_le(self.0);
+ Self(b)
}
#[inline]
fn from_little_endian(self) -> Self {
- Self(i8::from_le(self.0))
+ let b = i8::from_le(self.0);
+ Self(b)
}
}
+impl<'a> flatbuffers::Verifiable for Color {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ i8::run_verifier(v, pos)
+ }
+}
+
+impl flatbuffers::SimpleToVerifyInSlice 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.")]
@@ -143,11 +157,13 @@ impl std::fmt::Debug for Equipment {
}
}
}
+pub struct EquipmentUnionTableOffset {}
impl<'a> flatbuffers::Follow<'a> for Equipment {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
- Self(flatbuffers::read_scalar_at::<u8>(buf, loc))
+ let b = flatbuffers::read_scalar_at::<u8>(buf, loc);
+ Self(b)
}
}
@@ -162,15 +178,27 @@ impl flatbuffers::Push for Equipment {
impl flatbuffers::EndianScalar for Equipment {
#[inline]
fn to_little_endian(self) -> Self {
- Self(u8::to_le(self.0))
+ let b = u8::to_le(self.0);
+ Self(b)
}
#[inline]
fn from_little_endian(self) -> Self {
- Self(u8::from_le(self.0))
+ let b = u8::from_le(self.0);
+ Self(b)
}
}
-pub struct EquipmentUnionTableOffset {}
+impl<'a> flatbuffers::Verifiable for Equipment {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl flatbuffers::SimpleToVerifyInSlice for Equipment {}
// struct Vec3, aligned to 4
#[repr(C, align(4))]
#[derive(Clone, Copy, PartialEq)]
@@ -189,6 +217,7 @@ impl std::fmt::Debug for Vec3 {
}
}
+impl flatbuffers::SimpleToVerifyInSlice for Vec3 {}
impl flatbuffers::SafeSliceAccess for Vec3 {}
impl<'a> flatbuffers::Follow<'a> for Vec3 {
type Inner = &'a Vec3;
@@ -226,7 +255,15 @@ impl<'b> flatbuffers::Push for &'b Vec3 {
}
}
-
+impl<'a> flatbuffers::Verifiable for Vec3 {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.in_buffer::<Self>(pos)
+ }
+}
impl Vec3 {
pub fn new(_x: f32, _y: f32, _z: f32) -> Self {
Vec3 {
@@ -324,7 +361,7 @@ impl<'a> Monster<'a> {
}
#[inline]
pub fn weapons(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Weapon<'a>>>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Weapon<'a>>>>>(Monster::VT_WEAPONS, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Weapon>>>>(Monster::VT_WEAPONS, None)
}
#[inline]
pub fn equipped_type(&self) -> Equipment {
@@ -336,7 +373,7 @@ impl<'a> Monster<'a> {
}
#[inline]
pub fn path(&self) -> Option<&'a [Vec3]> {
- self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<Vec3>>>(Monster::VT_PATH, None).map(|v| v.safe_slice() )
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, Vec3>>>(Monster::VT_PATH, None).map(|v| v.safe_slice())
}
#[inline]
#[allow(non_snake_case)]
@@ -350,6 +387,31 @@ impl<'a> Monster<'a> {
}
+impl flatbuffers::Verifiable for Monster<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<Vec3>(&"pos", Self::VT_POS, false)?
+ .visit_field::<i16>(&"mana", Self::VT_MANA, false)?
+ .visit_field::<i16>(&"hp", Self::VT_HP, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<&str>>(&"name", Self::VT_NAME, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, u8>>>(&"inventory", Self::VT_INVENTORY, false)?
+ .visit_field::<Color>(&"color", Self::VT_COLOR, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<Weapon>>>>(&"weapons", Self::VT_WEAPONS, false)?
+ .visit_union::<Equipment, _>(&"equipped_type", Self::VT_EQUIPPED_TYPE, &"equipped", Self::VT_EQUIPPED, false, |key, v, pos| {
+ match key {
+ Equipment::Weapon => v.verify_union_variant::<flatbuffers::ForwardsUOffset<Weapon>>("Equipment::Weapon", pos),
+ _ => Ok(()),
+ }
+ })?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, Vec3>>>(&"path", Self::VT_PATH, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct MonsterArgs<'a> {
pub pos: Option<&'a Vec3>,
pub mana: i16,
@@ -512,6 +574,19 @@ impl<'a> Weapon<'a> {
}
}
+impl flatbuffers::Verifiable for Weapon<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<flatbuffers::ForwardsUOffset<&str>>(&"name", Self::VT_NAME, false)?
+ .visit_field::<i16>(&"damage", Self::VT_DAMAGE, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct WeaponArgs<'a> {
pub name: Option<flatbuffers::WIPOffset<&'a str>>,
pub damage: i16,
@@ -562,16 +637,78 @@ impl std::fmt::Debug for Weapon<'_> {
}
}
#[inline]
+#[deprecated(since="1.13", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> {
- flatbuffers::get_root::<Monster<'a>>(buf)
+ unsafe { flatbuffers::root_unchecked::<Monster<'a>>(buf) }
}
#[inline]
+#[deprecated(since="1.13", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_size_prefixed_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> {
- flatbuffers::get_size_prefixed_root::<Monster<'a>>(buf)
+ unsafe { flatbuffers::size_prefixed_root_unchecked::<Monster<'a>>(buf) }
}
#[inline]
+/// Verifies that a buffer of bytes contains a `Monster`
+/// 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_monster_unchecked`.
+pub fn root_as_monster(buf: &[u8]) -> Result<Monster, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::root::<Monster>(buf)
+}
+#[inline]
+/// Verifies that a buffer of bytes contains a size prefixed
+/// `Monster` 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_monster_unchecked`.
+pub fn size_prefixed_root_as_monster(buf: &[u8]) -> Result<Monster, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::size_prefixed_root::<Monster>(buf)
+}
+#[inline]
+/// Verifies, with the given options, that a buffer of bytes
+/// contains a `Monster` 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_monster_unchecked`.
+pub fn root_as_monster_with_opts<'b, 'o>(
+ opts: &'o flatbuffers::VerifierOptions,
+ buf: &'b [u8],
+) -> Result<Monster<'b>, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::root_with_opts::<Monster<'b>>(opts, buf)
+}
+#[inline]
+/// Verifies, with the given verifier options, that a buffer of
+/// bytes contains a size prefixed `Monster` 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_monster_unchecked`.
+pub fn size_prefixed_root_as_monster_with_opts<'b, 'o>(
+ opts: &'o flatbuffers::VerifierOptions,
+ buf: &'b [u8],
+) -> Result<Monster<'b>, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::size_prefixed_root_with_opts::<Monster<'b>>(opts, buf)
+}
+#[inline]
+/// Assumes, without verification, that a buffer of bytes contains a Monster and returns it.
+/// # Safety
+/// Callers must trust the given bytes do indeed contain a valid `Monster`.
+pub unsafe fn root_as_monster_unchecked(buf: &[u8]) -> Monster {
+ flatbuffers::root_unchecked::<Monster>(buf)
+}
+#[inline]
+/// Assumes, without verification, that a buffer of bytes contains a size prefixed Monster and returns it.
+/// # Safety
+/// Callers must trust the given bytes do indeed contain a valid size prefixed `Monster`.
+pub unsafe fn size_prefixed_root_as_monster_unchecked(buf: &[u8]) -> Monster {
+ flatbuffers::size_prefixed_root_unchecked::<Monster>(buf)
+}
+#[inline]
pub fn finish_monster_buffer<'a, 'b>(
fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,
root: flatbuffers::WIPOffset<Monster<'a>>) {
diff --git a/samples/sample_binary.rs b/samples/sample_binary.rs
index 6fb987eb..649babf3 100644
--- a/samples/sample_binary.rs
+++ b/samples/sample_binary.rs
@@ -20,8 +20,7 @@ extern crate flatbuffers;
// import the generated code
#[path = "./monster_generated.rs"]
mod monster_generated;
-pub use monster_generated::my_game::sample::{get_root_as_monster,
- Color, Equipment,
+pub use monster_generated::my_game::sample::{Color, Equipment,
Monster, MonsterArgs,
Vec3,
Weapon, WeaponArgs};
@@ -98,7 +97,7 @@ fn main() {
let buf = builder.finished_data(); // Of type `&[u8]`
// Get access to the root:
- let monster = get_root_as_monster(buf);
+ let monster = flatbuffers::root::<Monster>(buf).unwrap();
// Get and test some scalar types from the FlatBuffer.
let hp = monster.hp();
diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp
index 3995a7f2..3c17b5cc 100644
--- a/src/idl_gen_rust.cpp
+++ b/src/idl_gen_rust.cpp
@@ -555,111 +555,93 @@ class RustGenerator : public BaseGenerator {
code_ += "pub use self::bitflags_{{ENUM_NAME_SNAKE}}::{{ENUM_NAME}};";
code_ += "";
- // Generate Follow and Push so we can serialize and stuff.
- code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
- code_ += " type Inner = Self;";
- code_ += " #[inline]";
- code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
- code_ += " let bits = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc);";
- code_ += " unsafe { Self::from_bits_unchecked(bits) }";
- code_ += " }";
- code_ += "}";
+ code_.SetValue("FROM_BASE", "unsafe { Self::from_bits_unchecked(b) }");
+ code_.SetValue("INTO_BASE", "self.bits()");
+ } else {
+ // Normal, c-modelled enums.
+ // Deprecated associated constants;
+ const std::string deprecation_warning =
+ "#[deprecated(since = \"1.13\", note = \"Use associated constants"
+ " instead. This will no longer be generated in 2021.\")]";
+ code_ += deprecation_warning;
+ code_ += "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
+ " = {{ENUM_MIN_BASE_VALUE}};";
+ code_ += deprecation_warning;
+ code_ += "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
+ " = {{ENUM_MAX_BASE_VALUE}};";
+ auto num_fields = NumToString(enum_def.size());
+ code_ += deprecation_warning;
+ code_ += "#[allow(non_camel_case_types)]";
+ code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " +
+ num_fields + "] = [";
+ ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
+ code_ += " " + GetEnumValue(enum_def, ev) + ",";
+ });
+ code_ += "];";
code_ += "";
- code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
- code_ += " type Output = {{ENUM_NAME}};";
- code_ += " #[inline]";
- code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
- code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
- "(dst, self.bits());";
- code_ += " }";
- code_ += "}";
+
+ GenComment(enum_def.doc_comment);
+ code_ +=
+ "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]";
+ code_ += "#[repr(transparent)]";
+ code_ += "pub struct {{ENUM_NAME}}(pub {{BASE_TYPE}});";
+ code_ += "#[allow(non_upper_case_globals)]";
+ code_ += "impl {{ENUM_NAME}} {";
+ ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
+ this->GenComment(ev.doc_comment, " ");
+ code_ += " pub const {{VARIANT}}: Self = Self({{VALUE}});";
+ });
code_ += "";
- code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
- code_ += " #[inline]";
- code_ += " fn to_little_endian(self) -> Self {";
- code_ += " let bits = {{BASE_TYPE}}::to_le(self.bits());";
- code_ += " unsafe { Self::from_bits_unchecked(bits) }";
- code_ += " }";
- code_ += " #[inline]";
- code_ += " fn from_little_endian(self) -> Self {";
- code_ += " let bits = {{BASE_TYPE}}::from_le(self.bits());";
- code_ += " unsafe { Self::from_bits_unchecked(bits) }";
+ // Generate Associated constants
+ code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};";
+ code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};";
+ code_ += " pub const ENUM_VALUES: &'static [Self] = &[";
+ ForAllEnumValues(enum_def, [&](){
+ code_ += " Self::{{VARIANT}},";
+ });
+ code_ += " ];";
+ code_ += " /// Returns the variant's name or \"\" if unknown.";
+ code_ += " pub fn variant_name(self) -> Option<&'static str> {";
+ code_ += " match self {";
+ ForAllEnumValues(enum_def, [&](){
+ code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),";
+ });
+ code_ += " _ => None,";
+ code_ += " }";
code_ += " }";
code_ += "}";
- code_ += "";
- return;
- }
- // Deprecated associated constants;
- code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
- " instead. This will no longer be generated in 2021.\")]";
- code_ += "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
- " = {{ENUM_MIN_BASE_VALUE}};";
- code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
- " instead. This will no longer be generated in 2021.\")]";
- code_ += "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}"
- " = {{ENUM_MAX_BASE_VALUE}};";
- auto num_fields = NumToString(enum_def.size());
- code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants"
- " instead. This will no longer be generated in 2021.\")]";
- code_ += "#[allow(non_camel_case_types)]";
- code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " +
- num_fields + "] = [";
- ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
- code_ += " " + GetEnumValue(enum_def, ev) + ",";
- });
- code_ += "];";
- code_ += "";
+ // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>".
+ code_ += "impl std::fmt::Debug for {{ENUM_NAME}} {";
+ code_ += " fn fmt(&self, f: &mut std::fmt::Formatter) ->"
+ " std::fmt::Result {";
+ code_ += " if let Some(name) = self.variant_name() {";
+ code_ += " f.write_str(name)";
+ code_ += " } else {";
+ code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))";
+ code_ += " }";
+ code_ += " }";
+ code_ += "}";
- GenComment(enum_def.doc_comment);
- code_ +=
- "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]";
- code_ += "#[repr(transparent)]";
- code_ += "pub struct {{ENUM_NAME}}(pub {{BASE_TYPE}});";
- code_ += "#[allow(non_upper_case_globals)]";
- code_ += "impl {{ENUM_NAME}} {";
- ForAllEnumValues1(enum_def, [&](const EnumVal &ev){
- this->GenComment(ev.doc_comment, " ");
- code_ += " pub const {{VARIANT}}: Self = Self({{VALUE}});";
- });
- code_ += "";
- // Generate Associated constants
- code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};";
- code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};";
- code_ += " pub const ENUM_VALUES: &'static [Self] = &[";
- ForAllEnumValues(enum_def, [&](){
- code_ += " Self::{{VARIANT}},";
- });
- code_ += " ];";
- code_ += " /// Returns the variant's name or \"\" if unknown.";
- code_ += " pub fn variant_name(self) -> Option<&'static str> {";
- code_ += " match self {";
- ForAllEnumValues(enum_def, [&](){
- code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),";
- });
- code_ += " _ => None,";
- code_ += " }";
- code_ += " }";
- code_ += "}";
+ if (enum_def.is_union) {
+ // Generate tyoesafe offset(s) for unions
+ code_.SetValue("NAME", Name(enum_def));
+ code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
+ code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
+ }
- // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>".
- code_ += "impl std::fmt::Debug for {{ENUM_NAME}} {";
- code_ += " fn fmt(&self, f: &mut std::fmt::Formatter) ->"
- " std::fmt::Result {";
- code_ += " if let Some(name) = self.variant_name() {";
- code_ += " f.write_str(name)";
- code_ += " } else {";
- code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))";
- code_ += " }";
- code_ += " }";
- code_ += "}";
+ code_.SetValue("FROM_BASE", "Self(b)");
+ code_.SetValue("INTO_BASE", "self.0");
+ }
// Generate Follow and Push so we can serialize and stuff.
code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
code_ += " type Inner = Self;";
code_ += " #[inline]";
code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
- code_ += " Self(flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc))";
+ code_ += " let b = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf,"
+ " loc);";
+ code_ += " {{FROM_BASE}}";
code_ += " }";
code_ += "}";
code_ += "";
@@ -668,28 +650,36 @@ class RustGenerator : public BaseGenerator {
code_ += " #[inline]";
code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>"
- "(dst, self.0);";
+ "(dst, {{INTO_BASE}});";
code_ += " }";
code_ += "}";
code_ += "";
code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
code_ += " #[inline]";
code_ += " fn to_little_endian(self) -> Self {";
- code_ += " Self({{BASE_TYPE}}::to_le(self.0))";
+ code_ += " let b = {{BASE_TYPE}}::to_le({{INTO_BASE}});";
+ code_ += " {{FROM_BASE}}";
code_ += " }";
code_ += " #[inline]";
code_ += " fn from_little_endian(self) -> Self {";
- code_ += " Self({{BASE_TYPE}}::from_le(self.0))";
+ code_ += " let b = {{BASE_TYPE}}::from_le({{INTO_BASE}});";
+ code_ += " {{FROM_BASE}}";
code_ += " }";
code_ += "}";
code_ += "";
-
- if (enum_def.is_union) {
- // Generate tyoesafe offset(s) for unions
- code_.SetValue("NAME", Name(enum_def));
- code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
- code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
- }
+ // Generate verifier - deferring to the base type.
+ code_ += "impl<'a> flatbuffers::Verifiable for {{ENUM_NAME}} {";
+ code_ += " #[inline]";
+ code_ += " fn run_verifier<'o, 'b>(";
+ code_ += " v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize";
+ code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
+ code_ += " use self::flatbuffers::Verifiable;";
+ code_ += " {{BASE_TYPE}}::run_verifier(v, pos)";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ // Enums are basically integers.
+ code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{ENUM_NAME}} {}";
}
std::string GetFieldOffsetName(const FieldDef &field) {
@@ -1003,109 +993,60 @@ class RustGenerator : public BaseGenerator {
return "INVALID_CODE_GENERATION"; // for return analysis
}
- std::string GenTableAccessorFuncBody(const FieldDef &field,
- const std::string &lifetime,
- const std::string &offset_prefix) {
- const std::string offset_name =
- offset_prefix + "::" + GetFieldOffsetName(field);
- const Type &type = field.value.type;
+ std::string FollowType(const Type &type, const std::string &lifetime) {
+ // IsVector... This can be made iterative?
- switch (GetFullType(field.value.type)) {
+ const auto WrapForwardsUOffset = [](std::string ty) -> std::string {
+ return "flatbuffers::ForwardsUOffset<" + ty + ">";
+ };
+ const auto WrapVector = [&](std::string ty) -> std::string {
+ return "flatbuffers::Vector<" + lifetime + ", " + ty + ">";
+ };
+ switch (GetFullType(type)) {
case ftInteger:
case ftFloat:
case ftBool: {
- const auto typname = GetTypeBasic(type);
- if (field.optional) {
- return "self._tab.get::<" + typname + ">(" + offset_name + ", None)";
- } else {
- const auto default_value = GetDefaultScalarValue(field);
- return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" +
- default_value + ")).unwrap()";
- }
+ return GetTypeBasic(type);
}
case ftStruct: {
- const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired(
- "self._tab.get::<" + typname + ">(" + offset_name + ", None)",
- field.required);
+ return WrapInNameSpace(*type.struct_def);
+ }
+ case ftUnionKey:
+ case ftEnumKey: {
+ return WrapInNameSpace(*type.enum_def);
}
case ftTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<" + typname + "<" +
- lifetime + ">>>(" + offset_name + ", None)",
- field.required);
+ return WrapForwardsUOffset(typname);
}
case ftUnionValue: {
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Table<" +
- lifetime + ">>>(" + offset_name + ", None)",
- field.required);
- }
- case ftUnionKey:
- case ftEnumKey: {
- const std::string typname = WrapInNameSpace(*type.enum_def);
- const std::string default_value = GetDefaultScalarValue(field);
- if (field.optional) {
- return "self._tab.get::<" + typname + ">(" + offset_name + ", None)";
- } else {
- return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" +
- default_value + ")).unwrap()";
- }
+ return WrapForwardsUOffset("flatbuffers::Table<" + lifetime + ">");
}
case ftString: {
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" +
- offset_name + ", None)",
- field.required);
+ return WrapForwardsUOffset("&str");
}
-
case ftVectorOfInteger:
case ftVectorOfBool:
case ftVectorOfFloat: {
const auto typname = GetTypeBasic(type.VectorType());
- std::string s =
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<" +
- lifetime + ", " + typname + ">>>(" + offset_name + ", None)";
- // single-byte values are safe to slice
- if (IsOneByte(type.VectorType().base_type)) {
- s += ".map(|v| v.safe_slice())";
- }
- return AddUnwrapIfRequired(s, field.required);
+ return WrapForwardsUOffset(WrapVector(typname));
}
case ftVectorOfEnumKey: {
- const auto typname = WrapInNameSpace(*type.enum_def);
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<" +
- lifetime + ", " + typname + ">>>(" + offset_name + ", None)",
- field.required);
+ const auto typname = WrapInNameSpace(*type.VectorType().enum_def);
+ return WrapForwardsUOffset(WrapVector(typname));
+
}
case ftVectorOfStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<" +
- typname + ">>>(" + offset_name +
- ", None).map(|v| v.safe_slice() )",
- field.required);
+ return WrapForwardsUOffset(WrapVector(typname));
}
case ftVectorOfTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" +
- typname + "<" + lifetime + ">>>>>(" + offset_name + ", None)",
- field.required);
+ return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(typname)));
}
case ftVectorOfString: {
- return AddUnwrapIfRequired(
- "self._tab.get::<flatbuffers::ForwardsUOffset<"
- "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" +
- lifetime + " str>>>>(" + offset_name + ", None)",
- field.required);
+ return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(
+ "&" + lifetime + " str")));
}
case ftVectorOfUnionValue: {
FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
@@ -1115,6 +1056,28 @@ class RustGenerator : public BaseGenerator {
return "INVALID_CODE_GENERATION"; // for return analysis
}
+ std::string GenTableAccessorFuncBody(const FieldDef &field,
+ const std::string &lifetime) {
+ const std::string vt_offset = GetFieldOffsetName(field);
+ const std::string typname = FollowType(field.value.type, lifetime);
+ // Default-y fields (scalars so far) are neither optional nor required.
+ const std::string default_value = !(field.optional || field.required) ?
+ "Some(" + GetDefaultScalarValue(field) + ")" : "None";
+ const std::string unwrap = field.optional ? "" : ".unwrap()";
+
+ const auto t = GetFullType(field.value.type);
+
+ // TODO(caspern): Shouldn't 1byte VectorOfEnumKey be slice too?
+ const std::string safe_slice = (
+ t == ftVectorOfStruct ||
+ ((t == ftVectorOfBool || t == ftVectorOfFloat || t == ftVectorOfInteger)
+ && IsOneByte(field.value.type.VectorType().base_type))
+ ) ? ".map(|v| v.safe_slice())" : "";
+
+ return "self._tab.get::<" + typname + ">({{STRUCT_NAME}}::" +
+ vt_offset + ", " + default_value + ")" + safe_slice + unwrap;
+ }
+
bool TableFieldReturnsOption(const FieldDef &field) {
if (field.optional) return true;
switch (GetFullType(field.value.type)) {
@@ -1272,17 +1235,14 @@ class RustGenerator : public BaseGenerator {
// pub fn name(&'a self) -> user_facing_type {
// self._tab.get::<internal_type>(offset, defaultval).unwrap()
// }
- const auto offset_prefix = Name(struct_def);
ForAllTableFields(struct_def, [&](const FieldDef &field) {
code_.SetValue("RETURN_TYPE",
GenTableAccessorFuncReturnType(field, "'a"));
- code_.SetValue("FUNC_BODY",
- GenTableAccessorFuncBody(field, "'a", offset_prefix));
this->GenComment(field.doc_comment, " ");
code_ += " #[inline]";
code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
- code_ += " {{FUNC_BODY}}";
+ code_ += " " + GenTableAccessorFuncBody(field, "'a");
code_ += " }";
// Generate a comparison function for this field if it is a key.
@@ -1369,6 +1329,50 @@ class RustGenerator : public BaseGenerator {
code_ += "}"; // End of table impl.
code_ += "";
+ // Generate Verifier;
+ code_ += "impl flatbuffers::Verifiable for {{STRUCT_NAME}}<'_> {";
+ code_ += " #[inline]";
+ code_ += " fn run_verifier<'o, 'b>(";
+ code_ += " v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize";
+ code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
+ code_ += " use self::flatbuffers::Verifiable;";
+ code_ += " v.visit_table(pos)?\\";
+ // Escape newline and insert it onthe next line so we can end the builder
+ // with a nice semicolon.
+ ForAllTableFields(struct_def, [&](const FieldDef &field) {
+ if (GetFullType(field.value.type) == ftUnionKey) return;
+
+ code_.SetValue("IS_REQ", field.required ? "true" : "false");
+ if (GetFullType(field.value.type) != ftUnionValue) {
+ // All types besides unions.
+ code_.SetValue("TY", FollowType(field.value.type, "'_"));
+ code_ += "\n .visit_field::<{{TY}}>(&\"{{FIELD_NAME}}\", "
+ "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\";
+ return;
+ }
+ // Unions.
+ EnumDef &union_def = *field.value.type.enum_def;
+ code_.SetValue("UNION_TYPE", Name(union_def));
+ code_ += "\n .visit_union::<{{UNION_TYPE}}, _>("
+ "&\"{{FIELD_NAME}}_type\", Self::{{OFFSET_NAME}}_TYPE, "
+ "&\"{{FIELD_NAME}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, "
+ "|key, v, pos| {";
+ code_ += " match key {";
+ ForAllUnionVariantsBesidesNone(union_def, [&](const EnumVal &unused) {
+ (void) unused;
+ code_ += " {{U_ELEMENT_ENUM_TYPE}} => v.verify_union_variant::"
+ "<flatbuffers::ForwardsUOffset<{{U_ELEMENT_TABLE_TYPE}}>>("
+ "\"{{U_ELEMENT_ENUM_TYPE}}\", pos),";
+ });
+ code_ += " _ => Ok(()),";
+ code_ += " }";
+ code_ += " })?\\";
+ });
+ code_ += "\n .finish();";
+ code_ += " Ok(())";
+ code_ += " }";
+ code_ += "}";
+
// Generate an args struct:
code_.SetValue("MAYBE_LT",
TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
@@ -1538,22 +1542,105 @@ class RustGenerator : public BaseGenerator {
// The root datatype accessors:
code_ += "#[inline]";
+ code_ += "#[deprecated(since=\"1.13\", "
+ "note=\"Deprecated in favor of `root_as...` methods.\")]";
code_ +=
"pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
" -> {{STRUCT_NAME}}<'a> {";
- code_ += " flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)";
+ code_ += " unsafe { flatbuffers::root_unchecked::<{{STRUCT_NAME}}"
+ "<'a>>(buf) }";
code_ += "}";
code_ += "";
code_ += "#[inline]";
+ code_ += "#[deprecated(since=\"1.13\", "
+ "note=\"Deprecated in favor of `root_as...` methods.\")]";
code_ +=
"pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
"<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
code_ +=
- " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
- "(buf)";
+ " unsafe { flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}"
+ "<'a>>(buf) }";
code_ += "}";
code_ += "";
+ // Default verifier root fns.
+ code_ += "#[inline]";
+ code_ += "/// Verifies that a buffer of bytes contains a `{{STRUCT_NAME}}`";
+ code_ += "/// and returns it.";
+ code_ += "/// Note that verification is still experimental and may not";
+ code_ += "/// catch every error, or be maximally performant. For the";
+ code_ += "/// previous, unchecked, behavior use";
+ code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
+ code_ += "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}(buf: &[u8]) "
+ "-> Result<{{STRUCT_NAME}}, flatbuffers::InvalidFlatbuffer> {";
+ code_ += " flatbuffers::root::<{{STRUCT_NAME}}>(buf)";
+ code_ += "}";
+ code_ += "#[inline]";
+ code_ += "/// Verifies that a buffer of bytes contains a size prefixed";
+ code_ += "/// `{{STRUCT_NAME}}` and returns it.";
+ code_ += "/// Note that verification is still experimental and may not";
+ code_ += "/// catch every error, or be maximally performant. For the";
+ code_ += "/// previous, unchecked, behavior use";
+ code_ += "/// `size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
+ code_ += "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
+ "(buf: &[u8]) -> Result<{{STRUCT_NAME}}, "
+ "flatbuffers::InvalidFlatbuffer> {";
+ code_ += " flatbuffers::size_prefixed_root::<{{STRUCT_NAME}}>(buf)";
+ code_ += "}";
+ // Verifier with options root fns.
+ code_ += "#[inline]";
+ code_ += "/// Verifies, with the given options, that a buffer of bytes";
+ code_ += "/// contains a `{{STRUCT_NAME}}` and returns it.";
+ code_ += "/// Note that verification is still experimental and may not";
+ code_ += "/// catch every error, or be maximally performant. For the";
+ code_ += "/// previous, unchecked, behavior use";
+ code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
+ code_ += "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts<'b, 'o>(";
+ code_ += " opts: &'o flatbuffers::VerifierOptions,";
+ code_ += " buf: &'b [u8],";
+ code_ += ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>"
+ " {";
+ code_ += " flatbuffers::root_with_opts::<{{STRUCT_NAME}}<'b>>(opts, buf)";
+ code_ += "}";
+ code_ += "#[inline]";
+ code_ += "/// Verifies, with the given verifier options, that a buffer of";
+ code_ += "/// bytes contains a size prefixed `{{STRUCT_NAME}}` and returns";
+ code_ += "/// it. Note that verification is still experimental and may not";
+ code_ += "/// catch every error, or be maximally performant. For the";
+ code_ += "/// previous, unchecked, behavior use";
+ code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`.";
+ code_ += "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts"
+ "<'b, 'o>(";
+ code_ += " opts: &'o flatbuffers::VerifierOptions,";
+ code_ += " buf: &'b [u8],";
+ code_ += ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>"
+ " {";
+ code_ += " flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_NAME}}"
+ "<'b>>(opts, buf)";
+ code_ += "}";
+ // Unchecked root fns.
+ code_ += "#[inline]";
+ code_ += "/// Assumes, without verification, that a buffer of bytes "
+ "contains a {{STRUCT_NAME}} and returns it.";
+ code_ += "/// # Safety";
+ code_ += "/// Callers must trust the given bytes do indeed contain a valid"
+ " `{{STRUCT_NAME}}`.";
+ code_ += "pub unsafe fn root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked"
+ "(buf: &[u8]) -> {{STRUCT_NAME}} {";
+ code_ += " flatbuffers::root_unchecked::<{{STRUCT_NAME}}>(buf)";
+ code_ += "}";
+ code_ += "#[inline]";
+ code_ += "/// Assumes, without verification, that a buffer of bytes "
+ "contains a size prefixed {{STRUCT_NAME}} and returns it.";
+ code_ += "/// # Safety";
+ code_ += "/// Callers must trust the given bytes do indeed contain a valid"
+ " size prefixed `{{STRUCT_NAME}}`.";
+ code_ += "pub unsafe fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
+ "_unchecked(buf: &[u8]) -> {{STRUCT_NAME}} {";
+ code_ += " flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}>"
+ "(buf)";
+ code_ += "}";
+
if (parser_.file_identifier_.length()) {
// Declare the identifier
@@ -1697,6 +1784,7 @@ class RustGenerator : public BaseGenerator {
// Generate impls for SafeSliceAccess (because all structs are endian-safe),
// Follow for the value type, Follow for the reference type, Push for the
// value type, and Push for the reference type.
+ code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{STRUCT_NAME}} {}";
code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
code_ += " type Inner = &'a {{STRUCT_NAME}};";
@@ -1738,7 +1826,18 @@ class RustGenerator : public BaseGenerator {
code_ += " }";
code_ += "}";
code_ += "";
- code_ += "";
+
+ // Generate verifier: Structs are simple so presence and alignment are
+ // all that need to be checked.
+ code_ += "impl<'a> flatbuffers::Verifiable for {{STRUCT_NAME}} {";
+ code_ += " #[inline]";
+ code_ += " fn run_verifier<'o, 'b>(";
+ code_ += " v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize";
+ code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {";
+ code_ += " use self::flatbuffers::Verifiable;";
+ code_ += " v.in_buffer::<Self>(pos)";
+ code_ += " }";
+ code_ += "}";
// Generate a constructor that takes all fields as arguments.
code_ += "impl {{STRUCT_NAME}} {";
diff --git a/tests/include_test/include_test1_generated.rs b/tests/include_test/include_test1_generated.rs
index 3c7b9bd8..cf63626e 100644
--- a/tests/include_test/include_test1_generated.rs
+++ b/tests/include_test/include_test1_generated.rs
@@ -45,10 +45,22 @@ impl<'a> TableA<'a> {
#[inline]
pub fn b(&self) -> Option<my_game::other_name_space::TableB<'a>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<my_game::other_name_space::TableB<'a>>>(TableA::VT_B, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<my_game::other_name_space::TableB>>(TableA::VT_B, None)
}
}
+impl flatbuffers::Verifiable for TableA<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<flatbuffers::ForwardsUOffset<my_game::other_name_space::TableB>>(&"b", Self::VT_B, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct TableAArgs<'a> {
pub b: Option<flatbuffers::WIPOffset<my_game::other_name_space::TableB<'a>>>,
}
diff --git a/tests/include_test/sub/include_test2_generated.rs b/tests/include_test/sub/include_test2_generated.rs
index 892c652d..a461b82a 100644
--- a/tests/include_test/sub/include_test2_generated.rs
+++ b/tests/include_test/sub/include_test2_generated.rs
@@ -72,7 +72,8 @@ impl<'a> flatbuffers::Follow<'a> for FromInclude {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
- Self(flatbuffers::read_scalar_at::<i64>(buf, loc))
+ let b = flatbuffers::read_scalar_at::<i64>(buf, loc);
+ Self(b)
}
}
@@ -87,14 +88,27 @@ impl flatbuffers::Push for FromInclude {
impl flatbuffers::EndianScalar for FromInclude {
#[inline]
fn to_little_endian(self) -> Self {
- Self(i64::to_le(self.0))
+ let b = i64::to_le(self.0);
+ Self(b)
}
#[inline]
fn from_little_endian(self) -> Self {
- Self(i64::from_le(self.0))
+ let b = i64::from_le(self.0);
+ Self(b)
}
}
+impl<'a> flatbuffers::Verifiable for FromInclude {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ i64::run_verifier(v, pos)
+ }
+}
+
+impl flatbuffers::SimpleToVerifyInSlice for FromInclude {}
// struct Unused, aligned to 4
#[repr(C, align(4))]
#[derive(Clone, Copy, PartialEq)]
@@ -109,6 +123,7 @@ impl std::fmt::Debug for Unused {
}
}
+impl flatbuffers::SimpleToVerifyInSlice for Unused {}
impl flatbuffers::SafeSliceAccess for Unused {}
impl<'a> flatbuffers::Follow<'a> for Unused {
type Inner = &'a Unused;
@@ -146,7 +161,15 @@ impl<'b> flatbuffers::Push for &'b Unused {
}
}
-
+impl<'a> flatbuffers::Verifiable for Unused {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.in_buffer::<Self>(pos)
+ }
+}
impl Unused {
pub fn new(_a: i32) -> Self {
Unused {
@@ -194,10 +217,22 @@ impl<'a> TableB<'a> {
#[inline]
pub fn a(&self) -> Option<super::super::TableA<'a>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<super::super::TableA<'a>>>(TableB::VT_A, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<super::super::TableA>>(TableB::VT_A, None)
}
}
+impl flatbuffers::Verifiable for TableB<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<flatbuffers::ForwardsUOffset<super::super::TableA>>(&"a", Self::VT_A, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct TableBArgs<'a> {
pub a: Option<flatbuffers::WIPOffset<super::super::TableA<'a>>>,
}
diff --git a/tests/monster_test_generated.rs b/tests/monster_test_generated.rs
index e6539335..f38ce6ad 100644
--- a/tests/monster_test_generated.rs
+++ b/tests/monster_test_generated.rs
@@ -58,6 +58,17 @@ impl<'a> InParentNamespace<'a> {
}
+impl flatbuffers::Verifiable for InParentNamespace<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .finish();
+ Ok(())
+ }
+}
pub struct InParentNamespaceArgs {
}
impl<'a> Default for InParentNamespaceArgs {
@@ -140,6 +151,17 @@ impl<'a> Monster<'a> {
}
+impl flatbuffers::Verifiable for Monster<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .finish();
+ Ok(())
+ }
+}
pub struct MonsterArgs {
}
impl<'a> Default for MonsterArgs {
@@ -208,8 +230,8 @@ impl<'a> flatbuffers::Follow<'a> for Color {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
- let bits = flatbuffers::read_scalar_at::<u8>(buf, loc);
- unsafe { Self::from_bits_unchecked(bits) }
+ let b = flatbuffers::read_scalar_at::<u8>(buf, loc);
+ unsafe { Self::from_bits_unchecked(b) }
}
}
@@ -224,16 +246,27 @@ impl flatbuffers::Push for Color {
impl flatbuffers::EndianScalar for Color {
#[inline]
fn to_little_endian(self) -> Self {
- let bits = u8::to_le(self.bits());
- unsafe { Self::from_bits_unchecked(bits) }
+ let b = u8::to_le(self.bits());
+ unsafe { Self::from_bits_unchecked(b) }
}
#[inline]
fn from_little_endian(self) -> Self {
- let bits = u8::from_le(self.bits());
- unsafe { Self::from_bits_unchecked(bits) }
+ let b = u8::from_le(self.bits());
+ unsafe { Self::from_bits_unchecked(b) }
+ }
+}
+
+impl<'a> flatbuffers::Verifiable for Color {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ u8::run_verifier(v, pos)
}
}
+impl flatbuffers::SimpleToVerifyInSlice for Color {}
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_RACE: i8 = -1;
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
@@ -289,7 +322,8 @@ impl<'a> flatbuffers::Follow<'a> for Race {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
- Self(flatbuffers::read_scalar_at::<i8>(buf, loc))
+ let b = flatbuffers::read_scalar_at::<i8>(buf, loc);
+ Self(b)
}
}
@@ -304,14 +338,27 @@ impl flatbuffers::Push for Race {
impl flatbuffers::EndianScalar for Race {
#[inline]
fn to_little_endian(self) -> Self {
- Self(i8::to_le(self.0))
+ let b = i8::to_le(self.0);
+ Self(b)
}
#[inline]
fn from_little_endian(self) -> Self {
- Self(i8::from_le(self.0))
+ let b = i8::from_le(self.0);
+ Self(b)
}
}
+impl<'a> flatbuffers::Verifiable for Race {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ i8::run_verifier(v, pos)
+ }
+}
+
+impl flatbuffers::SimpleToVerifyInSlice for Race {}
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_ANY: u8 = 0;
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
@@ -363,11 +410,13 @@ impl std::fmt::Debug for Any {
}
}
}
+pub struct AnyUnionTableOffset {}
impl<'a> flatbuffers::Follow<'a> for Any {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
- Self(flatbuffers::read_scalar_at::<u8>(buf, loc))
+ let b = flatbuffers::read_scalar_at::<u8>(buf, loc);
+ Self(b)
}
}
@@ -382,15 +431,27 @@ impl flatbuffers::Push for Any {
impl flatbuffers::EndianScalar for Any {
#[inline]
fn to_little_endian(self) -> Self {
- Self(u8::to_le(self.0))
+ let b = u8::to_le(self.0);
+ Self(b)
}
#[inline]
fn from_little_endian(self) -> Self {
- Self(u8::from_le(self.0))
+ let b = u8::from_le(self.0);
+ Self(b)
}
}
-pub struct AnyUnionTableOffset {}
+impl<'a> flatbuffers::Verifiable for Any {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl flatbuffers::SimpleToVerifyInSlice for Any {}
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_ANY_UNIQUE_ALIASES: u8 = 0;
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
@@ -442,11 +503,13 @@ impl std::fmt::Debug for AnyUniqueAliases {
}
}
}
+pub struct AnyUniqueAliasesUnionTableOffset {}
impl<'a> flatbuffers::Follow<'a> for AnyUniqueAliases {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
- Self(flatbuffers::read_scalar_at::<u8>(buf, loc))
+ let b = flatbuffers::read_scalar_at::<u8>(buf, loc);
+ Self(b)
}
}
@@ -461,15 +524,27 @@ impl flatbuffers::Push for AnyUniqueAliases {
impl flatbuffers::EndianScalar for AnyUniqueAliases {
#[inline]
fn to_little_endian(self) -> Self {
- Self(u8::to_le(self.0))
+ let b = u8::to_le(self.0);
+ Self(b)
}
#[inline]
fn from_little_endian(self) -> Self {
- Self(u8::from_le(self.0))
+ let b = u8::from_le(self.0);
+ Self(b)
}
}
-pub struct AnyUniqueAliasesUnionTableOffset {}
+impl<'a> flatbuffers::Verifiable for AnyUniqueAliases {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl flatbuffers::SimpleToVerifyInSlice for AnyUniqueAliases {}
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_ANY_AMBIGUOUS_ALIASES: u8 = 0;
#[deprecated(since = "1.13", note = "Use associated constants instead. This will no longer be generated in 2021.")]
@@ -521,11 +596,13 @@ impl std::fmt::Debug for AnyAmbiguousAliases {
}
}
}
+pub struct AnyAmbiguousAliasesUnionTableOffset {}
impl<'a> flatbuffers::Follow<'a> for AnyAmbiguousAliases {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
- Self(flatbuffers::read_scalar_at::<u8>(buf, loc))
+ let b = flatbuffers::read_scalar_at::<u8>(buf, loc);
+ Self(b)
}
}
@@ -540,15 +617,27 @@ impl flatbuffers::Push for AnyAmbiguousAliases {
impl flatbuffers::EndianScalar for AnyAmbiguousAliases {
#[inline]
fn to_little_endian(self) -> Self {
- Self(u8::to_le(self.0))
+ let b = u8::to_le(self.0);
+ Self(b)
}
#[inline]
fn from_little_endian(self) -> Self {
- Self(u8::from_le(self.0))
+ let b = u8::from_le(self.0);
+ Self(b)
}
}
-pub struct AnyAmbiguousAliasesUnionTableOffset {}
+impl<'a> flatbuffers::Verifiable for AnyAmbiguousAliases {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ u8::run_verifier(v, pos)
+ }
+}
+
+impl flatbuffers::SimpleToVerifyInSlice for AnyAmbiguousAliases {}
// struct Test, aligned to 2
#[repr(C, align(2))]
#[derive(Clone, Copy, PartialEq)]
@@ -566,6 +655,7 @@ impl std::fmt::Debug for Test {
}
}
+impl flatbuffers::SimpleToVerifyInSlice for Test {}
impl flatbuffers::SafeSliceAccess for Test {}
impl<'a> flatbuffers::Follow<'a> for Test {
type Inner = &'a Test;
@@ -603,7 +693,15 @@ impl<'b> flatbuffers::Push for &'b Test {
}
}
-
+impl<'a> flatbuffers::Verifiable for Test {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.in_buffer::<Self>(pos)
+ }
+}
impl Test {
pub fn new(_a: i16, _b: i8) -> Self {
Test {
@@ -652,6 +750,7 @@ impl std::fmt::Debug for Vec3 {
}
}
+impl flatbuffers::SimpleToVerifyInSlice for Vec3 {}
impl flatbuffers::SafeSliceAccess for Vec3 {}
impl<'a> flatbuffers::Follow<'a> for Vec3 {
type Inner = &'a Vec3;
@@ -689,7 +788,15 @@ impl<'b> flatbuffers::Push for &'b Vec3 {
}
}
-
+impl<'a> flatbuffers::Verifiable for Vec3 {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.in_buffer::<Self>(pos)
+ }
+}
impl Vec3 {
pub fn new(_x: f32, _y: f32, _z: f32, _test1: f64, _test2: Color, _test3: &Test) -> Self {
Vec3 {
@@ -745,6 +852,7 @@ impl std::fmt::Debug for Ability {
}
}
+impl flatbuffers::SimpleToVerifyInSlice for Ability {}
impl flatbuffers::SafeSliceAccess for Ability {}
impl<'a> flatbuffers::Follow<'a> for Ability {
type Inner = &'a Ability;
@@ -782,7 +890,15 @@ impl<'b> flatbuffers::Push for &'b Ability {
}
}
-
+impl<'a> flatbuffers::Verifiable for Ability {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.in_buffer::<Self>(pos)
+ }
+}
impl Ability {
pub fn new(_id: u32, _distance: u32) -> Self {
Ability {
@@ -856,6 +972,18 @@ impl<'a> TestSimpleTableWithEnum<'a> {
}
}
+impl flatbuffers::Verifiable for TestSimpleTableWithEnum<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<Color>(&"color", Self::VT_COLOR, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct TestSimpleTableWithEnumArgs {
pub color: Color,
}
@@ -953,6 +1081,20 @@ impl<'a> Stat<'a> {
}
}
+impl flatbuffers::Verifiable for Stat<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<flatbuffers::ForwardsUOffset<&str>>(&"id", Self::VT_ID, false)?
+ .visit_field::<i64>(&"val", Self::VT_VAL, false)?
+ .visit_field::<u16>(&"count", Self::VT_COUNT, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct StatArgs<'a> {
pub id: Option<flatbuffers::WIPOffset<&'a str>>,
pub val: i64,
@@ -1062,6 +1204,18 @@ impl<'a> Referrable<'a> {
}
}
+impl flatbuffers::Verifiable for Referrable<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<u64>(&"id", Self::VT_ID, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct ReferrableArgs {
pub id: u64,
}
@@ -1282,21 +1436,21 @@ impl<'a> Monster<'a> {
}
#[inline]
pub fn test4(&self) -> Option<&'a [Test]> {
- self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<Test>>>(Monster::VT_TEST4, None).map(|v| v.safe_slice() )
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, Test>>>(Monster::VT_TEST4, None).map(|v| v.safe_slice())
}
#[inline]
pub fn testarrayofstring(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<&'a str>>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<&'a str>>>>(Monster::VT_TESTARRAYOFSTRING, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<&'a str>>>>(Monster::VT_TESTARRAYOFSTRING, None)
}
/// an example documentation comment: this will end up in the generated code
/// multiline too
#[inline]
pub fn testarrayoftables(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Monster<'a>>>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Monster<'a>>>>>(Monster::VT_TESTARRAYOFTABLES, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Monster>>>>(Monster::VT_TESTARRAYOFTABLES, None)
}
#[inline]
pub fn enemy(&self) -> Option<Monster<'a>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<Monster<'a>>>(Monster::VT_ENEMY, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<Monster>>(Monster::VT_ENEMY, None)
}
#[inline]
pub fn testnestedflatbuffer(&self) -> Option<&'a [u8]> {
@@ -1310,7 +1464,7 @@ impl<'a> Monster<'a> {
}
#[inline]
pub fn testempty(&self) -> Option<Stat<'a>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<Stat<'a>>>(Monster::VT_TESTEMPTY, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<Stat>>(Monster::VT_TESTEMPTY, None)
}
#[inline]
pub fn testbool(&self) -> bool {
@@ -1366,11 +1520,11 @@ impl<'a> Monster<'a> {
}
#[inline]
pub fn testarrayofstring2(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<&'a str>>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<&'a str>>>>(Monster::VT_TESTARRAYOFSTRING2, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<&'a str>>>>(Monster::VT_TESTARRAYOFSTRING2, None)
}
#[inline]
pub fn testarrayofsortedstruct(&self) -> Option<&'a [Ability]> {
- self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<Ability>>>(Monster::VT_TESTARRAYOFSORTEDSTRUCT, None).map(|v| v.safe_slice() )
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, Ability>>>(Monster::VT_TESTARRAYOFSORTEDSTRUCT, None).map(|v| v.safe_slice())
}
#[inline]
pub fn flex(&self) -> Option<&'a [u8]> {
@@ -1378,7 +1532,7 @@ impl<'a> Monster<'a> {
}
#[inline]
pub fn test5(&self) -> Option<&'a [Test]> {
- self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<Test>>>(Monster::VT_TEST5, None).map(|v| v.safe_slice() )
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, Test>>>(Monster::VT_TEST5, None).map(|v| v.safe_slice())
}
#[inline]
pub fn vector_of_longs(&self) -> Option<flatbuffers::Vector<'a, i64>> {
@@ -1390,11 +1544,11 @@ impl<'a> Monster<'a> {
}
#[inline]
pub fn parent_namespace_test(&self) -> Option<super::InParentNamespace<'a>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<super::InParentNamespace<'a>>>(Monster::VT_PARENT_NAMESPACE_TEST, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<super::InParentNamespace>>(Monster::VT_PARENT_NAMESPACE_TEST, None)
}
#[inline]
pub fn vector_of_referrables(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Referrable<'a>>>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Referrable<'a>>>>>(Monster::VT_VECTOR_OF_REFERRABLES, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Referrable>>>>(Monster::VT_VECTOR_OF_REFERRABLES, None)
}
#[inline]
pub fn single_weak_reference(&self) -> u64 {
@@ -1406,7 +1560,7 @@ impl<'a> Monster<'a> {
}
#[inline]
pub fn vector_of_strong_referrables(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Referrable<'a>>>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Referrable<'a>>>>>(Monster::VT_VECTOR_OF_STRONG_REFERRABLES, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Referrable>>>>(Monster::VT_VECTOR_OF_STRONG_REFERRABLES, None)
}
#[inline]
pub fn co_owning_reference(&self) -> u64 {
@@ -1550,6 +1704,84 @@ impl<'a> Monster<'a> {
}
+impl flatbuffers::Verifiable for Monster<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<Vec3>(&"pos", Self::VT_POS, false)?
+ .visit_field::<i16>(&"mana", Self::VT_MANA, false)?
+ .visit_field::<i16>(&"hp", Self::VT_HP, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<&str>>(&"name", Self::VT_NAME, true)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, u8>>>(&"inventory", Self::VT_INVENTORY, false)?
+ .visit_field::<Color>(&"color", Self::VT_COLOR, false)?
+ .visit_union::<Any, _>(&"test_type", Self::VT_TEST_TYPE, &"test", Self::VT_TEST, false, |key, v, pos| {
+ match key {
+ Any::Monster => v.verify_union_variant::<flatbuffers::ForwardsUOffset<Monster>>("Any::Monster", pos),
+ Any::TestSimpleTableWithEnum => v.verify_union_variant::<flatbuffers::ForwardsUOffset<TestSimpleTableWithEnum>>("Any::TestSimpleTableWithEnum", pos),
+ Any::MyGame_Example2_Monster => v.verify_union_variant::<flatbuffers::ForwardsUOffset<super::example_2::Monster>>("Any::MyGame_Example2_Monster", pos),
+ _ => Ok(()),
+ }
+ })?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, Test>>>(&"test4", Self::VT_TEST4, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<&'_ str>>>>(&"testarrayofstring", Self::VT_TESTARRAYOFSTRING, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<Monster>>>>(&"testarrayoftables", Self::VT_TESTARRAYOFTABLES, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<Monster>>(&"enemy", Self::VT_ENEMY, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, u8>>>(&"testnestedflatbuffer", Self::VT_TESTNESTEDFLATBUFFER, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<Stat>>(&"testempty", Self::VT_TESTEMPTY, false)?
+ .visit_field::<bool>(&"testbool", Self::VT_TESTBOOL, false)?
+ .visit_field::<i32>(&"testhashs32_fnv1", Self::VT_TESTHASHS32_FNV1, false)?
+ .visit_field::<u32>(&"testhashu32_fnv1", Self::VT_TESTHASHU32_FNV1, false)?
+ .visit_field::<i64>(&"testhashs64_fnv1", Self::VT_TESTHASHS64_FNV1, false)?
+ .visit_field::<u64>(&"testhashu64_fnv1", Self::VT_TESTHASHU64_FNV1, false)?
+ .visit_field::<i32>(&"testhashs32_fnv1a", Self::VT_TESTHASHS32_FNV1A, false)?
+ .visit_field::<u32>(&"testhashu32_fnv1a", Self::VT_TESTHASHU32_FNV1A, false)?
+ .visit_field::<i64>(&"testhashs64_fnv1a", Self::VT_TESTHASHS64_FNV1A, false)?
+ .visit_field::<u64>(&"testhashu64_fnv1a", Self::VT_TESTHASHU64_FNV1A, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, bool>>>(&"testarrayofbools", Self::VT_TESTARRAYOFBOOLS, false)?
+ .visit_field::<f32>(&"testf", Self::VT_TESTF, false)?
+ .visit_field::<f32>(&"testf2", Self::VT_TESTF2, false)?
+ .visit_field::<f32>(&"testf3", Self::VT_TESTF3, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<&'_ str>>>>(&"testarrayofstring2", Self::VT_TESTARRAYOFSTRING2, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, Ability>>>(&"testarrayofsortedstruct", Self::VT_TESTARRAYOFSORTEDSTRUCT, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, u8>>>(&"flex", Self::VT_FLEX, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, Test>>>(&"test5", Self::VT_TEST5, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, i64>>>(&"vector_of_longs", Self::VT_VECTOR_OF_LONGS, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, f64>>>(&"vector_of_doubles", Self::VT_VECTOR_OF_DOUBLES, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<super::InParentNamespace>>(&"parent_namespace_test", Self::VT_PARENT_NAMESPACE_TEST, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<Referrable>>>>(&"vector_of_referrables", Self::VT_VECTOR_OF_REFERRABLES, false)?
+ .visit_field::<u64>(&"single_weak_reference", Self::VT_SINGLE_WEAK_REFERENCE, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, u64>>>(&"vector_of_weak_references", Self::VT_VECTOR_OF_WEAK_REFERENCES, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<Referrable>>>>(&"vector_of_strong_referrables", Self::VT_VECTOR_OF_STRONG_REFERRABLES, false)?
+ .visit_field::<u64>(&"co_owning_reference", Self::VT_CO_OWNING_REFERENCE, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, u64>>>(&"vector_of_co_owning_references", Self::VT_VECTOR_OF_CO_OWNING_REFERENCES, false)?
+ .visit_field::<u64>(&"non_owning_reference", Self::VT_NON_OWNING_REFERENCE, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, u64>>>(&"vector_of_non_owning_references", Self::VT_VECTOR_OF_NON_OWNING_REFERENCES, false)?
+ .visit_union::<AnyUniqueAliases, _>(&"any_unique_type", Self::VT_ANY_UNIQUE_TYPE, &"any_unique", Self::VT_ANY_UNIQUE, false, |key, v, pos| {
+ match key {
+ AnyUniqueAliases::M => v.verify_union_variant::<flatbuffers::ForwardsUOffset<Monster>>("AnyUniqueAliases::M", pos),
+ AnyUniqueAliases::TS => v.verify_union_variant::<flatbuffers::ForwardsUOffset<TestSimpleTableWithEnum>>("AnyUniqueAliases::TS", pos),
+ AnyUniqueAliases::M2 => v.verify_union_variant::<flatbuffers::ForwardsUOffset<super::example_2::Monster>>("AnyUniqueAliases::M2", pos),
+ _ => Ok(()),
+ }
+ })?
+ .visit_union::<AnyAmbiguousAliases, _>(&"any_ambiguous_type", Self::VT_ANY_AMBIGUOUS_TYPE, &"any_ambiguous", Self::VT_ANY_AMBIGUOUS, false, |key, v, pos| {
+ match key {
+ AnyAmbiguousAliases::M1 => v.verify_union_variant::<flatbuffers::ForwardsUOffset<Monster>>("AnyAmbiguousAliases::M1", pos),
+ AnyAmbiguousAliases::M2 => v.verify_union_variant::<flatbuffers::ForwardsUOffset<Monster>>("AnyAmbiguousAliases::M2", pos),
+ AnyAmbiguousAliases::M3 => v.verify_union_variant::<flatbuffers::ForwardsUOffset<Monster>>("AnyAmbiguousAliases::M3", pos),
+ _ => Ok(()),
+ }
+ })?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, Color>>>(&"vector_of_enums", Self::VT_VECTOR_OF_ENUMS, false)?
+ .visit_field::<Race>(&"signed_enum", Self::VT_SIGNED_ENUM, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, u8>>>(&"testrequirednestedflatbuffer", Self::VT_TESTREQUIREDNESTEDFLATBUFFER, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct MonsterArgs<'a> {
pub pos: Option<&'a Vec3>,
pub mana: i16,
@@ -2116,6 +2348,29 @@ impl<'a> TypeAliases<'a> {
}
}
+impl flatbuffers::Verifiable for TypeAliases<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<i8>(&"i8_", Self::VT_I8_, false)?
+ .visit_field::<u8>(&"u8_", Self::VT_U8_, false)?
+ .visit_field::<i16>(&"i16_", Self::VT_I16_, false)?
+ .visit_field::<u16>(&"u16_", Self::VT_U16_, false)?
+ .visit_field::<i32>(&"i32_", Self::VT_I32_, false)?
+ .visit_field::<u32>(&"u32_", Self::VT_U32_, false)?
+ .visit_field::<i64>(&"i64_", Self::VT_I64_, false)?
+ .visit_field::<u64>(&"u64_", Self::VT_U64_, false)?
+ .visit_field::<f32>(&"f32_", Self::VT_F32_, false)?
+ .visit_field::<f64>(&"f64_", Self::VT_F64_, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, i8>>>(&"v8", Self::VT_V8, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, f64>>>(&"vf64", Self::VT_VF64, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct TypeAliasesArgs<'a> {
pub i8_: i8,
pub u8_: u8,
@@ -2236,15 +2491,77 @@ impl std::fmt::Debug for TypeAliases<'_> {
}
}
#[inline]
+#[deprecated(since="1.13", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> {
- flatbuffers::get_root::<Monster<'a>>(buf)
+ unsafe { flatbuffers::root_unchecked::<Monster<'a>>(buf) }
}
#[inline]
+#[deprecated(since="1.13", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_size_prefixed_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> {
- flatbuffers::get_size_prefixed_root::<Monster<'a>>(buf)
+ unsafe { flatbuffers::size_prefixed_root_unchecked::<Monster<'a>>(buf) }
}
+#[inline]
+/// Verifies that a buffer of bytes contains a `Monster`
+/// 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_monster_unchecked`.
+pub fn root_as_monster(buf: &[u8]) -> Result<Monster, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::root::<Monster>(buf)
+}
+#[inline]
+/// Verifies that a buffer of bytes contains a size prefixed
+/// `Monster` 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_monster_unchecked`.
+pub fn size_prefixed_root_as_monster(buf: &[u8]) -> Result<Monster, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::size_prefixed_root::<Monster>(buf)
+}
+#[inline]
+/// Verifies, with the given options, that a buffer of bytes
+/// contains a `Monster` 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_monster_unchecked`.
+pub fn root_as_monster_with_opts<'b, 'o>(
+ opts: &'o flatbuffers::VerifierOptions,
+ buf: &'b [u8],
+) -> Result<Monster<'b>, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::root_with_opts::<Monster<'b>>(opts, buf)
+}
+#[inline]
+/// Verifies, with the given verifier options, that a buffer of
+/// bytes contains a size prefixed `Monster` 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_monster_unchecked`.
+pub fn size_prefixed_root_as_monster_with_opts<'b, 'o>(
+ opts: &'o flatbuffers::VerifierOptions,
+ buf: &'b [u8],
+) -> Result<Monster<'b>, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::size_prefixed_root_with_opts::<Monster<'b>>(opts, buf)
+}
+#[inline]
+/// Assumes, without verification, that a buffer of bytes contains a Monster and returns it.
+/// # Safety
+/// Callers must trust the given bytes do indeed contain a valid `Monster`.
+pub unsafe fn root_as_monster_unchecked(buf: &[u8]) -> Monster {
+ flatbuffers::root_unchecked::<Monster>(buf)
+}
+#[inline]
+/// Assumes, without verification, that a buffer of bytes contains a size prefixed Monster and returns it.
+/// # Safety
+/// Callers must trust the given bytes do indeed contain a valid size prefixed `Monster`.
+pub unsafe fn size_prefixed_root_as_monster_unchecked(buf: &[u8]) -> Monster {
+ flatbuffers::size_prefixed_root_unchecked::<Monster>(buf)
+}
pub const MONSTER_IDENTIFIER: &str = "MONS";
#[inline]
diff --git a/tests/namespace_test/namespace_test1_generated.rs b/tests/namespace_test/namespace_test1_generated.rs
index dd735a60..b5f062b1 100644
--- a/tests/namespace_test/namespace_test1_generated.rs
+++ b/tests/namespace_test/namespace_test1_generated.rs
@@ -77,7 +77,8 @@ impl<'a> flatbuffers::Follow<'a> for EnumInNestedNS {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
- Self(flatbuffers::read_scalar_at::<i8>(buf, loc))
+ let b = flatbuffers::read_scalar_at::<i8>(buf, loc);
+ Self(b)
}
}
@@ -92,14 +93,27 @@ impl flatbuffers::Push for EnumInNestedNS {
impl flatbuffers::EndianScalar for EnumInNestedNS {
#[inline]
fn to_little_endian(self) -> Self {
- Self(i8::to_le(self.0))
+ let b = i8::to_le(self.0);
+ Self(b)
}
#[inline]
fn from_little_endian(self) -> Self {
- Self(i8::from_le(self.0))
+ let b = i8::from_le(self.0);
+ Self(b)
}
}
+impl<'a> flatbuffers::Verifiable for EnumInNestedNS {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ i8::run_verifier(v, pos)
+ }
+}
+
+impl flatbuffers::SimpleToVerifyInSlice for EnumInNestedNS {}
// struct StructInNestedNS, aligned to 4
#[repr(C, align(4))]
#[derive(Clone, Copy, PartialEq)]
@@ -116,6 +130,7 @@ impl std::fmt::Debug for StructInNestedNS {
}
}
+impl flatbuffers::SimpleToVerifyInSlice for StructInNestedNS {}
impl flatbuffers::SafeSliceAccess for StructInNestedNS {}
impl<'a> flatbuffers::Follow<'a> for StructInNestedNS {
type Inner = &'a StructInNestedNS;
@@ -153,7 +168,15 @@ impl<'b> flatbuffers::Push for &'b StructInNestedNS {
}
}
-
+impl<'a> flatbuffers::Verifiable for StructInNestedNS {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.in_buffer::<Self>(pos)
+ }
+}
impl StructInNestedNS {
pub fn new(_a: i32, _b: i32) -> Self {
StructInNestedNS {
@@ -217,6 +240,18 @@ impl<'a> TableInNestedNS<'a> {
}
}
+impl flatbuffers::Verifiable for TableInNestedNS<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<i32>(&"foo", Self::VT_FOO, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct TableInNestedNSArgs {
pub foo: i32,
}
diff --git a/tests/namespace_test/namespace_test2_generated.rs b/tests/namespace_test/namespace_test2_generated.rs
index b1d84cf0..64120050 100644
--- a/tests/namespace_test/namespace_test2_generated.rs
+++ b/tests/namespace_test/namespace_test2_generated.rs
@@ -63,7 +63,7 @@ impl<'a> TableInFirstNS<'a> {
#[inline]
pub fn foo_table(&self) -> Option<namespace_b::TableInNestedNS<'a>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<namespace_b::TableInNestedNS<'a>>>(TableInFirstNS::VT_FOO_TABLE, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<namespace_b::TableInNestedNS>>(TableInFirstNS::VT_FOO_TABLE, None)
}
#[inline]
pub fn foo_enum(&self) -> namespace_b::EnumInNestedNS {
@@ -75,6 +75,20 @@ impl<'a> TableInFirstNS<'a> {
}
}
+impl flatbuffers::Verifiable for TableInFirstNS<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<flatbuffers::ForwardsUOffset<namespace_b::TableInNestedNS>>(&"foo_table", Self::VT_FOO_TABLE, false)?
+ .visit_field::<namespace_b::EnumInNestedNS>(&"foo_enum", Self::VT_FOO_ENUM, false)?
+ .visit_field::<namespace_b::StructInNestedNS>(&"foo_struct", Self::VT_FOO_STRUCT, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct TableInFirstNSArgs<'a> {
pub foo_table: Option<flatbuffers::WIPOffset<namespace_b::TableInNestedNS<'a>>>,
pub foo_enum: namespace_b::EnumInNestedNS,
@@ -170,10 +184,22 @@ impl<'a> SecondTableInA<'a> {
#[inline]
pub fn refer_to_c(&self) -> Option<super::namespace_c::TableInC<'a>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<super::namespace_c::TableInC<'a>>>(SecondTableInA::VT_REFER_TO_C, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<super::namespace_c::TableInC>>(SecondTableInA::VT_REFER_TO_C, None)
}
}
+impl flatbuffers::Verifiable for SecondTableInA<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<flatbuffers::ForwardsUOffset<super::namespace_c::TableInC>>(&"refer_to_c", Self::VT_REFER_TO_C, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct SecondTableInAArgs<'a> {
pub refer_to_c: Option<flatbuffers::WIPOffset<super::namespace_c::TableInC<'a>>>,
}
@@ -269,14 +295,27 @@ impl<'a> TableInC<'a> {
#[inline]
pub fn refer_to_a1(&self) -> Option<super::namespace_a::TableInFirstNS<'a>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<super::namespace_a::TableInFirstNS<'a>>>(TableInC::VT_REFER_TO_A1, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<super::namespace_a::TableInFirstNS>>(TableInC::VT_REFER_TO_A1, None)
}
#[inline]
pub fn refer_to_a2(&self) -> Option<super::namespace_a::SecondTableInA<'a>> {
- self._tab.get::<flatbuffers::ForwardsUOffset<super::namespace_a::SecondTableInA<'a>>>(TableInC::VT_REFER_TO_A2, None)
+ self._tab.get::<flatbuffers::ForwardsUOffset<super::namespace_a::SecondTableInA>>(TableInC::VT_REFER_TO_A2, None)
}
}
+impl flatbuffers::Verifiable for TableInC<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<flatbuffers::ForwardsUOffset<super::namespace_a::TableInFirstNS>>(&"refer_to_a1", Self::VT_REFER_TO_A1, false)?
+ .visit_field::<flatbuffers::ForwardsUOffset<super::namespace_a::SecondTableInA>>(&"refer_to_a2", Self::VT_REFER_TO_A2, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct TableInCArgs<'a> {
pub refer_to_a1: Option<flatbuffers::WIPOffset<super::namespace_a::TableInFirstNS<'a>>>,
pub refer_to_a2: Option<flatbuffers::WIPOffset<super::namespace_a::SecondTableInA<'a>>>,
diff --git a/tests/optional_scalars_generated.rs b/tests/optional_scalars_generated.rs
index 793a8ac4..08468d85 100644
--- a/tests/optional_scalars_generated.rs
+++ b/tests/optional_scalars_generated.rs
@@ -69,7 +69,8 @@ impl<'a> flatbuffers::Follow<'a> for OptionalByte {
type Inner = Self;
#[inline]
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
- Self(flatbuffers::read_scalar_at::<i8>(buf, loc))
+ let b = flatbuffers::read_scalar_at::<i8>(buf, loc);
+ Self(b)
}
}
@@ -84,14 +85,27 @@ impl flatbuffers::Push for OptionalByte {
impl flatbuffers::EndianScalar for OptionalByte {
#[inline]
fn to_little_endian(self) -> Self {
- Self(i8::to_le(self.0))
+ let b = i8::to_le(self.0);
+ Self(b)
}
#[inline]
fn from_little_endian(self) -> Self {
- Self(i8::from_le(self.0))
+ let b = i8::from_le(self.0);
+ Self(b)
}
}
+impl<'a> flatbuffers::Verifiable for OptionalByte {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ i8::run_verifier(v, pos)
+ }
+}
+
+impl flatbuffers::SimpleToVerifyInSlice for OptionalByte {}
pub enum ScalarStuffOffset {}
#[derive(Copy, Clone, PartialEq)]
@@ -341,6 +355,53 @@ impl<'a> ScalarStuff<'a> {
}
}
+impl flatbuffers::Verifiable for ScalarStuff<'_> {
+ #[inline]
+ fn run_verifier<'o, 'b>(
+ v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize
+ ) -> Result<(), flatbuffers::InvalidFlatbuffer> {
+ use self::flatbuffers::Verifiable;
+ v.visit_table(pos)?
+ .visit_field::<i8>(&"just_i8", Self::VT_JUST_I8, false)?
+ .visit_field::<i8>(&"maybe_i8", Self::VT_MAYBE_I8, false)?
+ .visit_field::<i8>(&"default_i8", Self::VT_DEFAULT_I8, false)?
+ .visit_field::<u8>(&"just_u8", Self::VT_JUST_U8, false)?
+ .visit_field::<u8>(&"maybe_u8", Self::VT_MAYBE_U8, false)?
+ .visit_field::<u8>(&"default_u8", Self::VT_DEFAULT_U8, false)?
+ .visit_field::<i16>(&"just_i16", Self::VT_JUST_I16, false)?
+ .visit_field::<i16>(&"maybe_i16", Self::VT_MAYBE_I16, false)?
+ .visit_field::<i16>(&"default_i16", Self::VT_DEFAULT_I16, false)?
+ .visit_field::<u16>(&"just_u16", Self::VT_JUST_U16, false)?
+ .visit_field::<u16>(&"maybe_u16", Self::VT_MAYBE_U16, false)?
+ .visit_field::<u16>(&"default_u16", Self::VT_DEFAULT_U16, false)?
+ .visit_field::<i32>(&"just_i32", Self::VT_JUST_I32, false)?
+ .visit_field::<i32>(&"maybe_i32", Self::VT_MAYBE_I32, false)?
+ .visit_field::<i32>(&"default_i32", Self::VT_DEFAULT_I32, false)?
+ .visit_field::<u32>(&"just_u32", Self::VT_JUST_U32, false)?
+ .visit_field::<u32>(&"maybe_u32", Self::VT_MAYBE_U32, false)?
+ .visit_field::<u32>(&"default_u32", Self::VT_DEFAULT_U32, false)?
+ .visit_field::<i64>(&"just_i64", Self::VT_JUST_I64, false)?
+ .visit_field::<i64>(&"maybe_i64", Self::VT_MAYBE_I64, false)?
+ .visit_field::<i64>(&"default_i64", Self::VT_DEFAULT_I64, false)?
+ .visit_field::<u64>(&"just_u64", Self::VT_JUST_U64, false)?
+ .visit_field::<u64>(&"maybe_u64", Self::VT_MAYBE_U64, false)?
+ .visit_field::<u64>(&"default_u64", Self::VT_DEFAULT_U64, false)?
+ .visit_field::<f32>(&"just_f32", Self::VT_JUST_F32, false)?
+ .visit_field::<f32>(&"maybe_f32", Self::VT_MAYBE_F32, false)?
+ .visit_field::<f32>(&"default_f32", Self::VT_DEFAULT_F32, false)?
+ .visit_field::<f64>(&"just_f64", Self::VT_JUST_F64, false)?
+ .visit_field::<f64>(&"maybe_f64", Self::VT_MAYBE_F64, false)?
+ .visit_field::<f64>(&"default_f64", Self::VT_DEFAULT_F64, false)?
+ .visit_field::<bool>(&"just_bool", Self::VT_JUST_BOOL, false)?
+ .visit_field::<bool>(&"maybe_bool", Self::VT_MAYBE_BOOL, false)?
+ .visit_field::<bool>(&"default_bool", Self::VT_DEFAULT_BOOL, false)?
+ .visit_field::<OptionalByte>(&"just_enum", Self::VT_JUST_ENUM, false)?
+ .visit_field::<OptionalByte>(&"maybe_enum", Self::VT_MAYBE_ENUM, false)?
+ .visit_field::<OptionalByte>(&"default_enum", Self::VT_DEFAULT_ENUM, false)?
+ .finish();
+ Ok(())
+ }
+}
pub struct ScalarStuffArgs {
pub just_i8: i8,
pub maybe_i8: Option<i8>,
@@ -629,15 +690,77 @@ impl std::fmt::Debug for ScalarStuff<'_> {
}
}
#[inline]
+#[deprecated(since="1.13", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_root_as_scalar_stuff<'a>(buf: &'a [u8]) -> ScalarStuff<'a> {
- flatbuffers::get_root::<ScalarStuff<'a>>(buf)
+ unsafe { flatbuffers::root_unchecked::<ScalarStuff<'a>>(buf) }
}
#[inline]
+#[deprecated(since="1.13", note="Deprecated in favor of `root_as...` methods.")]
pub fn get_size_prefixed_root_as_scalar_stuff<'a>(buf: &'a [u8]) -> ScalarStuff<'a> {
- flatbuffers::get_size_prefixed_root::<ScalarStuff<'a>>(buf)
+ unsafe { flatbuffers::size_prefixed_root_unchecked::<ScalarStuff<'a>>(buf) }
}
+#[inline]
+/// Verifies that a buffer of bytes contains a `ScalarStuff`
+/// 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_scalar_stuff_unchecked`.
+pub fn root_as_scalar_stuff(buf: &[u8]) -> Result<ScalarStuff, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::root::<ScalarStuff>(buf)
+}
+#[inline]
+/// Verifies that a buffer of bytes contains a size prefixed
+/// `ScalarStuff` 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_scalar_stuff_unchecked`.
+pub fn size_prefixed_root_as_scalar_stuff(buf: &[u8]) -> Result<ScalarStuff, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::size_prefixed_root::<ScalarStuff>(buf)
+}
+#[inline]
+/// Verifies, with the given options, that a buffer of bytes
+/// contains a `ScalarStuff` 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_scalar_stuff_unchecked`.
+pub fn root_as_scalar_stuff_with_opts<'b, 'o>(
+ opts: &'o flatbuffers::VerifierOptions,
+ buf: &'b [u8],
+) -> Result<ScalarStuff<'b>, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::root_with_opts::<ScalarStuff<'b>>(opts, buf)
+}
+#[inline]
+/// Verifies, with the given verifier options, that a buffer of
+/// bytes contains a size prefixed `ScalarStuff` 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_scalar_stuff_unchecked`.
+pub fn size_prefixed_root_as_scalar_stuff_with_opts<'b, 'o>(
+ opts: &'o flatbuffers::VerifierOptions,
+ buf: &'b [u8],
+) -> Result<ScalarStuff<'b>, flatbuffers::InvalidFlatbuffer> {
+ flatbuffers::size_prefixed_root_with_opts::<ScalarStuff<'b>>(opts, buf)
+}
+#[inline]
+/// Assumes, without verification, that a buffer of bytes contains a ScalarStuff and returns it.
+/// # Safety
+/// Callers must trust the given bytes do indeed contain a valid `ScalarStuff`.
+pub unsafe fn root_as_scalar_stuff_unchecked(buf: &[u8]) -> ScalarStuff {
+ flatbuffers::root_unchecked::<ScalarStuff>(buf)
+}
+#[inline]
+/// Assumes, without verification, that a buffer of bytes contains a size prefixed ScalarStuff and returns it.
+/// # Safety
+/// Callers must trust the given bytes do indeed contain a valid size prefixed `ScalarStuff`.
+pub unsafe fn size_prefixed_root_as_scalar_stuff_unchecked(buf: &[u8]) -> ScalarStuff {
+ flatbuffers::size_prefixed_root_unchecked::<ScalarStuff>(buf)
+}
pub const SCALAR_STUFF_IDENTIFIER: &str = "NULL";
#[inline]
diff --git a/tests/rust_usage_test/bin/flatbuffers_alloc_check.rs b/tests/rust_usage_test/bin/flatbuffers_alloc_check.rs
index c47e86e1..a02609ab 100644
--- a/tests/rust_usage_test/bin/flatbuffers_alloc_check.rs
+++ b/tests/rust_usage_test/bin/flatbuffers_alloc_check.rs
@@ -131,7 +131,7 @@ fn main() {
// do many reads, forcing them to execute by using assert_eq:
{
- let m = my_game::example::get_root_as_monster(buf);
+ let m = unsafe { my_game::example::root_as_monster_unchecked(buf) };
assert_eq!(80, m.hp());
assert_eq!(150, m.mana());
assert_eq!("MyMonster", m.name());
diff --git a/tests/rust_usage_test/bin/monster_example.rs b/tests/rust_usage_test/bin/monster_example.rs
index d0b75d72..a3c4300d 100644
--- a/tests/rust_usage_test/bin/monster_example.rs
+++ b/tests/rust_usage_test/bin/monster_example.rs
@@ -20,7 +20,7 @@ fn main() {
let mut buf = Vec::new();
f.read_to_end(&mut buf).expect("file reading failed");
- let monster = my_game::example::get_root_as_monster(&buf[..]);
+ let monster = my_game::example::root_as_monster(&buf[..]).unwrap();
println!("{}", monster.hp()); // `80`
println!("{}", monster.mana()); // default value of `150`
println!("{:?}", monster.name()); // Some("MyMonster")
diff --git a/tests/rust_usage_test/tests/integration_test.rs b/tests/rust_usage_test/tests/integration_test.rs
index 5957e2c1..4f047604 100644
--- a/tests/rust_usage_test/tests/integration_test.rs
+++ b/tests/rust_usage_test/tests/integration_test.rs
@@ -177,9 +177,9 @@ fn serialized_example_is_accessible_and_correct(bytes: &[u8], identifier_require
}
let m = if size_prefixed {
- my_game::example::get_size_prefixed_root_as_monster(bytes)
+ my_game::example::size_prefixed_root_as_monster(bytes).unwrap()
} else {
- my_game::example::get_root_as_monster(bytes)
+ my_game::example::root_as_monster(bytes).unwrap()
};
check_eq!(m.hp(), 80)?;
@@ -245,6 +245,106 @@ fn builder_collapses_into_vec() {
serialized_example_is_accessible_and_correct(&backing_buf[head..], true, false).unwrap();
}
+#[test]
+fn verifier_one_byte_errors_do_not_crash() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ create_serialized_example_with_library_code(&mut b);
+ let mut badbuf = b.finished_data().to_vec();
+ // If the verifier says a buffer is okay then using it won't cause a crash.
+ // We use write_fmt since Debug visits all the fields - but there's no need to store anything.
+ struct ForgetfulWriter;
+ use std::fmt::Write;
+ impl Write for ForgetfulWriter {
+ fn write_str(&mut self, _: &str) -> Result<(), std::fmt::Error> {
+ Ok(())
+ }
+ }
+ let mut w = ForgetfulWriter;
+ for d in 1..=255u8 {
+ for i in 0..badbuf.len() {
+ let orig = badbuf[i];
+ badbuf[i] = badbuf[i].wrapping_add(d);
+ if let Ok(m) = flatbuffers::root::<my_game::example::Monster>(&badbuf) {
+ w.write_fmt(format_args!("{:?}", m)).unwrap()
+ }
+ badbuf[i] = orig;
+ }
+ }
+}
+#[test]
+fn verifier_too_many_tables() {
+ use my_game::example::*;
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ let r = Referrable::create(b, &ReferrableArgs { id: 42 });
+ let rs = b.create_vector(&vec![r; 500]);
+ let name = Some(b.create_string("foo"));
+ let m = Monster::create(b, &MonsterArgs {
+ vector_of_referrables: Some(rs),
+ name, // required field.
+ ..Default::default()
+ });
+ b.finish(m, None);
+
+ let data = b.finished_data();
+ let mut opts = flatbuffers::VerifierOptions::default();
+
+ opts.max_tables = 500;
+ let res = flatbuffers::root_with_opts::<Monster>(&opts, data);
+ assert_eq!(res.unwrap_err(), flatbuffers::InvalidFlatbuffer::TooManyTables);
+
+ opts.max_tables += 2;
+ assert!(flatbuffers::root_with_opts::<Monster>(&opts, data).is_ok());
+}
+#[test]
+fn verifier_apparent_size_too_large() {
+ use my_game::example::*;
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ let name = Some(b.create_string("foo"));
+ // String amplification attack.
+ let s = b.create_string(&(std::iter::repeat("X").take(1000).collect::<String>()));
+ let testarrayofstring = Some(b.create_vector(&vec![s; 1000]));
+ let m = Monster::create(b, &MonsterArgs {
+ testarrayofstring,
+ name, // required field.
+ ..Default::default()
+ });
+ b.finish(m, None);
+ let data = b.finished_data();
+ assert!(data.len() < 5100); // est 4000 for the vector + 1000 for the string + 100 overhead.
+ let mut opts = flatbuffers::VerifierOptions::default();
+ opts.max_apparent_size = 1_000_000;
+
+ let res = flatbuffers::root_with_opts::<Monster>(&opts, data);
+ assert_eq!(res.unwrap_err(), flatbuffers::InvalidFlatbuffer::ApparentSizeTooLarge);
+
+ opts.max_apparent_size += 20_000;
+ assert!(flatbuffers::root_with_opts::<Monster>(&opts, data).is_ok());
+}
+#[test]
+fn verifier_in_too_deep() {
+ use my_game::example::*;
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ let name = Some(b.create_string("foo"));
+ let mut prev_monster = None;
+ for _ in 0..11 {
+ prev_monster = Some(Monster::create(b, &MonsterArgs {
+ enemy: prev_monster,
+ name, // required field.
+ ..Default::default()
+ }));
+ };
+ b.finish(prev_monster.unwrap(), None);
+ let mut opts = flatbuffers::VerifierOptions::default();
+ opts.max_depth = 10;
+
+ let data = b.finished_data();
+ let res = flatbuffers::root_with_opts::<Monster>(&opts, data);
+ assert_eq!(res.unwrap_err(), flatbuffers::InvalidFlatbuffer::DepthLimitReached);
+
+ opts.max_depth += 1;
+ assert!(flatbuffers::root_with_opts::<Monster>(&opts, data).is_ok());
+}
+
#[cfg(test)]
mod generated_constants {
extern crate flatbuffers;
@@ -316,7 +416,7 @@ mod lifetime_correctness {
let slice: &[u8] = &buf;
let slice: &'static [u8] = unsafe { mem::transmute(slice) };
// make sure values retrieved from the 'static buffer are themselves 'static
- let monster: my_game::example::Monster<'static> = my_game::example::get_root_as_monster(slice);
+ let monster: my_game::example::Monster<'static> = my_game::example::root_as_monster(slice).unwrap();
// this line should compile:
let name: Option<&'static str> = monster._tab.get::<flatbuffers::ForwardsUOffset<&str>>(my_game::example::Monster::VT_NAME, None);
assert_eq!(name, Some("MyMonster"));
@@ -334,7 +434,7 @@ mod lifetime_correctness {
fn table_object_self_lifetime_in_closure() {
// This test is designed to ensure that lifetimes for temporary intermediate tables aren't inflated beyond where the need to be.
let buf = load_file("../monsterdata_test.mon").expect("missing monsterdata_test.mon");
- let monster = my_game::example::get_root_as_monster(&buf);
+ let monster = my_game::example::root_as_monster(&buf).unwrap();
let enemy: Option<my_game::example::Monster> = monster.enemy();
// This line won't compile if "self" is required to live for the lifetime of buf above as the borrow disappears at the end of the closure.
let enemy_of_my_enemy = enemy.map(|e| {
@@ -357,7 +457,7 @@ mod roundtrip_generated_code {
fn build_mon<'a, 'b>(builder: &'a mut flatbuffers::FlatBufferBuilder, args: &'b my_game::example::MonsterArgs) -> my_game::example::Monster<'a> {
let mon = my_game::example::Monster::create(builder, &args);
my_game::example::finish_monster_buffer(builder, mon);
- my_game::example::get_root_as_monster(builder.finished_data())
+ my_game::example::root_as_monster(builder.finished_data()).unwrap()
}
#[test]
@@ -437,7 +537,7 @@ mod roundtrip_generated_code {
my_game::example::finish_monster_buffer(b, outer);
}
- let mon = my_game::example::get_root_as_monster(b.finished_data());
+ let mon = my_game::example::root_as_monster(b.finished_data()).unwrap();
assert_eq!(mon.name(), "bar");
assert_eq!(mon.test_type(), my_game::example::Any::Monster);
assert_eq!(my_game::example::Monster::init_from_table(mon.test().unwrap()).name(),
@@ -473,7 +573,7 @@ mod roundtrip_generated_code {
my_game::example::finish_monster_buffer(b, outer);
}
- let mon = my_game::example::get_root_as_monster(b.finished_data());
+ let mon = my_game::example::root_as_monster(b.finished_data()).unwrap();
assert_eq!(mon.name(), "bar");
assert_eq!(mon.enemy().unwrap().name(), "foo");
}
@@ -503,7 +603,7 @@ mod roundtrip_generated_code {
my_game::example::finish_monster_buffer(b, outer);
}
- let mon = my_game::example::get_root_as_monster(b.finished_data());
+ let mon = my_game::example::root_as_monster(b.finished_data()).unwrap();
assert_eq!(mon.name(), "bar");
assert_eq!(mon.testempty().unwrap().id(), Some("foo"));
}
@@ -540,12 +640,12 @@ mod roundtrip_generated_code {
b1
};
- let m = my_game::example::get_root_as_monster(b1.finished_data());
+ let m = my_game::example::root_as_monster(b1.finished_data()).unwrap();
assert!(m.testnestedflatbuffer().is_some());
assert_eq!(m.testnestedflatbuffer().unwrap(), b0.finished_data());
- let m2_a = my_game::example::get_root_as_monster(m.testnestedflatbuffer().unwrap());
+ let m2_a = my_game::example::root_as_monster(m.testnestedflatbuffer().unwrap()).unwrap();
assert_eq!(m2_a.hp(), 123);
assert_eq!(m2_a.name(), "foobar");
@@ -799,7 +899,7 @@ mod generated_code_alignment_and_padding {
my_game::example::finish_monster_buffer(b, mon);
}
let buf = b.finished_data();
- let mon = my_game::example::get_root_as_monster(buf);
+ let mon = my_game::example::root_as_monster(buf).unwrap();
let vec3 = mon.pos().unwrap();
let start_ptr = buf.as_ptr() as usize;
@@ -835,7 +935,7 @@ mod generated_code_alignment_and_padding {
my_game::example::finish_monster_buffer(b, mon);
}
let buf = b.finished_data();
- let mon = my_game::example::get_root_as_monster(buf);
+ let mon = my_game::example::root_as_monster(buf).unwrap();
let abilities = mon.testarrayofsortedstruct().unwrap();
let start_ptr = buf.as_ptr() as usize;
@@ -1142,7 +1242,7 @@ mod framing_format {
// Access it.
let buf = b.finished_data();
- let m = flatbuffers::get_size_prefixed_root::<my_game::example::Monster>(buf);
+ let m = flatbuffers::size_prefixed_root::<my_game::example::Monster>(buf).unwrap();
assert_eq!(m.mana(), 200);
assert_eq!(m.hp(), 300);
assert_eq!(m.name(), "bob");
@@ -1538,7 +1638,7 @@ mod write_and_read_examples {
create_serialized_example_with_generated_code(b);
let buf = b.finished_data();
serialized_example_is_accessible_and_correct(&buf, true, false).unwrap();
- let m = super::my_game::example::get_root_as_monster(buf);
+ let m = super::my_game::example::root_as_monster(buf).unwrap();
assert_eq!(
format!("{:.5?}", &m),
"Monster { pos: Some(Vec3 { x: 1.00000, y: 2.00000, z: 3.00000, \
@@ -1728,7 +1828,7 @@ mod generated_key_comparisons {
let builder = &mut flatbuffers::FlatBufferBuilder::new();
super::create_serialized_example_with_library_code(builder);
let buf = builder.finished_data();
- let a = my_game::example::get_root_as_monster(buf);
+ let a = my_game::example::root_as_monster(buf).unwrap();
// preconditions
assert_eq!(a.name(), "MyMonster");
@@ -1744,7 +1844,7 @@ mod generated_key_comparisons {
let builder = &mut flatbuffers::FlatBufferBuilder::new();
super::create_serialized_example_with_library_code(builder);
let buf = builder.finished_data();
- let a = my_game::example::get_root_as_monster(buf);
+ let a = my_game::example::root_as_monster(buf).unwrap();
let b = a.test_as_monster().unwrap();
// preconditions
diff --git a/tests/rust_usage_test/tests/optional_scalars_test.rs b/tests/rust_usage_test/tests/optional_scalars_test.rs
index f029d032..5a662414 100644
--- a/tests/rust_usage_test/tests/optional_scalars_test.rs
+++ b/tests/rust_usage_test/tests/optional_scalars_test.rs
@@ -27,13 +27,13 @@ macro_rules! make_test {
);
builder.finish(ss, None);
- let s = flatbuffers::get_root::<ScalarStuff>(builder.finished_data());
+ let s = flatbuffers::root::<ScalarStuff>(builder.finished_data()).unwrap();
assert_eq!(s.$just(), $five);
assert_eq!(s.$default(), $five);
assert_eq!(s.$maybe(), Some($five));
// Test defaults are used when not specified.
- let s = flatbuffers::get_root::<ScalarStuff>(&[0; 8]);
+ let s = flatbuffers::root::<ScalarStuff>(&[0; 8]).unwrap();
assert_eq!(s.$just(), $zero);
assert_eq!(s.$default(), $fortytwo);
assert_eq!(s.$maybe(), None);