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