ferroui_base/utilities/
pooled_inline_list.rs1use std::rc::Rc;
2
3pub struct PooledInlineList<T: ?Sized> {
9 item: ItemState<T>,
10}
11
12enum ItemState<T: ?Sized> {
14 Null,
15 Single(Rc<T>),
16 List(SimplePooledList<T>),
17}
18
19pub struct PooledInlineListRawState<T: ?Sized>(ItemState<T>);
22
23impl<T: ?Sized> Default for PooledInlineList<T> {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29impl<T: ?Sized> PooledInlineList<T> {
30 pub fn new() -> Self {
31 Self { item: ItemState::Null }
32 }
33
34 pub fn from_raw_state(raw_state: PooledInlineListRawState<T>) -> Self {
36 Self { item: raw_state.0 }
37 }
38
39 pub fn add(&mut self, item: Rc<T>) {
40 if matches!(self.item, ItemState::Null) {
41 self.item = ItemState::Single(item);
42 } else {
43 self.convert_to_list();
44 if let ItemState::List(list) = &mut self.item {
45 list.add(item);
46 }
47 }
48 }
49
50 pub fn remove(&mut self, item: &Rc<T>) -> bool {
55 let same = matches!(&self.item, ItemState::Single(single) if Rc::ptr_eq(single, item));
56 if same {
57 self.item = ItemState::Null;
58 return true;
59 }
60
61 false
62 }
63
64 fn convert_to_list(&mut self) {
65 if matches!(self.item, ItemState::List(_)) {
66 return;
67 }
68 let mut list = SimplePooledList::new();
69 if let ItemState::Single(item) = std::mem::replace(&mut self.item, ItemState::Null) {
70 list.add(item);
71 }
72 self.item = ItemState::List(list);
73 }
74
75 pub fn ensure_capacity(&mut self, count: i32) {
76 if count < 2 {
77 return;
78 }
79 self.convert_to_list();
80 if let ItemState::List(list) = &mut self.item {
81 list.ensure_capacity(count as usize);
82 }
83 }
84
85 pub fn dispose(&mut self) {
86 if let ItemState::List(list) = &mut self.item {
87 list.dispose();
88 }
89 self.item = ItemState::Null;
90 }
91
92 pub fn count(&self) -> i32 {
93 match &self.item {
94 ItemState::Null => 0,
95 ItemState::List(list) => list.count() as i32,
96 ItemState::Single(_) => 1,
97 }
98 }
99
100 pub fn get_enumerator(&self) -> PooledInlineListEnumerator<'_, T> {
101 PooledInlineListEnumerator::new(&self.item)
102 }
103
104 pub fn transfer_raw_state(&mut self) -> PooledInlineListRawState<T> {
106 PooledInlineListRawState(std::mem::replace(&mut self.item, ItemState::Null))
107 }
108}
109
110impl<'a, T: ?Sized> IntoIterator for &'a PooledInlineList<T> {
111 type Item = &'a Rc<T>;
112 type IntoIter = PooledInlineListEnumerator<'a, T>;
113
114 fn into_iter(self) -> Self::IntoIter {
115 self.get_enumerator()
116 }
117}
118
119struct SimplePooledList<T: ?Sized> {
120 items: Option<Vec<Rc<T>>>,
121}
122
123impl<T: ?Sized> SimplePooledList<T> {
124 fn new() -> Self {
125 Self { items: None }
126 }
127
128 fn count(&self) -> usize {
129 self.items.as_ref().map_or(0, Vec::len)
130 }
131
132 fn add(&mut self, item: Rc<T>) {
133 let items = self.items.get_or_insert_with(|| Vec::with_capacity(4));
134 if items.len() == items.capacity() {
135 let count = items.len();
136 items.reserve_exact(count);
137 }
138
139 items.push(item);
140 }
141
142 fn ensure_capacity(&mut self, count: usize) {
143 if self.items.is_none() {
144 self.items = Some(Vec::with_capacity(count));
145 return;
146 }
147 if let Some(items) = &mut self.items {
148 if items.capacity() < count {
149 items.reserve_exact(count - items.len());
150 }
151 }
152 }
153
154 fn dispose(&mut self) {
155 self.items = None;
156 }
157}
158
159pub struct PooledInlineListEnumerator<'a, T: ?Sized> {
162 single_item: Option<&'a Rc<T>>,
163 index: i32,
164 list: Option<&'a SimplePooledList<T>>,
165}
166
167impl<'a, T: ?Sized> PooledInlineListEnumerator<'a, T> {
168 fn new(item: &'a ItemState<T>) -> Self {
169 let mut result = Self { single_item: None, index: -1, list: None };
170 match item {
171 ItemState::List(list) => result.list = Some(list),
172 ItemState::Single(single) => result.single_item = Some(single),
173 ItemState::Null => {}
174 }
175 result
176 }
177
178 pub fn move_next(&mut self) -> bool {
179 if self.single_item.is_some() {
180 if self.index >= 0 {
181 return false;
182 }
183 self.index = 0;
184 return true;
185 }
186
187 if let Some(list) = self.list {
188 if self.index >= list.count() as i32 - 1 {
189 return false;
190 }
191 self.index += 1;
192 return true;
193 }
194
195 false
196 }
197
198 pub fn reset(&mut self) {
200 panic!("Specified method is not supported.");
201 }
202
203 pub fn current(&self) -> &'a Rc<T> {
207 if let Some(list) = self.list {
208 return match &list.items {
209 Some(items) => &items[self.index as usize],
210 None => panic!("Object reference not set to an instance of an object."),
211 };
212 }
213 match self.single_item {
214 Some(single_item) => single_item,
215 None => panic!("Object reference not set to an instance of an object."),
216 }
217 }
218
219 pub fn dispose(&mut self) {}
220}
221
222impl<'a, T: ?Sized> Iterator for PooledInlineListEnumerator<'a, T> {
223 type Item = &'a Rc<T>;
224
225 fn next(&mut self) -> Option<Self::Item> {
226 if self.move_next() {
227 Some(self.current())
228 } else {
229 None
230 }
231 }
232}
233
234#[cfg(test)]
235mod tests {
236 use super::*;
238
239 fn values(list: &PooledInlineList<i32>) -> Vec<i32> {
240 list.get_enumerator().map(|item| **item).collect()
241 }
242
243 #[test]
244 fn holds_one_item_in_place_and_more_in_a_list() {
245 let mut target = PooledInlineList::<i32>::new();
246 assert_eq!(0, target.count());
247 assert!(values(&target).is_empty());
248
249 let first = Rc::new(1);
250 target.add(first.clone());
251 assert_eq!(1, target.count());
252 assert_eq!(vec![1], values(&target));
253
254 for value in 2..=9 {
255 target.add(Rc::new(value));
256 }
257 assert_eq!(9, target.count());
258 assert_eq!((1..=9).collect::<Vec<_>>(), values(&target));
259
260 assert!(!target.remove(&first));
262 assert_eq!(9, target.count());
263
264 target.dispose();
265 assert_eq!(0, target.count());
266 }
267
268 #[test]
269 fn removes_the_item_held_in_place() {
270 let mut target = PooledInlineList::<i32>::new();
271 let item = Rc::new(1);
272 target.add(item.clone());
273
274 assert!(!target.remove(&Rc::new(1)));
275 assert!(target.remove(&item));
276 assert_eq!(0, target.count());
277 assert!(!target.remove(&item));
278 }
279
280 #[test]
281 fn ensure_capacity_converts_to_a_list_for_two_or_more_items() {
282 let mut target = PooledInlineList::<i32>::new();
283 target.ensure_capacity(1);
284 target.add(Rc::new(1));
285 assert_eq!(1, target.count());
286
287 target.ensure_capacity(8);
288 assert_eq!(1, target.count());
289 assert_eq!(vec![1], values(&target));
290 }
291
292 #[test]
293 fn transfers_its_state() {
294 let mut target = PooledInlineList::<i32>::new();
295 target.add(Rc::new(1));
296 target.add(Rc::new(2));
297
298 let state = target.transfer_raw_state();
299 assert_eq!(0, target.count());
300
301 let restored = PooledInlineList::from_raw_state(state);
302 assert_eq!(vec![1, 2], values(&restored));
303 }
304}