rkyv/niche/
option_nonzero.rs

1//! Niched archived `Option<NonZero>` integers that use less space.
2
3use crate::Archived;
4use core::{
5    cmp, fmt, hash,
6    num::{
7        NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU128, NonZeroU16,
8        NonZeroU32, NonZeroU64, NonZeroU8,
9    },
10    pin::Pin,
11};
12
13macro_rules! impl_archived_option_nonzero {
14    ($ar:ident, $nz:ty, $ne:ty) => {
15        #[doc = concat!("A niched archived `Option<", stringify!($nz), ">`")]
16        #[repr(transparent)]
17        pub struct $ar {
18            inner: Archived<$ne>,
19        }
20
21        impl $ar {
22            /// Returns `true` if the option is a `None` value.
23            #[inline]
24            pub fn is_none(&self) -> bool {
25                self.inner == 0
26            }
27
28            /// Returns `true` if the option is a `Some` value.
29            #[inline]
30            pub fn is_some(&self) -> bool {
31                self.inner != 0
32            }
33
34            #[doc = concat!("Converts to an `Option<&Archived<", stringify!($nz), ">>`")]
35            pub fn as_ref(&self) -> Option<&Archived<$nz>> {
36                if self.inner != 0 {
37                    let as_nonzero = unsafe {
38                        // SAFETY: NonZero types have the same memory layout and bit patterns as
39                        // their integer counterparts, regardless of endianness
40                        &*(&self.inner as *const _ as *const Archived<$nz>)
41                    };
42                    Some(as_nonzero)
43                } else {
44                    None
45                }
46            }
47
48            #[doc = concat!("Converts to an `Option<&mut Archived<", stringify!($nz), ">>`")]
49            pub fn as_mut(&mut self) -> Option<&mut Archived<$nz>> {
50                if self.inner != 0 {
51                    let as_nonzero = unsafe {
52                        // SAFETY: NonZero types have the same memory layout and bit patterns as
53                        // their integer counterparts, regardless of endianness
54                        &mut *(&mut self.inner as *mut _ as *mut Archived<$nz>)
55                    };
56                    Some(as_nonzero)
57                } else {
58                    None
59                }
60            }
61
62            #[doc = concat!("Converts from `Pin<&ArchivedOption", stringify!($nz), ">` to `Option<Pin<&Archived<", stringify!($nz), ">>>`.")]
63            #[inline]
64            pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&Archived<$nz>>> {
65                unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) }
66            }
67
68            #[doc = concat!("Converts from `Pin<&mut ArchivedOption", stringify!($nz), ">` to `Option<Pin<&mut Archived<", stringify!($nz), ">>>`.")]
69            #[inline]
70            pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut Archived<$nz>>> {
71                unsafe {
72                    Pin::get_unchecked_mut(self)
73                        .as_mut()
74                        .map(|x| Pin::new_unchecked(x))
75                }
76            }
77
78            /// Returns an iterator over the possibly contained value.
79            #[inline]
80            pub fn iter(&self) -> Iter<'_, Archived<$nz>> {
81                Iter {
82                    inner: self.as_ref(),
83                }
84            }
85
86            /// Returns a mutable iterator over the possibly contained value.
87            #[inline]
88            pub fn iter_mut(&mut self) -> IterMut<'_, Archived<$nz>> {
89                IterMut {
90                    inner: self.as_mut(),
91                }
92            }
93
94            /// Inserts `v` into the option if it is `None`, then returns a mutable
95            /// reference to the contained value.
96            #[inline]
97            pub fn get_or_insert(&mut self, v: $nz) -> &mut Archived<$nz> {
98                self.get_or_insert_with(move || v)
99            }
100
101            /// Inserts a value computed from `f` into the option if it is `None`, then
102            /// returns a mutable reference to the contained value.
103            #[inline]
104            pub fn get_or_insert_with<F: FnOnce() -> $nz>(&mut self, f: F) -> &mut Archived<$nz> {
105                if self.inner == 0 {
106                    self.inner = f().get().into();
107                }
108                unsafe {
109                    // SAFETY: self.inner is nonzero
110                    &mut *(&mut self.inner as *mut _ as *mut Archived<$nz>)
111                }
112            }
113
114            /// Resolves an `ArchivedOptionNonZero` from an `Option<NonZero>`.
115            ///
116            /// # Safety
117            ///
118            /// - `pos` must be the position of `out` within the archive
119            #[inline]
120            pub unsafe fn resolve_from_option(field: Option<$nz>, out: *mut Self) {
121                let (_, fo) = out_field!(out.inner);
122                if let Some(nz) = field {
123                    fo.write(nz.get().into());
124                } else {
125                    fo.write((0 as $ne).into());
126                }
127            }
128        }
129
130        impl fmt::Debug for $ar {
131            #[inline]
132            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133                match self.as_ref() {
134                    Some(inner) => inner.fmt(f),
135                    None => f.debug_tuple("None").finish(),
136                }
137            }
138        }
139
140        impl Eq for $ar {}
141
142        impl hash::Hash for $ar {
143            #[inline]
144            fn hash<H: hash::Hasher>(&self, state: &mut H) {
145                self.as_ref().hash(state)
146            }
147        }
148
149        impl Ord for $ar {
150            #[inline]
151            fn cmp(&self, other: &Self) -> cmp::Ordering {
152                self.as_ref().cmp(&other.as_ref())
153            }
154        }
155
156        impl PartialEq for $ar {
157            #[inline]
158            fn eq(&self, other: &Self) -> bool {
159                self.as_ref().eq(&other.as_ref())
160            }
161        }
162
163        impl PartialOrd for $ar {
164            #[inline]
165            fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
166                Some(self.cmp(other))
167            }
168        }
169    };
170}
171
172impl_archived_option_nonzero!(ArchivedOptionNonZeroI8, NonZeroI8, i8);
173impl_archived_option_nonzero!(ArchivedOptionNonZeroI16, NonZeroI16, i16);
174impl_archived_option_nonzero!(ArchivedOptionNonZeroI32, NonZeroI32, i32);
175impl_archived_option_nonzero!(ArchivedOptionNonZeroI64, NonZeroI64, i64);
176impl_archived_option_nonzero!(ArchivedOptionNonZeroI128, NonZeroI128, i128);
177
178impl_archived_option_nonzero!(ArchivedOptionNonZeroU8, NonZeroU8, u8);
179impl_archived_option_nonzero!(ArchivedOptionNonZeroU16, NonZeroU16, u16);
180impl_archived_option_nonzero!(ArchivedOptionNonZeroU32, NonZeroU32, u32);
181impl_archived_option_nonzero!(ArchivedOptionNonZeroU64, NonZeroU64, u64);
182impl_archived_option_nonzero!(ArchivedOptionNonZeroU128, NonZeroU128, u128);
183
184/// An iterator over a reference to the `Some` variant of an `ArchivedOptionNonZero` integer.
185///
186/// This iterator yields one value if the `ArchivedOptionNonZero` integer is a `Some`, otherwise
187/// none.
188pub type Iter<'a, T> = crate::option::Iter<'a, T>;
189
190/// An iterator over a mutable reference to the `Some` variant of an `ArchivedOptionNonZero`
191/// integer.
192///
193/// This iterator yields one value if the `ArchivedOptionNonZero` integer is a `Some`, otherwise
194/// none.
195pub type IterMut<'a, T> = crate::option::IterMut<'a, T>;