| // 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 crate::Buffer; | |
| 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. | |
| pub struct MapReader<B> { | |
| pub(super) buffer: B, | |
| 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<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<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") | |
| .field("values_address", &self.values_address) | |
| .field("keys_address", &self.keys_address) | |
| .field("values_width", &self.values_width) | |
| .field("keys_width", &self.keys_width) | |
| .field("length", &self.length) | |
| .finish() | |
| } | |
| } | |
| impl<B: Buffer> MapReader<B> { | |
| /// 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<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<B> { | |
| i.index_map_reader(self).unwrap_or_default() | |
| } | |
| fn usize_index(&self, i: usize) -> Result<Reader<B>, 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.shallow_copy(), data_address, fxb_type, width, self.values_width) | |
| } | |
| 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<B> { | |
| ReaderIterator::new(VectorReader { | |
| reader: Reader { | |
| buffer: self.buffer.shallow_copy(), | |
| 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 = B::BufferString> + DoubleEndedIterator + ExactSizeIterator + FusedIterator | |
| { | |
| self.keys_vector().iter().map(|k| k.as_str()) | |
| } | |
| pub fn keys_vector(&self) -> VectorReader<B> { | |
| VectorReader { | |
| reader: Reader { | |
| buffer: self.buffer.shallow_copy(), | |
| fxb_type: crate::FlexBufferType::VectorKey, | |
| width: self.keys_width, | |
| address: self.keys_address, | |
| }, | |
| length: self.length, | |
| } | |
| } | |
| } | |
| pub trait MapReaderIndexer { | |
| fn index_map_reader<B: Buffer>(self, r: &MapReader<B>) -> Result<Reader<B>, Error>; | |
| } | |
| impl MapReaderIndexer for usize { | |
| #[inline] | |
| 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<B: Buffer>(self, r: &MapReader<B>) -> Result<Reader<B>, Error> { | |
| r.key_index(self) | |
| } | |
| } |