musli_zerocopy/pointer/coerce.rs
1use crate::error::CoerceError;
2use crate::pointer::{CoerceSlice, Pointee, Size};
3use crate::traits::ZeroCopy;
4
5/// A trait indicating that a coercion from `Self` to `U` is correct from a size
6/// perspective.
7pub trait Coerce<U>
8where
9 Self: Pointee,
10 U: ?Sized + Pointee,
11{
12 /// Coerce metadata from `Self` to `U`.
13 ///
14 /// Any overflow will wrap around.
15 fn coerce_metadata<O>(metadata: Self::Stored<O>) -> U::Stored<O>
16 where
17 O: Size;
18
19 /// Try to coerce metadata from `Self` to `U`.
20 ///
21 /// Any overflow will result in `None`.
22 fn try_coerce_metadata<O>(metadata: Self::Stored<O>) -> Result<U::Stored<O>, CoerceError>
23 where
24 O: Size;
25}
26
27/// Defines a coercion from a slice `[T]` to `[U]`.
28///
29/// Since slices have a length which depends on the exact sizing of `T` and `U`,
30/// this conversion is constrained by a special trait [`CoerceSlice<T>`].
31impl<T, U> Coerce<[U]> for [T]
32where
33 T: ZeroCopy,
34 U: ZeroCopy,
35 [T]: CoerceSlice<[U]>,
36{
37 #[inline]
38 fn coerce_metadata<O>(metadata: O) -> O
39 where
40 O: Size,
41 {
42 <[T]>::resize(metadata)
43 }
44
45 #[inline]
46 fn try_coerce_metadata<O>(metadata: O) -> Result<O, CoerceError>
47 where
48 O: Size,
49 {
50 <[T]>::try_resize(metadata)
51 }
52}
53
54/// Defines the coercion from `str` to `[T]`.
55///
56/// Broadly speaking, this inherits the coercions which are possible for `[u8]`,
57/// which basically limits it to `u8` and `i8` and other single byte types.
58///
59/// # Examples
60///
61/// ```
62/// use musli_zerocopy::Ref;
63///
64/// let reference: Ref<str> = Ref::with_metadata(0u32, 12);
65/// let reference2 = reference.coerce::<[u8]>();
66/// let reference3 = reference.coerce::<[i8]>();
67/// assert_eq!(reference2.len(), 12);
68/// assert_eq!(reference3.len(), 12);
69/// ```
70impl<T> Coerce<[T]> for str
71where
72 [u8]: CoerceSlice<[T]>,
73 T: ZeroCopy,
74{
75 #[inline]
76 fn coerce_metadata<O: Size>(metadata: O) -> O {
77 <[u8]>::resize(metadata)
78 }
79
80 #[inline]
81 fn try_coerce_metadata<O: Size>(metadata: O) -> Result<O, CoerceError> {
82 <[u8]>::try_resize(metadata)
83 }
84}
85
86/// Defines the coercion from `[T]` to `str`.
87///
88/// Broadly speaking, this inherits the coercions which are possible into `[u8]`,
89/// which means any type can be coerced into a `str`.
90///
91/// # Examples
92///
93/// ```
94/// use musli_zerocopy::Ref;
95///
96/// let reference: Ref<[u32]> = Ref::with_metadata(0u32, 12);
97/// let reference2 = reference.coerce::<str>();
98/// assert_eq!(reference2.len(), 12 * 4);
99/// ```
100impl<T> Coerce<str> for [T]
101where
102 [T]: CoerceSlice<[u8]>,
103 T: ZeroCopy,
104{
105 #[inline]
106 fn coerce_metadata<O: Size>(metadata: O) -> O {
107 <[T]>::resize(metadata)
108 }
109
110 #[inline]
111 fn try_coerce_metadata<O: Size>(metadata: O) -> Result<O, CoerceError> {
112 <[T]>::try_resize(metadata)
113 }
114}
115
116macro_rules! same_size_inner {
117 ($from:ty, {$($to:ty),*}) => {
118 $(
119 #[doc = concat!("Defines the coercion for `", stringify!($from) ,"` to `", stringify!($to), "`.")]
120 ///
121 /// # Examples
122 ///
123 /// ```
124 /// use musli_zerocopy::Ref;
125 ///
126 #[doc = concat!("let reference: Ref<", stringify!($from), "> = Ref::zero();")]
127 #[doc = concat!("let reference2 = reference.coerce::<", stringify!($to), ">();")]
128 /// assert_eq!(reference.offset(), reference2.offset());
129 /// ```
130 impl Coerce<$to> for $from {
131 #[inline(always)]
132 fn coerce_metadata<O: Size>(metadata: ()) -> () {
133 metadata
134 }
135
136 #[inline(always)]
137 fn try_coerce_metadata<O: Size>(metadata: ()) -> Result<(), CoerceError> {
138 Ok(metadata)
139 }
140 }
141 )*
142 }
143}
144
145macro_rules! same_size {
146 ([$({$($from:ty),*}),*], [$($to:tt),*]) => {
147 $(
148 $(
149 same_size_inner!($from, $to);
150 )*
151 )*
152 };
153}
154
155same_size!([{u8, i8}], [{u8, i8}]);
156same_size!([{u16, i16}], [{u16, i16, [u8; 2], [i8; 2]}]);
157same_size!([{u32, i32}], [{u32, i32, [u16; 2], [i16; 2], [u8; 4], [i8; 4]}]);
158same_size!([{u64, i64}], [{u64, i64, [u32; 2], [i32; 2], [u16; 4], [i16; 4], [u8; 8], [i8; 8]}]);
159same_size!([{u128, i128}], [{u128, i128, [u64; 2], [i64; 2], [u32; 4], [i32; 4], [u16; 8], [i16; 8], [u8; 16], [i8; 16]}]);
160
161/// Defines the primitive coercion from `T` to `[U]`.
162///
163/// This coercion results in a single element slice of type `T`, and is largely
164/// defined through the help of [`CoerceSlice<T>`].
165///
166/// Note that coercing from a smaller to a larger type is not possible, since we
167/// don't know how many elements of the smaller type is in use:
168///
169/// ```compile_fail
170/// use musli_zerocopy::Ref;
171///
172/// let reference: Ref<u8> = Ref::zero();
173/// let reference2 = reference.coerce::<[u32]>();
174/// ```
175///
176/// # Examples
177///
178/// ```
179/// use musli_zerocopy::Ref;
180///
181/// let reference: Ref<u32> = Ref::zero();
182/// let reference2 = reference.coerce::<[u32]>();
183/// assert_eq!(reference2.len(), 1);
184///
185/// let reference: Ref<u64> = Ref::zero();
186/// let reference2 = reference.coerce::<[u32]>();
187/// assert_eq!(reference2.len(), 2);
188///
189/// let reference: Ref<u128> = Ref::zero();
190/// let reference2 = reference.coerce::<[u32]>();
191/// assert_eq!(reference2.len(), 4);
192/// ```
193impl<T, U> Coerce<[U]> for T
194where
195 T: ZeroCopy,
196 U: ZeroCopy,
197 [T]: CoerceSlice<[U]>,
198{
199 #[inline]
200 fn coerce_metadata<O: Size>((): ()) -> O {
201 <[T]>::resize(O::ONE)
202 }
203
204 #[inline]
205 fn try_coerce_metadata<O: Size>((): ()) -> Result<O, CoerceError> {
206 <[T]>::try_resize(O::ONE)
207 }
208}
209
210/// Defines the coercion from `[T; N]` to `[U]`.
211///
212/// This coercion results in a single element slice of type `T`, and is largely
213/// defined through the help of [`CoerceSlice<T>`].
214///
215/// # Examples
216///
217/// ```
218/// use musli_zerocopy::Ref;
219///
220/// let reference: Ref<[u32; 2]> = Ref::zero();
221/// let reference2 = reference.coerce::<[u32]>();
222/// assert_eq!(reference2.len(), 2);
223///
224/// let reference: Ref<[u128; 4]> = Ref::zero();
225/// let reference2 = reference.coerce::<[u64]>();
226/// assert_eq!(reference2.len(), 8);
227/// ```
228impl<T, const N: usize, U> Coerce<[U]> for [T; N]
229where
230 T: ZeroCopy,
231 U: ZeroCopy,
232 [T]: CoerceSlice<[U]>,
233{
234 #[inline]
235 fn coerce_metadata<O>((): ()) -> <[T] as Pointee>::Stored<O>
236 where
237 O: Size,
238 {
239 let factor = O::try_from_usize(N).unwrap_or(O::MAX);
240 <[T]>::resize(factor)
241 }
242
243 #[inline]
244 fn try_coerce_metadata<O>((): ()) -> Result<<[T] as Pointee>::Stored<O>, CoerceError>
245 where
246 O: Size,
247 {
248 let factor = O::try_from_usize(N)?;
249 <[T]>::try_resize(factor)
250 }
251}
252
253macro_rules! non_zero_inner {
254 ($from:ident, {$($to:ty),*}) => {
255 $(
256 #[doc = concat!("Defines the coercion for `", stringify!($from) ,"` to `", stringify!($to), "`.")]
257 ///
258 /// # Examples
259 ///
260 /// ```
261 #[doc = concat!("use std::num::", stringify!($from), ";")]
262 ///
263 /// use musli_zerocopy::Ref;
264 ///
265 #[doc = concat!("let reference: Ref<", stringify!($from), "> = Ref::zero();")]
266 #[doc = concat!("let reference2 = reference.coerce::<", stringify!($to), ">();")]
267 /// assert_eq!(reference.offset(), reference2.offset());
268 /// ```
269 impl Coerce<$to> for core::num::$from {
270 #[inline(always)]
271 fn coerce_metadata<O: Size>(metadata: ()) -> () {
272 metadata
273 }
274
275 #[inline(always)]
276 fn try_coerce_metadata<O: Size>(metadata: ()) -> Result<(), CoerceError> {
277 Ok(metadata)
278 }
279 }
280 )*
281 }
282}
283
284macro_rules! non_zero {
285 ([$({$($from:ident),*}),*], [$($to:tt),*]) => {
286 $(
287 $(
288 non_zero_inner!($from, $to);
289 )*
290 )*
291 };
292}
293
294non_zero!([{NonZeroU8, NonZeroI8}], [{u8, i8}]);
295non_zero!([{NonZeroU16, NonZeroI16}], [{u16, i16}]);
296non_zero!([{NonZeroU32, NonZeroI32}], [{u32, i32}]);
297non_zero!([{NonZeroU64, NonZeroI64}], [{u64, i64}]);
298non_zero!([{NonZeroU128, NonZeroI128}], [{u128, i128}]);
299
300/// Defines the coercion for `core::num::Wrapping<T>` to `U`.
301///
302/// This is largely defined by the [`Coerce<T>`] of `T` to `U`.
303///
304/// # Examples
305///
306/// ```
307/// use std::num::Wrapping;
308///
309/// use musli_zerocopy::Ref;
310///
311/// let reference: Ref<Wrapping<i128>> = Ref::zero();
312/// let reference2 = reference.coerce::<u128>();
313/// let reference3 = reference.coerce::<[u32; 4]>();
314/// let reference4 = reference.coerce::<u128>().coerce::<[u32]>();
315/// assert_eq!(reference4.len(), 4);
316/// ```
317impl<T, U> Coerce<U> for core::num::Wrapping<T>
318where
319 T: Coerce<U>,
320 U: ZeroCopy,
321 T: ZeroCopy,
322{
323 #[inline(always)]
324 fn coerce_metadata<O: Size>(metadata: ()) {
325 metadata
326 }
327
328 #[inline(always)]
329 fn try_coerce_metadata<O: Size>(metadata: ()) -> Result<(), CoerceError> {
330 Ok(metadata)
331 }
332}