gio/
list_model.rs
1use std::{cell::Cell, fmt, iter::FusedIterator, marker::PhantomData, rc::Rc};
4
5use glib::SignalHandlerId;
6
7use crate::{prelude::*, ListModel};
8
9mod sealed {
10 pub trait Sealed {}
11 impl<T: super::IsA<super::ListModel>> Sealed for T {}
12}
13
14pub trait ListModelExtManual: sealed::Sealed + IsA<ListModel> + Sized {
15 fn snapshot(&self) -> Vec<glib::Object> {
20 let mut res = Vec::with_capacity(self.n_items() as usize);
21 for i in 0..self.n_items() {
22 res.push(self.item(i).unwrap())
23 }
24 res
25 }
26
27 fn iter<LT: IsA<glib::Object>>(&self) -> ListModelIter<LT> {
35 assert!(self.item_type().is_a(LT::static_type()));
36
37 let len = self.n_items();
38 let changed = Rc::new(Cell::new(false));
39
40 let changed_clone = changed.clone();
41 let signal_id = Some(self.connect_items_changed(move |_, pos, _, _| {
42 if pos < len {
43 changed_clone.set(true);
44 }
45 }));
46
47 ListModelIter {
48 ty: Default::default(),
49 i: 0,
50 reverse_pos: len,
51 model: self.upcast_ref(),
52 changed,
53 signal_id,
54 }
55 }
56}
57
58impl<T: IsA<ListModel>> ListModelExtManual for T {}
59
60#[derive(Debug, PartialEq, Eq)]
61pub struct ListModelMutatedDuringIter;
62
63impl std::error::Error for ListModelMutatedDuringIter {}
64
65impl fmt::Display for ListModelMutatedDuringIter {
66 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
67 fmt.write_str("the list model was mutated during iteration")
68 }
69}
70
71pub struct ListModelIter<'a, T: IsA<glib::Object>> {
79 ty: PhantomData<T>,
80 i: u32,
81 reverse_pos: u32,
83 model: &'a ListModel,
84 changed: Rc<Cell<bool>>,
85 signal_id: Option<SignalHandlerId>,
86}
87impl<T: IsA<glib::Object>> Iterator for ListModelIter<'_, T> {
88 type Item = Result<T, ListModelMutatedDuringIter>;
89
90 fn next(&mut self) -> Option<Self::Item> {
91 if self.i >= self.reverse_pos {
92 return None;
93 }
94 let res = match self.changed.get() {
95 true => Err(ListModelMutatedDuringIter),
96 false => Ok(self.model.item(self.i).unwrap().downcast::<T>().unwrap()),
97 };
98 self.i += 1;
99 Some(res)
100 }
101
102 fn size_hint(&self) -> (usize, Option<usize>) {
103 let n: usize = (self.reverse_pos - self.i) as _;
104 (n, Some(n))
105 }
106
107 fn count(self) -> usize {
108 (self.reverse_pos - self.i) as usize
109 }
110
111 fn nth(&mut self, n: usize) -> Option<Self::Item> {
112 let (end, overflow) = (self.i as usize).overflowing_add(n);
113 if end >= self.reverse_pos as usize || overflow {
114 self.i = self.reverse_pos;
115 None
116 } else {
117 let end = end as u32;
118 self.i = end + 1;
119
120 let res = match self.changed.get() {
121 true => Err(ListModelMutatedDuringIter),
122 false => Ok(self.model.item(end).unwrap().downcast::<T>().unwrap()),
123 };
124 Some(res)
125 }
126 }
127
128 fn last(self) -> Option<Self::Item> {
129 if self.i == self.reverse_pos {
130 None
131 } else {
132 let res = match self.changed.get() {
133 true => Err(ListModelMutatedDuringIter),
134 false => Ok(self
135 .model
136 .item(self.reverse_pos - 1)
137 .unwrap()
138 .downcast::<T>()
139 .unwrap()),
140 };
141 Some(res)
142 }
143 }
144}
145
146impl<T: IsA<glib::Object>> FusedIterator for ListModelIter<'_, T> {}
147
148impl<T: IsA<glib::Object>> ExactSizeIterator for ListModelIter<'_, T> {}
149
150impl<T: IsA<glib::Object>> DoubleEndedIterator for ListModelIter<'_, T> {
151 fn next_back(&mut self) -> Option<Self::Item> {
152 if self.reverse_pos == self.i {
153 return None;
154 }
155 self.reverse_pos -= 1;
156 let res = match self.changed.get() {
157 true => Err(ListModelMutatedDuringIter),
158 false => Ok(self
159 .model
160 .item(self.reverse_pos)
161 .unwrap()
162 .downcast::<T>()
163 .unwrap()),
164 };
165 Some(res)
166 }
167
168 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
169 let (end, overflow) = (self.reverse_pos as usize).overflowing_sub(n);
170 if end <= self.i as usize || overflow {
171 self.i = self.reverse_pos;
172 None
173 } else {
174 let end = end as u32;
175 self.reverse_pos = end - 1;
176
177 let res = match self.changed.get() {
178 true => Err(ListModelMutatedDuringIter),
179 false => Ok(self.model.item(end - 1).unwrap().downcast::<T>().unwrap()),
180 };
181 Some(res)
182 }
183 }
184}
185impl<T: IsA<glib::Object>> Drop for ListModelIter<'_, T> {
186 #[inline]
187 fn drop(&mut self) {
188 self.model.disconnect(self.signal_id.take().unwrap());
189 }
190}
191
192impl<'a> std::iter::IntoIterator for &'a ListModel {
193 type Item = Result<glib::Object, ListModelMutatedDuringIter>;
194 type IntoIter = ListModelIter<'a, glib::Object>;
195
196 fn into_iter(self) -> Self::IntoIter {
197 self.iter()
198 }
199}
200
201#[test]
202fn list_model_iter_ok() {
203 let list = crate::ListStore::new::<crate::Menu>();
204 let m1 = crate::Menu::new();
205 let m2 = crate::Menu::new();
206 let m3 = crate::Menu::new();
207 let m4 = crate::Menu::new();
208
209 list.append(&m1);
210 list.append(&m2);
211 list.append(&m3);
212
213 let mut iter = list.iter::<crate::Menu>();
214
215 assert_eq!(iter.len(), 3);
216 assert_eq!(iter.next(), Some(Ok(m1)));
217 list.append(&m4);
220 assert_eq!(iter.next_back(), Some(Ok(m3)));
221 assert_eq!(iter.len(), 1);
222 assert_eq!(iter.next_back(), Some(Ok(m2)));
223 assert_eq!(iter.next(), None);
224 assert_eq!(iter.next_back(), None);
225}
226
227#[test]
228fn list_model_iter_err() {
229 let list = crate::ListStore::new::<crate::Menu>();
230 let m1 = crate::Menu::new();
231 let m2 = crate::Menu::new();
232 let m3 = crate::Menu::new();
233 let m4 = crate::Menu::new();
234
235 list.append(&m1);
236 list.append(&m2);
237 list.append(&m3);
238 list.append(&m4);
239
240 let mut iter = list.iter::<crate::Menu>();
241
242 assert_eq!(iter.next_back(), Some(Ok(m4)));
243
244 list.append(&m2);
246 list.append(&m2);
247
248 assert_eq!(iter.next(), Some(Ok(m1)));
249
250 list.remove(2);
252 list.remove(4);
254 assert_eq!(iter.next(), Some(Err(ListModelMutatedDuringIter)));
255 assert_eq!(iter.next(), Some(Err(ListModelMutatedDuringIter)));
256 assert_eq!(iter.next(), None);
258}
259
260#[test]
261fn list_model_iter_nth() {
262 let list = crate::ListStore::new::<crate::Menu>();
263 let m1 = crate::Menu::new();
264 let m2 = crate::Menu::new();
265 let m3 = crate::Menu::new();
266 let m4 = crate::Menu::new();
267 let m5 = crate::Menu::new();
268 let m6 = crate::Menu::new();
269
270 list.append(&m1);
271 list.append(&m2);
272 list.append(&m3);
273 list.append(&m4);
274 list.append(&m5);
275 list.append(&m6);
276
277 let mut iter = list.iter::<crate::Menu>();
278
279 assert_eq!(iter.len(), 6);
280 assert_eq!(iter.nth(1), Some(Ok(m2)));
281 assert_eq!(iter.len(), 4);
282 assert_eq!(iter.next(), Some(Ok(m3)));
283 assert_eq!(iter.nth_back(2), Some(Ok(m4)));
284 assert_eq!(iter.len(), 0);
285 assert_eq!(iter.next(), None);
286 assert_eq!(iter.next_back(), None);
287}
288
289#[test]
290fn list_model_iter_last() {
291 let list = crate::ListStore::new::<crate::Menu>();
292 let m1 = crate::Menu::new();
293 let m2 = crate::Menu::new();
294 let m3 = crate::Menu::new();
295
296 list.append(&m1);
297 list.append(&m2);
298 list.append(&m3);
299
300 let iter = list.iter::<crate::Menu>();
301
302 assert_eq!(iter.len(), 3);
303 assert_eq!(iter.last(), Some(Ok(m3)));
304}
305
306#[test]
307fn list_model_iter_count() {
308 let list = crate::ListStore::new::<crate::Menu>();
309 let m1 = crate::Menu::new();
310 let m2 = crate::Menu::new();
311 let m3 = crate::Menu::new();
312
313 list.append(&m1);
314 list.append(&m2);
315 list.append(&m3);
316
317 let iter = list.iter::<crate::Menu>();
318
319 assert_eq!(iter.len(), 3);
320 assert_eq!(iter.count(), 3);
321}