Skip to main content

rkyv/niche/
option_nonzero.rs

1//! Niched archived `Option<NonZero>` integers that use less space.
2
3use core::{
4    cmp, fmt, hash,
5    num::{
6        NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8,
7        NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8,
8    },
9};
10
11use munge::munge;
12
13use crate::{seal::Seal, traits::NoUndef, Archived, Place, Portable};
14
15macro_rules! impl_archived_option_nonzero {
16    ($ar:ident, $nz:ty, $ne:ty) => {
17        #[doc = concat!("A niched archived `Option<", stringify!($nz), ">`")]
18        #[derive(Copy, Clone, Portable)]
19        #[rkyv(crate)]
20        #[repr(transparent)]
21        #[cfg_attr(feature = "bytecheck", derive(bytecheck::CheckBytes))]
22        pub struct $ar {
23            inner: Archived<$ne>,
24        }
25
26        impl $ar {
27            /// Returns `true` if the option is a `None` value.
28            #[inline]
29            pub fn is_none(&self) -> bool {
30                self.inner == 0
31            }
32
33            /// Returns `true` if the option is a `Some` value.
34            #[inline]
35            pub fn is_some(&self) -> bool {
36                self.inner != 0
37            }
38
39            #[rustfmt::skip]
40            #[doc = concat!(
41                "Converts to an `Option<&Archived<",
42                stringify!($nz),
43                ">>`"
44            )]
45            #[inline]
46            pub fn as_ref(&self) -> Option<&Archived<$nz>> {
47                if self.inner != 0 {
48                    let as_nonzero = unsafe {
49                        // SAFETY: NonZero types have the same memory layout and
50                        // bit patterns as their integer counterparts,
51                        // regardless of endianness.
52                        &*(&self.inner as *const _ as *const Archived<$nz>)
53                    };
54                    Some(as_nonzero)
55                } else {
56                    None
57                }
58            }
59
60            #[rustfmt::skip]
61            #[doc = concat!(
62                "Converts to an `Option<&mut Archived<",
63                stringify!($nz),
64                ">>`",
65            )]
66            #[inline]
67            pub fn as_mut(&mut self) -> Option<&mut Archived<$nz>> {
68                if self.inner != 0 {
69                    let as_nonzero = unsafe {
70                        // SAFETY: NonZero types have the same memory layout and
71                        // bit patterns as their integer counterparts,
72                        // regardless of endianness.
73                        &mut *(&mut self.inner as *mut _ as *mut Archived<$nz>)
74                    };
75                    Some(as_nonzero)
76                } else {
77                    None
78                }
79            }
80
81            #[rustfmt::skip]
82            #[doc = concat!(
83                "Converts from `Seal<'_, ArchivedOption",
84                stringify!($nz),
85                ">` to `Option<Seal<'_, Archived<",
86                stringify!($nz),
87                ">>>`.",
88            )]
89            #[inline]
90            pub fn as_seal(
91                this: Seal<'_, Self>,
92            ) -> Option<Seal<'_, Archived<$nz>>> {
93                let this = unsafe { Seal::unseal_unchecked(this) };
94                this.as_mut().map(Seal::new)
95            }
96
97            /// Takes the value out of the option, leaving a `None` in its
98            /// place.
99            #[inline]
100            pub fn take(&mut self) -> Option<Archived<$nz>> {
101                if self.inner != 0 {
102                    // SAFETY: self.inner is nonzero
103                    let result = unsafe {
104                        Archived::<$nz>::new_unchecked(self.inner.into())
105                    };
106                    self.inner = 0.into();
107                    Some(result)
108                } else {
109                    None
110                }
111            }
112
113            /// Returns an iterator over the possibly-contained value.
114            #[inline]
115            pub fn iter(&self) -> Iter<&'_ Archived<$nz>> {
116                Iter::new(self.as_ref())
117            }
118
119            /// Returns an iterator over the mutable possibly-contained value.
120            #[inline]
121            pub fn iter_mut(&mut self) -> Iter<&'_ mut Archived<$nz>> {
122                Iter::new(self.as_mut())
123            }
124
125            /// Returns an iterator over the sealed mutable possibly-contained
126            /// value.
127            #[inline]
128            pub fn iter_seal(
129                this: Seal<'_, Self>,
130            ) -> Iter<Seal<'_, Archived<$nz>>> {
131                Iter::new(Self::as_seal(this))
132            }
133
134            /// Inserts `v` into the option if it is `None`, then returns a
135            /// mutable reference to the contained value.
136            #[inline]
137            pub fn get_or_insert(&mut self, v: $nz) -> &mut Archived<$nz> {
138                self.get_or_insert_with(move || v)
139            }
140
141            /// Inserts a value computed from `f` into the option if it is
142            /// `None`, then returns a mutable reference to the contained value.
143            pub fn get_or_insert_with<F>(&mut self, f: F) -> &mut Archived<$nz>
144            where
145                F: FnOnce() -> $nz,
146            {
147                if self.inner == 0 {
148                    self.inner = f().get().into();
149                }
150                unsafe {
151                    // SAFETY: self.inner is nonzero
152                    &mut *(&mut self.inner as *mut _ as *mut Archived<$nz>)
153                }
154            }
155
156            /// Resolves an `ArchivedOptionNonZero` from an `Option<NonZero>`.
157            #[inline]
158            pub fn resolve_from_option(
159                field: Option<$nz>,
160                out: Place<Self>,
161            ) {
162                munge!(let Self { inner } = out);
163                if let Some(nz) = field {
164                    inner.write(nz.get().into());
165                } else {
166                    inner.write((0 as $ne).into());
167                }
168            }
169        }
170
171        impl fmt::Debug for $ar {
172            #[inline]
173            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174                self.as_ref().fmt(f)
175            }
176        }
177
178        impl Eq for $ar {}
179
180        impl hash::Hash for $ar {
181            fn hash<H: hash::Hasher>(&self, state: &mut H) {
182                self.as_ref().hash(state)
183            }
184        }
185
186        impl Ord for $ar {
187            #[inline]
188            fn cmp(&self, other: &Self) -> cmp::Ordering {
189                self.as_ref().cmp(&other.as_ref())
190            }
191        }
192
193        impl PartialEq for $ar {
194            #[inline]
195            fn eq(&self, other: &Self) -> bool {
196                self.as_ref().eq(&other.as_ref())
197            }
198        }
199
200        impl PartialOrd for $ar {
201            #[inline]
202            fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
203                Some(self.cmp(other))
204            }
205        }
206
207        unsafe impl NoUndef for $ar {}
208    };
209}
210
211impl_archived_option_nonzero!(ArchivedOptionNonZeroI8, NonZeroI8, i8);
212impl_archived_option_nonzero!(ArchivedOptionNonZeroI16, NonZeroI16, i16);
213impl_archived_option_nonzero!(ArchivedOptionNonZeroI32, NonZeroI32, i32);
214impl_archived_option_nonzero!(ArchivedOptionNonZeroI64, NonZeroI64, i64);
215impl_archived_option_nonzero!(ArchivedOptionNonZeroI128, NonZeroI128, i128);
216
217/// A niched archived `Option<NonZeroIsize>`
218pub type ArchivedOptionNonZeroIsize = match_pointer_width!(
219    ArchivedOptionNonZeroI16,
220    ArchivedOptionNonZeroI32,
221    ArchivedOptionNonZeroI64,
222);
223
224impl_archived_option_nonzero!(ArchivedOptionNonZeroU8, NonZeroU8, u8);
225impl_archived_option_nonzero!(ArchivedOptionNonZeroU16, NonZeroU16, u16);
226impl_archived_option_nonzero!(ArchivedOptionNonZeroU32, NonZeroU32, u32);
227impl_archived_option_nonzero!(ArchivedOptionNonZeroU64, NonZeroU64, u64);
228impl_archived_option_nonzero!(ArchivedOptionNonZeroU128, NonZeroU128, u128);
229
230/// A niched archived `Option<NonZeroUsize>`
231pub type ArchivedOptionNonZeroUsize = match_pointer_width!(
232    ArchivedOptionNonZeroU16,
233    ArchivedOptionNonZeroU32,
234    ArchivedOptionNonZeroU64,
235);
236
237/// An iterator over a reference to the `Some` variant of an
238/// `ArchivedOptionNonZero` integer.
239///
240/// This iterator yields one value if the `ArchivedOptionNonZero` integer is a
241/// `Some`, otherwise none.
242pub type Iter<P> = crate::option::Iter<P>;