rust: Allow for usage in no_std environment (#6989)

This commit is contained in:
Marcin Witkowski
2022-01-20 17:49:02 +01:00
committed by GitHub
parent d7b75417fc
commit aff818cebf
14 changed files with 70 additions and 40 deletions

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "flatbuffers" name = "flatbuffers"
version = "2.0.0" version = "2.1.0"
edition = "2018" edition = "2018"
authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"] authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
license = "Apache-2.0" license = "Apache-2.0"
@@ -11,7 +11,13 @@ keywords = ["flatbuffers", "serialization", "zero-copy"]
categories = ["encoding", "data-structures", "memory-management"] categories = ["encoding", "data-structures", "memory-management"]
rust = "1.51" rust = "1.51"
[features]
default = ["thiserror"]
no_std = ["core2", "thiserror_core2"]
[dependencies] [dependencies]
smallvec = "1.6.1" smallvec = "1.6.1"
bitflags = "1.2.1" bitflags = "1.2.1"
thiserror = "1.0.23" thiserror = { version = "1.0.23", optional = true }
core2 = { version = "0.3.3", optional = true }
thiserror_core2 = { git = "https://github.com/antmicro/thiserror-core2.git", branch = "remaining-errors", optional = true }

View File

@@ -17,9 +17,9 @@
use crate::follow::Follow; use crate::follow::Follow;
use crate::vector::VectorIter; use crate::vector::VectorIter;
use crate::EndianScalar; use crate::EndianScalar;
use std::fmt::{Debug, Formatter, Result}; use core::fmt::{Debug, Formatter, Result};
use std::marker::PhantomData; use core::marker::PhantomData;
use std::mem::size_of; use core::mem::size_of;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Array<'a, T: 'a, const N: usize>(&'a [u8], PhantomData<T>); pub struct Array<'a, T: 'a, const N: usize>(&'a [u8], PhantomData<T>);

View File

@@ -16,11 +16,13 @@
extern crate smallvec; extern crate smallvec;
use std::cmp::max; use core::cmp::max;
use std::iter::{DoubleEndedIterator, ExactSizeIterator}; use core::iter::{DoubleEndedIterator, ExactSizeIterator};
use std::marker::PhantomData; use core::marker::PhantomData;
use std::ptr::write_bytes; use core::ptr::write_bytes;
use std::slice::from_raw_parts; use core::slice::from_raw_parts;
#[cfg(feature = "no_std")]
use alloc::{vec, vec::Vec};
use crate::endian_scalar::{emplace_scalar, read_scalar_at}; use crate::endian_scalar::{emplace_scalar, read_scalar_at};
use crate::primitives::*; use crate::primitives::*;

View File

@@ -15,7 +15,7 @@
*/ */
#![allow(clippy::wrong_self_convention)] #![allow(clippy::wrong_self_convention)]
use std::mem::size_of; use core::mem::size_of;
/// Trait for values that must be stored in little-endian byte order, but /// Trait for values that must be stored in little-endian byte order, but
/// might be represented in memory as big-endian. Every type that implements /// might be represented in memory as big-endian. Every type that implements

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
use std::marker::PhantomData; use core::marker::PhantomData;
/// Follow is a trait that allows us to access FlatBuffers in a declarative, /// Follow is a trait that allows us to access FlatBuffers in a declarative,
/// type safe, and fast way. They compile down to almost no code (after /// type safe, and fast way. They compile down to almost no code (after

View File

@@ -28,6 +28,11 @@
//! 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.) //! (On OSX, you can install FlatBuffers from `HEAD` with the Homebrew package manager.)
#![cfg_attr(feature = "no_std", no_std)]
#[cfg(feature = "no_std")]
extern crate alloc;
mod array; mod array;
mod builder; mod builder;
mod endian_scalar; mod endian_scalar;

View File

@@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
use std::marker::PhantomData; use core::marker::PhantomData;
use std::mem::size_of; use core::mem::size_of;
use std::ops::Deref; use core::ops::Deref;
use crate::endian_scalar::{emplace_scalar, read_scalar, read_scalar_at}; use crate::endian_scalar::{emplace_scalar, read_scalar, read_scalar_at};
use crate::follow::Follow; use crate::follow::Follow;

View File

@@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
use std::cmp::max; use core::cmp::max;
use std::mem::{align_of, size_of}; use core::mem::{align_of, size_of};
use crate::endian_scalar::emplace_scalar; use crate::endian_scalar::emplace_scalar;

View File

@@ -14,12 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
use std::fmt::{Debug, Formatter, Result}; use core::fmt::{Debug, Formatter, Result};
use std::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator}; use core::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator};
use std::marker::PhantomData; use core::marker::PhantomData;
use std::mem::size_of; use core::mem::size_of;
use std::slice::from_raw_parts; use core::slice::from_raw_parts;
use std::str::from_utf8_unchecked; use core::str::from_utf8_unchecked;
use crate::endian_scalar::read_scalar_at; use crate::endian_scalar::read_scalar_at;
#[cfg(target_endian = "little")] #[cfg(target_endian = "little")]

