flatcontainer/impls/
option.rs

1//! A region that stores options.
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6use crate::{IntoOwned, Push, Region, RegionPreference, ReserveItems};
7
8impl<T: RegionPreference> RegionPreference for Option<T> {
9    type Owned = Option<T::Owned>;
10    type Region = OptionRegion<T::Region>;
11}
12
13/// A region to hold [`Option`]s.
14///
15/// # Examples
16///
17/// The region can hold options:
18/// ```
19/// # use flatcontainer::{RegionPreference, Push, OptionRegion, Region};
20/// let mut r = <OptionRegion<<u8 as RegionPreference>::Region>>::default();
21///
22/// let some_index = r.push(Some(123));
23/// // Type annotations required for `None`:
24/// let none_index = r.push(Option::<u8>::None);
25///
26/// assert_eq!(Some(123), r.index(some_index));
27/// assert_eq!(None, r.index(none_index));
28/// ```
29#[derive(Default, Debug)]
30#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
31pub struct OptionRegion<R> {
32    inner: R,
33}
34
35impl<R: Clone> Clone for OptionRegion<R> {
36    fn clone(&self) -> Self {
37        Self {
38            inner: self.inner.clone(),
39        }
40    }
41
42    fn clone_from(&mut self, source: &Self) {
43        self.inner.clone_from(&source.inner);
44    }
45}
46
47impl<R: Region> Region for OptionRegion<R> {
48    type Owned = Option<R::Owned>;
49    type ReadItem<'a> = Option<<R as Region>::ReadItem<'a>> where Self: 'a;
50    type Index = Option<R::Index>;
51
52    #[inline]
53    fn merge_regions<'a>(regions: impl Iterator<Item = &'a Self> + Clone) -> Self
54    where
55        Self: 'a,
56    {
57        Self {
58            inner: R::merge_regions(regions.map(|r| &r.inner)),
59        }
60    }
61
62    #[inline]
63    fn index(&self, index: Self::Index) -> Self::ReadItem<'_> {
64        index.map(|t| self.inner.index(t))
65    }
66
67    #[inline]
68    fn reserve_regions<'a, I>(&mut self, regions: I)
69    where
70        Self: 'a,
71        I: Iterator<Item = &'a Self> + Clone,
72    {
73        self.inner.reserve_regions(regions.map(|r| &r.inner));
74    }
75
76    #[inline]
77    fn clear(&mut self) {
78        self.inner.clear();
79    }
80
81    #[inline]
82    fn heap_size<F: FnMut(usize, usize)>(&self, callback: F) {
83        self.inner.heap_size(callback);
84    }
85
86    #[inline]
87    fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b>
88    where
89        Self: 'a,
90    {
91        item.map(R::reborrow)
92    }
93}
94
95impl<'a, T> IntoOwned<'a> for Option<T>
96where
97    T: IntoOwned<'a>,
98{
99    type Owned = Option<T::Owned>;
100
101    #[inline]
102    fn into_owned(self) -> Self::Owned {
103        self.map(IntoOwned::into_owned)
104    }
105
106    #[inline]
107    fn clone_onto(self, other: &mut Self::Owned) {
108        match (self, other) {
109            (Some(item), Some(target)) => T::clone_onto(item, target),
110            (Some(item), target) => *target = Some(T::into_owned(item)),
111            (None, target) => *target = None,
112        }
113    }
114
115    #[inline]
116    fn borrow_as(owned: &'a Self::Owned) -> Self {
117        owned.as_ref().map(T::borrow_as)
118    }
119}
120
121impl<T, TR> Push<Option<T>> for OptionRegion<TR>
122where
123    TR: Region + Push<T>,
124{
125    #[inline]
126    fn push(&mut self, item: Option<T>) -> <OptionRegion<TR> as Region>::Index {
127        item.map(|t| self.inner.push(t))
128    }
129}
130
131impl<'a, T: 'a, TR> Push<&'a Option<T>> for OptionRegion<TR>
132where
133    TR: Region + Push<&'a T>,
134{
135    #[inline]
136    fn push(&mut self, item: &'a Option<T>) -> <OptionRegion<TR> as Region>::Index {
137        item.as_ref().map(|t| self.inner.push(t))
138    }
139}
140
141impl<T, TR> ReserveItems<Option<T>> for OptionRegion<TR>
142where
143    TR: Region + ReserveItems<T>,
144{
145    #[inline]
146    fn reserve_items<I>(&mut self, items: I)
147    where
148        I: Iterator<Item = Option<T>> + Clone,
149    {
150        // Clippy is confused about using `flatten` here, which we cannot use because
151        // the iterator isn't `Clone`.
152        #[allow(clippy::filter_map_identity)]
153        self.inner.reserve_items(items.filter_map(|r| r));
154    }
155}
156
157impl<'a, T: 'a, TR> ReserveItems<&'a Option<T>> for OptionRegion<TR>
158where
159    TR: Region + ReserveItems<&'a T>,
160{
161    #[inline]
162    fn reserve_items<I>(&mut self, items: I)
163    where
164        I: Iterator<Item = &'a Option<T>> + Clone,
165    {
166        self.inner.reserve_items(items.filter_map(|r| r.as_ref()));
167    }
168}
169
170#[cfg(test)]
171mod tests {
172    use crate::{MirrorRegion, OwnedRegion, Region, ReserveItems};
173
174    use super::*;
175
176    #[test]
177    fn test_reserve() {
178        let mut r = <OptionRegion<MirrorRegion<u8>>>::default();
179        ReserveItems::reserve_items(&mut r, [Some(0), None].iter());
180
181        ReserveItems::reserve_items(&mut r, [Some(0), None].into_iter());
182    }
183
184    #[test]
185    fn test_heap_size() {
186        let mut r = <OptionRegion<OwnedRegion<u8>>>::default();
187        ReserveItems::reserve_items(&mut r, [Some([1; 1]), None].iter());
188        let mut cap = 0;
189        r.heap_size(|_, ca| {
190            cap += ca;
191        });
192        assert!(cap > 0);
193    }
194}