[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

@@ -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)
}
}