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