mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-11 23:40:57 +00:00
Rust Flexbuffers (#5669)
* Cargo clippy lints * more lints * more lints * Restored a doc comment * Comment on float eps-eq and adjusted casting * Rust Flexbuffers * more serde tests, removed some unsafe * Redid serde to be map-like and Reader is Display * Moved iter from Reader to VectorReader * Serious quickcheck + bugs * wvo api * Made types smaller for a reasonable speedup * redid reading in a way that's a bit faster. Profiling shows the rust slowdown as building +10%, reading +20% * src/bin are developer binaries in rust * Root and Map width are not packed * key null check is debug only + doc changes * BuilderOptions * Documentation * Documentation * Moved tests to rust_usage_test * Moved rust flexbuffers samples to Flatbuffers/samples * Fixed RustTest * Fixed for Rust 1.37.0 * Upgraded to rust 1_40_0 * fixed a little-endian-only feature in a test * 1.40.0 * fixed some benchmarks for bigendian * Updated .bat file * misspelling * Gold Flexbuffer test. * Serialize,Deserialize, std::error::Error for Errors. * Undo rustfmt in integration_test.rs * from_slice instead of from_vec * Added comments to unsafe blocks * expanded on comment * bump Co-authored-by: CasperN <cneo@google.com>
This commit is contained in:
250
rust/flexbuffers/src/reader/de.rs
Normal file
250
rust/flexbuffers/src/reader/de.rs
Normal file
@@ -0,0 +1,250 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 super::Error;
|
||||
use crate::{FlexBufferType, Reader, ReaderIterator};
|
||||
use serde::de::{
|
||||
DeserializeSeed, Deserializer, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,
|
||||
VariantAccess, Visitor,
|
||||
};
|
||||
|
||||
/// Errors that may happen when deserializing a flexbuffer with serde.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum DeserializationError {
|
||||
Reader(Error),
|
||||
Serde(String),
|
||||
}
|
||||
|
||||
impl std::error::Error for DeserializationError {}
|
||||
impl std::fmt::Display for DeserializationError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
match self {
|
||||
Self::Reader(r) => write!(f, "Flexbuffer Read Error: {:?}", r),
|
||||
Self::Serde(s) => write!(f, "Serde Error: {}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl serde::de::Error for DeserializationError {
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: std::fmt::Display,
|
||||
{
|
||||
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> {
|
||||
type Error = DeserializationError;
|
||||
fn next_element_seed<T>(
|
||||
&mut self,
|
||||
seed: T,
|
||||
) -> Result<Option<<T as DeserializeSeed<'de>>::Value>, Self::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
if let Some(elem) = self.next() {
|
||||
seed.deserialize(elem).map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
fn size_hint(&self) -> Option<usize> {
|
||||
Some(self.len())
|
||||
}
|
||||
}
|
||||
|
||||
struct EnumReader<'de> {
|
||||
variant: &'de str,
|
||||
value: Option<Reader<'de>>,
|
||||
}
|
||||
|
||||
impl<'de> EnumAccess<'de> for EnumReader<'de> {
|
||||
type Error = DeserializationError;
|
||||
type Variant = Reader<'de>;
|
||||
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
|
||||
where
|
||||
V: DeserializeSeed<'de>,
|
||||
{
|
||||
seed.deserialize(self.variant.into_deserializer())
|
||||
.map(|v| (v, self.value.unwrap_or_default()))
|
||||
}
|
||||
}
|
||||
|
||||
struct MapAccessor<'de> {
|
||||
keys: ReaderIterator<'de>,
|
||||
vals: ReaderIterator<'de>,
|
||||
}
|
||||
impl<'de> MapAccess<'de> for MapAccessor<'de> {
|
||||
type Error = DeserializationError;
|
||||
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
|
||||
where
|
||||
K: DeserializeSeed<'de>,
|
||||
{
|
||||
if let Some(k) = self.keys.next() {
|
||||
seed.deserialize(k).map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: DeserializeSeed<'de>,
|
||||
{
|
||||
let val = self.vals.next().ok_or(Error::IndexOutOfBounds)?;
|
||||
seed.deserialize(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> VariantAccess<'de> for Reader<'de> {
|
||||
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>
|
||||
where
|
||||
V: Visitor<'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>(
|
||||
self,
|
||||
_fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let m = self.get_map()?;
|
||||
visitor.visit_map(MapAccessor {
|
||||
keys: m.keys_vector().iter(),
|
||||
vals: m.iter_values(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserializer<'de> for crate::Reader<'de> {
|
||||
type Error = DeserializationError;
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
use crate::BitWidth::*;
|
||||
use crate::FlexBufferType::*;
|
||||
match (self.flexbuffer_type(), self.bitwidth()) {
|
||||
(Bool, _) => visitor.visit_bool(self.as_bool()),
|
||||
(UInt, W8) => visitor.visit_u8(self.as_u8()),
|
||||
(UInt, W16) => visitor.visit_u16(self.as_u16()),
|
||||
(UInt, W32) => visitor.visit_u32(self.as_u32()),
|
||||
(UInt, W64) => visitor.visit_u64(self.as_u64()),
|
||||
(Int, W8) => visitor.visit_i8(self.as_i8()),
|
||||
(Int, W16) => visitor.visit_i16(self.as_i16()),
|
||||
(Int, W32) => visitor.visit_i32(self.as_i32()),
|
||||
(Int, W64) => visitor.visit_i64(self.as_i64()),
|
||||
(Float, W32) => visitor.visit_f32(self.as_f32()),
|
||||
(Float, W64) => visitor.visit_f64(self.as_f64()),
|
||||
(Float, _) => Err(Error::InvalidPackedType.into()), // f8 and f16 are not supported.
|
||||
(Null, _) => visitor.visit_unit(),
|
||||
(String, _) | (Key, _) => visitor.visit_borrowed_str(self.as_str()),
|
||||
(Blob, _) => visitor.visit_borrowed_bytes(self.get_blob()?.0),
|
||||
(Map, _) => {
|
||||
let m = self.get_map()?;
|
||||
visitor.visit_map(MapAccessor {
|
||||
keys: m.keys_vector().iter(),
|
||||
vals: m.iter_values(),
|
||||
})
|
||||
}
|
||||
(ty, _) if ty.is_vector() => visitor.visit_seq(self.as_vector().iter()),
|
||||
(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>,
|
||||
{
|
||||
if self.flexbuffer_type() == FlexBufferType::Null {
|
||||
visitor.visit_none()
|
||||
} else {
|
||||
visitor.visit_some(self)
|
||||
}
|
||||
}
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
visitor.visit_newtype_struct(self)
|
||||
}
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let (variant, value) = match self.fxb_type {
|
||||
FlexBufferType::String => (self.as_str(), None),
|
||||
FlexBufferType::Map => {
|
||||
let m = self.get_map()?;
|
||||
let variant = m.keys_vector().idx(0).get_key()?;
|
||||
let value = Some(m.idx(0));
|
||||
(variant, value)
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnexpectedFlexbufferType {
|
||||
expected: FlexBufferType::Map,
|
||||
actual: self.fxb_type,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
};
|
||||
visitor.visit_enum(EnumReader { variant, value })
|
||||
}
|
||||
}
|
||||
63
rust/flexbuffers/src/reader/iter.rs
Normal file
63
rust/flexbuffers/src/reader/iter.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 super::{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(super) front: usize,
|
||||
end: usize,
|
||||
}
|
||||
impl<'de> ReaderIterator<'de> {
|
||||
pub(super) fn new(reader: VectorReader<'de>) -> Self {
|
||||
let end = reader.len();
|
||||
ReaderIterator {
|
||||
reader,
|
||||
front: 0,
|
||||
end,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'de> Iterator for ReaderIterator<'de> {
|
||||
type Item = Reader<'de>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.front < self.end {
|
||||
let r = self.reader.idx(self.front);
|
||||
self.front += 1;
|
||||
Some(r)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let remaining = self.end - self.front;
|
||||
(remaining, Some(remaining))
|
||||
}
|
||||
}
|
||||
impl<'de> DoubleEndedIterator for ReaderIterator<'de> {
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
if self.front < self.end {
|
||||
self.end -= 1;
|
||||
Some(self.reader.idx(self.end))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'de> ExactSizeIterator for ReaderIterator<'de> {}
|
||||
impl<'de> FusedIterator for ReaderIterator<'de> {}
|
||||
144
rust/flexbuffers/src/reader/map.rs
Normal file
144
rust/flexbuffers/src/reader/map.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 super::{deref_offset, unpack_type, Error, Reader, ReaderIterator, VectorReader};
|
||||
use crate::BitWidth;
|
||||
use std::cmp::Ordering;
|
||||
use std::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator};
|
||||
|
||||
/// Allows indexing on a flexbuffer map.
|
||||
///
|
||||
/// 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(DebugStub, Default, Clone)]
|
||||
pub struct MapReader<'de> {
|
||||
#[debug_stub = "&[..]"]
|
||||
pub(super) buffer: &'de [u8],
|
||||
pub(super) values_address: usize,
|
||||
pub(super) keys_address: usize,
|
||||
pub(super) values_width: BitWidth,
|
||||
pub(super) keys_width: BitWidth,
|
||||
pub(super) length: usize,
|
||||
}
|
||||
|
||||
impl<'de> MapReader<'de> {
|
||||
/// Returns the number of key/value pairs are in the map.
|
||||
pub fn len(&self) -> usize {
|
||||
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 {
|
||||
// TODO: Can we know this won't OOB and panic?
|
||||
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);
|
||||
while low < high {
|
||||
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()?;
|
||||
match self.lazy_strcmp(key_address, key) {
|
||||
Ordering::Equal => return Some(i),
|
||||
Ordering::Less => low = if i == low { i + 1 } else { i },
|
||||
Ordering::Greater => high = i,
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Index into a map with a key or usize.
|
||||
pub fn index<I: MapReaderIndexer>(&self, i: I) -> Result<Reader<'de>, 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> {
|
||||
i.index_map_reader(self).unwrap_or_default()
|
||||
}
|
||||
fn usize_index(&self, i: usize) -> Result<Reader<'de>, Error> {
|
||||
if i >= self.length {
|
||||
return Err(Error::IndexOutOfBounds);
|
||||
}
|
||||
let data_address = self.values_address + self.values_width.n_bytes() * i;
|
||||
let type_address = self.values_address + self.values_width.n_bytes() * self.length + i;
|
||||
let (fxb_type, width) = self
|
||||
.buffer
|
||||
.get(type_address)
|
||||
.ok_or(Error::FlexbufferOutOfBounds)
|
||||
.and_then(|&b| unpack_type(b))?;
|
||||
Reader::new(
|
||||
&self.buffer,
|
||||
data_address,
|
||||
fxb_type,
|
||||
width,
|
||||
self.values_width,
|
||||
)
|
||||
}
|
||||
fn key_index(&self, k: &str) -> Result<Reader<'de>, 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> {
|
||||
ReaderIterator::new(VectorReader {
|
||||
reader: Reader {
|
||||
buffer: self.buffer,
|
||||
fxb_type: crate::FlexBufferType::Map,
|
||||
width: self.values_width,
|
||||
address: self.values_address,
|
||||
},
|
||||
length: self.length,
|
||||
})
|
||||
}
|
||||
/// Iterate over the keys of the map.
|
||||
pub fn iter_keys(
|
||||
&self,
|
||||
) -> impl Iterator<Item = &'de str> + DoubleEndedIterator + ExactSizeIterator + FusedIterator
|
||||
{
|
||||
self.keys_vector().iter().map(|k| k.as_str())
|
||||
}
|
||||
pub fn keys_vector(&self) -> VectorReader<'de> {
|
||||
VectorReader {
|
||||
reader: Reader {
|
||||
buffer: self.buffer,
|
||||
fxb_type: crate::FlexBufferType::VectorKey,
|
||||
width: self.keys_width,
|
||||
address: self.keys_address,
|
||||
},
|
||||
length: self.length,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub trait MapReaderIndexer {
|
||||
fn index_map_reader<'de>(self, r: &MapReader<'de>) -> Result<Reader<'de>, Error>;
|
||||
}
|
||||
impl MapReaderIndexer for usize {
|
||||
#[inline]
|
||||
fn index_map_reader<'de>(self, r: &MapReader<'de>) -> Result<Reader<'de>, Error> {
|
||||
r.usize_index(self)
|
||||
}
|
||||
}
|
||||
impl MapReaderIndexer for &str {
|
||||
#[inline]
|
||||
fn index_map_reader<'de>(self, r: &MapReader<'de>) -> Result<Reader<'de>, Error> {
|
||||
r.key_index(self)
|
||||
}
|
||||
}
|
||||
592
rust/flexbuffers/src/reader/mod.rs
Normal file
592
rust/flexbuffers/src/reader/mod.rs
Normal file
@@ -0,0 +1,592 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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::bitwidth::BitWidth;
|
||||
use crate::flexbuffer_type::FlexBufferType;
|
||||
use crate::Blob;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::fmt;
|
||||
use std::ops::Rem;
|
||||
use std::str::FromStr;
|
||||
mod de;
|
||||
mod iter;
|
||||
mod map;
|
||||
mod vector;
|
||||
pub use de::DeserializationError;
|
||||
pub use iter::ReaderIterator;
|
||||
pub use map::{MapReader, MapReaderIndexer};
|
||||
pub use vector::VectorReader;
|
||||
|
||||
/// All the possible errors when reading a flexbuffer.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||
pub enum Error {
|
||||
/// One of the following data errors occured:
|
||||
///
|
||||
/// * The read flexbuffer had an offset that pointed outside the flexbuffer.
|
||||
/// * The 'negative indicies' where length and map keys are stored were out of bounds
|
||||
/// * The buffer was too small to contain a flexbuffer root.
|
||||
FlexbufferOutOfBounds,
|
||||
/// Failed to parse a valid FlexbufferType and Bitwidth from a type byte.
|
||||
InvalidPackedType,
|
||||
/// Flexbuffer type of the read data does not match function used.
|
||||
UnexpectedFlexbufferType {
|
||||
expected: FlexBufferType,
|
||||
actual: FlexBufferType,
|
||||
},
|
||||
/// BitWidth type of the read data does not match function used.
|
||||
UnexpectedBitWidth {
|
||||
expected: BitWidth,
|
||||
actual: BitWidth,
|
||||
},
|
||||
/// Read a flexbuffer offset or length that overflowed usize.
|
||||
ReadUsizeOverflowed,
|
||||
/// Tried to index a type that's not one of the Flexbuffer vector types.
|
||||
CannotIndexAsVector,
|
||||
/// Tried to index a Flexbuffer vector or map out of bounds.
|
||||
IndexOutOfBounds,
|
||||
/// A Map was indexed with a key that it did not contain.
|
||||
KeyNotFound,
|
||||
/// Failed to parse a Utf8 string.
|
||||
/// The Option will be `None` if and only if this Error was deserialized.
|
||||
// NOTE: std::str::Utf8Error does not implement Serialize, Deserialize, nor Default. We tell
|
||||
// serde to skip the field and default to None. We prefer to have the boxed error so it can be
|
||||
// used with std::error::Error::source, though another (worse) option could be to drop that
|
||||
// information.
|
||||
Utf8Error(#[serde(skip)] Option<Box<std::str::Utf8Error>>),
|
||||
/// get_slice failed because the given data buffer is misaligned.
|
||||
AlignmentError,
|
||||
InvalidRootWidth,
|
||||
InvalidMapKeysVectorWidth,
|
||||
}
|
||||
impl std::convert::From<std::str::Utf8Error> for Error {
|
||||
fn from(e: std::str::Utf8Error) -> Self {
|
||||
Self::Utf8Error(Some(Box::new(e)))
|
||||
}
|
||||
}
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::UnexpectedBitWidth { expected, actual } => write!(
|
||||
f,
|
||||
"Error reading flexbuffer: Expected bitwidth: {:?}, found bitwidth: {:?}",
|
||||
expected, actual
|
||||
),
|
||||
Self::UnexpectedFlexbufferType { expected, actual } => write!(
|
||||
f,
|
||||
"Error reading flexbuffer: Expected type: {:?}, found type: {:?}",
|
||||
expected, actual
|
||||
),
|
||||
_ => write!(f, "Error reading flexbuffer: {:?}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
if let Self::Utf8Error(Some(e)) = self {
|
||||
Some(e)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ReadLE: crate::private::Sealed + std::marker::Sized {
|
||||
const VECTOR_TYPE: FlexBufferType;
|
||||
const WIDTH: BitWidth;
|
||||
}
|
||||
macro_rules! rle {
|
||||
($T: ty, $VECTOR_TYPE: ident, $WIDTH: ident) => {
|
||||
impl ReadLE for $T {
|
||||
const VECTOR_TYPE: FlexBufferType = FlexBufferType::$VECTOR_TYPE;
|
||||
const WIDTH: BitWidth = BitWidth::$WIDTH;
|
||||
}
|
||||
};
|
||||
}
|
||||
rle!(u8, VectorUInt, W8);
|
||||
rle!(u16, VectorUInt, W16);
|
||||
rle!(u32, VectorUInt, W32);
|
||||
rle!(u64, VectorUInt, W64);
|
||||
rle!(i8, VectorInt, W8);
|
||||
rle!(i16, VectorInt, W16);
|
||||
rle!(i32, VectorInt, W32);
|
||||
rle!(i64, VectorInt, W64);
|
||||
rle!(f32, VectorFloat, W32);
|
||||
rle!(f64, VectorFloat, W64);
|
||||
|
||||
macro_rules! as_default {
|
||||
($as: ident, $get: ident, $T: ty) => {
|
||||
pub fn $as(&self) -> $T {
|
||||
self.$get().unwrap_or_default()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// `Reader`s allow access to data stored in a Flexbuffer.
|
||||
///
|
||||
/// Each reader represents a single address in the buffer so data is read lazily. Start a reader
|
||||
/// by calling `get_root` on your flexbuffer `&[u8]`.
|
||||
///
|
||||
/// - The `get_T` methods return a `Result<T, Error>`. They return an OK value if and only if the
|
||||
/// flexbuffer type matches `T`. This is analogous to the behavior of Rust's json library, though
|
||||
/// with Result instead of Option.
|
||||
/// - 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(DebugStub, Default, Clone)]
|
||||
pub struct Reader<'de> {
|
||||
fxb_type: FlexBufferType,
|
||||
width: BitWidth,
|
||||
address: usize,
|
||||
#[debug_stub = "&[..]"]
|
||||
buffer: &'de [u8],
|
||||
}
|
||||
|
||||
macro_rules! try_cast_fn {
|
||||
($name: ident, $full_width: ident, $Ty: ident) => {
|
||||
pub fn $name(&self) -> $Ty {
|
||||
self.$full_width().try_into().unwrap_or_default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn safe_sub(a: usize, b: usize) -> Result<usize, Error> {
|
||||
a.checked_sub(b).ok_or(Error::FlexbufferOutOfBounds)
|
||||
}
|
||||
|
||||
fn deref_offset(buffer: &[u8], address: usize, width: BitWidth) -> Result<usize, Error> {
|
||||
let off = read_usize(buffer, address, width);
|
||||
safe_sub(address, off)
|
||||
}
|
||||
|
||||
impl<'de> Reader<'de> {
|
||||
fn new(
|
||||
buffer: &'de [u8],
|
||||
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)?;
|
||||
// Indirects were dereferenced.
|
||||
if let Some(t) = fxb_type.to_direct() {
|
||||
fxb_type = t;
|
||||
}
|
||||
}
|
||||
Ok(Reader {
|
||||
address,
|
||||
fxb_type,
|
||||
width,
|
||||
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> {
|
||||
let end = buffer.len();
|
||||
if end < 3 {
|
||||
return Err(Error::FlexbufferOutOfBounds);
|
||||
}
|
||||
// Last byte is the root width.
|
||||
let root_width = BitWidth::from_nbytes(buffer[end - 1]).ok_or(Error::InvalidRootWidth)?;
|
||||
// Second last byte is root type.
|
||||
let (fxb_type, width) = unpack_type(buffer[end - 2])?;
|
||||
// Location of root data. (BitWidth bits before root type)
|
||||
let address = safe_sub(end - 2, root_width.n_bytes())?;
|
||||
Self::new(buffer, address, fxb_type, width, root_width)
|
||||
}
|
||||
/// 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)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
/// 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`.
|
||||
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>);
|
||||
|
||||
fn expect_type(&self, ty: FlexBufferType) -> Result<(), Error> {
|
||||
if self.fxb_type == ty {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::UnexpectedFlexbufferType {
|
||||
expected: ty,
|
||||
actual: self.fxb_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
fn expect_bw(&self, bw: BitWidth) -> Result<(), Error> {
|
||||
if self.width == bw {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::UnexpectedBitWidth {
|
||||
expected: bw,
|
||||
actual: self.width,
|
||||
})
|
||||
}
|
||||
}
|
||||
/// 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> {
|
||||
if self.flexbuffer_type().typed_vector_type() != T::VECTOR_TYPE.typed_vector_type() {
|
||||
self.expect_type(T::VECTOR_TYPE)?;
|
||||
}
|
||||
if self.bitwidth().n_bytes() != std::mem::size_of::<T>() {
|
||||
self.expect_bw(T::WIDTH)?;
|
||||
}
|
||||
let end = self.address + self.length() * std::mem::size_of::<T>();
|
||||
let slice = &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).
|
||||
let (pre, mid, suf) = unsafe { slice.align_to::<T>() };
|
||||
if pre.is_empty() && suf.is_empty() {
|
||||
Ok(mid)
|
||||
} else {
|
||||
Err(Error::AlignmentError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_bool(&self) -> Result<bool, Error> {
|
||||
self.expect_type(FlexBufferType::Bool)?;
|
||||
Ok(
|
||||
self.buffer[self.address..self.address + self.width.n_bytes()]
|
||||
.iter()
|
||||
.any(|&b| b != 0),
|
||||
)
|
||||
}
|
||||
pub fn get_key(&self) -> Result<&'de str, 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)?)
|
||||
}
|
||||
pub fn get_blob(&self) -> Result<Blob<'de>, Error> {
|
||||
self.expect_type(FlexBufferType::Blob)?;
|
||||
Ok(Blob(
|
||||
&self.buffer[self.address..self.address + self.length()],
|
||||
))
|
||||
}
|
||||
pub fn as_blob(&self) -> Blob<'de> {
|
||||
self.get_blob().unwrap_or(Blob(&[]))
|
||||
}
|
||||
pub fn get_str(&self) -> Result<&'de str, Error> {
|
||||
self.expect_type(FlexBufferType::String)?;
|
||||
let bytes = &self.buffer[self.address..self.address + self.length()];
|
||||
Ok(std::str::from_utf8(bytes)?)
|
||||
}
|
||||
fn get_map_info(&self) -> Result<(usize, BitWidth), Error> {
|
||||
self.expect_type(FlexBufferType::Map)?;
|
||||
if 3 * self.width.n_bytes() >= self.address {
|
||||
return Err(Error::FlexbufferOutOfBounds);
|
||||
}
|
||||
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);
|
||||
BitWidth::from_nbytes(kw).ok_or(Error::InvalidMapKeysVectorWidth)
|
||||
}?;
|
||||
Ok((keys_offset_address, keys_width))
|
||||
}
|
||||
pub fn get_map(&self) -> Result<MapReader<'de>, Error> {
|
||||
let (keys_offset_address, keys_width) = self.get_map_info()?;
|
||||
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,
|
||||
values_address: self.address,
|
||||
values_width: self.width,
|
||||
keys_address,
|
||||
keys_width,
|
||||
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> {
|
||||
self.expect_type(FlexBufferType::UInt)?;
|
||||
let cursor = self
|
||||
.buffer
|
||||
.get(self.address..self.address + self.width.n_bytes());
|
||||
match self.width {
|
||||
BitWidth::W8 => cursor.map(|s| s[0] as u8).map(Into::into),
|
||||
BitWidth::W16 => cursor
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(<u16>::from_le_bytes)
|
||||
.map(Into::into),
|
||||
BitWidth::W32 => cursor
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(<u32>::from_le_bytes)
|
||||
.map(Into::into),
|
||||
BitWidth::W64 => cursor
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(<u64>::from_le_bytes),
|
||||
}
|
||||
.ok_or(Error::FlexbufferOutOfBounds)
|
||||
}
|
||||
/// Tries to read a FlexBufferType::Int. Returns Err if the type is not a UInt or if the
|
||||
/// address is out of bounds.
|
||||
pub fn get_i64(&self) -> Result<i64, Error> {
|
||||
self.expect_type(FlexBufferType::Int)?;
|
||||
let cursor = self
|
||||
.buffer
|
||||
.get(self.address..self.address + self.width.n_bytes());
|
||||
match self.width {
|
||||
BitWidth::W8 => cursor.map(|s| s[0] as i8).map(Into::into),
|
||||
BitWidth::W16 => cursor
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(<i16>::from_le_bytes)
|
||||
.map(Into::into),
|
||||
BitWidth::W32 => cursor
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(<i32>::from_le_bytes)
|
||||
.map(Into::into),
|
||||
BitWidth::W64 => cursor
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(<i64>::from_le_bytes),
|
||||
}
|
||||
.ok_or(Error::FlexbufferOutOfBounds)
|
||||
}
|
||||
/// Tries to read a FlexBufferType::Float. Returns Err if the type is not a UInt, if the
|
||||
/// address is out of bounds, or if its a f16 or f8 (not currently supported).
|
||||
pub fn get_f64(&self) -> Result<f64, Error> {
|
||||
self.expect_type(FlexBufferType::Float)?;
|
||||
let cursor = self
|
||||
.buffer
|
||||
.get(self.address..self.address + self.width.n_bytes());
|
||||
match self.width {
|
||||
BitWidth::W8 | BitWidth::W16 => return Err(Error::InvalidPackedType),
|
||||
BitWidth::W32 => cursor
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(f32_from_le_bytes)
|
||||
.map(Into::into),
|
||||
BitWidth::W64 => cursor
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(f64_from_le_bytes),
|
||||
}
|
||||
.ok_or(Error::FlexbufferOutOfBounds)
|
||||
}
|
||||
pub fn as_bool(&self) -> bool {
|
||||
use FlexBufferType::*;
|
||||
match self.fxb_type {
|
||||
Bool => self.get_bool().unwrap_or_default(),
|
||||
UInt => self.as_u64() != 0,
|
||||
Int => self.as_i64() != 0,
|
||||
Float => self.as_f64().abs() > std::f64::EPSILON,
|
||||
String | Key => !self.as_str().is_empty(),
|
||||
Null => false,
|
||||
Blob => self.length() != 0,
|
||||
ty if ty.is_vector() => self.length() != 0,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
/// Returns a u64, casting if necessary. For Maps and Vectors, their length is
|
||||
/// returned. If anything fails, 0 is returned.
|
||||
pub fn as_u64(&self) -> u64 {
|
||||
match self.fxb_type {
|
||||
FlexBufferType::UInt => self.get_u64().unwrap_or_default(),
|
||||
FlexBufferType::Int => self
|
||||
.get_i64()
|
||||
.unwrap_or_default()
|
||||
.try_into()
|
||||
.unwrap_or_default(),
|
||||
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) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
_ if self.fxb_type.is_vector() => self.length() as u64,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
try_cast_fn!(as_u32, as_u64, u32);
|
||||
try_cast_fn!(as_u16, as_u64, u16);
|
||||
try_cast_fn!(as_u8, as_u64, u8);
|
||||
|
||||
/// Returns an i64, casting if necessary. For Maps and Vectors, their length is
|
||||
/// returned. If anything fails, 0 is returned.
|
||||
pub fn as_i64(&self) -> i64 {
|
||||
match self.fxb_type {
|
||||
FlexBufferType::Int => self.get_i64().unwrap_or_default(),
|
||||
FlexBufferType::UInt => self
|
||||
.get_u64()
|
||||
.unwrap_or_default()
|
||||
.try_into()
|
||||
.unwrap_or_default(),
|
||||
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) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
_ if self.fxb_type.is_vector() => self.length() as i64,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
try_cast_fn!(as_i32, as_i64, i32);
|
||||
try_cast_fn!(as_i16, as_i64, i16);
|
||||
try_cast_fn!(as_i8, as_i64, i8);
|
||||
|
||||
/// Returns an f64, casting if necessary. For Maps and Vectors, their length is
|
||||
/// returned. If anything fails, 0 is returned.
|
||||
pub fn as_f64(&self) -> f64 {
|
||||
match self.fxb_type {
|
||||
FlexBufferType::Int => self.get_i64().unwrap_or_default() as f64,
|
||||
FlexBufferType::UInt => self.get_u64().unwrap_or_default() as f64,
|
||||
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) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
0.0
|
||||
}
|
||||
_ if self.fxb_type.is_vector() => self.length() as f64,
|
||||
_ => 0.0,
|
||||
}
|
||||
}
|
||||
pub fn as_f32(&self) -> f32 {
|
||||
self.as_f64() as f32
|
||||
}
|
||||
|
||||
/// Returns empty string if you're not trying to read a string.
|
||||
pub fn as_str(&self) -> &'de str {
|
||||
match self.fxb_type {
|
||||
FlexBufferType::String => self.get_str().unwrap_or_default(),
|
||||
FlexBufferType::Key => self.get_key().unwrap_or_default(),
|
||||
_ => "",
|
||||
}
|
||||
}
|
||||
pub fn get_vector(&self) -> Result<VectorReader<'de>, Error> {
|
||||
if !self.fxb_type.is_vector() {
|
||||
self.expect_type(FlexBufferType::Vector)?;
|
||||
};
|
||||
Ok(VectorReader {
|
||||
reader: self.clone(),
|
||||
length: self.length(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> fmt::Display for Reader<'de> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use FlexBufferType::*;
|
||||
match self.flexbuffer_type() {
|
||||
Null => write!(f, "null"),
|
||||
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()),
|
||||
Bool => write!(f, "{}", self.as_bool()),
|
||||
Blob => write!(f, "blob"),
|
||||
Map => {
|
||||
write!(f, "{{")?;
|
||||
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)?;
|
||||
for (k, v) in pairs {
|
||||
write!(f, ", {:?}: {}", k, v)?;
|
||||
}
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
t if t.is_vector() => {
|
||||
write!(f, "[")?;
|
||||
let mut elems = self.as_vector().iter();
|
||||
if let Some(first) = elems.next() {
|
||||
write!(f, "{}", first)?;
|
||||
for e in elems {
|
||||
write!(f, ", {}", e)?;
|
||||
}
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
_ => unreachable!("Display not implemented for {:?}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(cneo): Use <f..>::from_le_bytes when we move past rustc 1.39.
|
||||
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)
|
||||
}
|
||||
|
||||
fn read_usize(buffer: &[u8], address: usize, width: BitWidth) -> usize {
|
||||
let cursor = &buffer[address..];
|
||||
match width {
|
||||
BitWidth::W8 => cursor[0] as usize,
|
||||
BitWidth::W16 => cursor
|
||||
.get(0..2)
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(<u16>::from_le_bytes)
|
||||
.unwrap_or_default() as usize,
|
||||
BitWidth::W32 => cursor
|
||||
.get(0..4)
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(<u32>::from_le_bytes)
|
||||
.unwrap_or_default() as usize,
|
||||
BitWidth::W64 => cursor
|
||||
.get(0..8)
|
||||
.and_then(|s| s.try_into().ok())
|
||||
.map(<u64>::from_le_bytes)
|
||||
.unwrap_or_default() as usize,
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
74
rust/flexbuffers/src/reader/vector.rs
Normal file
74
rust/flexbuffers/src/reader/vector.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 super::{unpack_type, Error, Reader, ReaderIterator};
|
||||
use crate::{BitWidth, 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>,
|
||||
// Cache the length because read_usize can be slow.
|
||||
pub(super) length: usize,
|
||||
}
|
||||
|
||||
impl<'de> VectorReader<'de> {
|
||||
/// Returns the number of elements in the vector.
|
||||
pub fn len(&self) -> usize {
|
||||
self.length
|
||||
}
|
||||
/// Returns true if there are 0 elements in the vector.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.length == 0
|
||||
}
|
||||
fn get_elem_type(&self, i: usize) -> Result<(FlexBufferType, BitWidth), Error> {
|
||||
if let Some(ty) = self.reader.fxb_type.typed_vector_type() {
|
||||
Ok((ty, self.reader.width))
|
||||
} else {
|
||||
let types_addr = self.reader.address + self.length * self.reader.width.n_bytes();
|
||||
self.reader
|
||||
.buffer
|
||||
.get(types_addr + i)
|
||||
.ok_or(Error::FlexbufferOutOfBounds)
|
||||
.and_then(|&t| unpack_type(t))
|
||||
}
|
||||
}
|
||||
/// Index into a flexbuffer vector. Any errors are defaulted to Null Readers.
|
||||
pub fn idx(&self, i: usize) -> Reader<'de> {
|
||||
self.index(i).unwrap_or_default()
|
||||
}
|
||||
/// Index into a flexbuffer.
|
||||
pub fn index(&self, i: usize) -> Result<Reader<'de>, 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,
|
||||
data_address,
|
||||
fxb_type,
|
||||
bw,
|
||||
self.reader.width,
|
||||
)
|
||||
}
|
||||
pub fn iter(&self) -> ReaderIterator<'de> {
|
||||
ReaderIterator::new(self.clone())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user