View File

@@ -1,6 +1,12 @@
#[cfg(feature = "no_std")]
use alloc::vec::Vec;
use core::ops::Range;
use core::option::Option;
use crate::follow::Follow; use crate::follow::Follow;
use crate::{ForwardsUOffset, SOffsetT, SkipSizePrefix, UOffsetT, VOffsetT, Vector, SIZE_UOFFSET}; use crate::{ForwardsUOffset, SOffsetT, SkipSizePrefix, UOffsetT, VOffsetT, Vector, SIZE_UOFFSET};
use std::ops::Range;
#[cfg(feature="no_std")]
extern crate thiserror_core2 as thiserror;
use thiserror::Error; use thiserror::Error;
/// Traces the location of data errors. Not populated for Dos detecting errors. /// Traces the location of data errors. Not populated for Dos detecting errors.
@@ -23,7 +29,7 @@ pub enum ErrorTraceDetail {
} }
#[derive(PartialEq, Eq, Default, Debug, Clone)] #[derive(PartialEq, Eq, Default, Debug, Clone)]
pub struct ErrorTrace(Vec<ErrorTraceDetail>); pub struct ErrorTrace(Vec<ErrorTraceDetail>);
impl std::convert::AsRef<[ErrorTraceDetail]> for ErrorTrace { impl core::convert::AsRef<[ErrorTraceDetail]> for ErrorTrace {
#[inline] #[inline]
fn as_ref(&self) -> &[ErrorTraceDetail] { fn as_ref(&self) -> &[ErrorTraceDetail] {
&self.0 &self.0
@@ -51,7 +57,7 @@ pub enum InvalidFlatbuffer {
#[error("Utf8 error for string in {range:?}: {error}\n{error_trace}")] #[error("Utf8 error for string in {range:?}: {error}\n{error_trace}")]
Utf8Error { Utf8Error {
#[source] #[source]
error: std::str::Utf8Error, error: core::str::Utf8Error,
range: Range<usize>, range: Range<usize>,
error_trace: ErrorTrace, error_trace: ErrorTrace,
}, },
@@ -90,8 +96,8 @@ pub enum InvalidFlatbuffer {
DepthLimitReached, DepthLimitReached,
} }
impl std::fmt::Display for ErrorTrace { impl core::fmt::Display for ErrorTrace {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
use ErrorTraceDetail::*; use ErrorTraceDetail::*;
for e in self.0.iter() { for e in self.0.iter() {
match e { match e {
@@ -125,7 +131,7 @@ impl std::fmt::Display for ErrorTrace {
} }
} }
pub type Result<T> = std::prelude::v1::Result<T, InvalidFlatbuffer>; pub type Result<T> = core::result::Result<T, InvalidFlatbuffer>;
impl InvalidFlatbuffer { impl InvalidFlatbuffer {
fn new_range_oob<T>(start: usize, end: usize) -> Result<T> { fn new_range_oob<T>(start: usize, end: usize) -> Result<T> {
@@ -245,11 +251,11 @@ impl<'opts, 'buf> Verifier<'opts, 'buf> {
/// `buffer[0]`. TODO(caspern). /// `buffer[0]`. TODO(caspern).
#[inline] #[inline]
fn is_aligned<T>(&self, pos: usize) -> Result<()> { fn is_aligned<T>(&self, pos: usize) -> Result<()> {
if pos % std::mem::align_of::<T>() == 0 { if pos % core::mem::align_of::<T>() == 0 {
Ok(()) Ok(())
} else { } else {
Err(InvalidFlatbuffer::Unaligned { Err(InvalidFlatbuffer::Unaligned {
unaligned_type: std::any::type_name::<T>(), unaligned_type: core::any::type_name::<T>(),
position: pos, position: pos,
error_trace: Default::default(), error_trace: Default::default(),
}) })
@@ -271,7 +277,7 @@ impl<'opts, 'buf> Verifier<'opts, 'buf> {
#[inline] #[inline]
pub fn in_buffer<T>(&mut self, pos: usize) -> Result<()> { pub fn in_buffer<T>(&mut self, pos: usize) -> Result<()> {
self.is_aligned::<T>(pos)?; self.is_aligned::<T>(pos)?;
self.range_in_buffer(pos, std::mem::size_of::<T>()) self.range_in_buffer(pos, core::mem::size_of::<T>())
} }
#[inline] #[inline]
fn get_u16(&mut self, pos: usize) -> Result<u16> { fn get_u16(&mut self, pos: usize) -> Result<u16> {
@@ -416,7 +422,7 @@ impl<'ver, 'opts, 'buf> TableVerifier<'ver, 'opts, 'buf> {
where where
Key: Follow<'buf> + Verifiable, Key: Follow<'buf> + Verifiable,
UnionVerifier: UnionVerifier:
(std::ops::FnOnce(<Key as Follow<'buf>>::Inner, &mut Verifier, usize) -> Result<()>), (core::ops::FnOnce(<Key as Follow<'buf>>::Inner, &mut Verifier, usize) -> Result<()>),
// NOTE: <Key as Follow<'buf>>::Inner == Key // NOTE: <Key as Follow<'buf>>::Inner == Key
{ {
// TODO(caspern): how to trace vtable errors? // TODO(caspern): how to trace vtable errors?
@@ -468,14 +474,14 @@ impl<T: Verifiable> Verifiable for ForwardsUOffset<T> {
} }
/// Checks and returns the range containing the flatbuffers vector. /// Checks and returns the range containing the flatbuffers vector.
fn verify_vector_range<T>(v: &mut Verifier, pos: usize) -> Result<std::ops::Range<usize>> { fn verify_vector_range<T>(v: &mut Verifier, pos: usize) -> Result<core::ops::Range<usize>> {
let len = v.get_uoffset(pos)? as usize; let len = v.get_uoffset(pos)? as usize;
let start = pos.saturating_add(SIZE_UOFFSET); let start = pos.saturating_add(SIZE_UOFFSET);
v.is_aligned::<T>(start)?; v.is_aligned::<T>(start)?;
let size = len.saturating_mul(std::mem::size_of::<T>()); let size = len.saturating_mul(core::mem::size_of::<T>());
let end = start.saturating_add(size); let end = start.saturating_add(size);
v.range_in_buffer(start, size)?; v.range_in_buffer(start, size)?;
Ok(std::ops::Range { start, end }) Ok(core::ops::Range { start, end })
} }
pub trait SimpleToVerifyInSlice {} pub trait SimpleToVerifyInSlice {}
@@ -509,7 +515,7 @@ impl<T: Verifiable> Verifiable for Vector<'_, ForwardsUOffset<T>> {
#[inline] #[inline]
fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> { fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
let range = verify_vector_range::<ForwardsUOffset<T>>(v, pos)?; let range = verify_vector_range::<ForwardsUOffset<T>>(v, pos)?;
let size = std::mem::size_of::<ForwardsUOffset<T>>(); let size = core::mem::size_of::<ForwardsUOffset<T>>();
for (i, element_pos) in range.step_by(size).enumerate() { for (i, element_pos) in range.step_by(size).enumerate() {
trace_elem( trace_elem(
<ForwardsUOffset<T>>::run_verifier(v, element_pos), <ForwardsUOffset<T>>::run_verifier(v, element_pos),
@@ -526,7 +532,7 @@ impl<'a> Verifiable for &'a str {
fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> { fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
let range = verify_vector_range::<u8>(v, pos)?; 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 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()]); let s = core::str::from_utf8(&v.buffer[range.clone()]);
if let Err(error) = s { if let Err(error) = s {
return Err(InvalidFlatbuffer::Utf8Error { return Err(InvalidFlatbuffer::Utf8Error {
error, error,

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
use std::ptr::write_bytes; use core::ptr::write_bytes;
use crate::endian_scalar::emplace_scalar; use crate::endian_scalar::emplace_scalar;
use crate::primitives::*; use crate::primitives::*;

View File

@@ -35,6 +35,8 @@ cd ./rust_usage_test
cargo test $TARGET_FLAG -- --quiet cargo test $TARGET_FLAG -- --quiet
check_test_result "Rust tests" check_test_result "Rust tests"
cargo test $TARGET_FLAG --no-default-features --features no_std -- --quiet
check_test_result "Rust tests (no_std)"
cargo run $TARGET_FLAG --bin=flatbuffers_alloc_check cargo run $TARGET_FLAG --bin=flatbuffers_alloc_check
check_test_result "Rust flatbuffers heap alloc test" check_test_result "Rust flatbuffers heap alloc test"

View File

@@ -6,11 +6,16 @@ authors = ["Robert Winslow <hello@rwinslow.com>",
"FlatBuffers Maintainers"] "FlatBuffers Maintainers"]
[dependencies] [dependencies]
flatbuffers = { path = "../../rust/flatbuffers" } flatbuffers = { path = "../../rust/flatbuffers", default-features = false }
flexbuffers = { path = "../../rust/flexbuffers" } flexbuffers = { path = "../../rust/flexbuffers" }
serde_derive = "1.0" serde_derive = "1.0"
serde = "1.0" serde = "1.0"
serde_bytes = "0.11" serde_bytes = "0.11"
libc_alloc = { version = "1.0.3", optional = true }
[features]
default = ["flatbuffers/default"]
no_std = ["flatbuffers/no_std", "libc_alloc"]
[[bin]] [[bin]]
name = "monster_example" name = "monster_example"

View File

@@ -15,6 +15,10 @@
* limitations under the License. * limitations under the License.
*/ */
#[cfg(feature = "no_std")]
#[global_allocator]
static ALLOCATOR: libc_alloc::LibcAlloc = libc_alloc::LibcAlloc;
#[macro_use] #[macro_use]
#[cfg(not(miri))] // slow. #[cfg(not(miri))] // slow.
extern crate quickcheck; extern crate quickcheck;