// 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 byteorder::{LittleEndian, WriteBytesExt}; use crate::bitwidth::BitWidth; use crate::bitwidth::BitWidth::*; use crate::flexbuffer_type::FlexBufferType; use crate::flexbuffer_type::FlexBufferType::*; /// Internal representation of FlexBuffer Types and Data before writing. /// These get placed on the builder's stack and are eventually commited. #[derive(Debug, Clone, Copy, PartialEq)] pub enum Value { // Inline types Null, Int(i64), UInt(u64), Float(f64), Bool(bool), /// Null termintated, c_string. Only used with `Map`s. Key(usize), /// The other ~20 or so types. Reference { address: usize, child_width: BitWidth, fxb_type: FlexBufferType, }, } macro_rules! new_typed_vector { ($name: ident, $v2: ident, $v3: ident, $v4: ident, $vn: ident) => { /// Returns a typed vector, fixed length if possible. /// Address and child width are zero initialized and must be set. pub fn $name(n: usize) -> Value { let address = 0; let child_width = W8; match n { 2 => Value::Reference { address, child_width, fxb_type: $v2, }, 3 => Value::Reference { address, child_width, fxb_type: $v3, }, 4 => Value::Reference { address, child_width, fxb_type: $v4, }, _ => Value::Reference { address, child_width, fxb_type: $vn, }, } } }; } impl Value { pub fn new_vector() -> Self { Value::Reference { address: 0, child_width: W8, fxb_type: Vector, } } pub fn new_map() -> Self { Value::Reference { address: 0, child_width: W8, fxb_type: Map, } } new_typed_vector!( new_int_vector, VectorInt2, VectorInt3, VectorInt4, VectorInt ); new_typed_vector!( new_uint_vector, VectorUInt2, VectorUInt3, VectorUInt4, VectorUInt ); new_typed_vector!( new_float_vector, VectorFloat2, VectorFloat3, VectorFloat4, VectorFloat ); pub fn fxb_type(&self) -> FlexBufferType { match *self { Value::Null => Null, Value::Int(_) => Int, Value::UInt(_) => UInt, Value::Float(_) => Float, Value::Bool(_) => Bool, Value::Key(_) => Key, Value::Reference { fxb_type, .. } => fxb_type, } } pub fn is_fixed_length_vector(&self) -> bool { self.fxb_type().is_fixed_length_vector() } pub fn is_inline(&self) -> bool { self.fxb_type().is_inline() } pub fn is_reference(&self) -> bool { !self.is_inline() } pub fn is_key(&self) -> bool { if let Value::Key(_) = self { true } else { false } } pub fn is_typed_vector_or_map(&self) -> bool { if let Value::Reference { fxb_type, .. } = self { fxb_type.is_heterogenous() } else { false } } pub fn prefix_length(&self) -> usize { if self.is_fixed_length_vector() || self.is_inline() { return 0; } if let Value::Reference { fxb_type, .. } = self { if *fxb_type == Map { return 3; } } 1 } pub fn set_fxb_type_or_panic(&mut self, new_type: FlexBufferType) { if let Value::Reference { fxb_type, .. } = self { *fxb_type = new_type; } else { panic!("`set_fxb_type_or_panic` called on {:?}", self) } } pub fn set_child_width_or_panic(&mut self, new_width: BitWidth) { if let Value::Reference { child_width, .. } = self { *child_width = new_width; } else { panic!("`set_child_width_or_panic` called on {:?}", self); } } pub fn get_address(&self) -> Option { if let Value::Reference { address, .. } | Value::Key(address) = self { Some(*address) } else { None } } pub fn set_address_or_panic(&mut self, new_address: usize) { if let Value::Reference { address, .. } | Value::Key(address) = self { *address = new_address; } else { panic!("`set_address_or_panic` called on {:?}", self); } } /// For inline types - the width of the value to be stored. /// For reference types, the width of the referred. /// Note Key types always refer to 8 bit data. pub fn width_or_child_width(&self) -> BitWidth { match *self { Value::Int(x) => x.into(), Value::UInt(x) => x.into(), Value::Float(x) => x.into(), Value::Key(_) | Value::Bool(_) | Value::Null => W8, Value::Reference { child_width, .. } => child_width, } } pub fn relative_address(self, written_at: usize) -> Option { self.get_address().map(|address| { let offset = written_at .checked_sub(address) .expect("Error: References may only refer backwards in buffer."); Value::UInt(offset as u64) }) } /// Computes the minimum required width of `value` when stored in a vector /// starting at `vector_start` at index `idx` (this index includes the prefix). /// `Value::Reference{..}` variants require location information because /// offsets are relative. pub fn width_in_vector(self, vector_start: usize, idx: usize) -> BitWidth { match self { Value::Bool(_) => W8, Value::Null => W8, Value::Int(x) => x.into(), Value::UInt(x) => x.into(), Value::Float(x) => x.into(), _ => { debug_assert!(self.is_reference()); for &width in BitWidth::iter() { let bytes = width as usize + 1; let alignment = (bytes - vector_start % bytes) % bytes; let written_at = vector_start + alignment + idx * bytes; // This match must always succeed. if let Some(Value::UInt(offset)) = self.relative_address(written_at) { if BitWidth::from(offset) == width { return width; } } } unreachable!() } } } pub fn packed_type(self, parent_width: BitWidth) -> u8 { let width = if self.is_inline() { std::cmp::max(parent_width, self.width_or_child_width()) } else { self.width_or_child_width() }; (self.fxb_type() as u8) << 2 | width as u8 } } pub fn find_vector_type<'a, T>(mut values: T) -> Value where T: std::iter::Iterator, { let first = values.next(); if first.is_none() { return Value::new_vector(); } let mut len = 1; let init = first.unwrap().fxb_type(); for v in values { if v.fxb_type() != init { return Value::new_vector(); } len += 1; } let vector_type = match init { Bool => VectorBool, UInt => return Value::new_uint_vector(len), Int => return Value::new_int_vector(len), Float => return Value::new_float_vector(len), Key => VectorKey, // Note that VectorString is deprecated for writing _ => return Value::new_vector(), }; Value::Reference { address: 0, child_width: W8, fxb_type: vector_type, } } #[inline] pub fn store_value(buffer: &mut Vec, mut value: Value, width: BitWidth) { // Remap to number types. use Value::*; if let Some(offset) = value.relative_address(buffer.len()) { value = offset; } else { value = match value { Bool(x) => UInt(x.into()), Null => UInt(0), // Should this be 0 bytes? _ => value, } } let write_result = match (value, width) { (UInt(x), W8) => buffer.write_u8(x as u8), (UInt(x), W16) => buffer.write_u16::(x as u16), (UInt(x), W32) => buffer.write_u32::(x as u32), (UInt(x), W64) => buffer.write_u64::(x), (Int(x), W8) => buffer.write_i8(x as i8), (Int(x), W16) => buffer.write_i16::(x as i16), (Int(x), W32) => buffer.write_i32::(x as i32), (Int(x), W64) => buffer.write_i64::(x), (Float(x), W32) => buffer.write_f32::(x as f32), (Float(x), W64) => buffer.write_f64::(x), (Float(_), _) => unreachable!("Error: Flatbuffers does not support 8 and 16 bit floats."), _ => unreachable!("Variant not considered: {:?}", value), }; write_result.unwrap_or_else(|err| { panic!( "Error writing value {:?} with width {:?}: {:?}", value, width, err ) }); }