rkyv/niche/
option_box.rs

1//! A niched archived `Option<Box<T>>` that uses less space.
2
3use crate::{
4    boxed::{ArchivedBox, BoxResolver},
5    ser::Serializer,
6    ArchivePointee, ArchiveUnsized, SerializeUnsized,
7};
8use core::{
9    cmp::{self, Eq, Ord, PartialEq, PartialOrd},
10    fmt, hash,
11    hint::unreachable_unchecked,
12    ops::Deref,
13    pin::Pin,
14};
15
16/// A niched archived `Option<Box<T>>`.
17///
18/// It uses less space by storing the `None` variant as a null pointer.
19#[repr(transparent)]
20pub struct ArchivedOptionBox<T: ArchivePointee + ?Sized> {
21    inner: ArchivedBox<T>,
22}
23
24impl<T: ArchivePointee + ?Sized> ArchivedOptionBox<T> {
25    /// Returns `true` if the option box is a `None` value.
26    #[inline]
27    pub fn is_none(&self) -> bool {
28        self.as_ref().is_none()
29    }
30
31    /// Returns `true` if the option box is a `Some` value.
32    #[inline]
33    pub fn is_some(&self) -> bool {
34        self.as_ref().is_some()
35    }
36
37    /// Converts to an `Option<&ArchivedBox<T>>`.
38    #[inline]
39    pub fn as_ref(&self) -> Option<&ArchivedBox<T>> {
40        if self.inner.is_null() {
41            None
42        } else {
43            Some(&self.inner)
44        }
45    }
46
47    /// Converts to an `Option<&mut ArchivedBox<T>>`.
48    #[inline]
49    pub fn as_mut(&mut self) -> Option<&mut ArchivedBox<T>> {
50        if self.inner.is_null() {
51            None
52        } else {
53            Some(&mut self.inner)
54        }
55    }
56
57    /// Converts from `Pin<&ArchivedOptionBox<T>>` to `Option<Pin<&ArchivedBox<T>>>`.
58    #[inline]
59    pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&ArchivedBox<T>>> {
60        unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) }
61    }
62
63    /// Converts from `Pin<&mut ArchivedOption<T>>` to `Option<Pin<&mut ArchivedBox<T>>>`.
64    #[inline]
65    pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut ArchivedBox<T>>> {
66        unsafe {
67            Pin::get_unchecked_mut(self)
68                .as_mut()
69                .map(|x| Pin::new_unchecked(x))
70        }
71    }
72
73    /// Returns an iterator over the possibly contained value.
74    #[inline]
75    pub fn iter(&self) -> Iter<'_, ArchivedBox<T>> {
76        Iter {
77            inner: self.as_ref(),
78        }
79    }
80
81    /// Returns a mutable iterator over the possibly contained value.
82    #[inline]
83    pub fn iter_mut(&mut self) -> IterMut<'_, ArchivedBox<T>> {
84        IterMut {
85            inner: self.as_mut(),
86        }
87    }
88
89    /// Converts from `&ArchivedOptionBox<T>` to `Option<&T>`.
90    ///
91    /// Leaves the original `ArchivedOptionBox` in-place, creating a new one with a reference to the
92    /// original one.
93    #[inline]
94    pub fn as_deref(&self) -> Option<&T> {
95        self.as_ref().map(|x| (*x).deref())
96    }
97}
98
99impl<T: ArchivePointee + ?Sized> ArchivedOptionBox<T>
100where
101    T::ArchivedMetadata: Default,
102{
103    /// Resolves an `ArchivedOptionBox<T::Archived>` from an `Option<&T>`.
104    ///
105    /// # Safety
106    ///
107    /// - `pos` must be the position of `out` within the archive
108    /// - `resolver` must be the result of serializing `field`
109    #[inline]
110    pub unsafe fn resolve_from_option<U: ArchiveUnsized<Archived = T> + ?Sized>(
111        field: Option<&U>,
112        pos: usize,
113        resolver: OptionBoxResolver<U::MetadataResolver>,
114        out: *mut Self,
115    ) {
116        let (fp, fo) = out_field!(out.inner);
117        if let Some(value) = field {
118            let resolver = if let OptionBoxResolver::Some(metadata_resolver) = resolver {
119                metadata_resolver
120            } else {
121                unreachable_unchecked();
122            };
123
124            ArchivedBox::resolve_from_ref(value, pos + fp, resolver, fo)
125        } else {
126            ArchivedBox::emplace_null(pos + fp, fo);
127        }
128    }
129
130    /// Serializes an `ArchivedOptionBox<T::Archived>` from an `Option<&T>`.
131    #[inline]
132    pub fn serialize_from_option<U, S>(
133        field: Option<&U>,
134        serializer: &mut S,
135    ) -> Result<OptionBoxResolver<U::MetadataResolver>, S::Error>
136    where
137        U: SerializeUnsized<S, Archived = T> + ?Sized,
138        S: Serializer + ?Sized,
139    {
140        if let Some(value) = field {
141            Ok(OptionBoxResolver::Some(ArchivedBox::serialize_from_ref(
142                value, serializer,
143            )?))
144        } else {
145            Ok(OptionBoxResolver::None)
146        }
147    }
148}
149
150impl<T: ArchivePointee + ?Sized> fmt::Debug for ArchivedOptionBox<T>
151where
152    T::ArchivedMetadata: fmt::Debug,
153{
154    #[inline]
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        match self.as_ref() {
157            Some(inner) => inner.fmt(f),
158            None => f.debug_tuple("None").finish(),
159        }
160    }
161}
162
163impl<T: ArchivePointee + Eq + ?Sized> Eq for ArchivedOptionBox<T> {}
164
165impl<T: ArchivePointee + hash::Hash + ?Sized> hash::Hash for ArchivedOptionBox<T> {
166    #[inline]
167    fn hash<H: hash::Hasher>(&self, state: &mut H) {
168        self.as_ref().hash(state)
169    }
170}
171
172impl<T: ArchivePointee + Ord + ?Sized> Ord for ArchivedOptionBox<T> {
173    #[inline]
174    fn cmp(&self, other: &Self) -> cmp::Ordering {
175        self.as_ref().cmp(&other.as_ref())
176    }
177}
178
179impl<T: ArchivePointee + PartialEq + ?Sized> PartialEq for ArchivedOptionBox<T> {
180    #[inline]
181    fn eq(&self, other: &Self) -> bool {
182        self.as_ref().eq(&other.as_ref())
183    }
184}
185
186impl<T: ArchivePointee + PartialOrd + ?Sized> PartialOrd for ArchivedOptionBox<T> {
187    #[inline]
188    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
189        self.as_ref().partial_cmp(&other.as_ref())
190    }
191}
192
193/// An iterator over a reference to the `Some` variant of an `ArchivedOptionBox`.
194///
195/// This iterator yields one value if the `ArchivedOptionBox` is a `Some`, otherwise none.
196///
197/// This `struct` is created by the [`ArchivedOptionBox::iter`] function.
198pub type Iter<'a, T> = crate::option::Iter<'a, T>;
199
200/// An iterator over a mutable reference to the `Some` variant of an `ArchivedOptionBox`.
201///
202/// This iterator yields one value if the `ArchivedOptionBox` is a `Some`, otherwise none.
203///
204/// This `struct` is created by the [`ArchivedOptionBox::iter_mut`] function.
205pub type IterMut<'a, T> = crate::option::IterMut<'a, T>;
206
207/// The resolver for [`ArchivedOptionBox`].
208pub enum OptionBoxResolver<T> {
209    /// The `ArchivedOptionBox` was `None`
210    None,
211    /// The resolver for the `ArchivedBox`
212    Some(BoxResolver<T>),
213}