Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 1 | // Copyright 2019 Google LLC |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | use crate::bitwidth::BitWidth; |
| 16 | use crate::flexbuffer_type::FlexBufferType; |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 17 | use crate::{Blob, Buffer}; |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 18 | use std::convert::{TryFrom, TryInto}; |
| 19 | use std::fmt; |
| 20 | use std::ops::Rem; |
| 21 | use std::str::FromStr; |
| 22 | mod de; |
| 23 | mod iter; |
| 24 | mod map; |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 25 | mod serialize; |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 26 | mod vector; |
| 27 | pub use de::DeserializationError; |
| 28 | pub use iter::ReaderIterator; |
| 29 | pub use map::{MapReader, MapReaderIndexer}; |
| 30 | pub use vector::VectorReader; |
| 31 | |
| 32 | /// All the possible errors when reading a flexbuffer. |
| 33 | #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] |
| 34 | pub enum Error { |
| 35 | /// One of the following data errors occured: |
| 36 | /// |
| 37 | /// * The read flexbuffer had an offset that pointed outside the flexbuffer. |
| 38 | /// * The 'negative indicies' where length and map keys are stored were out of bounds |
| 39 | /// * The buffer was too small to contain a flexbuffer root. |
| 40 | FlexbufferOutOfBounds, |
| 41 | /// Failed to parse a valid FlexbufferType and Bitwidth from a type byte. |
| 42 | InvalidPackedType, |
| 43 | /// Flexbuffer type of the read data does not match function used. |
| 44 | UnexpectedFlexbufferType { |
| 45 | expected: FlexBufferType, |
| 46 | actual: FlexBufferType, |
| 47 | }, |
| 48 | /// BitWidth type of the read data does not match function used. |
| 49 | UnexpectedBitWidth { |
| 50 | expected: BitWidth, |
| 51 | actual: BitWidth, |
| 52 | }, |
| 53 | /// Read a flexbuffer offset or length that overflowed usize. |
| 54 | ReadUsizeOverflowed, |
| 55 | /// Tried to index a type that's not one of the Flexbuffer vector types. |
| 56 | CannotIndexAsVector, |
| 57 | /// Tried to index a Flexbuffer vector or map out of bounds. |
| 58 | IndexOutOfBounds, |
| 59 | /// A Map was indexed with a key that it did not contain. |
| 60 | KeyNotFound, |
| 61 | /// Failed to parse a Utf8 string. |
| 62 | /// The Option will be `None` if and only if this Error was deserialized. |
| 63 | // NOTE: std::str::Utf8Error does not implement Serialize, Deserialize, nor Default. We tell |
| 64 | // serde to skip the field and default to None. We prefer to have the boxed error so it can be |
| 65 | // used with std::error::Error::source, though another (worse) option could be to drop that |
| 66 | // information. |
| 67 | Utf8Error(#[serde(skip)] Option<Box<std::str::Utf8Error>>), |
| 68 | /// get_slice failed because the given data buffer is misaligned. |
| 69 | AlignmentError, |
| 70 | InvalidRootWidth, |
| 71 | InvalidMapKeysVectorWidth, |
| 72 | } |
| 73 | impl std::convert::From<std::str::Utf8Error> for Error { |
| 74 | fn from(e: std::str::Utf8Error) -> Self { |
| 75 | Self::Utf8Error(Some(Box::new(e))) |
| 76 | } |
| 77 | } |
| 78 | impl fmt::Display for Error { |
| 79 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 80 | match self { |
| 81 | Self::UnexpectedBitWidth { expected, actual } => write!( |
| 82 | f, |
| 83 | "Error reading flexbuffer: Expected bitwidth: {:?}, found bitwidth: {:?}", |
| 84 | expected, actual |
| 85 | ), |
| 86 | Self::UnexpectedFlexbufferType { expected, actual } => write!( |
| 87 | f, |
| 88 | "Error reading flexbuffer: Expected type: {:?}, found type: {:?}", |
| 89 | expected, actual |
| 90 | ), |
| 91 | _ => write!(f, "Error reading flexbuffer: {:?}", self), |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | impl std::error::Error for Error { |
| 96 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { |
| 97 | if let Self::Utf8Error(Some(e)) = self { |
| 98 | Some(e) |
| 99 | } else { |
| 100 | None |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | pub trait ReadLE: crate::private::Sealed + std::marker::Sized { |
| 106 | const VECTOR_TYPE: FlexBufferType; |
| 107 | const WIDTH: BitWidth; |
| 108 | } |
| 109 | macro_rules! rle { |
| 110 | ($T: ty, $VECTOR_TYPE: ident, $WIDTH: ident) => { |
| 111 | impl ReadLE for $T { |
| 112 | const VECTOR_TYPE: FlexBufferType = FlexBufferType::$VECTOR_TYPE; |
| 113 | const WIDTH: BitWidth = BitWidth::$WIDTH; |
| 114 | } |
| 115 | }; |
| 116 | } |
| 117 | rle!(u8, VectorUInt, W8); |
| 118 | rle!(u16, VectorUInt, W16); |
| 119 | rle!(u32, VectorUInt, W32); |
| 120 | rle!(u64, VectorUInt, W64); |
| 121 | rle!(i8, VectorInt, W8); |
| 122 | rle!(i16, VectorInt, W16); |
| 123 | rle!(i32, VectorInt, W32); |
| 124 | rle!(i64, VectorInt, W64); |
| 125 | rle!(f32, VectorFloat, W32); |
| 126 | rle!(f64, VectorFloat, W64); |
| 127 | |
| 128 | macro_rules! as_default { |
| 129 | ($as: ident, $get: ident, $T: ty) => { |
| 130 | pub fn $as(&self) -> $T { |
| 131 | self.$get().unwrap_or_default() |
| 132 | } |
| 133 | }; |
| 134 | } |
| 135 | |
| 136 | /// `Reader`s allow access to data stored in a Flexbuffer. |
| 137 | /// |
| 138 | /// Each reader represents a single address in the buffer so data is read lazily. Start a reader |
| 139 | /// by calling `get_root` on your flexbuffer `&[u8]`. |
| 140 | /// |
| 141 | /// - The `get_T` methods return a `Result<T, Error>`. They return an OK value if and only if the |
| 142 | /// flexbuffer type matches `T`. This is analogous to the behavior of Rust's json library, though |
| 143 | /// with Result instead of Option. |
| 144 | /// - The `as_T` methods will try their best to return to a value of type `T` |
| 145 | /// (by casting or even parsing a string if necessary) but ultimately returns `T::default` if it |
| 146 | /// fails. This behavior is analogous to that of flexbuffers C++. |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 147 | pub struct Reader<B> { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 148 | fxb_type: FlexBufferType, |
| 149 | width: BitWidth, |
| 150 | address: usize, |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 151 | buffer: B, |
| 152 | } |
| 153 | |
| 154 | impl<B: Buffer> Clone for Reader<B> { |
| 155 | fn clone(&self) -> Self { |
| 156 | Reader { |
| 157 | fxb_type: self.fxb_type, |
| 158 | width: self.width, |
| 159 | address: self.address, |
| 160 | buffer: self.buffer.shallow_copy(), |
| 161 | } |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | impl<B: Buffer> Default for Reader<B> { |
| 166 | fn default() -> Self { |
| 167 | Reader { |
| 168 | fxb_type: FlexBufferType::default(), |
| 169 | width: BitWidth::default(), |
| 170 | address: usize::default(), |
| 171 | buffer: B::empty(), |
| 172 | } |
| 173 | } |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 174 | } |
| 175 | |
| 176 | // manual implementation of Debug because buffer slice can't be automatically displayed |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 177 | impl<B> std::fmt::Debug for Reader<B> { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 178 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 179 | // skips buffer field |
| 180 | f.debug_struct("Reader") |
| 181 | .field("fxb_type", &self.fxb_type) |
| 182 | .field("width", &self.width) |
| 183 | .field("address", &self.address) |
| 184 | .finish() |
| 185 | } |
| 186 | } |
| 187 | |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 188 | macro_rules! try_cast_fn { |
| 189 | ($name: ident, $full_width: ident, $Ty: ident) => { |
| 190 | pub fn $name(&self) -> $Ty { |
| 191 | self.$full_width().try_into().unwrap_or_default() |
| 192 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 193 | }; |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 194 | } |
| 195 | |
| 196 | fn safe_sub(a: usize, b: usize) -> Result<usize, Error> { |
| 197 | a.checked_sub(b).ok_or(Error::FlexbufferOutOfBounds) |
| 198 | } |
| 199 | |
| 200 | fn deref_offset(buffer: &[u8], address: usize, width: BitWidth) -> Result<usize, Error> { |
| 201 | let off = read_usize(buffer, address, width); |
| 202 | safe_sub(address, off) |
| 203 | } |
| 204 | |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 205 | impl<B: Buffer> Reader<B> { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 206 | fn new( |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 207 | buffer: B, |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 208 | mut address: usize, |
| 209 | mut fxb_type: FlexBufferType, |
| 210 | width: BitWidth, |
| 211 | parent_width: BitWidth, |
| 212 | ) -> Result<Self, Error> { |
| 213 | if fxb_type.is_reference() { |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 214 | address = deref_offset(&buffer, address, parent_width)?; |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 215 | // Indirects were dereferenced. |
| 216 | if let Some(t) = fxb_type.to_direct() { |
| 217 | fxb_type = t; |
| 218 | } |
| 219 | } |
| 220 | Ok(Reader { |
| 221 | address, |
| 222 | fxb_type, |
| 223 | width, |
| 224 | buffer, |
| 225 | }) |
| 226 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 227 | |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 228 | /// Parses the flexbuffer from the given buffer. Assumes the flexbuffer root is the last byte |
| 229 | /// of the buffer. |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 230 | pub fn get_root(buffer: B) -> Result<Self, Error> { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 231 | let end = buffer.len(); |
| 232 | if end < 3 { |
| 233 | return Err(Error::FlexbufferOutOfBounds); |
| 234 | } |
| 235 | // Last byte is the root width. |
| 236 | let root_width = BitWidth::from_nbytes(buffer[end - 1]).ok_or(Error::InvalidRootWidth)?; |
| 237 | // Second last byte is root type. |
| 238 | let (fxb_type, width) = unpack_type(buffer[end - 2])?; |
| 239 | // Location of root data. (BitWidth bits before root type) |
| 240 | let address = safe_sub(end - 2, root_width.n_bytes())?; |
| 241 | Self::new(buffer, address, fxb_type, width, root_width) |
| 242 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 243 | |
| 244 | /// Convenience function to get the underlying buffer. By using `shallow_copy`, this preserves |
| 245 | /// the lifetime that the underlying buffer has. |
| 246 | pub fn buffer(&self) -> B { |
| 247 | self.buffer.shallow_copy() |
| 248 | } |
| 249 | |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 250 | /// Returns the FlexBufferType of this Reader. |
| 251 | pub fn flexbuffer_type(&self) -> FlexBufferType { |
| 252 | self.fxb_type |
| 253 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 254 | |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 255 | /// Returns the bitwidth of this Reader. |
| 256 | pub fn bitwidth(&self) -> BitWidth { |
| 257 | self.width |
| 258 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 259 | |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 260 | /// Returns the length of the Flexbuffer. If the type has no length, or if an error occurs, |
| 261 | /// 0 is returned. |
| 262 | pub fn length(&self) -> usize { |
| 263 | if let Some(len) = self.fxb_type.fixed_length_vector_length() { |
| 264 | len |
| 265 | } else if self.fxb_type.has_length_slot() && self.address >= self.width.n_bytes() { |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 266 | read_usize( |
| 267 | &self.buffer, |
| 268 | self.address - self.width.n_bytes(), |
| 269 | self.width, |
| 270 | ) |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 271 | } else { |
| 272 | 0 |
| 273 | } |
| 274 | } |
| 275 | /// Returns true if the flexbuffer is aligned to 8 bytes. This guarantees, for valid |
| 276 | /// flexbuffers, that the data is correctly aligned in memory and slices can be read directly |
| 277 | /// e.g. with `get_f64s` or `get_i16s`. |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 278 | #[inline] |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 279 | pub fn is_aligned(&self) -> bool { |
| 280 | (self.buffer.as_ptr() as usize).rem(8) == 0 |
| 281 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 282 | |
| 283 | as_default!(as_vector, get_vector, VectorReader<B>); |
| 284 | as_default!(as_map, get_map, MapReader<B>); |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 285 | |
| 286 | fn expect_type(&self, ty: FlexBufferType) -> Result<(), Error> { |
| 287 | if self.fxb_type == ty { |
| 288 | Ok(()) |
| 289 | } else { |
| 290 | Err(Error::UnexpectedFlexbufferType { |
| 291 | expected: ty, |
| 292 | actual: self.fxb_type, |
| 293 | }) |
| 294 | } |
| 295 | } |
| 296 | fn expect_bw(&self, bw: BitWidth) -> Result<(), Error> { |
| 297 | if self.width == bw { |
| 298 | Ok(()) |
| 299 | } else { |
| 300 | Err(Error::UnexpectedBitWidth { |
| 301 | expected: bw, |
| 302 | actual: self.width, |
| 303 | }) |
| 304 | } |
| 305 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 306 | |
| 307 | /// Directly reads a slice of type `T` where `T` is one of `u8,u16,u32,u64,i8,i16,i32,i64,f32,f64`. |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 308 | /// Returns Err if the type, bitwidth, or memory alignment does not match. Since the bitwidth is |
| 309 | /// dynamic, its better to use a VectorReader unless you know your data and performance is critical. |
| 310 | #[cfg(target_endian = "little")] |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 311 | #[deprecated( |
| 312 | since = "0.3.0", |
| 313 | note = "This function is unsafe - if this functionality is needed use `Reader::buffer::align_to`" |
| 314 | )] |
| 315 | pub fn get_slice<T: ReadLE>(&self) -> Result<&[T], Error> { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 316 | if self.flexbuffer_type().typed_vector_type() != T::VECTOR_TYPE.typed_vector_type() { |
| 317 | self.expect_type(T::VECTOR_TYPE)?; |
| 318 | } |
| 319 | if self.bitwidth().n_bytes() != std::mem::size_of::<T>() { |
| 320 | self.expect_bw(T::WIDTH)?; |
| 321 | } |
| 322 | let end = self.address + self.length() * std::mem::size_of::<T>(); |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 323 | let slice: &[u8] = self |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 324 | .buffer |
| 325 | .get(self.address..end) |
| 326 | .ok_or(Error::FlexbufferOutOfBounds)?; |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 327 | |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 328 | // `align_to` is required because the point of this function is to directly hand back a |
| 329 | // slice of scalars. This can fail because Rust's default allocator is not 16byte aligned |
| 330 | // (though in practice this only happens for small buffers). |
| 331 | let (pre, mid, suf) = unsafe { slice.align_to::<T>() }; |
| 332 | if pre.is_empty() && suf.is_empty() { |
| 333 | Ok(mid) |
| 334 | } else { |
| 335 | Err(Error::AlignmentError) |
| 336 | } |
| 337 | } |
| 338 | |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 339 | /// Returns the value of the reader if it is a boolean. |
| 340 | /// Otherwise Returns error. |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 341 | pub fn get_bool(&self) -> Result<bool, Error> { |
| 342 | self.expect_type(FlexBufferType::Bool)?; |
| 343 | Ok( |
| 344 | self.buffer[self.address..self.address + self.width.n_bytes()] |
| 345 | .iter() |
| 346 | .any(|&b| b != 0), |
| 347 | ) |
| 348 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 349 | |
| 350 | /// Gets the length of the key if this type is a key. |
| 351 | /// |
| 352 | /// Otherwise, returns an error. |
| 353 | #[inline] |
| 354 | fn get_key_len(&self) -> Result<usize, Error> { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 355 | self.expect_type(FlexBufferType::Key)?; |
| 356 | let (length, _) = self.buffer[self.address..] |
| 357 | .iter() |
| 358 | .enumerate() |
| 359 | .find(|(_, &b)| b == b'\0') |
| 360 | .unwrap_or((0, &0)); |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 361 | Ok(length) |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 362 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 363 | |
| 364 | /// Retrieves the string value up until the first `\0` character. |
| 365 | pub fn get_key(&self) -> Result<B::BufferString, Error> { |
| 366 | let bytes = self |
| 367 | .buffer |
| 368 | .slice(self.address..self.address + self.get_key_len()?) |
| 369 | .ok_or(Error::IndexOutOfBounds)?; |
| 370 | Ok(bytes.buffer_str()?) |
| 371 | } |
| 372 | |
| 373 | pub fn get_blob(&self) -> Result<Blob<B>, Error> { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 374 | self.expect_type(FlexBufferType::Blob)?; |
| 375 | Ok(Blob( |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 376 | self.buffer |
| 377 | .slice(self.address..self.address + self.length()) |
| 378 | .ok_or(Error::IndexOutOfBounds)?, |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 379 | )) |
| 380 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 381 | |
| 382 | pub fn as_blob(&self) -> Blob<B> { |
James Kuszmaul | 3b15b0c | 2022-11-08 14:03:16 -0800 | [diff] [blame^] | 383 | self.get_blob().unwrap_or_else(|_| Blob(B::empty())) |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 384 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 385 | |
| 386 | /// Retrieves str pointer, errors if invalid UTF-8, or the provided index |
| 387 | /// is out of bounds. |
| 388 | pub fn get_str(&self) -> Result<B::BufferString, Error> { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 389 | self.expect_type(FlexBufferType::String)?; |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 390 | let bytes = self |
| 391 | .buffer |
| 392 | .slice(self.address..self.address + self.length()); |
| 393 | Ok(bytes.ok_or(Error::ReadUsizeOverflowed)?.buffer_str()?) |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 394 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 395 | |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 396 | fn get_map_info(&self) -> Result<(usize, BitWidth), Error> { |
| 397 | self.expect_type(FlexBufferType::Map)?; |
| 398 | if 3 * self.width.n_bytes() >= self.address { |
| 399 | return Err(Error::FlexbufferOutOfBounds); |
| 400 | } |
| 401 | let keys_offset_address = self.address - 3 * self.width.n_bytes(); |
| 402 | let keys_width = { |
| 403 | let kw_addr = self.address - 2 * self.width.n_bytes(); |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 404 | let kw = read_usize(&self.buffer, kw_addr, self.width); |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 405 | BitWidth::from_nbytes(kw).ok_or(Error::InvalidMapKeysVectorWidth) |
| 406 | }?; |
| 407 | Ok((keys_offset_address, keys_width)) |
| 408 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 409 | |
| 410 | pub fn get_map(&self) -> Result<MapReader<B>, Error> { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 411 | let (keys_offset_address, keys_width) = self.get_map_info()?; |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 412 | let keys_address = deref_offset(&self.buffer, keys_offset_address, self.width)?; |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 413 | // TODO(cneo): Check that vectors length equals keys length. |
| 414 | Ok(MapReader { |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 415 | buffer: self.buffer.shallow_copy(), |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 416 | values_address: self.address, |
| 417 | values_width: self.width, |
| 418 | keys_address, |
| 419 | keys_width, |
| 420 | length: self.length(), |
| 421 | }) |
| 422 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 423 | |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 424 | /// Tries to read a FlexBufferType::UInt. Returns Err if the type is not a UInt or if the |
| 425 | /// address is out of bounds. |
| 426 | pub fn get_u64(&self) -> Result<u64, Error> { |
| 427 | self.expect_type(FlexBufferType::UInt)?; |
| 428 | let cursor = self |
| 429 | .buffer |
| 430 | .get(self.address..self.address + self.width.n_bytes()); |
| 431 | match self.width { |
| 432 | BitWidth::W8 => cursor.map(|s| s[0] as u8).map(Into::into), |
| 433 | BitWidth::W16 => cursor |
| 434 | .and_then(|s| s.try_into().ok()) |
| 435 | .map(<u16>::from_le_bytes) |
| 436 | .map(Into::into), |
| 437 | BitWidth::W32 => cursor |
| 438 | .and_then(|s| s.try_into().ok()) |
| 439 | .map(<u32>::from_le_bytes) |
| 440 | .map(Into::into), |
| 441 | BitWidth::W64 => cursor |
| 442 | .and_then(|s| s.try_into().ok()) |
| 443 | .map(<u64>::from_le_bytes), |
| 444 | } |
| 445 | .ok_or(Error::FlexbufferOutOfBounds) |
| 446 | } |
| 447 | /// Tries to read a FlexBufferType::Int. Returns Err if the type is not a UInt or if the |
| 448 | /// address is out of bounds. |
| 449 | pub fn get_i64(&self) -> Result<i64, Error> { |
| 450 | self.expect_type(FlexBufferType::Int)?; |
| 451 | let cursor = self |
| 452 | .buffer |
| 453 | .get(self.address..self.address + self.width.n_bytes()); |
| 454 | match self.width { |
| 455 | BitWidth::W8 => cursor.map(|s| s[0] as i8).map(Into::into), |
| 456 | BitWidth::W16 => cursor |
| 457 | .and_then(|s| s.try_into().ok()) |
| 458 | .map(<i16>::from_le_bytes) |
| 459 | .map(Into::into), |
| 460 | BitWidth::W32 => cursor |
| 461 | .and_then(|s| s.try_into().ok()) |
| 462 | .map(<i32>::from_le_bytes) |
| 463 | .map(Into::into), |
| 464 | BitWidth::W64 => cursor |
| 465 | .and_then(|s| s.try_into().ok()) |
| 466 | .map(<i64>::from_le_bytes), |
| 467 | } |
| 468 | .ok_or(Error::FlexbufferOutOfBounds) |
| 469 | } |
| 470 | /// Tries to read a FlexBufferType::Float. Returns Err if the type is not a UInt, if the |
| 471 | /// address is out of bounds, or if its a f16 or f8 (not currently supported). |
| 472 | pub fn get_f64(&self) -> Result<f64, Error> { |
| 473 | self.expect_type(FlexBufferType::Float)?; |
| 474 | let cursor = self |
| 475 | .buffer |
| 476 | .get(self.address..self.address + self.width.n_bytes()); |
| 477 | match self.width { |
| 478 | BitWidth::W8 | BitWidth::W16 => return Err(Error::InvalidPackedType), |
| 479 | BitWidth::W32 => cursor |
| 480 | .and_then(|s| s.try_into().ok()) |
| 481 | .map(f32_from_le_bytes) |
| 482 | .map(Into::into), |
| 483 | BitWidth::W64 => cursor |
| 484 | .and_then(|s| s.try_into().ok()) |
| 485 | .map(f64_from_le_bytes), |
| 486 | } |
| 487 | .ok_or(Error::FlexbufferOutOfBounds) |
| 488 | } |
| 489 | pub fn as_bool(&self) -> bool { |
| 490 | use FlexBufferType::*; |
| 491 | match self.fxb_type { |
| 492 | Bool => self.get_bool().unwrap_or_default(), |
| 493 | UInt => self.as_u64() != 0, |
| 494 | Int => self.as_i64() != 0, |
| 495 | Float => self.as_f64().abs() > std::f64::EPSILON, |
| 496 | String | Key => !self.as_str().is_empty(), |
| 497 | Null => false, |
| 498 | Blob => self.length() != 0, |
| 499 | ty if ty.is_vector() => self.length() != 0, |
| 500 | _ => unreachable!(), |
| 501 | } |
| 502 | } |
| 503 | /// Returns a u64, casting if necessary. For Maps and Vectors, their length is |
| 504 | /// returned. If anything fails, 0 is returned. |
| 505 | pub fn as_u64(&self) -> u64 { |
| 506 | match self.fxb_type { |
| 507 | FlexBufferType::UInt => self.get_u64().unwrap_or_default(), |
| 508 | FlexBufferType::Int => self |
| 509 | .get_i64() |
| 510 | .unwrap_or_default() |
| 511 | .try_into() |
| 512 | .unwrap_or_default(), |
| 513 | FlexBufferType::Float => self.get_f64().unwrap_or_default() as u64, |
| 514 | FlexBufferType::String => { |
| 515 | if let Ok(s) = self.get_str() { |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 516 | if let Ok(f) = u64::from_str(&s) { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 517 | return f; |
| 518 | } |
| 519 | } |
| 520 | 0 |
| 521 | } |
| 522 | _ if self.fxb_type.is_vector() => self.length() as u64, |
| 523 | _ => 0, |
| 524 | } |
| 525 | } |
| 526 | try_cast_fn!(as_u32, as_u64, u32); |
| 527 | try_cast_fn!(as_u16, as_u64, u16); |
| 528 | try_cast_fn!(as_u8, as_u64, u8); |
| 529 | |
| 530 | /// Returns an i64, casting if necessary. For Maps and Vectors, their length is |
| 531 | /// returned. If anything fails, 0 is returned. |
| 532 | pub fn as_i64(&self) -> i64 { |
| 533 | match self.fxb_type { |
| 534 | FlexBufferType::Int => self.get_i64().unwrap_or_default(), |
| 535 | FlexBufferType::UInt => self |
| 536 | .get_u64() |
| 537 | .unwrap_or_default() |
| 538 | .try_into() |
| 539 | .unwrap_or_default(), |
| 540 | FlexBufferType::Float => self.get_f64().unwrap_or_default() as i64, |
| 541 | FlexBufferType::String => { |
| 542 | if let Ok(s) = self.get_str() { |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 543 | if let Ok(f) = i64::from_str(&s) { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 544 | return f; |
| 545 | } |
| 546 | } |
| 547 | 0 |
| 548 | } |
| 549 | _ if self.fxb_type.is_vector() => self.length() as i64, |
| 550 | _ => 0, |
| 551 | } |
| 552 | } |
| 553 | try_cast_fn!(as_i32, as_i64, i32); |
| 554 | try_cast_fn!(as_i16, as_i64, i16); |
| 555 | try_cast_fn!(as_i8, as_i64, i8); |
| 556 | |
| 557 | /// Returns an f64, casting if necessary. For Maps and Vectors, their length is |
| 558 | /// returned. If anything fails, 0 is returned. |
| 559 | pub fn as_f64(&self) -> f64 { |
| 560 | match self.fxb_type { |
| 561 | FlexBufferType::Int => self.get_i64().unwrap_or_default() as f64, |
| 562 | FlexBufferType::UInt => self.get_u64().unwrap_or_default() as f64, |
| 563 | FlexBufferType::Float => self.get_f64().unwrap_or_default(), |
| 564 | FlexBufferType::String => { |
| 565 | if let Ok(s) = self.get_str() { |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 566 | if let Ok(f) = f64::from_str(&s) { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 567 | return f; |
| 568 | } |
| 569 | } |
| 570 | 0.0 |
| 571 | } |
| 572 | _ if self.fxb_type.is_vector() => self.length() as f64, |
| 573 | _ => 0.0, |
| 574 | } |
| 575 | } |
| 576 | pub fn as_f32(&self) -> f32 { |
| 577 | self.as_f64() as f32 |
| 578 | } |
| 579 | |
| 580 | /// Returns empty string if you're not trying to read a string. |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 581 | pub fn as_str(&self) -> B::BufferString { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 582 | match self.fxb_type { |
James Kuszmaul | 3b15b0c | 2022-11-08 14:03:16 -0800 | [diff] [blame^] | 583 | FlexBufferType::String => self.get_str().unwrap_or_else(|_| B::empty_str()), |
| 584 | FlexBufferType::Key => self.get_key().unwrap_or_else(|_| B::empty_str()), |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 585 | _ => B::empty_str(), |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 586 | } |
| 587 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 588 | |
| 589 | pub fn get_vector(&self) -> Result<VectorReader<B>, Error> { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 590 | if !self.fxb_type.is_vector() { |
| 591 | self.expect_type(FlexBufferType::Vector)?; |
| 592 | }; |
| 593 | Ok(VectorReader { |
| 594 | reader: self.clone(), |
| 595 | length: self.length(), |
| 596 | }) |
| 597 | } |
| 598 | } |
| 599 | |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 600 | impl<B: Buffer> fmt::Display for Reader<B> { |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 601 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 602 | use FlexBufferType::*; |
| 603 | match self.flexbuffer_type() { |
| 604 | Null => write!(f, "null"), |
| 605 | UInt => write!(f, "{}", self.as_u64()), |
| 606 | Int => write!(f, "{}", self.as_i64()), |
| 607 | Float => write!(f, "{}", self.as_f64()), |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 608 | Key | String => write!(f, "{:?}", &self.as_str() as &str), |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 609 | Bool => write!(f, "{}", self.as_bool()), |
| 610 | Blob => write!(f, "blob"), |
| 611 | Map => { |
| 612 | write!(f, "{{")?; |
| 613 | let m = self.as_map(); |
| 614 | let mut pairs = m.iter_keys().zip(m.iter_values()); |
| 615 | if let Some((k, v)) = pairs.next() { |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 616 | write!(f, "{:?}: {}", &k as &str, v)?; |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 617 | for (k, v) in pairs { |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 618 | write!(f, ", {:?}: {}", &k as &str, v)?; |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 619 | } |
| 620 | } |
| 621 | write!(f, "}}") |
| 622 | } |
| 623 | t if t.is_vector() => { |
| 624 | write!(f, "[")?; |
| 625 | let mut elems = self.as_vector().iter(); |
| 626 | if let Some(first) = elems.next() { |
| 627 | write!(f, "{}", first)?; |
| 628 | for e in elems { |
| 629 | write!(f, ", {}", e)?; |
| 630 | } |
| 631 | } |
| 632 | write!(f, "]") |
| 633 | } |
| 634 | _ => unreachable!("Display not implemented for {:?}", self), |
| 635 | } |
| 636 | } |
| 637 | } |
| 638 | |
| 639 | // TODO(cneo): Use <f..>::from_le_bytes when we move past rustc 1.39. |
| 640 | fn f32_from_le_bytes(bytes: [u8; 4]) -> f32 { |
| 641 | let bits = <u32>::from_le_bytes(bytes); |
| 642 | <f32>::from_bits(bits) |
| 643 | } |
James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame] | 644 | |
Austin Schuh | 272c613 | 2020-11-14 16:37:52 -0800 | [diff] [blame] | 645 | fn f64_from_le_bytes(bytes: [u8; 8]) -> f64 { |
| 646 | let bits = <u64>::from_le_bytes(bytes); |
| 647 | <f64>::from_bits(bits) |
| 648 | } |
| 649 | |
| 650 | fn read_usize(buffer: &[u8], address: usize, width: BitWidth) -> usize { |
| 651 | let cursor = &buffer[address..]; |
| 652 | match width { |
| 653 | BitWidth::W8 => cursor[0] as usize, |
| 654 | BitWidth::W16 => cursor |
| 655 | .get(0..2) |
| 656 | .and_then(|s| s.try_into().ok()) |
| 657 | .map(<u16>::from_le_bytes) |
| 658 | .unwrap_or_default() as usize, |
| 659 | BitWidth::W32 => cursor |
| 660 | .get(0..4) |
| 661 | .and_then(|s| s.try_into().ok()) |
| 662 | .map(<u32>::from_le_bytes) |
| 663 | .unwrap_or_default() as usize, |
| 664 | BitWidth::W64 => cursor |
| 665 | .get(0..8) |
| 666 | .and_then(|s| s.try_into().ok()) |
| 667 | .map(<u64>::from_le_bytes) |
| 668 | .unwrap_or_default() as usize, |
| 669 | } |
| 670 | } |
| 671 | |
| 672 | fn unpack_type(ty: u8) -> Result<(FlexBufferType, BitWidth), Error> { |
| 673 | let w = BitWidth::try_from(ty & 3u8).map_err(|_| Error::InvalidPackedType)?; |
| 674 | let t = FlexBufferType::try_from(ty >> 2).map_err(|_| Error::InvalidPackedType)?; |
| 675 | Ok((t, w)) |
| 676 | } |