dynfidl/
lib.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! An implementation of the [FIDL wire format] for laying out messages whose types are defined
6//! at runtime.
7//!
8//! [FIDL wire format]: https://fuchsia.dev/fuchsia-src/reference/fidl/language/wire-format
9
10use fidl_constants::{ALLOC_ABSENT_U64, ALLOC_PRESENT_U64};
11
12/// A FIDL struct for encoding. Fields are defined in order.
13#[derive(Default)]
14pub struct Structure {
15    fields: Vec<Field>,
16}
17
18impl Structure {
19    fn alignment(&self) -> usize {
20        let mut alignment = 1;
21        for field in &self.fields {
22            if field.alignment() > alignment {
23                alignment = field.alignment();
24            }
25        }
26        alignment
27    }
28
29    /// Add a field and its value to this dynamic struct definition.
30    pub fn field(mut self, field: Field) -> Self {
31        self.fields.push(field);
32        self
33    }
34
35    /// Encode this struct into it's [persistent message encoding].
36    ///
37    /// [persistent message encoding]: https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs/0120_standalone_use_of_fidl_wire_format
38    pub fn encode_persistent(&self) -> Vec<u8> {
39        let mut buf = Vec::new();
40
41        // encode the persistent header:
42        buf.push(0); // disambiguator
43        buf.push(1); // current wire format magic number
44        buf.extend(2u16.to_le_bytes()); // v2 wire format
45        buf.extend([0; 4]); // reserved with zeroes
46
47        // encode the body of the message
48        self.encode(&mut buf);
49
50        buf
51    }
52
53    /// Encode this struct without any header.
54    pub fn encode(&self, buf: &mut Vec<u8>) {
55        self.encode_inline(buf);
56        // Externally, the structure is aligned on an 8-byte boundary, and may therefore contain
57        // final padding to meet that requirement.
58        buf.pad_to(8);
59    }
60
61    pub fn encode_inline(&self, buf: &mut Vec<u8>) {
62        self.encode_fields(buf);
63    }
64
65    pub fn encode_fields(&self, buf: &mut Vec<u8>) {
66        // encode the struct's fields:
67        if self.fields.is_empty() {
68            // A structure can be:
69            //
70            // * empty — it has no fields. Such a structure is 1 byte in size, with an alignment of
71            // 1 byte, and is exactly equivalent to a structure containing a uint8 with the value
72            // zero.
73            BasicField::UInt8(0).encode_inline(buf);
74        } else {
75            // encode primary objects first
76            for field in &self.fields {
77                field.encode_inline(buf);
78            }
79
80            for field in &self.fields {
81                field.encode_out_of_line(buf);
82            }
83            buf.pad_to(self.alignment());
84        }
85    }
86}
87
88/// A boxed struct. Boxes are encoded out of line, and are optional.
89#[derive(Default)]
90pub struct Box {
91    inner: Option<Structure>,
92}
93
94impl Box {
95    pub fn set_present(self) -> Self {
96        Box {
97            inner: match self.inner {
98                Some(s) => Some(s),
99                None => Some(Structure::default()),
100            },
101        }
102    }
103    /// Add a field and its value to this dynamic struct definition.
104    pub fn field(mut self, field: Field) -> Self {
105        self.inner = match self.inner {
106            Some(s) => Some(s.field(field)),
107            None => Some(Structure::default().field(field)),
108        };
109        self
110    }
111
112    fn alignment(&self) -> usize {
113        8
114    }
115
116    fn encode_inline(&self, buf: &mut Vec<u8>) {
117        // When encoded for transfer, `data` indicates presence of content:
118        //   * `0`: struct is absent
119        //   * `UINTPTR_MAX`: struct is present, data is the next out-of-line object */
120        match &self.inner {
121            None => buf.extend(ALLOC_ABSENT_U64.to_le_bytes()),
122            Some(_) => buf.extend(ALLOC_PRESENT_U64.to_le_bytes()),
123        }
124    }
125
126    fn encode_out_of_line(&self, buf: &mut Vec<u8>) {
127        match &self.inner {
128            None => (),
129            Some(s) => s.encode_fields(buf),
130        }
131    }
132}
133
134/// A field of a FIDL struct.
135pub enum Field {
136    Basic(BasicField),
137    Vector(VectorField),
138    Struct(Structure),
139    Box(Box),
140}
141
142impl Field {
143    fn alignment(&self) -> usize {
144        match self {
145            Self::Basic(b) => b.alignment(),
146            Self::Vector(l) => l.alignment(),
147            Self::Struct(s) => s.alignment(),
148            Self::Box(s) => s.alignment(),
149        }
150    }
151
152    fn encode_inline(&self, buf: &mut Vec<u8>) {
153        buf.pad_to(self.alignment());
154        match self {
155            Self::Basic(b) => b.encode_inline(buf),
156            Self::Vector(l) => l.encode_inline(buf),
157            Self::Struct(s) => s.encode_inline(buf),
158            Self::Box(s) => s.encode_inline(buf),
159        }
160    }
161
162    fn encode_out_of_line(&self, buf: &mut Vec<u8>) {
163        match self {
164            Self::Basic(_) => (),
165            Self::Vector(l) => {
166                // each secondary object must be padded to 8 bytes, as well as the primary
167                buf.pad_to(8);
168                l.encode_out_of_line(buf);
169            }
170            Self::Struct(_) => (),
171            Self::Box(s) => {
172                // each secondary object must be padded to 8 bytes, as well as the primary
173                buf.pad_to(8);
174                s.encode_out_of_line(buf)
175            }
176        }
177    }
178}
179
180pub enum BasicField {
181    Bool(bool),
182    UInt8(u8),
183    UInt16(u16),
184    UInt32(u32),
185    UInt64(u64),
186    Int8(i8),
187    Int16(i16),
188    Int32(i32),
189    Int64(i64),
190}
191
192impl BasicField {
193    fn encode_inline(&self, buf: &mut Vec<u8>) {
194        match self {
195            Self::Bool(b) => buf.push(if *b { 1u8 } else { 0u8 }),
196            Self::UInt8(n) => buf.push(*n),
197            Self::UInt16(n) => buf.extend(n.to_le_bytes()),
198            Self::UInt32(n) => buf.extend(n.to_le_bytes()),
199            Self::UInt64(n) => buf.extend(n.to_le_bytes()),
200            Self::Int8(n) => buf.extend(n.to_le_bytes()),
201            Self::Int16(n) => buf.extend(n.to_le_bytes()),
202            Self::Int32(n) => buf.extend(n.to_le_bytes()),
203            Self::Int64(n) => buf.extend(n.to_le_bytes()),
204        }
205    }
206
207    fn alignment(&self) -> usize {
208        match self {
209            Self::Bool(_) | Self::UInt8(_) | Self::Int8(_) => 1,
210            Self::UInt16(_) | Self::Int16(_) => 2,
211            Self::UInt32(_) | Self::Int32(_) => 4,
212            _ => 8,
213        }
214    }
215}
216
217pub enum VectorField {
218    /// A null vector is one that does not exist.
219    Null,
220    BoolVector(Vec<bool>),
221    UInt8Vector(Vec<u8>),
222    UInt16Vector(Vec<u16>),
223    UInt32Vector(Vec<u32>),
224    UInt64Vector(Vec<u64>),
225    Int8Vector(Vec<i8>),
226    Int16Vector(Vec<i16>),
227    Int32Vector(Vec<i32>),
228    Int64Vector(Vec<i64>),
229    // TODO(https://fxbug.dev/42169377) figure out a better api for nested vectors
230    UInt8VectorVector(Vec<Vec<u8>>),
231}
232
233impl VectorField {
234    fn alignment(&self) -> usize {
235        8
236    }
237
238    fn encode_inline(&self, buf: &mut Vec<u8>) {
239        // Stored as a 16 byte record consisting of:
240        //   * `size`: 64-bit unsigned number of elements
241        //   * `data`: 64-bit presence indication or pointer to out-of-line element data
242        let size = match self {
243            Self::Null => 0,
244            Self::BoolVector(v) => v.len(),
245            Self::UInt8Vector(v) => v.len(),
246            Self::UInt16Vector(v) => v.len(),
247            Self::UInt32Vector(v) => v.len(),
248            Self::UInt64Vector(v) => v.len(),
249            Self::Int8Vector(v) => v.len(),
250            Self::Int16Vector(v) => v.len(),
251            Self::Int32Vector(v) => v.len(),
252            Self::Int64Vector(v) => v.len(),
253            Self::UInt8VectorVector(v) => v.len(),
254        } as u64;
255        buf.extend(size.to_le_bytes());
256
257        // When encoded for transfer, `data` indicates presence of content:
258        //   * `0`: vector is absent
259        //   * `UINTPTR_MAX`: vector is present, data is the next out-of-line object */
260        match self {
261            Self::Null => buf.extend(ALLOC_ABSENT_U64.to_le_bytes()),
262            _ => buf.extend(ALLOC_PRESENT_U64.to_le_bytes()),
263        }
264    }
265
266    fn encode_out_of_line(&self, buf: &mut Vec<u8>) {
267        match self {
268            Self::Null => (),
269            Self::BoolVector(v) => {
270                for b in v {
271                    BasicField::Bool(*b).encode_inline(buf);
272                }
273            }
274            Self::UInt8Vector(v) => buf.extend(v),
275            Self::UInt16Vector(v) => {
276                for n in v {
277                    BasicField::UInt16(*n).encode_inline(buf);
278                }
279            }
280            Self::UInt32Vector(v) => {
281                for n in v {
282                    BasicField::UInt32(*n).encode_inline(buf);
283                }
284            }
285            Self::UInt64Vector(v) => {
286                for n in v {
287                    BasicField::UInt64(*n).encode_inline(buf);
288                }
289            }
290            Self::Int8Vector(v) => {
291                for n in v {
292                    BasicField::Int8(*n).encode_inline(buf);
293                }
294            }
295            Self::Int16Vector(v) => {
296                for n in v {
297                    BasicField::Int16(*n).encode_inline(buf);
298                }
299            }
300            Self::Int32Vector(v) => {
301                for n in v {
302                    BasicField::Int32(*n).encode_inline(buf);
303                }
304            }
305            Self::Int64Vector(v) => {
306                for n in v {
307                    BasicField::Int64(*n).encode_inline(buf);
308                }
309            }
310            Self::UInt8VectorVector(outer) => {
311                let as_fields = outer
312                    .iter()
313                    .map(|v| Field::Vector(VectorField::UInt8Vector(v.clone())))
314                    .collect::<Vec<_>>();
315
316                for field in &as_fields {
317                    field.encode_inline(buf);
318                }
319                for field in &as_fields {
320                    field.encode_out_of_line(buf);
321                }
322            }
323        }
324    }
325}
326
327trait Padding {
328    fn pad_to(&mut self, align: usize);
329}
330
331impl Padding for Vec<u8> {
332    fn pad_to(&mut self, align: usize) {
333        let start_len = self.len();
334        let num_bytes = (align - (start_len % align)) % align;
335        self.resize(start_len + num_bytes, 0);
336    }
337}