musli_zerocopy/pointer/
coerce_slice.rs

1use crate::error::{CoerceError, CoerceErrorKind};
2use crate::pointer::Size;
3
4mod sealed {
5    pub trait Sealed<U: ?Sized> {}
6}
7
8/// Trait to coerce slice metadata, which defines its length.
9///
10/// Coercing from one kind of slice to another means that the length must be
11/// adjusted. We can only perform upwards adjustments such as `[u32]` to `[u16]`
12/// since independent of the length of the slice we know that it defines a
13/// region of memory which is appropriately sized.
14pub trait CoerceSlice<U>
15where
16    Self: self::sealed::Sealed<U>,
17    U: ?Sized,
18{
19    /// Resize with the given `factor`.
20    #[doc(hidden)]
21    fn resize<O>(factor: O) -> O
22    where
23        O: Size;
24
25    /// Try to resize with the given `factor`.
26    #[doc(hidden)]
27    fn try_resize<O>(factor: O) -> Result<O, CoerceError>
28    where
29        O: Size;
30}
31
32macro_rules! self_impl_inner {
33    ($from:ty, {$($to:ty),*}) => {
34        $(
35            impl self::sealed::Sealed<[$to]> for [$from] {}
36
37            #[doc = concat!("Defines the coercion from `[", stringify!($from) ,"]` to `[", stringify!($to), "]`.")]
38            ///
39            /// # Examples
40            ///
41            /// ```
42            /// use musli_zerocopy::Ref;
43            ///
44            #[doc = concat!("let reference: Ref<", stringify!($from), "> = Ref::zero();")]
45            #[doc = concat!("let reference2 = reference.coerce::<[", stringify!($from), "]>();")]
46            /// assert_eq!(reference2.len(), 1);
47            ///
48            #[doc = concat!("let reference3 = reference.coerce::<", stringify!($to), ">();")]
49            #[doc = concat!("let reference4 = reference2.coerce::<[", stringify!($to), "]>();")]
50            /// assert_eq!(reference4.len(), 1);
51            /// ```
52            impl CoerceSlice<[$to]> for [$from] {
53                #[inline]
54                fn resize<O: Size>(len: O) -> O {
55                    len
56                }
57
58                #[inline]
59                fn try_resize<O: Size>(len: O) -> Result<O, CoerceError> {
60                    Ok(len)
61                }
62            }
63        )*
64    }
65}
66
67macro_rules! self_impl {
68    ([$({$($from:ty),*}),*], [$($to:tt),*]) => {
69        $(
70            $(
71                self_impl_inner!($from, $to);
72            )*
73        )*
74    };
75}
76
77macro_rules! coerce_slice_inner {
78    ($factor:ident, $value:literal, $from:ty, {$($to:ty),*}) => {
79        $(
80            impl self::sealed::Sealed<[$to]> for [$from] {}
81
82            #[doc = concat!("Defines the coercion from `[", stringify!($from) ,"]` to `[", stringify!($to), "]`.")]
83            ///
84            /// # Examples
85            ///
86            /// ```
87            /// use musli_zerocopy::Ref;
88            ///
89            #[doc = concat!("let reference: Ref<", stringify!($from), "> = Ref::zero();")]
90            #[doc = concat!("let reference2 = reference.coerce::<[", stringify!($to), "]>();")]
91            #[doc = concat!("assert_eq!(reference2.len(), ", stringify!($value), ");")]
92            ///
93            #[doc = concat!("let reference: Ref<[", stringify!($from), "]> = Ref::with_metadata(0u32, 5);")]
94            #[doc = concat!("let reference2 = reference.coerce::<[", stringify!($to), "]>();")]
95            #[doc = concat!("assert_eq!(reference2.len(), 5 * ", stringify!($value), ");")]
96            /// ```
97            impl CoerceSlice<[$to]> for [$from] {
98                #[inline]
99                fn resize<O>(len: O) -> O
100                where
101                    O: Size,
102                {
103                    len.wrapping_mul(O::$factor)
104                }
105
106                #[inline]
107                fn try_resize<O>(len: O) -> Result<O, CoerceError>
108                where
109                    O: Size,
110                {
111                    let Some(len) = len.checked_mul(O::$factor) else {
112                        return Err(CoerceError::new(CoerceErrorKind::SliceLengthOverflow {
113                            item: len.as_usize(),
114                            len: O::$factor.as_usize(),
115                        }));
116                    };
117
118                    Ok(len)
119                }
120            }
121        )*
122    }
123}
124
125macro_rules! coerce_slice {
126    ($factor:ident, $value:literal, [$({$($from:ty),*}),*], [$($to:tt),*]) => {
127        $(
128            $(
129                coerce_slice_inner!($factor, $value, $from, $to);
130            )*
131        )*
132    }
133}
134
135self_impl! {
136    [
137        {u8, i8},
138        {u16, i16},
139        {u32, i32},
140        {u64, i64},
141        {u128, i128}
142    ],
143    [
144        {u8, i8},
145        {u16, i16, [u8; 2], [i8; 2]},
146        {u32, i32, [u16; 2], [i16; 2], [u8; 4], [i8; 4]},
147        {u64, i64, [u32; 2], [i32; 2], [u16; 4], [i16; 4], [u8; 8], [i8; 8]},
148        {u128, i128, [u64; 2], [i64; 2], [u32; 4], [i32; 4], [u16; 8], [i16; 8], [u8; 16], [i8; 16]}
149    ]
150}
151
152coerce_slice! {
153    N2, 2,
154    [
155        {u16, i16},
156        {u32, i32},
157        {u64, i64},
158        {u128, i128}
159    ],
160    [
161        {u8, i8},
162        {u16, i16, [u8; 2], [i8; 2]},
163        {u32, i32, [u16; 2], [i16; 2], [u8; 4], [i8; 4]},
164        {u64, i64, [u32; 2], [i32; 2], [u16; 4], [i16; 4], [u8; 8], [i8; 8]}
165    ]
166}
167
168coerce_slice! {
169    N4, 4,
170    [
171        {u32, i32},
172        {u64, i64},
173        {u128, i128}
174    ],
175    [
176        {u8, i8},
177        {u16, i16, [u8; 2], [i8; 2]},
178        {u32, i32, [u16; 2], [i16; 2], [u8; 4], [i8; 4]}
179    ]
180}
181
182coerce_slice! {
183    N8, 8,
184    [
185        {u64, i64},
186        {u128, i128}
187    ],
188    [
189        {u8, i8},
190        {u16, i16, [u8; 2], [i8; 2]}
191    ]
192}
193
194coerce_slice! {
195    N16, 16,
196    [
197        {u128, i128}
198    ],
199    [
200        {u8, i8}
201    ]
202}