[rust] Genericize flexbuffer reader (#6450)

* feature/rust-tokio-bytes added feature name for tokio-bytes

* Added flexbuffer implementation, TODO: typecast to avoid recurse

* Converted codebase to utilize FlexBuffer implementation, need to resolve deserialization issues

* Added todo for lifetime issue, may use &'de [u8] for deserializer instead of current method

* Added proper &[u8] implementation

* Removed unused struct

* Added experimental fix to get_slice

* Added experimental fix to get_slice

* Avoided lifetime issues via ref structs, need to check if this hurts peformance

* Updated deserializer implementation to allow for borrowed data from Reader struct

* Fixed bug with str

* Removed unnecessary generic parameter

* Added unsafe to avoid lifetime complaints, current tests pass, need to review alternatives to unsafe

* Opinionated: Removed bytes crate as this implementation could be done in a separate crate

* Cleaned up flatbuffer

* Fixed sample / example

* Resolved PR feedback, need to resolve issues with tests

* Cleaned up FlexBuffer trait to be an auto impl

* Removed TODO

* Reverted Deserializer to only support &'de [u8]

* Cleaned up / renamed function for clarification

* Renamed FlexBuffer -> InternalBuffer for clarification on it's purpose

* Fixed issue with key bytes

* resolved issues with broken tests, confirming this is a breaking change

* Removed FIXME that's solved by splitting String and Key variants

* Implemented associated types approach

* Fixed backward slice logic

* Fixed MapReader compile error

* Added from_buffer for deserialization, removed  function since it's only needed for deserialization

* Removed dead code

* Cleaned up buffer, removed AsRef in favor of Deref

* Renamed Buffer::as_str -> Buffer::buffer_str

* Minor cleanup

* Updated documentation, need to fix tests

* Removed unnecessary &

* Removed unused lifetime

* removed unnecessary as_ref

* Minor optimization wrap-up

* resolved issue with Clone

* Added test to verify no deep-copy

* Added  for optimization

* Updated to use empty fn instead of default

* Updated comments / test name - plus the 0.3.0 version bump

* comment
This commit is contained in:
Colin
2021-02-16 08:04:48 -05:00
committed by GitHub
parent a20f606c29
commit 4174c10e7a
14 changed files with 385 additions and 128 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "flexbuffers"
version = "0.2.2"
version = "0.3.0"
authors = ["Casper Neo <cneo@google.com>", "FlatBuffers Maintainers"]
edition = "2018"
license = "Apache-2.0"
@@ -20,7 +20,6 @@ serialize_human_readable = []
# You basically never need this to be true unless reading data from old binaries.
deserialize_human_readable = []
[dependencies]
serde = "1.0.119"
serde_derive = "1.0.119"

View File

@@ -0,0 +1,81 @@
use std::ops::{Deref, Range};
/// The underlying buffer that is used by a flexbuffer Reader.
///
/// This allows for custom buffer implementations as long as they can be viewed as a &[u8].
pub trait Buffer: Deref<Target = [u8]> + Sized {
// The `BufferString` allows for a buffer to return a custom string which will have the
// lifetime of the underlying buffer. A simple `std::str::from_utf8` wouldn't work since that
// returns a &str, which is then owned by the callee (cannot be returned from a function).
//
// Example: During deserialization a `BufferString` is returned, allowing the deserializer
// to "borrow" the given str - b/c there is a "lifetime" guarantee, so to speak, from the
// underlying buffer.
/// A BufferString which will live at least as long as the Buffer itself.
///
/// Deref's to UTF-8 `str`, and only generated from the `buffer_str` function Result.
type BufferString: Deref<Target = str> + Sized;
/// This method returns an instance of type Self. This allows for lifetimes to be tracked
/// in cases of deserialization.
///
/// It also lets custom buffers manage reference counts.
///
/// Returns None if:
/// - range start is greater than end
/// - range end is out of bounds
///
/// This operation should be fast -> O(1), ideally with no heap allocations.
fn slice(&self, range: Range<usize>) -> Option<Self>;
/// Creates a shallow copy of the given buffer, similar to `slice`.
///
/// This operation should be fast -> O(1), ideally with no heap allocations.
#[inline]
fn shallow_copy(&self) -> Self {
self.slice(0..self.len()).unwrap()
}
/// Creates an empty instance of a `Buffer`. This is different than `Default` b/c it
/// guarantees that the buffer instance will have length zero.
///
/// Most impls shold be able to implement this via `Default`.
fn empty() -> Self;
/// Based off of the `empty` function, allows override for optimization purposes.
#[inline]
fn empty_str() -> Self::BufferString {
Self::empty().buffer_str().unwrap()
}
/// Attempts to convert the given buffer to a custom string type.
///
/// This should fail if the type does not have valid UTF-8 bytes, and must be zero copy.
fn buffer_str(&self) -> Result<Self::BufferString, std::str::Utf8Error>;
}
impl<'de> Buffer for &'de [u8] {
type BufferString = &'de str;
#[inline]
fn slice(&self, range: Range<usize>) -> Option<Self> {
self.get(range)
}
#[inline]
fn empty() -> Self {
&[]
}
/// Based off of the `empty` function, allows override for optimization purposes.
#[inline]
fn empty_str() -> Self::BufferString {
&""
}
#[inline]
fn buffer_str(&self) -> Result<Self::BufferString, std::str::Utf8Error> {
std::str::from_utf8(self)
}
}

View File

@@ -14,9 +14,9 @@
use crate::builder::Builder;
use crate::private::Sealed;
use crate::{Blob, IndirectFloat, IndirectInt, IndirectUInt};
use crate::{Blob, Buffer, IndirectFloat, IndirectInt, IndirectUInt};
impl<'a> Sealed for Blob<'a> {}
impl<B: Buffer> Sealed for Blob<B> {}
impl Sealed for () {}
// TODO: String interning
@@ -44,9 +44,10 @@ impl Pushable for () {
builder.push_null();
}
}
impl<'a> Pushable for Blob<'a> {
impl<B: Buffer> Pushable for Blob<B> {
fn push_to_builder(self, builder: &mut Builder) {
builder.push_blob(self.0);
builder.push_blob(&self.0);
}
}

View File

@@ -44,12 +44,15 @@ mod bitwidth;
mod builder;
mod flexbuffer_type;
mod reader;
mod buffer;
pub use bitwidth::BitWidth;
pub use builder::Error as SerializationError;
pub use builder::{
singleton, Builder, BuilderOptions, FlexbufferSerializer, MapBuilder, Pushable, VectorBuilder,
};
pub use flexbuffer_type::FlexBufferType;
pub use buffer::Buffer;
pub use reader::Error as ReaderError;
pub use reader::{DeserializationError, MapReader, Reader, ReaderIterator, VectorReader};
use serde::{Deserialize, Serialize};
@@ -64,17 +67,32 @@ pub fn to_vec<T: Serialize>(x: T) -> Result<Vec<u8>, SerializationError> {
x.serialize(&mut s)?;
Ok(s.take_buffer())
}
/// Deserialize a type from a flexbuffer.
pub fn from_slice<'de, T: Deserialize<'de>>(buf: &'de [u8]) -> Result<T, DeserializationError> {
let r = Reader::get_root(buf)?;
T::deserialize(r)
}
/// Deserialize a type from a flexbuffer.
pub fn from_buffer<'de, T: Deserialize<'de>, B: Buffer>(
buf: &'de B
) -> Result<T, DeserializationError> {
let r = Reader::get_root(buf as &'de [u8])?;
T::deserialize(r)
}
/// This struct, when pushed will be serialized as a `FlexBufferType::Blob`.
///
/// A `Blob` is a variable width `length` followed by that many bytes of data.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Blob<'a>(pub &'a [u8]);
#[derive(Debug, PartialEq, Eq)]
pub struct Blob<B>(pub B);
impl<B: Buffer> Clone for Blob<B> {
fn clone(&self) -> Self {
Blob(self.0.shallow_copy())
}
}
/// This struct, when pushed, will be serialized as a `FlexBufferType::IndirectUInt`.
///

View File

@@ -35,6 +35,7 @@ impl std::fmt::Display for DeserializationError {
}
}
}
impl serde::de::Error for DeserializationError {
fn custom<T>(msg: T) -> Self
where
@@ -43,14 +44,16 @@ impl serde::de::Error for DeserializationError {
Self::Serde(format!("{}", msg))
}
}
impl std::convert::From<super::Error> for DeserializationError {
fn from(e: super::Error) -> Self {
Self::Reader(e)
}
}
impl<'de> SeqAccess<'de> for ReaderIterator<'de> {
impl<'de> SeqAccess<'de> for ReaderIterator<&'de [u8]> {
type Error = DeserializationError;
fn next_element_seed<T>(
&mut self,
seed: T,
@@ -64,6 +67,7 @@ impl<'de> SeqAccess<'de> for ReaderIterator<'de> {
Ok(None)
}
}
fn size_hint(&self) -> Option<usize> {
Some(self.len())
}
@@ -71,12 +75,13 @@ impl<'de> SeqAccess<'de> for ReaderIterator<'de> {
struct EnumReader<'de> {
variant: &'de str,
value: Option<Reader<'de>>,
value: Option<Reader<&'de [u8]>>,
}
impl<'de> EnumAccess<'de> for EnumReader<'de> {
type Error = DeserializationError;
type Variant = Reader<'de>;
type Variant = Reader<&'de [u8]>;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
@@ -87,9 +92,10 @@ impl<'de> EnumAccess<'de> for EnumReader<'de> {
}
struct MapAccessor<'de> {
keys: ReaderIterator<'de>,
vals: ReaderIterator<'de>,
keys: ReaderIterator<&'de [u8]>,
vals: ReaderIterator<&'de [u8]>,
}
impl<'de> MapAccess<'de> for MapAccessor<'de> {
type Error = DeserializationError;
@@ -103,6 +109,7 @@ impl<'de> MapAccess<'de> for MapAccessor<'de> {
Ok(None)
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: DeserializeSeed<'de>,
@@ -112,17 +119,20 @@ impl<'de> MapAccess<'de> for MapAccessor<'de> {
}
}
impl<'de> VariantAccess<'de> for Reader<'de> {
impl<'de> VariantAccess<'de> for Reader<&'de [u8]> {
type Error = DeserializationError;
fn unit_variant(self) -> Result<(), Self::Error> {
Ok(())
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
seed.deserialize(self)
}
// Tuple variants have an internally tagged representation. They are vectors where Index 0 is
// the discriminant and index N is field N-1.
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
@@ -131,6 +141,7 @@ impl<'de> VariantAccess<'de> for Reader<'de> {
{
visitor.visit_seq(self.as_vector().iter())
}
// Struct variants have an internally tagged representation. They are vectors where Index 0 is
// the discriminant and index N is field N-1.
fn struct_variant<V>(
@@ -149,7 +160,7 @@ impl<'de> VariantAccess<'de> for Reader<'de> {
}
}
impl<'de> Deserializer<'de> for crate::Reader<'de> {
impl<'de> Deserializer<'de> for Reader<&'de [u8]> {
type Error = DeserializationError;
fn is_human_readable(&self) -> bool {
cfg!(deserialize_human_readable)
@@ -188,22 +199,26 @@ impl<'de> Deserializer<'de> for crate::Reader<'de> {
(ty, bw) => unreachable!("TODO deserialize_any {:?} {:?}.", ty, bw),
}
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 str unit unit_struct bytes
ignored_any map identifier struct tuple tuple_struct seq string
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_char(self.as_u8() as char)
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_byte_buf(self.get_blob()?.0.to_vec())
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
@@ -214,6 +229,7 @@ impl<'de> Deserializer<'de> for crate::Reader<'de> {
visitor.visit_some(self)
}
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
@@ -224,6 +240,7 @@ impl<'de> Deserializer<'de> for crate::Reader<'de> {
{
visitor.visit_newtype_struct(self)
}
fn deserialize_enum<V>(
self,
_name: &'static str,

View File

@@ -12,19 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use super::{Reader, VectorReader};
use crate::{Buffer, Reader, VectorReader};
use std::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator};
/// Iterates over a flexbuffer vector, typed vector, or map. Yields [Readers](struct.Reader.html).
///
/// If any error occurs, the Reader is defaulted to a Null flexbuffer Reader.
pub struct ReaderIterator<'de> {
pub(super) reader: VectorReader<'de>,
pub struct ReaderIterator<B> {
pub(super) reader: VectorReader<B>,
pub(super) front: usize,
end: usize,
}
impl<'de> ReaderIterator<'de> {
pub(super) fn new(reader: VectorReader<'de>) -> Self {
impl<B: Buffer> ReaderIterator<B> {
pub(super) fn new(reader: VectorReader<B>) -> Self {
let end = reader.len();
ReaderIterator {
reader,
@@ -33,8 +34,9 @@ impl<'de> ReaderIterator<'de> {
}
}
}
impl<'de> Iterator for ReaderIterator<'de> {
type Item = Reader<'de>;
impl<B: Buffer> Iterator for ReaderIterator<B> {
type Item = Reader<B>;
fn next(&mut self) -> Option<Self::Item> {
if self.front < self.end {
let r = self.reader.idx(self.front);
@@ -49,7 +51,8 @@ impl<'de> Iterator for ReaderIterator<'de> {
(remaining, Some(remaining))
}
}
impl<'de> DoubleEndedIterator for ReaderIterator<'de> {
impl<B: Buffer> DoubleEndedIterator for ReaderIterator<B> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.front < self.end {
self.end -= 1;
@@ -59,5 +62,6 @@ impl<'de> DoubleEndedIterator for ReaderIterator<'de> {
}
}
}
impl<'de> ExactSizeIterator for ReaderIterator<'de> {}
impl<'de> FusedIterator for ReaderIterator<'de> {}
impl<B: Buffer> ExactSizeIterator for ReaderIterator<B> {}
impl<B: Buffer> FusedIterator for ReaderIterator<B> {}

View File

@@ -14,6 +14,7 @@
use super::{deref_offset, unpack_type, Error, Reader, ReaderIterator, VectorReader};
use crate::BitWidth;
use crate::Buffer;
use std::cmp::Ordering;
use std::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator};
@@ -22,9 +23,8 @@ use std::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}
/// MapReaders may be indexed with strings or usizes. `index` returns a result type,
/// which may indicate failure due to a missing key or bad data, `idx` returns an Null Reader in
/// cases of error.
#[derive(Default, Clone)]
pub struct MapReader<'de> {
pub(super) buffer: &'de [u8],
pub struct MapReader<B> {
pub(super) buffer: B,
pub(super) values_address: usize,
pub(super) keys_address: usize,
pub(super) values_width: BitWidth,
@@ -32,8 +32,30 @@ pub struct MapReader<'de> {
pub(super) length: usize,
}
impl<B: Buffer> Clone for MapReader<B> {
fn clone(&self) -> Self {
MapReader {
buffer: self.buffer.shallow_copy(),
..*self
}
}
}
impl<B: Buffer> Default for MapReader<B> {
fn default() -> Self {
MapReader {
buffer: B::empty(),
values_address: usize::default(),
keys_address: usize::default(),
values_width: BitWidth::default(),
keys_width: BitWidth::default(),
length: usize::default(),
}
}
}
// manual implementation of Debug because buffer slice can't be automatically displayed
impl<'de> std::fmt::Debug for MapReader<'de> {
impl<B: Buffer> std::fmt::Debug for MapReader<B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// skips buffer field
f.debug_struct("MapReader")
@@ -46,15 +68,19 @@ impl<'de> std::fmt::Debug for MapReader<'de> {
}
}
impl<'de> MapReader<'de> {
impl<B: Buffer> MapReader<B> {
/// Returns the number of key/value pairs are in the map.
pub fn len(&self) -> usize {
let thing = self.clone();
println!("{:?}", &thing);
self.length
}
/// Returns true if the map has zero key/value pairs.
pub fn is_empty(&self) -> bool {
self.length == 0
}
// Using &CStr will eagerly compute the length of the key. &str needs length info AND utf8
// validation. This version is faster than both.
fn lazy_strcmp(&self, key_addr: usize, key: &str) -> Ordering {
@@ -62,6 +88,7 @@ impl<'de> MapReader<'de> {
let k = self.buffer[key_addr..].iter().take_while(|&&b| b != b'\0');
k.cmp(key.as_bytes().iter())
}
/// Returns the index of a given key in the map.
pub fn index_key(&self, key: &str) -> Option<usize> {
let (mut low, mut high) = (0, self.length);
@@ -69,7 +96,7 @@ impl<'de> MapReader<'de> {
let i = (low + high) / 2;
let key_offset_address = self.keys_address + i * self.keys_width.n_bytes();
let key_address =
deref_offset(self.buffer, key_offset_address, self.keys_width).ok()?;
deref_offset(&self.buffer, key_offset_address, self.keys_width).ok()?;
match self.lazy_strcmp(key_address, key) {
Ordering::Equal => return Some(i),
Ordering::Less => low = if i == low { i + 1 } else { i },
@@ -78,15 +105,18 @@ impl<'de> MapReader<'de> {
}
None
}
/// Index into a map with a key or usize.
pub fn index<I: MapReaderIndexer>(&self, i: I) -> Result<Reader<'de>, Error> {
pub fn index<I: MapReaderIndexer>(&self, i: I) -> Result<Reader<B>, Error> {
i.index_map_reader(self)
}
/// Index into a map with a key or usize. If any errors occur a Null reader is returned.
pub fn idx<I: MapReaderIndexer>(&self, i: I) -> Reader<'de> {
pub fn idx<I: MapReaderIndexer>(&self, i: I) -> Reader<B> {
i.index_map_reader(self).unwrap_or_default()
}
fn usize_index(&self, i: usize) -> Result<Reader<'de>, Error> {
fn usize_index(&self, i: usize) -> Result<Reader<B>, Error> {
if i >= self.length {
return Err(Error::IndexOutOfBounds);
}
@@ -98,22 +128,24 @@ impl<'de> MapReader<'de> {
.ok_or(Error::FlexbufferOutOfBounds)
.and_then(|&b| unpack_type(b))?;
Reader::new(
&self.buffer,
self.buffer.shallow_copy(),
data_address,
fxb_type,
width,
self.values_width,
)
}
fn key_index(&self, k: &str) -> Result<Reader<'de>, Error> {
fn key_index(&self, k: &str) -> Result<Reader<B>, Error> {
let i = self.index_key(k).ok_or(Error::KeyNotFound)?;
self.usize_index(i)
}
/// Iterate over the values of the map.
pub fn iter_values(&self) -> ReaderIterator<'de> {
pub fn iter_values(&self) -> ReaderIterator<B> {
ReaderIterator::new(VectorReader {
reader: Reader {
buffer: self.buffer,
buffer: self.buffer.shallow_copy(),
fxb_type: crate::FlexBufferType::Map,
width: self.values_width,
address: self.values_address,
@@ -121,17 +153,19 @@ impl<'de> MapReader<'de> {
length: self.length,
})
}
/// Iterate over the keys of the map.
pub fn iter_keys(
&self,
) -> impl Iterator<Item = &'de str> + DoubleEndedIterator + ExactSizeIterator + FusedIterator
) -> impl Iterator<Item = B::BufferString> + DoubleEndedIterator + ExactSizeIterator + FusedIterator
{
self.keys_vector().iter().map(|k| k.as_str())
}
pub fn keys_vector(&self) -> VectorReader<'de> {
pub fn keys_vector(&self) -> VectorReader<B> {
VectorReader {
reader: Reader {
buffer: self.buffer,
buffer: self.buffer.shallow_copy(),
fxb_type: crate::FlexBufferType::VectorKey,
width: self.keys_width,
address: self.keys_address,
@@ -140,18 +174,21 @@ impl<'de> MapReader<'de> {
}
}
}
pub trait MapReaderIndexer {
fn index_map_reader<'de>(self, r: &MapReader<'de>) -> Result<Reader<'de>, Error>;
fn index_map_reader<B: Buffer>(self, r: &MapReader<B>) -> Result<Reader<B>, Error>;
}
impl MapReaderIndexer for usize {
#[inline]
fn index_map_reader<'de>(self, r: &MapReader<'de>) -> Result<Reader<'de>, Error> {
fn index_map_reader<B: Buffer>(self, r: &MapReader<B>) -> Result<Reader<B>, Error> {
r.usize_index(self)
}
}
impl MapReaderIndexer for &str {
#[inline]
fn index_map_reader<'de>(self, r: &MapReader<'de>) -> Result<Reader<'de>, Error> {
fn index_map_reader<B: Buffer>(self, r: &MapReader<B>) -> Result<Reader<B>, Error> {
r.key_index(self)
}
}

View File

@@ -14,7 +14,7 @@
use crate::bitwidth::BitWidth;
use crate::flexbuffer_type::FlexBufferType;
use crate::Blob;
use crate::{Buffer, Blob};
use std::convert::{TryFrom, TryInto};
use std::fmt;
use std::ops::Rem;
@@ -143,16 +143,37 @@ macro_rules! as_default {
/// - The `as_T` methods will try their best to return to a value of type `T`
/// (by casting or even parsing a string if necessary) but ultimately returns `T::default` if it
/// fails. This behavior is analogous to that of flexbuffers C++.
#[derive(Default, Clone)]
pub struct Reader<'de> {
pub struct Reader<B> {
fxb_type: FlexBufferType,
width: BitWidth,
address: usize,
buffer: &'de [u8],
buffer: B,
}
impl<B: Buffer> Clone for Reader<B> {
fn clone(&self) -> Self {
Reader {
fxb_type: self.fxb_type,
width: self.width,
address: self.address,
buffer: self.buffer.shallow_copy(),
}
}
}
impl<B: Buffer> Default for Reader<B> {
fn default() -> Self {
Reader {
fxb_type: FlexBufferType::default(),
width: BitWidth::default(),
address: usize::default(),
buffer: B::empty(),
}
}
}
// manual implementation of Debug because buffer slice can't be automatically displayed
impl<'de> std::fmt::Debug for Reader<'de> {
impl<B> std::fmt::Debug for Reader<B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// skips buffer field
f.debug_struct("Reader")
@@ -181,16 +202,16 @@ fn deref_offset(buffer: &[u8], address: usize, width: BitWidth) -> Result<usize,
safe_sub(address, off)
}
impl<'de> Reader<'de> {
impl<B: Buffer> Reader<B> {
fn new(
buffer: &'de [u8],
buffer: B,
mut address: usize,
mut fxb_type: FlexBufferType,
width: BitWidth,
parent_width: BitWidth,
) -> Result<Self, Error> {
if fxb_type.is_reference() {
address = deref_offset(buffer, address, parent_width)?;
address = deref_offset(&buffer, address, parent_width)?;
// Indirects were dereferenced.
if let Some(t) = fxb_type.to_direct() {
fxb_type = t;
@@ -203,9 +224,10 @@ impl<'de> Reader<'de> {
buffer,
})
}
/// Parses the flexbuffer from the given buffer. Assumes the flexbuffer root is the last byte
/// of the buffer.
pub fn get_root(buffer: &'de [u8]) -> Result<Self, Error> {
pub fn get_root(buffer: B) -> Result<Self, Error> {
let end = buffer.len();
if end < 3 {
return Err(Error::FlexbufferOutOfBounds);
@@ -218,21 +240,30 @@ impl<'de> Reader<'de> {
let address = safe_sub(end - 2, root_width.n_bytes())?;
Self::new(buffer, address, fxb_type, width, root_width)
}
/// Convenience function to get the underlying buffer. By using `shallow_copy`, this preserves
/// the lifetime that the underlying buffer has.
pub fn buffer(&self) -> B {
self.buffer.shallow_copy()
}
/// Returns the FlexBufferType of this Reader.
pub fn flexbuffer_type(&self) -> FlexBufferType {
self.fxb_type
}
/// Returns the bitwidth of this Reader.
pub fn bitwidth(&self) -> BitWidth {
self.width
}
/// Returns the length of the Flexbuffer. If the type has no length, or if an error occurs,
/// 0 is returned.
pub fn length(&self) -> usize {
if let Some(len) = self.fxb_type.fixed_length_vector_length() {
len
} else if self.fxb_type.has_length_slot() && self.address >= self.width.n_bytes() {
read_usize(self.buffer, self.address - self.width.n_bytes(), self.width)
read_usize(&self.buffer, self.address - self.width.n_bytes(), self.width)
} else {
0
}
@@ -240,11 +271,13 @@ impl<'de> Reader<'de> {
/// Returns true if the flexbuffer is aligned to 8 bytes. This guarantees, for valid
/// flexbuffers, that the data is correctly aligned in memory and slices can be read directly
/// e.g. with `get_f64s` or `get_i16s`.
#[inline]
pub fn is_aligned(&self) -> bool {
(self.buffer.as_ptr() as usize).rem(8) == 0
}
as_default!(as_vector, get_vector, VectorReader<'de>);
as_default!(as_map, get_map, MapReader<'de>);
as_default!(as_vector, get_vector, VectorReader<B>);
as_default!(as_map, get_map, MapReader<B>);
fn expect_type(&self, ty: FlexBufferType) -> Result<(), Error> {
if self.fxb_type == ty {
@@ -266,11 +299,16 @@ impl<'de> Reader<'de> {
})
}
}
/// Directly reads a slice of type `T`where `T` is one of `u8,u16,u32,u64,i8,i16,i32,i64,f32,f64`.
/// Directly reads a slice of type `T` where `T` is one of `u8,u16,u32,u64,i8,i16,i32,i64,f32,f64`.
/// Returns Err if the type, bitwidth, or memory alignment does not match. Since the bitwidth is
/// dynamic, its better to use a VectorReader unless you know your data and performance is critical.
#[cfg(target_endian = "little")]
pub fn get_slice<T: ReadLE>(&self) -> Result<&'de [T], Error> {
#[deprecated(
since = "0.3.0",
note = "This function is unsafe - if this functionality is needed it can be added separately via the `buffer` function."
)]
pub fn get_slice<T: ReadLE>(&self) -> Result<&[T], Error> {
if self.flexbuffer_type().typed_vector_type() != T::VECTOR_TYPE.typed_vector_type() {
self.expect_type(T::VECTOR_TYPE)?;
}
@@ -278,10 +316,11 @@ impl<'de> Reader<'de> {
self.expect_bw(T::WIDTH)?;
}
let end = self.address + self.length() * std::mem::size_of::<T>();
let slice = &self
let slice: &[u8] = self
.buffer
.get(self.address..end)
.ok_or(Error::FlexbufferOutOfBounds)?;
// `align_to` is required because the point of this function is to directly hand back a
// slice of scalars. This can fail because Rust's default allocator is not 16byte aligned
// (though in practice this only happens for small buffers).
@@ -293,6 +332,8 @@ impl<'de> Reader<'de> {
}
}
/// Returns the value of the reader if it is a boolean.
/// Otherwise Returns error.
pub fn get_bool(&self) -> Result<bool, Error> {
self.expect_type(FlexBufferType::Bool)?;
Ok(
@@ -301,30 +342,50 @@ impl<'de> Reader<'de> {
.any(|&b| b != 0),
)
}
pub fn get_key(&self) -> Result<&'de str, Error> {
/// Gets the length of the key if this type is a key.
///
/// Otherwise, returns an error.
#[inline]
fn get_key_len(&self) -> Result<usize, Error> {
self.expect_type(FlexBufferType::Key)?;
let (length, _) = self.buffer[self.address..]
.iter()
.enumerate()
.find(|(_, &b)| b == b'\0')
.unwrap_or((0, &0));
let bytes = &self.buffer[self.address..self.address + length];
Ok(std::str::from_utf8(bytes)?)
Ok(length)
}
pub fn get_blob(&self) -> Result<Blob<'de>, Error> {
/// Retrieves the string value up until the first `\0` character.
pub fn get_key(&self) -> Result<B::BufferString, Error> {
let bytes = self.buffer
.slice(self.address..self.address + self.get_key_len()?)
.ok_or(Error::IndexOutOfBounds)?;
Ok(bytes.buffer_str()?)
}
pub fn get_blob(&self) -> Result<Blob<B>, Error> {
self.expect_type(FlexBufferType::Blob)?;
Ok(Blob(
&self.buffer[self.address..self.address + self.length()],
self.buffer
.slice(self.address..self.address + self.length())
.ok_or(Error::IndexOutOfBounds)?
))
}
pub fn as_blob(&self) -> Blob<'de> {
self.get_blob().unwrap_or(Blob(&[]))
pub fn as_blob(&self) -> Blob<B> {
self.get_blob().unwrap_or(Blob(B::empty()))
}
pub fn get_str(&self) -> Result<&'de str, Error> {
/// Retrieves str pointer, errors if invalid UTF-8, or the provided index
/// is out of bounds.
pub fn get_str(&self) -> Result<B::BufferString, Error> {
self.expect_type(FlexBufferType::String)?;
let bytes = &self.buffer[self.address..self.address + self.length()];
Ok(std::str::from_utf8(bytes)?)
let bytes = self.buffer.slice(self.address..self.address + self.length());
Ok(bytes.ok_or(Error::ReadUsizeOverflowed)?.buffer_str()?)
}
fn get_map_info(&self) -> Result<(usize, BitWidth), Error> {
self.expect_type(FlexBufferType::Map)?;
if 3 * self.width.n_bytes() >= self.address {
@@ -333,17 +394,18 @@ impl<'de> Reader<'de> {
let keys_offset_address = self.address - 3 * self.width.n_bytes();
let keys_width = {
let kw_addr = self.address - 2 * self.width.n_bytes();
let kw = read_usize(self.buffer, kw_addr, self.width);
let kw = read_usize(&self.buffer, kw_addr, self.width);
BitWidth::from_nbytes(kw).ok_or(Error::InvalidMapKeysVectorWidth)
}?;
Ok((keys_offset_address, keys_width))
}
pub fn get_map(&self) -> Result<MapReader<'de>, Error> {
pub fn get_map(&self) -> Result<MapReader<B>, Error> {
let (keys_offset_address, keys_width) = self.get_map_info()?;
let keys_address = deref_offset(self.buffer, keys_offset_address, self.width)?;
let keys_address = deref_offset(&self.buffer, keys_offset_address, self.width)?;
// TODO(cneo): Check that vectors length equals keys length.
Ok(MapReader {
buffer: self.buffer,
buffer: self.buffer.shallow_copy(),
values_address: self.address,
values_width: self.width,
keys_address,
@@ -351,6 +413,7 @@ impl<'de> Reader<'de> {
length: self.length(),
})
}
/// Tries to read a FlexBufferType::UInt. Returns Err if the type is not a UInt or if the
/// address is out of bounds.
pub fn get_u64(&self) -> Result<u64, Error> {
@@ -443,7 +506,7 @@ impl<'de> Reader<'de> {
FlexBufferType::Float => self.get_f64().unwrap_or_default() as u64,
FlexBufferType::String => {
if let Ok(s) = self.get_str() {
if let Ok(f) = u64::from_str(s) {
if let Ok(f) = u64::from_str(&s) {
return f;
}
}
@@ -470,7 +533,7 @@ impl<'de> Reader<'de> {
FlexBufferType::Float => self.get_f64().unwrap_or_default() as i64,
FlexBufferType::String => {
if let Ok(s) = self.get_str() {
if let Ok(f) = i64::from_str(s) {
if let Ok(f) = i64::from_str(&s) {
return f;
}
}
@@ -493,7 +556,7 @@ impl<'de> Reader<'de> {
FlexBufferType::Float => self.get_f64().unwrap_or_default(),
FlexBufferType::String => {
if let Ok(s) = self.get_str() {
if let Ok(f) = f64::from_str(s) {
if let Ok(f) = f64::from_str(&s) {
return f;
}
}
@@ -508,14 +571,15 @@ impl<'de> Reader<'de> {
}
/// Returns empty string if you're not trying to read a string.
pub fn as_str(&self) -> &'de str {
pub fn as_str(&self) -> B::BufferString {
match self.fxb_type {
FlexBufferType::String => self.get_str().unwrap_or_default(),
FlexBufferType::Key => self.get_key().unwrap_or_default(),
_ => "",
FlexBufferType::String => self.get_str().unwrap_or(B::empty_str()),
FlexBufferType::Key => self.get_key().unwrap_or(B::empty_str()),
_ => B::empty_str(),
}
}
pub fn get_vector(&self) -> Result<VectorReader<'de>, Error> {
pub fn get_vector(&self) -> Result<VectorReader<B>, Error> {
if !self.fxb_type.is_vector() {
self.expect_type(FlexBufferType::Vector)?;
};
@@ -526,7 +590,7 @@ impl<'de> Reader<'de> {
}
}
impl<'de> fmt::Display for Reader<'de> {
impl<B: Buffer> fmt::Display for Reader<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use FlexBufferType::*;
match self.flexbuffer_type() {
@@ -534,7 +598,7 @@ impl<'de> fmt::Display for Reader<'de> {
UInt => write!(f, "{}", self.as_u64()),
Int => write!(f, "{}", self.as_i64()),
Float => write!(f, "{}", self.as_f64()),
Key | String => write!(f, "{:?}", self.as_str()),
Key | String => write!(f, "{:?}", &self.as_str() as &str),
Bool => write!(f, "{}", self.as_bool()),
Blob => write!(f, "blob"),
Map => {
@@ -542,9 +606,9 @@ impl<'de> fmt::Display for Reader<'de> {
let m = self.as_map();
let mut pairs = m.iter_keys().zip(m.iter_values());
if let Some((k, v)) = pairs.next() {
write!(f, "{:?}: {}", k, v)?;
write!(f, "{:?}: {}", &k as &str, v)?;
for (k, v) in pairs {
write!(f, ", {:?}: {}", k, v)?;
write!(f, ", {:?}: {}", &k as &str, v)?;
}
}
write!(f, "}}")
@@ -570,6 +634,7 @@ fn f32_from_le_bytes(bytes: [u8; 4]) -> f32 {
let bits = <u32>::from_le_bytes(bytes);
<f32>::from_bits(bits)
}
fn f64_from_le_bytes(bytes: [u8; 8]) -> f64 {
let bits = <u64>::from_le_bytes(bytes);
<f64>::from_bits(bits)
@@ -601,4 +666,4 @@ fn unpack_type(ty: u8) -> Result<(FlexBufferType, BitWidth), Error> {
let w = BitWidth::try_from(ty & 3u8).map_err(|_| Error::InvalidPackedType)?;
let t = FlexBufferType::try_from(ty >> 2).map_err(|_| Error::InvalidPackedType)?;
Ok((t, w))
}
}

View File

@@ -13,22 +13,39 @@
// limitations under the License.
use super::{unpack_type, Error, Reader, ReaderIterator};
use crate::{BitWidth, FlexBufferType};
use crate::{BitWidth, Buffer, FlexBufferType};
#[derive(Default, Clone)]
/// Allows indexing on any flexbuffer vector type, (heterogenous vector, typed vector, or fixed
/// length typed vector).
///
/// VectorReaders may be indexed with usize, `index` returns a result type
/// which may indicate failure due to indexing out of bounds or bad data. `idx` returns a
/// Null Reader in the event of any failure.
pub struct VectorReader<'de> {
pub(super) reader: Reader<'de>,
pub struct VectorReader<B> {
pub(super) reader: Reader<B>,
// Cache the length because read_usize can be slow.
pub(super) length: usize,
}
impl<'de> VectorReader<'de> {
impl<B: Buffer> Clone for VectorReader<B> {
fn clone(&self) -> Self {
VectorReader {
reader: self.reader.clone(),
..*self
}
}
}
impl<B: Buffer> Default for VectorReader<B> {
fn default() -> Self {
VectorReader {
reader: Reader::default(),
length: usize::default()
}
}
}
impl<B: Buffer> VectorReader<B> {
/// Returns the number of elements in the vector.
pub fn len(&self) -> usize {
self.length
@@ -50,25 +67,26 @@ impl<'de> VectorReader<'de> {
}
}
/// Index into a flexbuffer vector. Any errors are defaulted to Null Readers.
pub fn idx(&self, i: usize) -> Reader<'de> {
pub fn idx(&self, i: usize) -> Reader<B> {
self.index(i).unwrap_or_default()
}
/// Index into a flexbuffer.
pub fn index(&self, i: usize) -> Result<Reader<'de>, Error> {
pub fn index(&self, i: usize) -> Result<Reader<B>, Error> {
if i >= self.length {
return Err(Error::IndexOutOfBounds);
}
let (fxb_type, bw) = self.get_elem_type(i)?;
let data_address = self.reader.address + self.reader.width.n_bytes() * i;
Reader::new(
self.reader.buffer,
self.reader.buffer.shallow_copy(),
data_address,
fxb_type,
bw,
self.reader.width,
)
}
pub fn iter(&self) -> ReaderIterator<'de> {
pub fn iter(&self) -> ReaderIterator<B> {
ReaderIterator::new(self.clone())
}
}

View File

@@ -224,7 +224,7 @@ fn serialize_monsters(b: &mut Bencher) {
b.iter(go);
b.bytes = n as u64;
}
fn validate_monster(r: MapReader) {
fn validate_monster(r: MapReader<&[u8]>) {
assert_eq!(r.idx("type").as_str(), "great orc");
assert_eq!(r.idx("age").as_u8(), 100);
assert_eq!(r.idx("name").as_str(), "Mr. Orc");

View File

@@ -311,7 +311,7 @@ fn utf8_snowman() {
1, // Root bytes
]
);
let r = Reader::get_root(&buf).unwrap();
let r = Reader::get_root(buf.as_ref()).unwrap();
assert_eq!(r.get_str(), Ok("snowman ☃︎"));
}
#[test]

View File

@@ -18,14 +18,14 @@ use flexbuffers::*;
fn read_golden_flexbuffer() {
let s =
std::fs::read("../gold_flexbuffer_example.bin").expect("Unable to read golden flexbuffer.");
let r = Reader::get_root(&s).unwrap();
let r = Reader::get_root(s.as_ref()).unwrap();
let m = r.as_map();
let vec = m.idx("vec").as_vector();
assert_eq!(vec.idx(0).as_i8(), -100);
assert_eq!(vec.idx(1).as_str(), "Fred");
assert_eq!(vec.idx(2).as_f32(), 4.0);
assert_eq!(vec.idx(3).as_blob(), Blob(&[77]));
assert_eq!(vec.idx(3).as_blob(), Blob([77].as_ref()));
assert_eq!(vec.idx(4).flexbuffer_type(), FlexBufferType::Bool);
assert_eq!(vec.idx(4).as_bool(), false);
assert_eq!(vec.idx(5).as_f64(), 4.0);

View File

@@ -20,7 +20,7 @@ use quickcheck::QuickCheck;
#[cfg(not(miri))] // slow.
fn qc_reader_no_crash() {
fn no_crash(xs: Vec<u8>) -> bool {
let r = Reader::get_root(&xs);
let r = Reader::get_root(xs.as_ref());
r.is_err() || r.is_ok()
}
QuickCheck::new()
@@ -133,7 +133,7 @@ fn string_as_num() {
}
#[test]
fn null_reader() {
let n = Reader::default();
let n = Reader::<&[u8]>::default();
assert_eq!(n.as_i8(), 0);
assert_eq!(n.as_i16(), 0);
assert_eq!(n.as_i32(), 0);
@@ -159,7 +159,7 @@ fn get_root_deref_oob() {
(FlexBufferType::Vector as u8) << 2 | BitWidth::W8 as u8,
1,
];
assert!(Reader::get_root(s).is_err());
assert!(Reader::get_root(s.as_ref()).is_err());
}
#[test]
fn get_root_deref_u64() {
@@ -170,7 +170,24 @@ fn get_root_deref_u64() {
1,
];
// The risk of crashing is reading 8 bytes from index 0.
assert_eq!(Reader::get_root(s).unwrap().as_u64(), 0);
assert_eq!(Reader::get_root(s.as_ref()).unwrap().as_u64(), 0);
}
/// Verifies that the clone operation is shallow / zero copy.
#[test]
fn clone_is_shallow() {
let mut fxb = Builder::default();
let mut m = fxb.start_map();
m.push("a", &[-1i8, -2, -3, -4]);
m.push("b", 250i64);
m.push("c", 5000u16);
m.end_map();
let r = Reader::get_root(fxb.view()).unwrap();
let r2 = r.clone();
assert_eq!(r.buffer().as_ptr(), r2.buffer().as_ptr());
}
#[test]

View File

@@ -43,7 +43,7 @@ quickcheck! {
v.push(x);
}
v.end_vector();
let r = Reader::get_root(&builder.view()).unwrap().as_vector();
let r = Reader::get_root(builder.view()).unwrap().as_vector();
xs.iter().enumerate().all(|(i, &x)| r.index(i).unwrap().get_bool().unwrap() == x)
}
fn qc_vec_uint(xs: Vec<u64>) -> bool {
@@ -53,7 +53,7 @@ quickcheck! {
v.push(x);
}
v.end_vector();
let r = Reader::get_root(&builder.view()).unwrap().as_vector();
let r = Reader::get_root(builder.view()).unwrap().as_vector();
xs.iter().enumerate().all(|(i, &x)| r.idx(i).as_u64() == x)
}
fn qc_vec_int(xs: Vec<i64>) -> bool {
@@ -63,7 +63,7 @@ quickcheck! {
v.push(x);
}
v.end_vector();
let r = Reader::get_root(&builder.view()).unwrap().as_vector();
let r = Reader::get_root(builder.view()).unwrap().as_vector();
xs.iter().enumerate().all(|(i, &x)| r.idx(i).as_i64() == x)
}
fn qc_vec_float(xs: Vec<f64>) -> bool {
@@ -73,7 +73,7 @@ quickcheck! {
v.push(x);
}
v.end_vector();
let r = Reader::get_root(&builder.view()).unwrap().as_vector();
let r = Reader::get_root(builder.view()).unwrap().as_vector();
xs.iter().enumerate().all(|(i, &x)| (r.idx(i).as_f64() - x).abs() < std::f64::EPSILON)
}
fn qc_vec_string(xs: Vec<String>) -> bool {
@@ -83,7 +83,7 @@ quickcheck! {
v.push(x as &str);
}
v.end_vector();
let r = Reader::get_root(&builder.view()).unwrap().as_vector();
let r = Reader::get_root(builder.view()).unwrap().as_vector();
xs.iter().enumerate().all(|(i, x)| (r.idx(i).as_str() == x))
}
fn qc_map_int(xs: std::collections::BTreeMap<NonNullString, i64>) -> bool {
@@ -93,7 +93,7 @@ quickcheck! {
m.push(&k.0, v);
}
m.end_map();
let r = Reader::get_root(&builder.view()).unwrap().as_map();
let r = Reader::get_root(builder.view()).unwrap().as_map();
xs.iter().enumerate().all(|(i, (k, &v))| {
r.idx(i).as_i64() == v && r.idx(k.0.as_str()).as_i64() == v
})
@@ -105,7 +105,7 @@ quickcheck! {
m.push(&k.0, v as &str);
}
m.end_map();
let r = Reader::get_root(&builder.view()).unwrap().as_map();
let r = Reader::get_root(builder.view()).unwrap().as_map();
xs.iter().enumerate().all(|(i, (k, v))| {
r.idx(i).as_str() == v && r.idx(k.0.as_str()).as_str() == v
})
@@ -114,10 +114,10 @@ quickcheck! {
let mut builder = Builder::default();
let mut v = builder.start_vector();
for x in &xs {
v.push(Blob(&x));
v.push(Blob(x.as_ref()));
}
v.end_vector();
let r = Reader::get_root(&builder.view()).unwrap().as_vector();
let r = Reader::get_root(builder.view()).unwrap().as_vector();
xs.iter().enumerate().all(
|(i, x)| r.idx(i).get_blob().unwrap().0.iter().eq(x.iter())
)
@@ -209,7 +209,7 @@ fn string() {
v.push("barrr");
v.push("bazzzzzz");
v.end_vector();
let r = Reader::get_root(&builder.view()).unwrap().as_vector();
let r = Reader::get_root(builder.view()).unwrap().as_vector();
assert_eq!(r.idx(0).as_str(), "foo");
assert_eq!(r.idx(1).as_str(), "barrr");
assert_eq!(r.idx(2).as_str(), "bazzzzzz");
@@ -218,7 +218,7 @@ fn string() {
#[test]
fn store_13() {
let finished = singleton::<i32>(13);
let r = Reader::get_root(&finished).unwrap();
let r = Reader::get_root(finished.as_ref()).unwrap();
assert_eq!(r.as_i32(), 13);
}
#[test]
@@ -233,7 +233,7 @@ fn singleton_vector_uint_4_16bit() {
let buf2 = singleton(&[2u8, 3, 5]);
assert_eq!(buf1, buf2.as_slice());
let r = Reader::get_root(&buf1).unwrap().as_vector();
let r = Reader::get_root(buf1).unwrap().as_vector();
assert_eq!(r.idx(0).get_u64(), Ok(2));
assert_eq!(r.idx(1).get_u64(), Ok(3));
assert_eq!(r.idx(2).get_u64(), Ok(5));
@@ -248,7 +248,7 @@ fn vector_uint4() {
v.push(5u8);
v.push(7u8);
v.end_vector();
let r = Reader::get_root(&fxb.view()).unwrap();
let r = Reader::get_root(fxb.view()).unwrap();
let v = r.as_vector();
assert_eq!(v.idx(0).get_u64(), Ok(2));
assert_eq!(v.idx(1).get_u64(), Ok(3));
@@ -264,13 +264,13 @@ fn vector_uint4() {
fn store_and_read_blob() {
let mut fxb = Builder::default();
let mut v = fxb.start_vector();
v.push(Blob(&[1, 2, 3, 4]));
v.push(Blob(&[5, 6, 7]));
v.push(Blob([1, 2, 3, 4].as_ref()));
v.push(Blob([5, 6, 7].as_ref()));
v.end_vector();
let r = Reader::get_root(&fxb.view()).unwrap().as_vector();
assert_eq!(r.idx(0).get_blob(), Ok(Blob(&[1, 2, 3, 4])));
assert_eq!(r.idx(1).get_blob(), Ok(Blob(&[5, 6, 7])));
let r = Reader::get_root(fxb.view()).unwrap().as_vector();
assert_eq!(r.idx(0).get_blob(), Ok(Blob([1, 2, 3, 4].as_ref())));
assert_eq!(r.idx(1).get_blob(), Ok(Blob([5, 6, 7].as_ref())));
}
#[test]
fn map_64bit() {
@@ -280,7 +280,7 @@ fn map_64bit() {
m.push("b", u64::max_value() - 3);
m.end_map();
let r = Reader::get_root(&fxb.view()).unwrap().as_map();
let r = Reader::get_root(fxb.view()).unwrap().as_map();
assert_eq!(r.idx("a").as_u16(), 257);
assert_eq!(r.idx("b").as_u64(), u64::max_value() - 3);
}
@@ -341,7 +341,7 @@ fn map_strings() {
#[test]
fn store_u64() {
let finished = singleton(u64::max_value() - 10);
let r = Reader::get_root(&finished).unwrap();
let r = Reader::get_root(finished.as_ref()).unwrap();
assert_eq!(r.get_u64(), Ok(u64::max_value() - 10));
}
#[test]
@@ -444,7 +444,7 @@ fn serialize_serde_with_bytes_as_blob() {
Foo(vec![5, 6, 7, 8]).serialize(&mut s).unwrap();
let reader = Reader::get_root(s.view()).unwrap();
assert_eq!(reader.flexbuffer_type(), FlexBufferType::Blob);
assert_eq!(reader.as_blob(), Blob(&[5, 6, 7, 8]));
assert_eq!(reader.as_blob(), Blob([5, 6, 7, 8].as_ref()));
}
#[test]
fn iter() {
@@ -466,7 +466,7 @@ fn deserialize_newtype_i8() {
#[derive(Deserialize)]
struct Foo(u8);
let data = [13, 4, 1];
let r = Reader::get_root(&data).unwrap();
let r = Reader::get_root(data.as_ref()).unwrap();
let foo = Foo::deserialize(r).unwrap();
assert_eq!(foo.0, 13);
}
@@ -475,7 +475,7 @@ fn deserialize_newtype_str() {
#[derive(Deserialize)]
struct Foo<'a>(&'a str);
let data = [5, b'h', b'e', b'l', b'l', b'o', b'\0', 6, 5 << 2, 1];
let r = Reader::get_root(&data).unwrap();
let r = Reader::get_root(data.as_ref()).unwrap();
let foo = Foo::deserialize(r).unwrap();
assert_eq!(foo.0, "hello");
}
@@ -490,7 +490,7 @@ fn deserialize_tuple_struct_to_vec_uint4() {
23 << 2 | 1, // (VectorUInt4, W16 - referring to data).
1, // Root width W8 - referring to vector.
];
let r = Reader::get_root(&data).unwrap();
let r = Reader::get_root(data.as_ref()).unwrap();
let foo = Foo::deserialize(r).unwrap();
assert_eq!(foo.0, 4);
assert_eq!(foo.1, 16);
@@ -503,7 +503,7 @@ fn deserialize_tuple_struct_to_vec_uint4() {
23 << 2, // Root type: VectorUInt4, W8.
1, // Root width: W8.
];
let r = Reader::get_root(&data).unwrap();
let r = Reader::get_root(data.as_ref()).unwrap();
let foo = Foo::deserialize(r).unwrap();
assert_eq!(foo.0, 1);
assert_eq!(foo.1, 2);