Skip to main content

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::{CopyOptimization, Wire};
15
16/// Encodes a value.
17///
18/// # Safety
19///
20/// `encode` must initialize all non-padding bytes of `out`.
21pub unsafe trait Encode<W: Wire, E: ?Sized>: Sized {
22    /// Whether the conversion from `Self` to `W` is equivalent to copying the
23    /// raw bytes of `Self`.
24    ///
25    /// Copy optimization is disabled by default.
26    const COPY_OPTIMIZATION: CopyOptimization<Self, W> = CopyOptimization::disable();
27
28    /// Encodes this value into an encoder and output.
29    fn encode(
30        self,
31        encoder: &mut E,
32        out: &mut MaybeUninit<W>,
33        constraint: W::Constraint,
34    ) -> Result<(), EncodeError>;
35}
36
37/// Encodes an optional value.
38///
39/// # Safety
40///
41/// `encode_option` must initialize all non-padding bytes of `out`.
42pub unsafe trait EncodeOption<W: Wire, E: ?Sized>: Sized {
43    /// Encodes this optional value into an encoder and output.
44    fn encode_option(
45        this: Option<Self>,
46        encoder: &mut E,
47        out: &mut MaybeUninit<W>,
48        constraint: W::Constraint,
49    ) -> Result<(), EncodeError>;
50}
51
52unsafe impl<W, E, T> Encode<W, E> for Box<T>
53where
54    W: Wire,
55    E: ?Sized,
56    T: Encode<W, E>,
57{
58    fn encode(
59        self,
60        encoder: &mut E,
61        out: &mut MaybeUninit<W>,
62        constraint: W::Constraint,
63    ) -> Result<(), EncodeError> {
64        T::encode(*self, encoder, out, constraint)
65    }
66}
67
68unsafe impl<'a, W, E, T> Encode<W, E> for &'a Box<T>
69where
70    W: Wire,
71    E: ?Sized,
72    &'a T: Encode<W, E>,
73{
74    fn encode(
75        self,
76        encoder: &mut E,
77        out: &mut MaybeUninit<W>,
78        constraint: W::Constraint,
79    ) -> Result<(), EncodeError> {
80        <&'a T>::encode(self, encoder, out, constraint)
81    }
82}
83
84unsafe impl<W, E, T> EncodeOption<W, E> for Box<T>
85where
86    W: Wire,
87    E: ?Sized,
88    T: EncodeOption<W, E>,
89{
90    fn encode_option(
91        this: Option<Self>,
92        encoder: &mut E,
93        out: &mut MaybeUninit<W>,
94        constraint: W::Constraint,
95    ) -> Result<(), EncodeError> {
96        T::encode_option(this.map(|value| *value), encoder, out, constraint)
97    }
98}
99
100unsafe impl<'a, W, E, T> EncodeOption<W, E> for &'a Box<T>
101where
102    W: Wire,
103    E: ?Sized,
104    &'a T: EncodeOption<W, E>,
105{
106    fn encode_option(
107        this: Option<Self>,
108        encoder: &mut E,
109        out: &mut MaybeUninit<W>,
110        constraint: W::Constraint,
111    ) -> Result<(), EncodeError> {
112        <&'a T>::encode_option(this.map(|value| &**value), encoder, out, constraint)
113    }
114}
115
116fn encode_to_array<A, W, E, T, const N: usize>(
117    value: A,
118    encoder: &mut E,
119    out: &mut MaybeUninit<[W; N]>,
120    constraint: W::Constraint,
121) -> Result<(), EncodeError>
122where
123    A: AsRef<[T]> + IntoIterator,
124    A::Item: Encode<W, E>,
125    W: Wire,
126    E: ?Sized,
127    T: Encode<W, E>,
128{
129    if T::COPY_OPTIMIZATION.is_enabled() {
130        // SAFETY: `T` has copy optimization enabled and so is safe to copy to the output.
131        unsafe {
132            copy_nonoverlapping(value.as_ref().as_ptr().cast(), out.as_mut_ptr(), 1);
133        }
134    } else {
135        for (i, item) in value.into_iter().enumerate() {
136            // SAFETY: `out` is a `MaybeUninit<[T::Encoded; N]>` and so consists of `N` copies of
137            // `T::Encoded` in order with no additional padding. We can make a `&mut MaybeUninit` to
138            // the `i`th element by:
139            // 1. Getting a pointer to the contents of the `MaybeUninit<[T::Encoded; N]>` (the
140            //    pointer is of type `*mut [T::Encoded; N]`).
141            // 2. Casting it to `*mut MaybeUninit<T::Encoded>`. Note that `MaybeUninit<T>` always
142            //    has the same layout as `T`.
143            // 3. Adding `i` to reach the `i`th element.
144            // 4. Dereferencing as `&mut`.
145            let out_i = unsafe { &mut *out.as_mut_ptr().cast::<MaybeUninit<W>>().add(i) };
146            item.encode(encoder, out_i, constraint)?;
147        }
148    }
149    Ok(())
150}
151
152unsafe impl<W, E, T, const N: usize> Encode<[W; N], E> for [T; N]
153where
154    W: Wire,
155    E: ?Sized,
156    T: Encode<W, E>,
157{
158    const COPY_OPTIMIZATION: CopyOptimization<Self, [W; N]> = T::COPY_OPTIMIZATION.infer_array();
159
160    fn encode(
161        self,
162        encoder: &mut E,
163        out: &mut MaybeUninit<[W; N]>,
164        constraint: W::Constraint,
165    ) -> Result<(), EncodeError> {
166        encode_to_array(self, encoder, out, constraint)
167    }
168}
169
170unsafe impl<'a, W, E, T, const N: usize> Encode<[W; N], E> for &'a [T; N]
171where
172    W: Wire,
173    E: ?Sized,
174    T: Encode<W, E>,
175    &'a T: Encode<W, E>,
176{
177    fn encode(
178        self,
179        encoder: &mut E,
180        out: &mut MaybeUninit<[W; N]>,
181        constraint: W::Constraint,
182    ) -> Result<(), EncodeError> {
183        encode_to_array(self, encoder, out, constraint)
184    }
185}
186
187unsafe impl<W, E, T> Encode<W, E> for Option<T>
188where
189    W: Wire,
190    E: ?Sized,
191    T: EncodeOption<W, E>,
192{
193    fn encode(
194        self,
195        encoder: &mut E,
196        out: &mut MaybeUninit<W>,
197        constraint: W::Constraint,
198    ) -> Result<(), EncodeError> {
199        T::encode_option(self, encoder, out, constraint)
200    }
201}
202
203unsafe impl<'a, W, E, T> Encode<W, E> for &'a Option<T>
204where
205    W: Wire,
206    E: ?Sized,
207    Option<&'a T>: Encode<W, E>,
208{
209    fn encode(
210        self,
211        encoder: &mut E,
212        out: &mut MaybeUninit<W>,
213        constraint: W::Constraint,
214    ) -> Result<(), EncodeError> {
215        self.as_ref().encode(encoder, out, constraint)
216    }
217}