1use std::ops::{Deref, DerefMut};
2
3pub enum OfferEntry<'a, T> {
7 Occupied(Offering<'a, T>),
8 Vacant(EmptyOffering<'a, T>),
9}
10
11pub struct EmptyOffering<'a, T> {
13 item: &'a mut Option<T>,
14}
15
16impl<'a, T> EmptyOffering<'a, T> {
17 pub fn insert(self, item: T) -> Offering<'a, T> {
19 *self.item = Some(item);
20 Offering { item: self.item }
21 }
22}
23
24pub 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 pub fn take(self) -> T {
52 match self.item.take() {
53 Some(item) => item,
54 None => unreachable!(),
55 }
56 }
57}
58
59pub 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 pub fn empty() -> Self {
73 Self { item: None }
74 }
75
76 pub fn new(item: T) -> Self {
78 Self { item: Some(item) }
79 }
80
81 pub fn is_empty(&self) -> bool {
83 self.item.is_none()
84 }
85
86 pub fn item(&self) -> Option<&T> {
88 self.item.as_ref()
89 }
90
91 pub fn item_mut(&mut self) -> Option<&mut T> {
93 self.item.as_mut()
94 }
95
96 pub fn take(&mut self) -> Option<T> {
98 self.item.take()
99 }
100
101 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 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 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 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}