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