fidl_next_codec/encode/
mod.rs

1// Copyright 2024 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//! Provides encoding for FIDL types.
6
7mod error;
8
9use core::mem::MaybeUninit;
10use core::ptr::copy_nonoverlapping;
11
12pub use self::error::EncodeError;
13
14use crate::{
15    CopyOptimization, Encoder, EncoderExt as _, Wire, WireBox, WireF32, WireF64, WireI16, WireI32,
16    WireI64, WireU16, WireU32, WireU64,
17};
18
19/// A type which can be encoded as FIDL.
20pub trait Encodable {
21    /// Whether the conversion from `Self` to `Self::Encoded` is equivalent to copying the raw bytes
22    /// of `Self`.
23    ///
24    /// Copy optimization is disabled by default.
25    const COPY_OPTIMIZATION: CopyOptimization<Self, Self::Encoded> = CopyOptimization::disable();
26
27    /// The wire type for the value.
28    type Encoded: Wire;
29}
30
31/// Encodes a value.
32///
33/// # Safety
34///
35/// `encode` must initialize all non-padding bytes of `out`.
36pub unsafe trait Encode<E: ?Sized>: Encodable + Sized {
37    /// Encodes this value into an encoder and output.
38    fn encode(
39        self,
40        encoder: &mut E,
41        out: &mut MaybeUninit<Self::Encoded>,
42    ) -> Result<(), EncodeError>;
43}
44
45/// Encodes a reference.
46///
47/// # Safety
48///
49/// `encode` must initialize all non-padding bytes of `out`.
50pub unsafe trait EncodeRef<E: ?Sized>: Encode<E> {
51    /// Encodes this reference into an encoder and output.
52    fn encode_ref(
53        &self,
54        encoder: &mut E,
55        out: &mut MaybeUninit<Self::Encoded>,
56    ) -> Result<(), EncodeError>;
57}
58
59/// A type which can be encoded as FIDL when optional.
60pub trait EncodableOption {
61    /// The wire type for the optional value.
62    type EncodedOption: Wire;
63}
64
65/// Encodes an optional value.
66///
67/// # Safety
68///
69/// `encode_option` must initialize all non-padding bytes of `out`.
70pub unsafe trait EncodeOption<E: ?Sized>: EncodableOption + Sized {
71    /// Encodes this optional value into an encoder and output.
72    fn encode_option(
73        this: Option<Self>,
74        encoder: &mut E,
75        out: &mut MaybeUninit<Self::EncodedOption>,
76    ) -> Result<(), EncodeError>;
77}
78
79/// Encodes an optional reference.
80///
81/// # Safety
82///
83/// `encode_option_ref` must initialize all non-padding bytes of `out`.
84pub unsafe trait EncodeOptionRef<E: ?Sized>: EncodeOption<E> {
85    /// Encodes this optional reference into an encoder and output.
86    fn encode_option_ref(
87        this: Option<&Self>,
88        encoder: &mut E,
89        out: &mut MaybeUninit<Self::EncodedOption>,
90    ) -> Result<(), EncodeError>;
91}
92
93impl<T: Encodable> Encodable for &T {
94    type Encoded = T::Encoded;
95}
96
97unsafe impl<E: ?Sized, T: EncodeRef<E>> Encode<E> for &T {
98    fn encode(
99        self,
100        encoder: &mut E,
101        out: &mut MaybeUninit<Self::Encoded>,
102    ) -> Result<(), EncodeError> {
103        T::encode_ref(self, encoder, out)
104    }
105}
106
107impl<T: EncodableOption> EncodableOption for &T {
108    type EncodedOption = T::EncodedOption;
109}
110
111unsafe impl<E: ?Sized, T: EncodeOptionRef<E>> EncodeOption<E> for &T {
112    fn encode_option(
113        this: Option<Self>,
114        encoder: &mut E,
115        out: &mut MaybeUninit<Self::EncodedOption>,
116    ) -> Result<(), EncodeError> {
117        T::encode_option_ref(this, encoder, out)
118    }
119}
120
121impl<T: Encodable> Encodable for Box<T> {
122    type Encoded = T::Encoded;
123}
124
125unsafe impl<E: ?Sized, T: Encode<E>> Encode<E> for Box<T> {
126    fn encode(
127        self,
128        encoder: &mut E,
129        out: &mut MaybeUninit<Self::Encoded>,
130    ) -> Result<(), EncodeError> {
131        T::encode(*self, encoder, out)
132    }
133}
134
135unsafe impl<E: ?Sized, T: EncodeRef<E>> EncodeRef<E> for Box<T> {
136    fn encode_ref(
137        &self,
138        encoder: &mut E,
139        out: &mut MaybeUninit<Self::Encoded>,
140    ) -> Result<(), EncodeError> {
141        T::encode_ref(self, encoder, out)
142    }
143}
144
145impl<T: EncodableOption> EncodableOption for Box<T> {
146    type EncodedOption = T::EncodedOption;
147}
148
149unsafe impl<E: ?Sized, T: EncodeOption<E>> EncodeOption<E> for Box<T> {
150    fn encode_option(
151        this: Option<Self>,
152        encoder: &mut E,
153        out: &mut MaybeUninit<Self::EncodedOption>,
154    ) -> Result<(), EncodeError> {
155        T::encode_option(this.map(|value| *value), encoder, out)
156    }
157}
158
159unsafe impl<E: ?Sized, T: EncodeOptionRef<E>> EncodeOptionRef<E> for Box<T> {
160    fn encode_option_ref(
161        this: Option<&Self>,
162        encoder: &mut E,
163        out: &mut MaybeUninit<Self::EncodedOption>,
164    ) -> Result<(), EncodeError> {
165        T::encode_option_ref(this.map(|value| &**value), encoder, out)
166    }
167}
168
169macro_rules! impl_primitive {
170    ($ty:ty) => {
171        impl_primitive!($ty, $ty);
172    };
173    ($ty:ty, $enc:ty) => {
174        impl Encodable for $ty {
175            const COPY_OPTIMIZATION: CopyOptimization<$ty, $enc> =
176                CopyOptimization::<$ty, $enc>::PRIMITIVE;
177
178            type Encoded = $enc;
179        }
180
181        unsafe impl<E: ?Sized> Encode<E> for $ty {
182            #[inline]
183            fn encode(
184                self,
185                encoder: &mut E,
186                out: &mut MaybeUninit<Self::Encoded>,
187            ) -> Result<(), EncodeError> {
188                self.encode_ref(encoder, out)
189            }
190        }
191
192        unsafe impl<E: ?Sized> EncodeRef<E> for $ty {
193            #[inline]
194            fn encode_ref(
195                &self,
196                _: &mut E,
197                out: &mut MaybeUninit<Self::Encoded>,
198            ) -> Result<(), EncodeError> {
199                out.write(<$enc>::from(*self));
200                Ok(())
201            }
202        }
203
204        impl EncodableOption for $ty {
205            type EncodedOption = WireBox<'static, $enc>;
206        }
207
208        unsafe impl<E: Encoder + ?Sized> EncodeOption<E> for $ty {
209            #[inline]
210            fn encode_option(
211                this: Option<Self>,
212                encoder: &mut E,
213                out: &mut MaybeUninit<Self::EncodedOption>,
214            ) -> Result<(), EncodeError> {
215                Self::encode_option_ref(this.as_ref(), encoder, out)
216            }
217        }
218
219        unsafe impl<E: Encoder + ?Sized> EncodeOptionRef<E> for $ty {
220            #[inline]
221            fn encode_option_ref(
222                this: Option<&Self>,
223                encoder: &mut E,
224                out: &mut MaybeUninit<Self::EncodedOption>,
225            ) -> Result<(), EncodeError> {
226                if let Some(value) = this {
227                    encoder.encode_next(value)?;
228                    WireBox::encode_present(out);
229                } else {
230                    WireBox::encode_absent(out);
231                }
232
233                Ok(())
234            }
235        }
236    };
237}
238
239macro_rules! impl_primitives {
240    ($($ty:ty $(, $enc:ty)?);* $(;)?) => {
241        $(
242            impl_primitive!($ty $(, $enc)?);
243        )*
244    }
245}
246
247impl_primitives! {
248    ();
249
250    bool;
251
252    i8;
253    i16, WireI16; i32, WireI32; i64, WireI64;
254    WireI16; WireI32; WireI64;
255
256    u8;
257    u16, WireU16; u32, WireU32; u64, WireU64;
258    WireU16; WireU32; WireU64;
259
260    f32, WireF32; f64, WireF64;
261    WireF32; WireF64;
262}
263
264impl<T: Encodable, const N: usize> Encodable for [T; N] {
265    const COPY_OPTIMIZATION: CopyOptimization<Self, Self::Encoded> =
266        T::COPY_OPTIMIZATION.infer_array();
267
268    type Encoded = [T::Encoded; N];
269}
270
271fn encode_to_array<A, E, T, const N: usize>(
272    value: A,
273    encoder: &mut E,
274    out: &mut MaybeUninit<[T::Encoded; N]>,
275) -> Result<(), EncodeError>
276where
277    A: AsRef<[T]> + IntoIterator,
278    A::Item: Encode<E, Encoded = T::Encoded>,
279    E: ?Sized,
280    T: Encode<E>,
281{
282    if T::COPY_OPTIMIZATION.is_enabled() {
283        // SAFETY: `T` has copy optimization enabled and so is safe to copy to the output.
284        unsafe {
285            copy_nonoverlapping(value.as_ref().as_ptr().cast(), out.as_mut_ptr(), 1);
286        }
287    } else {
288        for (i, item) in value.into_iter().enumerate() {
289            // SAFETY: `out` is a `MaybeUninit<[T::Encoded; N]>` and so consists of `N` copies of
290            // `T::Encoded` in order with no additional padding. We can make a `&mut MaybeUninit` to
291            // the `i`th element by:
292            // 1. Getting a pointer to the contents of the `MaybeUninit<[T::Encoded; N]>` (the
293            //    pointer is of type `*mut [T::Encoded; N]`).
294            // 2. Casting it to `*mut MaybeUninit<T::Encoded>`. Note that `MaybeUninit<T>` always
295            //    has the same layout as `T`.
296            // 3. Adding `i` to reach the `i`th element.
297            // 4. Dereferencing as `&mut`.
298            let out_i = unsafe { &mut *out.as_mut_ptr().cast::<MaybeUninit<T::Encoded>>().add(i) };
299            item.encode(encoder, out_i)?;
300        }
301    }
302    Ok(())
303}
304
305unsafe impl<E, T, const N: usize> Encode<E> for [T; N]
306where
307    E: ?Sized,
308    T: Encode<E>,
309{
310    fn encode(
311        self,
312        encoder: &mut E,
313        out: &mut MaybeUninit<Self::Encoded>,
314    ) -> Result<(), EncodeError> {
315        encode_to_array(self, encoder, out)
316    }
317}
318
319unsafe impl<E, T, const N: usize> EncodeRef<E> for [T; N]
320where
321    E: ?Sized,
322    T: EncodeRef<E>,
323{
324    fn encode_ref(
325        &self,
326        encoder: &mut E,
327        out: &mut MaybeUninit<Self::Encoded>,
328    ) -> Result<(), EncodeError> {
329        encode_to_array(self, encoder, out)
330    }
331}
332
333#[cfg(test)]
334mod tests {
335    use crate::chunks;
336    use crate::testing::assert_encoded;
337
338    #[test]
339    fn encode_unit() {
340        assert_encoded((), &chunks![]);
341    }
342
343    #[test]
344    fn encode_bool() {
345        assert_encoded(true, &chunks![0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
346        assert_encoded(false, &chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
347    }
348
349    #[test]
350    fn encode_ints() {
351        assert_encoded(0xa3u8, &chunks![0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
352        assert_encoded(-0x45i8, &chunks![0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
353
354        assert_encoded(0x1234u16, &chunks![0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
355        assert_encoded(-0x1234i16, &chunks![0xcc, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
356
357        assert_encoded(0x12345678u32, &chunks![0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00]);
358        assert_encoded(-0x12345678i32, &chunks![0x88, 0xa9, 0xcb, 0xed, 0x00, 0x00, 0x00, 0x00]);
359
360        assert_encoded(
361            0x123456789abcdef0u64,
362            &chunks![0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12],
363        );
364        assert_encoded(
365            -0x123456789abcdef0i64,
366            &chunks![0x10, 0x21, 0x43, 0x65, 0x87, 0xa9, 0xcb, 0xed],
367        );
368    }
369
370    #[test]
371    fn encode_floats() {
372        assert_encoded(
373            ::core::f32::consts::PI,
374            &chunks![0xdb, 0x0f, 0x49, 0x40, 0x00, 0x00, 0x00, 0x00],
375        );
376        assert_encoded(
377            ::core::f64::consts::PI,
378            &chunks![0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40],
379        );
380    }
381
382    #[test]
383    fn encode_box() {
384        assert_encoded(None::<u64>, &chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
385        assert_encoded(
386            Some(0x123456789abcdef0u64),
387            &chunks![
388                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56,
389                0x34, 0x12,
390            ],
391        );
392    }
393
394    #[test]
395    fn encode_vec() {
396        assert_encoded(
397            None::<Vec<u32>>,
398            &chunks![
399                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400                0x00, 0x00,
401            ],
402        );
403        assert_encoded(
404            Some(vec![0x12345678u32, 0x9abcdef0u32]),
405            &chunks![
406                0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
407                0xff, 0xff, 0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a,
408            ],
409        );
410        assert_encoded(
411            Some(Vec::<u32>::new()),
412            &chunks![
413                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
414                0xff, 0xff,
415            ],
416        );
417    }
418
419    #[test]
420    fn encode_string() {
421        assert_encoded(
422            None::<String>,
423            &chunks![
424                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
425                0x00, 0x00,
426            ],
427        );
428        assert_encoded(
429            Some("0123".to_string()),
430            &chunks![
431                0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
432                0xff, 0xff, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00,
433            ],
434        );
435        assert_encoded(
436            Some(String::new()),
437            &chunks![
438                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
439                0xff, 0xff,
440            ],
441        );
442    }
443}