offer_cell/
lib.rs

1use std::ops::{Deref, DerefMut};
2
3/// A view into the offering of a [`OfferCell`]
4///
5/// This `enum` is constructed from the [`entry`](OfferCell::entry) method on [`OfferCell`]
6pub enum OfferEntry<'a, T> {
7    Occupied(Offering<'a, T>),
8    Vacant(EmptyOffering<'a, T>),
9}
10
11/// Represents an empty offering from a [`OfferCell`]
12pub struct EmptyOffering<'a, T> {
13    item: &'a mut Option<T>,
14}
15
16impl<'a, T> EmptyOffering<'a, T> {
17    /// Consumes the empty offering, inserting `item` into the source [`OfferCell`] and returns an [`Offering`]
18    pub fn insert(self, item: T) -> Offering<'a, T> {
19        *self.item = Some(item);
20        Offering { item: self.item }
21    }
22}
23
24/// A ownership offering that comes from a [`OfferCell`]
25pub struct Offering<'a, T> {
26    item: &'a mut Option<T>,
27}
28
29impl<'a, T> Deref for Offering<'a, T> {
30    type Target = T;
31
32    fn deref(&self) -> &Self::Target {
33        match &self.item {
34            Some(item) => item,
35            _ => unreachable!(),
36        }
37    }
38}
39
40impl<'a, T> DerefMut for Offering<'a, T> {
41    fn deref_mut(&mut self) -> &mut Self::Target {
42        match &mut self.item {
43            Some(item) => item,
44            _ => unreachable!(),
45        }
46    }
47}
48
49impl<'a, T> Offering<'a, T> {
50    /// Consumes the offering, and takes ownership of the data
51    pub fn take(self) -> T {
52        match self.item.take() {
53            Some(item) => item,
54            None => unreachable!(),
55        }
56    }
57}
58
59/// A data container that can offer optional ownership of its stored information
60pub struct OfferCell<T> {
61    item: Option<T>,
62}
63
64impl<T> Default for OfferCell<T> {
65    fn default() -> Self {
66        Self::empty()
67    }
68}
69
70impl<T> OfferCell<T> {
71    /// Returns an empty cell
72    pub fn empty() -> Self {
73        Self { item: None }
74    }
75
76    /// Returns a new cell that stores `item`
77    pub fn new(item: T) -> Self {
78        Self { item: Some(item) }
79    }
80
81    /// Returns true if the cell is empty
82    pub fn is_empty(&self) -> bool {
83        self.item.is_none()
84    }
85
86    /// Returns a reference to the stored item
87    pub fn item(&self) -> Option<&T> {
88        self.item.as_ref()
89    }
90
91    /// Returns a mutable reference to the stored item
92    pub fn item_mut(&mut self) -> Option<&mut T> {
93        self.item.as_mut()
94    }
95
96    /// Returns the stored data leaving nothing in its place
97    pub fn take(&mut self) -> Option<T> {
98        self.item.take()
99    }
100
101    /// Offers optional ownership of the stored data as a [`Offering`] item
102    pub fn offer(&mut self) -> Option<Offering<T>> {
103        if self.item.is_none() {
104            return None;
105        }
106
107        Some(Offering {
108            item: &mut self.item,
109        })
110    }
111
112    /// Inserts `item` into the cell and returns the item as an offering
113    pub fn insert_offer(&mut self, item: T) -> Offering<T> {
114        self.item = Some(item);
115        Offering {
116            item: &mut self.item,
117        }
118    }
119
120    /// Inserts data if there is none currently, then returns the stored data
121    pub fn offer_or_insert(&mut self, mut insert: impl FnMut() -> T) -> Offering<T> {
122        if self.item.is_none() {
123            self.item = Some(insert());
124        }
125
126        Offering {
127            item: &mut self.item,
128        }
129    }
130
131    /// Returns an [`Offering`] if there is one.
132    /// Otherwise returns an [`EmptyOffering`].
133    pub fn entry(&mut self) -> OfferEntry<T> {
134        match self.item.is_some() {
135            true => OfferEntry::Occupied(Offering {
136                item: &mut self.item,
137            }),
138            false => OfferEntry::Vacant(EmptyOffering {
139                item: &mut self.item,
140            }),
141        }
142    }
143}