1*890232f2SAndroid Build Coastguard Worker // Copyright 2019 Google LLC 2*890232f2SAndroid Build Coastguard Worker // 3*890232f2SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*890232f2SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*890232f2SAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*890232f2SAndroid Build Coastguard Worker // 7*890232f2SAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0 8*890232f2SAndroid Build Coastguard Worker // 9*890232f2SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*890232f2SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*890232f2SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*890232f2SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*890232f2SAndroid Build Coastguard Worker // limitations under the License. 14*890232f2SAndroid Build Coastguard Worker 15*890232f2SAndroid Build Coastguard Worker use super::{deref_offset, unpack_type, Error, Reader, ReaderIterator, VectorReader}; 16*890232f2SAndroid Build Coastguard Worker use crate::BitWidth; 17*890232f2SAndroid Build Coastguard Worker use crate::Buffer; 18*890232f2SAndroid Build Coastguard Worker use std::cmp::Ordering; 19*890232f2SAndroid Build Coastguard Worker use std::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; 20*890232f2SAndroid Build Coastguard Worker 21*890232f2SAndroid Build Coastguard Worker /// Allows indexing on a flexbuffer map. 22*890232f2SAndroid Build Coastguard Worker /// 23*890232f2SAndroid Build Coastguard Worker /// MapReaders may be indexed with strings or usizes. `index` returns a result type, 24*890232f2SAndroid Build Coastguard Worker /// which may indicate failure due to a missing key or bad data, `idx` returns an Null Reader in 25*890232f2SAndroid Build Coastguard Worker /// cases of error. 26*890232f2SAndroid Build Coastguard Worker pub struct MapReader<B> { 27*890232f2SAndroid Build Coastguard Worker pub(super) buffer: B, 28*890232f2SAndroid Build Coastguard Worker pub(super) values_address: usize, 29*890232f2SAndroid Build Coastguard Worker pub(super) keys_address: usize, 30*890232f2SAndroid Build Coastguard Worker pub(super) values_width: BitWidth, 31*890232f2SAndroid Build Coastguard Worker pub(super) keys_width: BitWidth, 32*890232f2SAndroid Build Coastguard Worker pub(super) length: usize, 33*890232f2SAndroid Build Coastguard Worker } 34*890232f2SAndroid Build Coastguard Worker 35*890232f2SAndroid Build Coastguard Worker impl<B: Buffer> Clone for MapReader<B> { clone(&self) -> Self36*890232f2SAndroid Build Coastguard Worker fn clone(&self) -> Self { 37*890232f2SAndroid Build Coastguard Worker MapReader { 38*890232f2SAndroid Build Coastguard Worker buffer: self.buffer.shallow_copy(), 39*890232f2SAndroid Build Coastguard Worker ..*self 40*890232f2SAndroid Build Coastguard Worker } 41*890232f2SAndroid Build Coastguard Worker } 42*890232f2SAndroid Build Coastguard Worker } 43*890232f2SAndroid Build Coastguard Worker 44*890232f2SAndroid Build Coastguard Worker impl<B: Buffer> Default for MapReader<B> { default() -> Self45*890232f2SAndroid Build Coastguard Worker fn default() -> Self { 46*890232f2SAndroid Build Coastguard Worker MapReader { 47*890232f2SAndroid Build Coastguard Worker buffer: B::empty(), 48*890232f2SAndroid Build Coastguard Worker values_address: usize::default(), 49*890232f2SAndroid Build Coastguard Worker keys_address: usize::default(), 50*890232f2SAndroid Build Coastguard Worker values_width: BitWidth::default(), 51*890232f2SAndroid Build Coastguard Worker keys_width: BitWidth::default(), 52*890232f2SAndroid Build Coastguard Worker length: usize::default(), 53*890232f2SAndroid Build Coastguard Worker } 54*890232f2SAndroid Build Coastguard Worker } 55*890232f2SAndroid Build Coastguard Worker } 56*890232f2SAndroid Build Coastguard Worker 57*890232f2SAndroid Build Coastguard Worker // manual implementation of Debug because buffer slice can't be automatically displayed 58*890232f2SAndroid Build Coastguard Worker impl<B: Buffer> std::fmt::Debug for MapReader<B> { fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result59*890232f2SAndroid Build Coastguard Worker fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 60*890232f2SAndroid Build Coastguard Worker // skips buffer field 61*890232f2SAndroid Build Coastguard Worker f.debug_struct("MapReader") 62*890232f2SAndroid Build Coastguard Worker .field("values_address", &self.values_address) 63*890232f2SAndroid Build Coastguard Worker .field("keys_address", &self.keys_address) 64*890232f2SAndroid Build Coastguard Worker .field("values_width", &self.values_width) 65*890232f2SAndroid Build Coastguard Worker .field("keys_width", &self.keys_width) 66*890232f2SAndroid Build Coastguard Worker .field("length", &self.length) 67*890232f2SAndroid Build Coastguard Worker .finish() 68*890232f2SAndroid Build Coastguard Worker } 69*890232f2SAndroid Build Coastguard Worker } 70*890232f2SAndroid Build Coastguard Worker 71*890232f2SAndroid Build Coastguard Worker impl<B: Buffer> MapReader<B> { 72*890232f2SAndroid Build Coastguard Worker /// Returns the number of key/value pairs are in the map. len(&self) -> usize73*890232f2SAndroid Build Coastguard Worker pub fn len(&self) -> usize { 74*890232f2SAndroid Build Coastguard Worker self.length 75*890232f2SAndroid Build Coastguard Worker } 76*890232f2SAndroid Build Coastguard Worker 77*890232f2SAndroid Build Coastguard Worker /// Returns true if the map has zero key/value pairs. is_empty(&self) -> bool78*890232f2SAndroid Build Coastguard Worker pub fn is_empty(&self) -> bool { 79*890232f2SAndroid Build Coastguard Worker self.length == 0 80*890232f2SAndroid Build Coastguard Worker } 81*890232f2SAndroid Build Coastguard Worker 82*890232f2SAndroid Build Coastguard Worker // Using &CStr will eagerly compute the length of the key. &str needs length info AND utf8 83*890232f2SAndroid Build Coastguard Worker // validation. This version is faster than both. lazy_strcmp(&self, key_addr: usize, key: &str) -> Ordering84*890232f2SAndroid Build Coastguard Worker fn lazy_strcmp(&self, key_addr: usize, key: &str) -> Ordering { 85*890232f2SAndroid Build Coastguard Worker // TODO: Can we know this won't OOB and panic? 86*890232f2SAndroid Build Coastguard Worker let k = self.buffer[key_addr..].iter().take_while(|&&b| b != b'\0'); 87*890232f2SAndroid Build Coastguard Worker k.cmp(key.as_bytes().iter()) 88*890232f2SAndroid Build Coastguard Worker } 89*890232f2SAndroid Build Coastguard Worker 90*890232f2SAndroid Build Coastguard Worker /// Returns the index of a given key in the map. index_key(&self, key: &str) -> Option<usize>91*890232f2SAndroid Build Coastguard Worker pub fn index_key(&self, key: &str) -> Option<usize> { 92*890232f2SAndroid Build Coastguard Worker let (mut low, mut high) = (0, self.length); 93*890232f2SAndroid Build Coastguard Worker while low < high { 94*890232f2SAndroid Build Coastguard Worker let i = (low + high) / 2; 95*890232f2SAndroid Build Coastguard Worker let key_offset_address = self.keys_address + i * self.keys_width.n_bytes(); 96*890232f2SAndroid Build Coastguard Worker let key_address = 97*890232f2SAndroid Build Coastguard Worker deref_offset(&self.buffer, key_offset_address, self.keys_width).ok()?; 98*890232f2SAndroid Build Coastguard Worker match self.lazy_strcmp(key_address, key) { 99*890232f2SAndroid Build Coastguard Worker Ordering::Equal => return Some(i), 100*890232f2SAndroid Build Coastguard Worker Ordering::Less => low = if i == low { i + 1 } else { i }, 101*890232f2SAndroid Build Coastguard Worker Ordering::Greater => high = i, 102*890232f2SAndroid Build Coastguard Worker } 103*890232f2SAndroid Build Coastguard Worker } 104*890232f2SAndroid Build Coastguard Worker None 105*890232f2SAndroid Build Coastguard Worker } 106*890232f2SAndroid Build Coastguard Worker 107*890232f2SAndroid Build Coastguard Worker /// Index into a map with a key or usize. index<I: MapReaderIndexer>(&self, i: I) -> Result<Reader<B>, Error>108*890232f2SAndroid Build Coastguard Worker pub fn index<I: MapReaderIndexer>(&self, i: I) -> Result<Reader<B>, Error> { 109*890232f2SAndroid Build Coastguard Worker i.index_map_reader(self) 110*890232f2SAndroid Build Coastguard Worker } 111*890232f2SAndroid Build Coastguard Worker 112*890232f2SAndroid Build Coastguard Worker /// Index into a map with a key or usize. If any errors occur a Null reader is returned. idx<I: MapReaderIndexer>(&self, i: I) -> Reader<B>113*890232f2SAndroid Build Coastguard Worker pub fn idx<I: MapReaderIndexer>(&self, i: I) -> Reader<B> { 114*890232f2SAndroid Build Coastguard Worker i.index_map_reader(self).unwrap_or_default() 115*890232f2SAndroid Build Coastguard Worker } 116*890232f2SAndroid Build Coastguard Worker usize_index(&self, i: usize) -> Result<Reader<B>, Error>117*890232f2SAndroid Build Coastguard Worker fn usize_index(&self, i: usize) -> Result<Reader<B>, Error> { 118*890232f2SAndroid Build Coastguard Worker if i >= self.length { 119*890232f2SAndroid Build Coastguard Worker return Err(Error::IndexOutOfBounds); 120*890232f2SAndroid Build Coastguard Worker } 121*890232f2SAndroid Build Coastguard Worker let data_address = self.values_address + self.values_width.n_bytes() * i; 122*890232f2SAndroid Build Coastguard Worker let type_address = self.values_address + self.values_width.n_bytes() * self.length + i; 123*890232f2SAndroid Build Coastguard Worker let (fxb_type, width) = self 124*890232f2SAndroid Build Coastguard Worker .buffer 125*890232f2SAndroid Build Coastguard Worker .get(type_address) 126*890232f2SAndroid Build Coastguard Worker .ok_or(Error::FlexbufferOutOfBounds) 127*890232f2SAndroid Build Coastguard Worker .and_then(|&b| unpack_type(b))?; 128*890232f2SAndroid Build Coastguard Worker Reader::new( 129*890232f2SAndroid Build Coastguard Worker self.buffer.shallow_copy(), 130*890232f2SAndroid Build Coastguard Worker data_address, 131*890232f2SAndroid Build Coastguard Worker fxb_type, 132*890232f2SAndroid Build Coastguard Worker width, 133*890232f2SAndroid Build Coastguard Worker self.values_width, 134*890232f2SAndroid Build Coastguard Worker ) 135*890232f2SAndroid Build Coastguard Worker } 136*890232f2SAndroid Build Coastguard Worker key_index(&self, k: &str) -> Result<Reader<B>, Error>137*890232f2SAndroid Build Coastguard Worker fn key_index(&self, k: &str) -> Result<Reader<B>, Error> { 138*890232f2SAndroid Build Coastguard Worker let i = self.index_key(k).ok_or(Error::KeyNotFound)?; 139*890232f2SAndroid Build Coastguard Worker self.usize_index(i) 140*890232f2SAndroid Build Coastguard Worker } 141*890232f2SAndroid Build Coastguard Worker 142*890232f2SAndroid Build Coastguard Worker /// Iterate over the values of the map. iter_values(&self) -> ReaderIterator<B>143*890232f2SAndroid Build Coastguard Worker pub fn iter_values(&self) -> ReaderIterator<B> { 144*890232f2SAndroid Build Coastguard Worker ReaderIterator::new(VectorReader { 145*890232f2SAndroid Build Coastguard Worker reader: Reader { 146*890232f2SAndroid Build Coastguard Worker buffer: self.buffer.shallow_copy(), 147*890232f2SAndroid Build Coastguard Worker fxb_type: crate::FlexBufferType::Map, 148*890232f2SAndroid Build Coastguard Worker width: self.values_width, 149*890232f2SAndroid Build Coastguard Worker address: self.values_address, 150*890232f2SAndroid Build Coastguard Worker }, 151*890232f2SAndroid Build Coastguard Worker length: self.length, 152*890232f2SAndroid Build Coastguard Worker }) 153*890232f2SAndroid Build Coastguard Worker } 154*890232f2SAndroid Build Coastguard Worker 155*890232f2SAndroid Build Coastguard Worker /// Iterate over the keys of the map. iter_keys( &self, ) -> impl Iterator<Item = B::BufferString> + DoubleEndedIterator + ExactSizeIterator + FusedIterator156*890232f2SAndroid Build Coastguard Worker pub fn iter_keys( 157*890232f2SAndroid Build Coastguard Worker &self, 158*890232f2SAndroid Build Coastguard Worker ) -> impl Iterator<Item = B::BufferString> + DoubleEndedIterator + ExactSizeIterator + FusedIterator 159*890232f2SAndroid Build Coastguard Worker { 160*890232f2SAndroid Build Coastguard Worker self.keys_vector().iter().map(|k| k.as_str()) 161*890232f2SAndroid Build Coastguard Worker } 162*890232f2SAndroid Build Coastguard Worker keys_vector(&self) -> VectorReader<B>163*890232f2SAndroid Build Coastguard Worker pub fn keys_vector(&self) -> VectorReader<B> { 164*890232f2SAndroid Build Coastguard Worker VectorReader { 165*890232f2SAndroid Build Coastguard Worker reader: Reader { 166*890232f2SAndroid Build Coastguard Worker buffer: self.buffer.shallow_copy(), 167*890232f2SAndroid Build Coastguard Worker fxb_type: crate::FlexBufferType::VectorKey, 168*890232f2SAndroid Build Coastguard Worker width: self.keys_width, 169*890232f2SAndroid Build Coastguard Worker address: self.keys_address, 170*890232f2SAndroid Build Coastguard Worker }, 171*890232f2SAndroid Build Coastguard Worker length: self.length, 172*890232f2SAndroid Build Coastguard Worker } 173*890232f2SAndroid Build Coastguard Worker } 174*890232f2SAndroid Build Coastguard Worker } 175*890232f2SAndroid Build Coastguard Worker 176*890232f2SAndroid Build Coastguard Worker pub trait MapReaderIndexer { index_map_reader<B: Buffer>(self, r: &MapReader<B>) -> Result<Reader<B>, Error>177*890232f2SAndroid Build Coastguard Worker fn index_map_reader<B: Buffer>(self, r: &MapReader<B>) -> Result<Reader<B>, Error>; 178*890232f2SAndroid Build Coastguard Worker } 179*890232f2SAndroid Build Coastguard Worker 180*890232f2SAndroid Build Coastguard Worker impl MapReaderIndexer for usize { 181*890232f2SAndroid Build Coastguard Worker #[inline] index_map_reader<B: Buffer>(self, r: &MapReader<B>) -> Result<Reader<B>, Error>182*890232f2SAndroid Build Coastguard Worker fn index_map_reader<B: Buffer>(self, r: &MapReader<B>) -> Result<Reader<B>, Error> { 183*890232f2SAndroid Build Coastguard Worker r.usize_index(self) 184*890232f2SAndroid Build Coastguard Worker } 185*890232f2SAndroid Build Coastguard Worker } 186*890232f2SAndroid Build Coastguard Worker 187*890232f2SAndroid Build Coastguard Worker impl MapReaderIndexer for &str { 188*890232f2SAndroid Build Coastguard Worker #[inline] index_map_reader<B: Buffer>(self, r: &MapReader<B>) -> Result<Reader<B>, Error>189*890232f2SAndroid Build Coastguard Worker fn index_map_reader<B: Buffer>(self, r: &MapReader<B>) -> Result<Reader<B>, Error> { 190*890232f2SAndroid Build Coastguard Worker r.key_index(self) 191*890232f2SAndroid Build Coastguard Worker } 192*890232f2SAndroid Build Coastguard Worker } 193