blob: f230c34f1bae58c0b33fcd294a2d1a2ac3257056 [file] [log] [blame]
Austin Schuh272c6132020-11-14 16:37:52 -08001// 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
15use byteorder::{LittleEndian, WriteBytesExt};
16
17use crate::bitwidth::BitWidth;
18use crate::bitwidth::BitWidth::*;
19use crate::flexbuffer_type::FlexBufferType;
20use crate::flexbuffer_type::FlexBufferType::*;
21
22/// Internal representation of FlexBuffer Types and Data before writing.
23/// These get placed on the builder's stack and are eventually commited.
24#[derive(Debug, Clone, Copy, PartialEq)]
25pub enum Value {
26 // Inline types
27 Null,
28 Int(i64),
29 UInt(u64),
30 Float(f64),
31 Bool(bool),
32 /// Null termintated, c_string. Only used with `Map`s.
33 Key(usize),
34 /// The other ~20 or so types.
35 Reference {
36 address: usize,
37 child_width: BitWidth,
38 fxb_type: FlexBufferType,
39 },
40}
41
42macro_rules! new_typed_vector {
43 ($name: ident, $v2: ident, $v3: ident, $v4: ident, $vn: ident) => {
44 /// Returns a typed vector, fixed length if possible.
45 /// Address and child width are zero initialized and must be set.
46 pub fn $name(n: usize) -> Value {
47 let address = 0;
48 let child_width = W8;
49 match n {
50 2 => Value::Reference {
51 address,
52 child_width,
53 fxb_type: $v2,
54 },
55 3 => Value::Reference {
56 address,
57 child_width,
58 fxb_type: $v3,
59 },
60 4 => Value::Reference {
61 address,
62 child_width,
63 fxb_type: $v4,
64 },
65 _ => Value::Reference {
66 address,
67 child_width,
68 fxb_type: $vn,
69 },
70 }
71 }
72 };
73}
74
75impl Value {
76 pub fn new_vector() -> Self {
77 Value::Reference {
78 address: 0,
79 child_width: W8,
80 fxb_type: Vector,
81 }
82 }
83 pub fn new_map() -> Self {
84 Value::Reference {
85 address: 0,
86 child_width: W8,
87 fxb_type: Map,
88 }
89 }
90 new_typed_vector!(
91 new_int_vector,
92 VectorInt2,
93 VectorInt3,
94 VectorInt4,
95 VectorInt
96 );
97 new_typed_vector!(
98 new_uint_vector,
99 VectorUInt2,
100 VectorUInt3,
101 VectorUInt4,
102 VectorUInt
103 );
104 new_typed_vector!(
105 new_float_vector,
106 VectorFloat2,
107 VectorFloat3,
108 VectorFloat4,
109 VectorFloat
110 );
111 pub fn fxb_type(&self) -> FlexBufferType {
112 match *self {
113 Value::Null => Null,
114 Value::Int(_) => Int,
115 Value::UInt(_) => UInt,
116 Value::Float(_) => Float,
117 Value::Bool(_) => Bool,
118 Value::Key(_) => Key,
119 Value::Reference { fxb_type, .. } => fxb_type,
120 }
121 }
122 pub fn is_fixed_length_vector(&self) -> bool {
123 self.fxb_type().is_fixed_length_vector()
124 }
125 pub fn is_inline(&self) -> bool {
126 self.fxb_type().is_inline()
127 }
128 pub fn is_reference(&self) -> bool {
129 !self.is_inline()
130 }
131 pub fn is_key(&self) -> bool {
132 match self {
133 Value::Key(_) => true,
134 _ => false,
135 }
136 }
137 pub fn is_typed_vector_or_map(&self) -> bool {
138 if let Value::Reference { fxb_type, .. } = self {
139 fxb_type.is_heterogenous()
140 } else {
141 false
142 }
143 }
144 pub fn prefix_length(&self) -> usize {
145 if self.is_fixed_length_vector() || self.is_inline() {
146 return 0;
147 }
148 if let Value::Reference { fxb_type, .. } = self {
149 if *fxb_type == Map {
150 return 3;
151 }
152 }
153 1
154 }
155 pub fn set_fxb_type_or_panic(&mut self, new_type: FlexBufferType) {
156 if let Value::Reference { fxb_type, .. } = self {
157 *fxb_type = new_type;
158 } else {
159 panic!("`set_fxb_type_or_panic` called on {:?}", self)
160 }
161 }
162 pub fn set_child_width_or_panic(&mut self, new_width: BitWidth) {
163 if let Value::Reference { child_width, .. } = self {
164 *child_width = new_width;
165 } else {
166 panic!("`set_child_width_or_panic` called on {:?}", self);
167 }
168 }
169 pub fn get_address(&self) -> Option<usize> {
170 if let Value::Reference { address, .. } | Value::Key(address) = self {
171 Some(*address)
172 } else {
173 None
174 }
175 }
176 pub fn set_address_or_panic(&mut self, new_address: usize) {
177 if let Value::Reference { address, .. } | Value::Key(address) = self {
178 *address = new_address;
179 } else {
180 panic!("`set_address_or_panic` called on {:?}", self);
181 }
182 }
183 /// For inline types - the width of the value to be stored.
184 /// For reference types, the width of the referred.
185 /// Note Key types always refer to 8 bit data.
186 pub fn width_or_child_width(&self) -> BitWidth {
187 match *self {
188 Value::Int(x) => x.into(),
189 Value::UInt(x) => x.into(),
190 Value::Float(x) => x.into(),
191 Value::Key(_) | Value::Bool(_) | Value::Null => W8,
192 Value::Reference { child_width, .. } => child_width,
193 }
194 }
195 pub fn relative_address(self, written_at: usize) -> Option<Value> {
196 self.get_address().map(|address| {
197 let offset = written_at
198 .checked_sub(address)
199 .expect("Error: References may only refer backwards in buffer.");
200 Value::UInt(offset as u64)
201 })
202 }
203 /// Computes the minimum required width of `value` when stored in a vector
204 /// starting at `vector_start` at index `idx` (this index includes the prefix).
205 /// `Value::Reference{..}` variants require location information because
206 /// offsets are relative.
207 pub fn width_in_vector(self, vector_start: usize, idx: usize) -> BitWidth {
208 match self {
209 Value::Bool(_) => W8,
210 Value::Null => W8,
211 Value::Int(x) => x.into(),
212 Value::UInt(x) => x.into(),
213 Value::Float(x) => x.into(),
214 _ => {
215 debug_assert!(self.is_reference());
216 for &width in BitWidth::iter() {
217 let bytes = width as usize + 1;
218 let alignment = (bytes - vector_start % bytes) % bytes;
219 let written_at = vector_start + alignment + idx * bytes;
220 // This match must always succeed.
221 if let Some(Value::UInt(offset)) = self.relative_address(written_at) {
222 if BitWidth::from(offset) == width {
223 return width;
224 }
225 }
226 }
227 unreachable!()
228 }
229 }
230 }
231 pub fn packed_type(self, parent_width: BitWidth) -> u8 {
232 let width = if self.is_inline() {
233 std::cmp::max(parent_width, self.width_or_child_width())
234 } else {
235 self.width_or_child_width()
236 };
237 (self.fxb_type() as u8) << 2 | width as u8
238 }
239}
240
241pub fn find_vector_type<'a, T>(mut values: T) -> Value
242where
243 T: std::iter::Iterator<Item = &'a Value>,
244{
245 let first = values.next();
246 if first.is_none() {
247 return Value::new_vector();
248 }
249 let mut len = 1;
250 let init = first.unwrap().fxb_type();
251 for v in values {
252 if v.fxb_type() != init {
253 return Value::new_vector();
254 }
255 len += 1;
256 }
257 let vector_type = match init {
258 Bool => VectorBool,
259 UInt => return Value::new_uint_vector(len),
260 Int => return Value::new_int_vector(len),
261 Float => return Value::new_float_vector(len),
262 Key => VectorKey,
263 // Note that VectorString is deprecated for writing
264 _ => return Value::new_vector(),
265 };
266 Value::Reference {
267 address: 0,
268 child_width: W8,
269 fxb_type: vector_type,
270 }
271}
272
273#[inline]
274pub fn store_value(buffer: &mut Vec<u8>, mut value: Value, width: BitWidth) {
275 // Remap to number types.
276 use Value::*;
277 if let Some(offset) = value.relative_address(buffer.len()) {
278 value = offset;
279 } else {
280 value = match value {
281 Bool(x) => UInt(x.into()),
282 Null => UInt(0), // Should this be 0 bytes?
283 _ => value,
284 }
285 }
286 let write_result = match (value, width) {
287 (UInt(x), W8) => buffer.write_u8(x as u8),
288 (UInt(x), W16) => buffer.write_u16::<LittleEndian>(x as u16),
289 (UInt(x), W32) => buffer.write_u32::<LittleEndian>(x as u32),
290 (UInt(x), W64) => buffer.write_u64::<LittleEndian>(x),
291 (Int(x), W8) => buffer.write_i8(x as i8),
292 (Int(x), W16) => buffer.write_i16::<LittleEndian>(x as i16),
293 (Int(x), W32) => buffer.write_i32::<LittleEndian>(x as i32),
294 (Int(x), W64) => buffer.write_i64::<LittleEndian>(x),
295 (Float(x), W32) => buffer.write_f32::<LittleEndian>(x as f32),
296 (Float(x), W64) => buffer.write_f64::<LittleEndian>(x),
297 (Float(_), _) => unreachable!("Error: Flatbuffers does not support 8 and 16 bit floats."),
298 _ => unreachable!("Variant not considered: {:?}", value),
299 };
300 write_result.unwrap_or_else(|err| {
301 panic!(
302 "Error writing value {:?} with width {:?}: {:?}",
303 value, width, err
304 )
305 });
306}