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