fidl_next_codec/
copy_optimization.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::marker::PhantomData;
6
7use crate::{WireF32, WireF64, WireI16, WireI32, WireI64, WireU16, WireU32, WireU64};
8
9/// An optimization hint about whether the conversion from `T` to `U` is equivalent to copying the
10/// raw bytes of `T`.
11pub struct CopyOptimization<T: ?Sized, U: ?Sized>(bool, PhantomData<(*mut T, *mut U)>);
12
13impl<T: ?Sized, U: ?Sized> CopyOptimization<T, U> {
14    /// Returns a `CopyOptimization` hint with the optimization enabled.
15    ///
16    /// # Safety
17    ///
18    /// `T` and `U` must be the same size and must not have any uninit bytes (e.g. padding).
19    pub const unsafe fn enable() -> Self {
20        Self(true, PhantomData)
21    }
22
23    /// Returns a `CopyOptimization` hint with the optimization enabled if `value` is `true`.
24    ///
25    /// # Safety
26    ///
27    /// `T` and `U` must be the same size and must not have any uninit bytes (e.g. padding) if
28    /// `value` is `true`.
29    pub const unsafe fn enable_if(value: bool) -> Self {
30        Self(value, PhantomData)
31    }
32
33    /// Returns a `CopyOptimization` hint with the optimization disabled.
34    pub const fn disable() -> Self {
35        Self(false, PhantomData)
36    }
37
38    /// Returns whether the optimization is enabled.
39    pub const fn is_enabled(&self) -> bool {
40        self.0
41    }
42
43    /// Infers whether the conversion from `[T; N]` to `[U; N]` is copy-optimizable based on the
44    /// conversion from `T` to `U`.
45    pub const fn infer_array<const N: usize>(&self) -> CopyOptimization<[T; N], [U; N]>
46    where
47        T: Sized,
48        U: Sized,
49    {
50        unsafe { CopyOptimization::enable_if(self.is_enabled()) }
51    }
52
53    /// Infers whether the conversion from `[T]` to `[U]` is copy-optimizable based on the
54    /// conversion from `T` to `U`.
55    pub const fn infer_slice(&self) -> CopyOptimization<[T], [U]>
56    where
57        T: Sized,
58        U: Sized,
59    {
60        unsafe { CopyOptimization::enable_if(self.is_enabled()) }
61    }
62}
63
64impl<T: ?Sized> CopyOptimization<T, T> {
65    /// Returns an enabled `CopyOptimization`, as copy optimization is always enabled from a type to
66    /// itself.
67    pub const fn identity() -> Self {
68        unsafe { Self::enable() }
69    }
70}
71
72macro_rules! impl_primitive {
73    ($ty:ty) => {
74        impl CopyOptimization<$ty, $ty> {
75            /// Whether copy optimization between the two primitive types is enabled.
76            pub const PRIMITIVE: Self = Self::identity();
77        }
78    };
79    ($natural:ty, $wire:ty) => {
80        impl_primitive!($wire);
81
82        impl CopyOptimization<$natural, $wire> {
83            /// Whether copy optimization between the two primitive types is enabled.
84            pub const PRIMITIVE: Self =
85                // SAFETY: Copy optimization for primitives is enabled if their size if <= 1 or the
86                // target is little-endian.
87                unsafe {
88                    CopyOptimization::enable_if(
89                        size_of::<Self>() <= 1 || cfg!(target_endian = "little"),
90                    )
91                };
92        }
93
94        impl CopyOptimization<$wire, $natural> {
95            /// Whether copy optimization between the two primitive types is enabled.
96            pub const PRIMITIVE: Self =
97                // SAFETY: Copy optimization between these two primitives is commutative.
98                unsafe {
99                    CopyOptimization::enable_if(
100                        CopyOptimization::<$natural, $wire>::PRIMITIVE.is_enabled(),
101                    )
102                };
103        }
104    };
105}
106
107macro_rules! impl_primitives {
108    ($($natural:ty $(, $wire:ty)?);* $(;)?) => {
109        $(
110            impl_primitive!($natural $(, $wire)?);
111        )*
112    }
113}
114
115impl_primitives! {
116    ();
117
118    bool;
119
120    i8;
121    i16, WireI16;
122    i32, WireI32;
123    i64, WireI64;
124
125    u8;
126    u16, WireU16;
127    u32, WireU32;
128    u64, WireU64;
129
130    f32, WireF32;
131    f64, WireF64;
132}