fidl_next_codec/
from_wire.rs

1// Copyright 2025 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
5use core::mem::{forget, MaybeUninit};
6use core::ptr::copy_nonoverlapping;
7
8use crate::{
9    CopyOptimization, WireF32, WireF64, WireI16, WireI32, WireI64, WireU16, WireU32, WireU64,
10};
11
12/// A type which is convertible from a wire type.
13pub trait FromWire<W>: Sized {
14    /// Whether the conversion from `W` to `Self` is equivalent to copying the raw bytes of `W`.
15    ///
16    /// Copy optimization is disabled by default.
17    const COPY_OPTIMIZATION: CopyOptimization<W, Self> = CopyOptimization::disable();
18
19    /// Converts the given `wire` to this type.
20    fn from_wire(wire: W) -> Self;
21}
22
23/// A type which is convertible from a reference to a wire type.
24pub trait FromWireRef<W>: FromWire<W> {
25    /// Converts the given `wire` reference to this type.
26    fn from_wire_ref(wire: &W) -> Self;
27}
28
29/// An optional type which is convertible from a wire type.
30pub trait FromWireOption<W>: Sized {
31    /// Converts the given `wire` to an option of this type.
32    fn from_wire_option(wire: W) -> Option<Self>;
33}
34
35/// An optional type which is convertible from a reference to a wire type.
36pub trait FromWireOptionRef<W>: FromWireOption<W> {
37    /// Converts the given `wire` reference to an option of this type.
38    fn from_wire_option_ref(wire: &W) -> Option<Self>;
39}
40
41macro_rules! impl_primitive {
42    ($ty:ty) => {
43        impl_primitive!($ty, $ty);
44    };
45    ($ty:ty, $enc:ty) => {
46        impl FromWire<$enc> for $ty {
47            const COPY_OPTIMIZATION: CopyOptimization<$enc, $ty> =
48                CopyOptimization::<$enc, $ty>::PRIMITIVE;
49
50            #[inline]
51            fn from_wire(wire: $enc) -> Self {
52                wire.into()
53            }
54        }
55
56        impl FromWireRef<$enc> for $ty {
57            #[inline]
58            fn from_wire_ref(wire: &$enc) -> Self {
59                (*wire).into()
60            }
61        }
62    };
63}
64
65macro_rules! impl_primitives {
66    ($($ty:ty $(, $enc:ty)?);* $(;)?) => {
67        $(
68            impl_primitive!($ty $(, $enc)?);
69        )*
70    }
71}
72
73impl_primitives! {
74    ();
75
76    bool;
77
78    i8;
79    i16, WireI16; i32, WireI32; i64, WireI64;
80    WireI16; WireI32; WireI64;
81
82    u8;
83    u16, WireU16; u32, WireU32; u64, WireU64;
84    WireU16; WireU32; WireU64;
85
86    f32, WireF32; f64, WireF64;
87    WireF32; WireF64;
88}
89
90impl<T: FromWire<W>, W, const N: usize> FromWire<[W; N]> for [T; N] {
91    fn from_wire(wire: [W; N]) -> Self {
92        let mut result = MaybeUninit::<[T; N]>::uninit();
93        if T::COPY_OPTIMIZATION.is_enabled() {
94            // SAFETY: `T` has copy optimization enabled and so is safe to copy bytewise.
95            unsafe {
96                copy_nonoverlapping(wire.as_ptr().cast(), result.as_mut_ptr(), 1);
97            }
98            forget(wire);
99        } else {
100            for (i, item) in wire.into_iter().enumerate() {
101                unsafe {
102                    result.as_mut_ptr().cast::<T>().add(i).write(T::from_wire(item));
103                }
104            }
105        }
106        unsafe { result.assume_init() }
107    }
108}
109
110impl<T: FromWireRef<W>, W, const N: usize> FromWireRef<[W; N]> for [T; N] {
111    fn from_wire_ref(wire: &[W; N]) -> Self {
112        let mut result = MaybeUninit::<[T; N]>::uninit();
113        if T::COPY_OPTIMIZATION.is_enabled() {
114            // SAFETY: `T` has copy optimization enabled and so is safe to copy bytewise.
115            unsafe {
116                copy_nonoverlapping(wire.as_ptr().cast(), result.as_mut_ptr(), 1);
117            }
118        } else {
119            for (i, item) in wire.iter().enumerate() {
120                unsafe {
121                    result.as_mut_ptr().cast::<T>().add(i).write(T::from_wire_ref(item));
122                }
123            }
124        }
125        unsafe { result.assume_init() }
126    }
127}
128
129impl<T: FromWire<W>, W> FromWire<W> for Box<T> {
130    fn from_wire(wire: W) -> Self {
131        Box::new(T::from_wire(wire))
132    }
133}
134
135impl<T: FromWireRef<W>, W> FromWireRef<W> for Box<T> {
136    fn from_wire_ref(wire: &W) -> Self {
137        Box::new(T::from_wire_ref(wire))
138    }
139}
140
141impl<T: FromWireOption<W>, W> FromWire<W> for Option<T> {
142    fn from_wire(wire: W) -> Self {
143        T::from_wire_option(wire)
144    }
145}
146
147impl<T: FromWireOptionRef<W>, W> FromWireRef<W> for Option<T> {
148    fn from_wire_ref(wire: &W) -> Self {
149        T::from_wire_option_ref(wire)
150    }
151}