Skip to main content

rkyv/
option.rs

1//! An archived version of `Option`.
2
3use core::{
4    cmp, hash, mem,
5    ops::{Deref, DerefMut},
6};
7
8use crate::{seal::Seal, Portable};
9
10/// An archived [`Option`].
11///
12/// It functions identically to [`Option`] but has a different internal
13/// representation to allow for archiving.
14#[derive(Clone, Copy, Debug, Portable)]
15#[cfg_attr(feature = "bytecheck", derive(bytecheck::CheckBytes))]
16#[repr(u8)]
17#[rkyv(crate)]
18pub enum ArchivedOption<T> {
19    /// No value
20    None,
21    /// Some value `T`
22    Some(T),
23}
24
25impl<T> ArchivedOption<T> {
26    /// Transforms the `ArchivedOption<T>` into a `Result<T, E>`, mapping
27    /// `Some(v)` to `Ok(v)` and `None` to `Err(err)`.
28    pub fn ok_or<E>(self, err: E) -> Result<T, E> {
29        match self {
30            ArchivedOption::None => Err(err),
31            ArchivedOption::Some(x) => Ok(x),
32        }
33    }
34    /// Returns the contained [`Some`] value, consuming the `self` value.
35    pub fn unwrap(self) -> T {
36        match self {
37            ArchivedOption::None => {
38                panic!("called `ArchivedOption::unwrap()` on a `None` value")
39            }
40            ArchivedOption::Some(value) => value,
41        }
42    }
43    /// Returns the contained [`Some`] value or a provided default.
44    pub fn unwrap_or(self, default: T) -> T {
45        match self {
46            ArchivedOption::None => default,
47            ArchivedOption::Some(value) => value,
48        }
49    }
50    /// Returns the contained [`Some`] value or computes it from a closure.
51    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
52        match self {
53            ArchivedOption::None => f(),
54            ArchivedOption::Some(value) => value,
55        }
56    }
57    /// Returns `true` if the option is a `None` value.
58    pub fn is_none(&self) -> bool {
59        match self {
60            ArchivedOption::None => true,
61            ArchivedOption::Some(_) => false,
62        }
63    }
64
65    /// Returns `true` if the option is a `Some` value.
66    pub fn is_some(&self) -> bool {
67        match self {
68            ArchivedOption::None => false,
69            ArchivedOption::Some(_) => true,
70        }
71    }
72
73    /// Converts to an `Option<&T>`.
74    pub const fn as_ref(&self) -> Option<&T> {
75        match self {
76            ArchivedOption::None => None,
77            ArchivedOption::Some(value) => Some(value),
78        }
79    }
80
81    /// Converts to an `Option<&mut T>`.
82    pub fn as_mut(&mut self) -> Option<&mut T> {
83        match self {
84            ArchivedOption::None => None,
85            ArchivedOption::Some(value) => Some(value),
86        }
87    }
88
89    /// Converts from `Seal<'_, ArchivedOption<T>>` to `Option<Seal<'_, T>>`.
90    pub fn as_seal(this: Seal<'_, Self>) -> Option<Seal<'_, T>> {
91        let inner = unsafe { Seal::unseal_unchecked(this) };
92        inner.as_mut().map(Seal::new)
93    }
94
95    /// Returns an iterator over the possibly-contained value.
96    pub const fn iter(&self) -> Iter<&'_ T> {
97        Iter {
98            inner: self.as_ref(),
99        }
100    }
101
102    /// Returns an iterator over the mutable possibly-contained value.
103    pub fn iter_mut(&mut self) -> Iter<&'_ mut T> {
104        Iter {
105            inner: self.as_mut(),
106        }
107    }
108
109    /// Returns an iterator over the sealed possibly-contained value.
110    pub fn iter_seal(this: Seal<'_, Self>) -> Iter<Seal<'_, T>> {
111        Iter {
112            inner: Self::as_seal(this),
113        }
114    }
115
116    /// Inserts `v` into the option if it is `None`, then returns a mutable
117    /// reference to the contained value.
118    pub fn get_or_insert(&mut self, v: T) -> &mut T {
119        self.get_or_insert_with(move || v)
120    }
121
122    /// Inserts a value computed from `f` into the option if it is `None`, then
123    /// returns a mutable reference to the contained value.
124    pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
125        if let ArchivedOption::Some(ref mut value) = self {
126            value
127        } else {
128            *self = ArchivedOption::Some(f());
129            self.as_mut().unwrap()
130        }
131    }
132}
133
134impl<T: Deref> ArchivedOption<T> {
135    /// Converts from `&ArchivedOption<T>` to `Option<&T::Target>`.
136    ///
137    /// Leaves the original `ArchivedOption` in-place, creating a new one with a
138    /// reference to the original one, additionally coercing the contents
139    /// via `Deref`.
140    pub fn as_deref(&self) -> Option<&<T as Deref>::Target> {
141        self.as_ref().map(|x| x.deref())
142    }
143}
144
145impl<T: DerefMut> ArchivedOption<T> {
146    /// Converts from `&mut ArchivedOption<T>` to `Option<&mut T::Target>`.
147    ///
148    /// Leaves the original `ArchivedOption` in-place, creating a new `Option`
149    /// with a mutable reference to the inner type's `Deref::Target` type.
150    pub fn as_deref_mut(&mut self) -> Option<&mut <T as Deref>::Target> {
151        self.as_mut().map(|x| x.deref_mut())
152    }
153}
154
155impl<T: Eq> Eq for ArchivedOption<T> {}
156
157impl<T: hash::Hash> hash::Hash for ArchivedOption<T> {
158    fn hash<H: hash::Hasher>(&self, state: &mut H) {
159        self.as_ref().hash(state)
160    }
161}
162
163impl<T: Ord> Ord for ArchivedOption<T> {
164    fn cmp(&self, other: &Self) -> cmp::Ordering {
165        self.as_ref().cmp(&other.as_ref())
166    }
167}
168
169impl<T: PartialEq> PartialEq for ArchivedOption<T> {
170    fn eq(&self, other: &Self) -> bool {
171        self.as_ref().eq(&other.as_ref())
172    }
173}
174
175impl<T: PartialOrd> PartialOrd for ArchivedOption<T> {
176    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
177        self.as_ref().partial_cmp(&other.as_ref())
178    }
179}
180
181impl<T, U: PartialOrd<T>> PartialOrd<Option<T>> for ArchivedOption<U> {
182    fn partial_cmp(&self, other: &Option<T>) -> Option<cmp::Ordering> {
183        match (self, other) {
184            (ArchivedOption::None, None) => Some(cmp::Ordering::Equal),
185            (ArchivedOption::None, Some(_)) => Some(cmp::Ordering::Less),
186            (ArchivedOption::Some(_), None) => Some(cmp::Ordering::Greater),
187            (ArchivedOption::Some(self_value), Some(other_value)) => {
188                self_value.partial_cmp(other_value)
189            }
190        }
191    }
192}
193
194impl<T, U: PartialEq<T>> PartialEq<Option<T>> for ArchivedOption<U> {
195    fn eq(&self, other: &Option<T>) -> bool {
196        if let ArchivedOption::Some(self_value) = self {
197            if let Some(other_value) = other {
198                self_value.eq(other_value)
199            } else {
200                false
201            }
202        } else {
203            other.is_none()
204        }
205    }
206}
207
208impl<T> From<T> for ArchivedOption<T> {
209    /// Moves `val` into a new [`Some`].
210    ///
211    /// # Examples
212    ///
213    /// ```
214    /// # use rkyv::option::ArchivedOption;
215    /// let o: ArchivedOption<u8> = ArchivedOption::from(67);
216    ///
217    /// assert!(matches!(o, ArchivedOption::Some(67)));
218    /// ```
219    fn from(val: T) -> ArchivedOption<T> {
220        ArchivedOption::Some(val)
221    }
222}
223
224/// An iterator over a reference to the `Some` variant of an `ArchivedOption`.
225///
226/// This iterator yields one value if the `ArchivedOption` is a `Some`,
227/// otherwise none.
228pub struct Iter<P> {
229    inner: Option<P>,
230}
231
232impl<P> Iter<P> {
233    /// Returns an iterator over the given `Option`.
234    pub fn new(inner: Option<P>) -> Self {
235        Self { inner }
236    }
237}
238
239impl<P> Iterator for Iter<P> {
240    type Item = P;
241
242    fn next(&mut self) -> Option<Self::Item> {
243        let mut result = None;
244        mem::swap(&mut self.inner, &mut result);
245        result
246    }
247}
248
249impl<P> DoubleEndedIterator for Iter<P> {
250    fn next_back(&mut self) -> Option<Self::Item> {
251        self.next()
252    }
253}
254
255impl<'a, T> IntoIterator for &'a ArchivedOption<T> {
256    type Item = &'a T;
257    type IntoIter = Iter<&'a T>;
258
259    fn into_iter(self) -> Self::IntoIter {
260        self.iter()
261    }
262}
263
264impl<'a, T> IntoIterator for &'a mut ArchivedOption<T> {
265    type Item = &'a mut T;
266    type IntoIter = Iter<&'a mut T>;
267
268    fn into_iter(self) -> Self::IntoIter {
269        self.iter_mut()
270    }
271}
272
273impl<'a, T> IntoIterator for Seal<'a, ArchivedOption<T>> {
274    type Item = Seal<'a, T>;
275    type IntoIter = Iter<Seal<'a, T>>;
276
277    fn into_iter(self) -> Self::IntoIter {
278        ArchivedOption::iter_seal(self)
279    }
280}
281
282#[cfg(test)]
283mod tests {
284    use super::*;
285
286    #[test]
287    fn partial_ord_option() {
288        use core::cmp::Ordering;
289
290        use super::ArchivedOption;
291
292        let a: ArchivedOption<u8> = ArchivedOption::Some(42);
293        let b = Some(42);
294        assert_eq!(Some(Ordering::Equal), a.partial_cmp(&b));
295
296        let a: ArchivedOption<u8> = ArchivedOption::Some(1);
297        let b = Some(2);
298        assert_eq!(Some(Ordering::Less), a.partial_cmp(&b));
299
300        let a: ArchivedOption<u8> = ArchivedOption::Some(2);
301        let b = Some(1);
302        assert_eq!(Some(Ordering::Greater), a.partial_cmp(&b));
303    }
304
305    #[test]
306    fn into_iter() {
307        let x: ArchivedOption<u8> = ArchivedOption::Some(1);
308        let mut iter = IntoIterator::into_iter(&x);
309        assert_eq!(iter.next(), Some(&1));
310        assert_eq!(iter.next(), None);
311
312        let x: ArchivedOption<u8> = ArchivedOption::None;
313        let mut iter = IntoIterator::into_iter(&x);
314        assert_eq!(iter.next(), None);
315    }
316}