rkyv/impls/core/
primitive.rs

1use core::num::{
2    NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize,
3    NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
4};
5
6use rancor::Fallible;
7
8use crate::{
9    primitive::{
10        ArchivedChar, ArchivedF32, ArchivedF64, ArchivedI128, ArchivedI16,
11        ArchivedI32, ArchivedI64, ArchivedIsize, ArchivedNonZeroI128,
12        ArchivedNonZeroI16, ArchivedNonZeroI32, ArchivedNonZeroI64,
13        ArchivedNonZeroIsize, ArchivedNonZeroU128, ArchivedNonZeroU16,
14        ArchivedNonZeroU32, ArchivedNonZeroU64, ArchivedNonZeroUsize,
15        ArchivedU128, ArchivedU16, ArchivedU32, ArchivedU64, ArchivedUsize,
16    },
17    traits::{CopyOptimization, NoUndef},
18    Archive, Deserialize, Place, Portable, Serialize,
19};
20
21macro_rules! unsafe_impl_primitive {
22    ($($ty:ty),* $(,)?) => {
23        $(
24            unsafe impl NoUndef for $ty {}
25            unsafe impl Portable for $ty {}
26        )*
27    };
28}
29
30unsafe_impl_primitive! {
31    (),
32    bool,
33    i8,
34    u8,
35    NonZeroI8,
36    NonZeroU8,
37    rend::NonZeroI16_be,
38    rend::NonZeroI16_le,
39    rend::NonZeroI32_be,
40    rend::NonZeroI32_le,
41    rend::NonZeroI64_be,
42    rend::NonZeroI64_le,
43    rend::NonZeroI128_be,
44    rend::NonZeroI128_le,
45    rend::NonZeroU16_be,
46    rend::NonZeroU16_le,
47    rend::NonZeroU32_be,
48    rend::NonZeroU32_le,
49    rend::NonZeroU64_be,
50    rend::NonZeroU64_le,
51    rend::NonZeroU128_be,
52    rend::NonZeroU128_le,
53    rend::char_be,
54    rend::char_le,
55    rend::f32_be,
56    rend::f32_le,
57    rend::f64_be,
58    rend::f64_le,
59    rend::i16_be,
60    rend::i16_le,
61    rend::i32_be,
62    rend::i32_le,
63    rend::i64_be,
64    rend::i64_le,
65    rend::i128_be,
66    rend::i128_le,
67    rend::u16_be,
68    rend::u16_le,
69    rend::u32_be,
70    rend::u32_le,
71    rend::u64_be,
72    rend::u64_le,
73    rend::u128_be,
74    rend::u128_le,
75    rend::unaligned::NonZeroI16_ube,
76    rend::unaligned::NonZeroI16_ule,
77    rend::unaligned::NonZeroI32_ube,
78    rend::unaligned::NonZeroI32_ule,
79    rend::unaligned::NonZeroI64_ube,
80    rend::unaligned::NonZeroI64_ule,
81    rend::unaligned::NonZeroI128_ube,
82    rend::unaligned::NonZeroI128_ule,
83    rend::unaligned::NonZeroU16_ube,
84    rend::unaligned::NonZeroU16_ule,
85    rend::unaligned::NonZeroU32_ube,
86    rend::unaligned::NonZeroU32_ule,
87    rend::unaligned::NonZeroU64_ube,
88    rend::unaligned::NonZeroU64_ule,
89    rend::unaligned::NonZeroU128_ube,
90    rend::unaligned::NonZeroU128_ule,
91    rend::unaligned::char_ube,
92    rend::unaligned::char_ule,
93    rend::unaligned::f32_ube,
94    rend::unaligned::f32_ule,
95    rend::unaligned::f64_ube,
96    rend::unaligned::f64_ule,
97    rend::unaligned::i16_ube,
98    rend::unaligned::i16_ule,
99    rend::unaligned::i32_ube,
100    rend::unaligned::i32_ule,
101    rend::unaligned::i64_ube,
102    rend::unaligned::i64_ule,
103    rend::unaligned::i128_ube,
104    rend::unaligned::i128_ule,
105    rend::unaligned::u16_ube,
106    rend::unaligned::u16_ule,
107    rend::unaligned::u32_ube,
108    rend::unaligned::u32_ule,
109    rend::unaligned::u64_ube,
110    rend::unaligned::u64_ule,
111    rend::unaligned::u128_ube,
112    rend::unaligned::u128_ule,
113}
114
115macro_rules! impl_serialize_noop {
116    ($type:ty) => {
117        impl<S: Fallible + ?Sized> Serialize<S> for $type {
118            fn serialize(&self, _: &mut S) -> Result<Self::Resolver, S::Error> {
119                Ok(())
120            }
121        }
122    };
123}
124
125macro_rules! impl_archive_self_primitive {
126    ($type:ty) => {
127        impl Archive for $type {
128            const COPY_OPTIMIZATION: CopyOptimization<Self> =
129                unsafe { CopyOptimization::enable() };
130
131            type Archived = Self;
132            type Resolver = ();
133
134            #[inline]
135            fn resolve(&self, _: Self::Resolver, out: Place<Self::Archived>) {
136                out.write(*self);
137            }
138        }
139
140        impl_serialize_noop!($type);
141
142        impl<D: Fallible + ?Sized> Deserialize<$type, D> for $type {
143            fn deserialize(&self, _: &mut D) -> Result<$type, D::Error> {
144                Ok(*self)
145            }
146        }
147    };
148}
149
150macro_rules! impl_archive_self_primitives {
151    ($($type:ty;)*) => {
152        $(
153            impl_archive_self_primitive!($type);
154        )*
155    }
156}
157
158impl_archive_self_primitives! {
159    ();
160    bool;
161    i8;
162    u8;
163    NonZeroI8;
164    NonZeroU8;
165}
166
167#[cfg(any(
168    all(not(feature = "big_endian"), target_endian = "little"),
169    all(feature = "big_endian", target_endian = "big"),
170))]
171const MULTIBYTE_PRIMITIVES_ARE_TRIVIALLY_COPYABLE: bool = true;
172#[cfg(any(
173    all(feature = "big_endian", target_endian = "little"),
174    all(not(feature = "big_endian"), target_endian = "big"),
175))]
176const MULTIBYTE_PRIMITIVES_ARE_TRIVIALLY_COPYABLE: bool = false;
177
178macro_rules! impl_multibyte_primitive {
179    ($archived:ident : $type:ty) => {
180        impl Archive for $type {
181            const COPY_OPTIMIZATION: CopyOptimization<Self> = unsafe {
182                CopyOptimization::enable_if(
183                    MULTIBYTE_PRIMITIVES_ARE_TRIVIALLY_COPYABLE,
184                )
185            };
186
187            type Archived = $archived;
188            type Resolver = ();
189
190            #[inline]
191            fn resolve(&self, _: Self::Resolver, out: Place<Self::Archived>) {
192                out.write(<$archived>::from_native(*self));
193            }
194        }
195
196        impl_serialize_noop!($type);
197
198        impl<D: Fallible + ?Sized> Deserialize<$type, D> for $archived {
199            fn deserialize(&self, _: &mut D) -> Result<$type, D::Error> {
200                Ok(self.to_native())
201            }
202        }
203    };
204}
205
206macro_rules! impl_multibyte_primitives {
207    ($($archived:ident: $type:ty),* $(,)?) => {
208        $(
209            impl_multibyte_primitive!($archived: $type);
210        )*
211    };
212}
213
214impl_multibyte_primitives! {
215    ArchivedI16: i16,
216    ArchivedI32: i32,
217    ArchivedI64: i64,
218    ArchivedI128: i128,
219    ArchivedU16: u16,
220    ArchivedU32: u32,
221    ArchivedU64: u64,
222    ArchivedU128: u128,
223    ArchivedF32: f32,
224    ArchivedF64: f64,
225    ArchivedChar: char,
226    ArchivedNonZeroI16: NonZeroI16,
227    ArchivedNonZeroI32: NonZeroI32,
228    ArchivedNonZeroI64: NonZeroI64,
229    ArchivedNonZeroI128: NonZeroI128,
230    ArchivedNonZeroU16: NonZeroU16,
231    ArchivedNonZeroU32: NonZeroU32,
232    ArchivedNonZeroU64: NonZeroU64,
233    ArchivedNonZeroU128: NonZeroU128,
234}
235
236// usize
237
238#[cfg(any(
239    all(target_pointer_width = "16", feature = "pointer_width_16"),
240    all(
241        target_pointer_width = "32",
242        not(any(feature = "pointer_width_16", feature = "pointer_width_64")),
243    ),
244    all(target_pointer_width = "64", feature = "pointer_width_64"),
245))]
246const POINTER_WIDTH_EQUALS_ARCHIVED_POINTER_WIDTH: bool = true;
247#[cfg(not(any(
248    all(target_pointer_width = "16", feature = "pointer_width_16"),
249    all(
250        target_pointer_width = "32",
251        not(any(feature = "pointer_width_16", feature = "pointer_width_64")),
252    ),
253    all(target_pointer_width = "64", feature = "pointer_width_64"),
254)))]
255const POINTER_WIDTH_EQUALS_ARCHIVED_POINTER_WIDTH: bool = false;
256
257impl Archive for usize {
258    const COPY_OPTIMIZATION: CopyOptimization<Self> = unsafe {
259        CopyOptimization::enable_if(
260            MULTIBYTE_PRIMITIVES_ARE_TRIVIALLY_COPYABLE
261                && POINTER_WIDTH_EQUALS_ARCHIVED_POINTER_WIDTH,
262        )
263    };
264
265    type Archived = ArchivedUsize;
266    type Resolver = ();
267
268    #[inline]
269    fn resolve(&self, _: Self::Resolver, out: Place<Self::Archived>) {
270        out.write(ArchivedUsize::from_native(*self as _));
271    }
272}
273
274impl<S: Fallible + ?Sized> Serialize<S> for usize {
275    fn serialize(&self, _: &mut S) -> Result<Self::Resolver, S::Error> {
276        Ok(())
277    }
278}
279
280impl<D: Fallible + ?Sized> Deserialize<usize, D> for ArchivedUsize {
281    fn deserialize(&self, _: &mut D) -> Result<usize, D::Error> {
282        Ok(self.to_native() as usize)
283    }
284}
285
286// isize
287
288impl Archive for isize {
289    const COPY_OPTIMIZATION: CopyOptimization<Self> = unsafe {
290        CopyOptimization::enable_if(
291            MULTIBYTE_PRIMITIVES_ARE_TRIVIALLY_COPYABLE
292                && POINTER_WIDTH_EQUALS_ARCHIVED_POINTER_WIDTH,
293        )
294    };
295
296    type Archived = ArchivedIsize;
297    type Resolver = ();
298
299    #[inline]
300    fn resolve(&self, _: Self::Resolver, out: Place<Self::Archived>) {
301        out.write(ArchivedIsize::from_native(*self as _));
302    }
303}
304
305impl<S: Fallible + ?Sized> Serialize<S> for isize {
306    fn serialize(&self, _: &mut S) -> Result<Self::Resolver, S::Error> {
307        Ok(())
308    }
309}
310
311impl<D: Fallible + ?Sized> Deserialize<isize, D> for ArchivedIsize {
312    fn deserialize(&self, _: &mut D) -> Result<isize, D::Error> {
313        Ok(self.to_native() as isize)
314    }
315}
316
317// NonZeroUsize
318
319impl Archive for NonZeroUsize {
320    const COPY_OPTIMIZATION: CopyOptimization<Self> = unsafe {
321        CopyOptimization::enable_if(
322            MULTIBYTE_PRIMITIVES_ARE_TRIVIALLY_COPYABLE
323                && POINTER_WIDTH_EQUALS_ARCHIVED_POINTER_WIDTH,
324        )
325    };
326
327    type Archived = ArchivedNonZeroUsize;
328    type Resolver = ();
329
330    #[inline]
331    fn resolve(&self, _: Self::Resolver, out: Place<Self::Archived>) {
332        let value =
333            unsafe { ArchivedNonZeroUsize::new_unchecked(self.get() as _) };
334        out.write(value);
335    }
336}
337
338impl<S: Fallible + ?Sized> Serialize<S> for NonZeroUsize {
339    fn serialize(&self, _: &mut S) -> Result<Self::Resolver, S::Error> {
340        Ok(())
341    }
342}
343
344impl<D> Deserialize<NonZeroUsize, D> for ArchivedNonZeroUsize
345where
346    D: Fallible + ?Sized,
347{
348    fn deserialize(&self, _: &mut D) -> Result<NonZeroUsize, D::Error> {
349        Ok(unsafe { NonZeroUsize::new_unchecked(self.get() as usize) })
350    }
351}
352
353// NonZeroIsize
354
355impl Archive for NonZeroIsize {
356    const COPY_OPTIMIZATION: CopyOptimization<Self> = unsafe {
357        CopyOptimization::enable_if(
358            MULTIBYTE_PRIMITIVES_ARE_TRIVIALLY_COPYABLE
359                && POINTER_WIDTH_EQUALS_ARCHIVED_POINTER_WIDTH,
360        )
361    };
362
363    type Archived = ArchivedNonZeroIsize;
364    type Resolver = ();
365
366    #[inline]
367    fn resolve(&self, _: Self::Resolver, out: Place<Self::Archived>) {
368        let value =
369            unsafe { ArchivedNonZeroIsize::new_unchecked(self.get() as _) };
370        out.write(value);
371    }
372}
373
374impl<S: Fallible + ?Sized> Serialize<S> for NonZeroIsize {
375    fn serialize(&self, _: &mut S) -> Result<Self::Resolver, S::Error> {
376        Ok(())
377    }
378}
379
380impl<D> Deserialize<NonZeroIsize, D> for ArchivedNonZeroIsize
381where
382    D: Fallible + ?Sized,
383{
384    fn deserialize(&self, _: &mut D) -> Result<NonZeroIsize, D::Error> {
385        Ok(unsafe { NonZeroIsize::new_unchecked(self.get() as isize) })
386    }
387}
388
389#[cfg(test)]
390mod tests {
391    use core::num::{
392        NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8,
393        NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64,
394        NonZeroU8, NonZeroUsize,
395    };
396
397    use crate::api::test::{roundtrip, roundtrip_with};
398
399    #[test]
400    fn roundtrip_portable_primitives() {
401        roundtrip(&());
402        roundtrip(&true);
403        roundtrip(&false);
404        roundtrip(&123i8);
405        roundtrip(&123u8);
406        roundtrip(&NonZeroI8::new(123i8).unwrap());
407        roundtrip(&NonZeroU8::new(123u8).unwrap());
408    }
409
410    #[test]
411    fn roundtrip_multibyte_primitives() {
412        roundtrip(&12345i16);
413        roundtrip(&1234567890i32);
414        roundtrip(&1234567890123456789i64);
415        roundtrip(&123456789012345678901234567890123456789i128);
416        roundtrip(&12345u16);
417        roundtrip(&1234567890u32);
418        roundtrip(&12345678901234567890u64);
419        roundtrip(&123456789012345678901234567890123456789u128);
420
421        roundtrip(&1234567f32);
422        roundtrip(&12345678901234f64);
423
424        roundtrip(&'x');
425        roundtrip(&'🥺');
426
427        roundtrip(&NonZeroI16::new(12345i16).unwrap());
428        roundtrip(&NonZeroI32::new(1234567890i32).unwrap());
429        roundtrip(&NonZeroI64::new(1234567890123456789i64).unwrap());
430        roundtrip(
431            &NonZeroI128::new(123456789012345678901234567890123456789i128)
432                .unwrap(),
433        );
434        roundtrip(&NonZeroU16::new(12345u16).unwrap());
435        roundtrip(&NonZeroU32::new(1234567890u32).unwrap());
436        roundtrip(&NonZeroU64::new(12345678901234567890u64).unwrap());
437        roundtrip(
438            &NonZeroU128::new(123456789012345678901234567890123456789u128)
439                .unwrap(),
440        );
441    }
442
443    #[test]
444    fn roundtrip_sizes() {
445        roundtrip_with(&12345isize, |a, b| {
446            assert_eq!(*a, isize::try_from(b.to_native()).unwrap())
447        });
448        roundtrip_with(&12345usize, |a, b| {
449            assert_eq!(*a, usize::try_from(b.to_native()).unwrap())
450        });
451        roundtrip_with(&NonZeroIsize::new(12345isize).unwrap(), |a, b| {
452            assert_eq!(*a, NonZeroIsize::try_from(b.to_native()).unwrap())
453        });
454        roundtrip_with(&NonZeroUsize::new(12345usize).unwrap(), |a, b| {
455            assert_eq!(*a, NonZeroUsize::try_from(b.to_native()).unwrap())
456        });
457    }
458}