Rust Flatbuffers Verifier (#6269)
authorCasper <casperneo@uchicago.edu>
Mon, 7 Dec 2020 23:37:51 +0000 (18:37 -0500)
committerGitHub <noreply@github.com>
Mon, 7 Dec 2020 23:37:51 +0000 (18:37 -0500)
* Updated comments and fixed a fundemental type error.

* bump rust flatbuffers semver

* Initial commit with verifier, need to clean up

* Verifier tested. Needs clean up and refactoring.

* Display for InvalidFlatbuffer and better errors for strings

* SimpleToVerify, some refactoring

* Combined VerifierType TableAccessorFuncBody into FollowType

* scrub todos

* Update Rust get_root functions.

There are 6 variants, with verifier options, default verifier options
and no verification "fast".

* Rename root fns

* inline

* Update to use thiserror

* fix for bad compiler

* improve error formatting

* Replace multiply with saturating_multiply

* saturating adds too

* Add docs disclaiming experimental verification system

Co-authored-by: Casper Neo <cneo@google.com>
21 files changed:
rust/flatbuffers/Cargo.toml
rust/flatbuffers/src/builder.rs
rust/flatbuffers/src/follow.rs
rust/flatbuffers/src/get_root.rs [new file with mode: 0644]
rust/flatbuffers/src/lib.rs
rust/flatbuffers/src/table.rs
rust/flatbuffers/src/vector.rs
rust/flatbuffers/src/verifier.rs [new file with mode: 0644]
samples/monster_generated.rs
samples/sample_binary.rs
src/idl_gen_rust.cpp
tests/include_test/include_test1_generated.rs
tests/include_test/sub/include_test2_generated.rs
tests/monster_test_generated.rs
tests/namespace_test/namespace_test1_generated.rs
tests/namespace_test/namespace_test2_generated.rs
tests/optional_scalars_generated.rs
tests/rust_usage_test/bin/flatbuffers_alloc_check.rs
tests/rust_usage_test/bin/monster_example.rs
tests/rust_usage_test/tests/integration_test.rs
tests/rust_usage_test/tests/optional_scalars_test.rs

index 460c552..ad95e67 100644 (file)
@@ -13,3 +13,4 @@ categories = ["encoding", "data-structures", "memory-management"]
 [dependencies]
 smallvec = "1.0"
 bitflags = "1.2"
+thiserror = "1.0"
index a3c15f2..f3bfcf2 100644 (file)
@@ -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.
index 8dd70da..a09003d 100644 (file)
@@ -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 (file)
index 0000000..2a01cf8
--- /dev/null
@@ -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)
+}
index 3abd33b..77d51f8 100644 (file)
 //! 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<...>>`.
index 46728cd..cfb8559 100644 (file)
@@ -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);
 
index 5236ea1..c53a878 100644 (file)
  * 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 (file)
index 0000000..f33bf92
--- /dev/null
@@ -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);
index e352b75..53070c0 100644 (file)
@@ -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>>) {
index 6fb987e..649babf 100644 (file)
@@ -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();
index 3995a7f..3c17b5c 100644 (file)
@@ -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}} {";
index 3c7b9bd..cf63626 100644 (file)
@@ -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>>>,
 }
index 892c652..a461b82 100644 (file)
@@ -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>>>,
 }
index e653933..f38ce6a 100644 (file)
@@ -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]
index dd735a6..b5f062b 100644 (file)
@@ -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,
 }
index b1d84cf..6412005 100644 (file)
@@ -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>>>,
index 793a8ac..08468d8 100644 (file)
@@ -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]
index c47e86e..a02609a 100644 (file)
@@ -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());
index d0b75d7..a3c4300 100644 (file)
@@ -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")
index 5957e2c..4f04760 100644 (file)
@@ -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
index f029d03..5a66241 100644 (file)
@@ -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);