glib/
variant_iter.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// This is similar to the GVariantIter provided by glib, but that would
4// introduce a heap allocation and doesn't provide a way to determine how
5// many items are left in the iterator.
6
7use std::iter::FusedIterator;
8
9use crate::{ffi, translate::*, Variant};
10
11// rustdoc-stripper-ignore-next
12/// Iterator over items in a variant.
13#[derive(Debug)]
14pub struct VariantIter {
15    variant: Variant,
16    head: usize,
17    tail: usize,
18}
19
20impl VariantIter {
21    pub(crate) fn new(variant: Variant) -> Self {
22        let tail = variant.n_children();
23        Self {
24            variant,
25            head: 0,
26            tail,
27        }
28    }
29}
30
31impl Iterator for VariantIter {
32    type Item = Variant;
33
34    fn next(&mut self) -> Option<Variant> {
35        if self.head == self.tail {
36            None
37        } else {
38            let value = self.variant.child_value(self.head);
39            self.head += 1;
40            Some(value)
41        }
42    }
43
44    fn size_hint(&self) -> (usize, Option<usize>) {
45        let size = self.tail - self.head;
46        (size, Some(size))
47    }
48
49    fn count(self) -> usize {
50        self.tail - self.head
51    }
52
53    fn nth(&mut self, n: usize) -> Option<Variant> {
54        let (end, overflow) = self.head.overflowing_add(n);
55        if end >= self.tail || overflow {
56            self.head = self.tail;
57            None
58        } else {
59            self.head = end + 1;
60            Some(self.variant.child_value(end))
61        }
62    }
63
64    fn last(self) -> Option<Variant> {
65        if self.head == self.tail {
66            None
67        } else {
68            Some(self.variant.child_value(self.tail - 1))
69        }
70    }
71}
72
73impl DoubleEndedIterator for VariantIter {
74    fn next_back(&mut self) -> Option<Variant> {
75        if self.head == self.tail {
76            None
77        } else {
78            self.tail -= 1;
79            Some(self.variant.child_value(self.tail))
80        }
81    }
82
83    fn nth_back(&mut self, n: usize) -> Option<Variant> {
84        let (end, overflow) = self.tail.overflowing_sub(n);
85        if end <= self.head || overflow {
86            self.head = self.tail;
87            None
88        } else {
89            self.tail = end - 1;
90            Some(self.variant.child_value(end - 1))
91        }
92    }
93}
94
95impl ExactSizeIterator for VariantIter {}
96
97impl FusedIterator for VariantIter {}
98
99// rustdoc-stripper-ignore-next
100/// Iterator over items in a variant of type `as`.
101#[derive(Debug)]
102pub struct VariantStrIter<'a> {
103    variant: &'a Variant,
104    head: usize,
105    tail: usize,
106}
107
108impl<'a> VariantStrIter<'a> {
109    pub(crate) fn new(variant: &'a Variant) -> Self {
110        let tail = variant.n_children();
111        Self {
112            variant,
113            head: 0,
114            tail,
115        }
116    }
117
118    fn impl_get(&self, i: usize) -> &'a str {
119        unsafe {
120            let mut p: *mut libc::c_char = std::ptr::null_mut();
121            let s = b"&s\0";
122            ffi::g_variant_get_child(
123                self.variant.to_glib_none().0,
124                i,
125                s as *const u8 as *const _,
126                &mut p,
127                std::ptr::null::<i8>(),
128            );
129            let p = std::ffi::CStr::from_ptr(p);
130            p.to_str().unwrap()
131        }
132    }
133}
134
135impl<'a> Iterator for VariantStrIter<'a> {
136    type Item = &'a str;
137
138    fn next(&mut self) -> Option<&'a str> {
139        if self.head == self.tail {
140            None
141        } else {
142            let v = self.impl_get(self.head);
143            self.head += 1;
144            Some(v)
145        }
146    }
147
148    fn size_hint(&self) -> (usize, Option<usize>) {
149        let size = self.tail - self.head;
150        (size, Some(size))
151    }
152
153    fn count(self) -> usize {
154        self.tail - self.head
155    }
156
157    fn nth(&mut self, n: usize) -> Option<&'a str> {
158        let (end, overflow) = self.head.overflowing_add(n);
159        if end >= self.tail || overflow {
160            self.head = self.tail;
161            None
162        } else {
163            self.head = end + 1;
164            Some(self.impl_get(end))
165        }
166    }
167
168    fn last(self) -> Option<&'a str> {
169        if self.head == self.tail {
170            None
171        } else {
172            Some(self.impl_get(self.tail - 1))
173        }
174    }
175}
176
177impl<'a> DoubleEndedIterator for VariantStrIter<'a> {
178    fn next_back(&mut self) -> Option<&'a str> {
179        if self.head == self.tail {
180            None
181        } else {
182            self.tail -= 1;
183            Some(self.impl_get(self.tail))
184        }
185    }
186
187    fn nth_back(&mut self, n: usize) -> Option<&'a str> {
188        let (end, overflow) = self.tail.overflowing_sub(n);
189        if end <= self.head || overflow {
190            self.head = self.tail;
191            None
192        } else {
193            self.tail = end - 1;
194            Some(self.impl_get(end - 1))
195        }
196    }
197}
198
199impl ExactSizeIterator for VariantStrIter<'_> {}
200
201impl FusedIterator for VariantStrIter<'_> {}
202
203#[cfg(test)]
204mod tests {
205    use std::collections::HashMap;
206
207    use crate::{
208        prelude::*,
209        variant::{DictEntry, Variant},
210    };
211
212    #[test]
213    fn test_variant_iter_variant() {
214        let v = Variant::from_variant(&"foo".to_string().to_variant());
215        let vec: Vec<String> = v.iter().map(|i| i.get().unwrap()).collect();
216        assert_eq!(vec, vec!["foo".to_string()]);
217    }
218
219    #[test]
220    fn test_variant_iter_array() {
221        let v = Variant::array_from_iter::<String>([
222            "foo".to_string().to_variant(),
223            "bar".to_string().to_variant(),
224        ]);
225        let vec: Vec<String> = v.iter().map(|i| i.get().unwrap()).collect();
226        let a = vec!["foo".to_string(), "bar".to_string()];
227        assert_eq!(&vec, &a);
228        let vec: Vec<_> = v.array_iter_str().unwrap().collect();
229        assert_eq!(&vec, &a);
230    }
231
232    #[test]
233    fn test_variant_iter_tuple() {
234        let v = Variant::tuple_from_iter([
235            "foo".to_string().to_variant(),
236            "bar".to_string().to_variant(),
237        ]);
238        let vec: Vec<String> = v.iter().map(|i| i.get().unwrap()).collect();
239        assert_eq!(vec, vec!["foo".to_string(), "bar".to_string()]);
240    }
241
242    #[test]
243    fn test_variant_iter_dictentry() {
244        let v = DictEntry::new("foo", 1337).to_variant();
245        println!("{:?}", v.iter().collect::<Vec<_>>());
246        assert_eq!(v.iter().count(), 2);
247    }
248
249    #[test]
250    fn test_variant_iter_map() {
251        let mut map = HashMap::new();
252        map.insert("foo", 1);
253        map.insert("bar", 1);
254        let v = map.to_variant();
255        assert_eq!(v.iter().count(), 2);
256    }
257
258    #[test]
259    fn test_variant_iter_nth() {
260        let v = Variant::array_from_iter::<String>([
261            "0".to_string().to_variant(),
262            "1".to_string().to_variant(),
263            "2".to_string().to_variant(),
264            "3".to_string().to_variant(),
265            "4".to_string().to_variant(),
266            "5".to_string().to_variant(),
267        ]);
268
269        let mut iter = v.iter();
270
271        assert_eq!(iter.len(), 6);
272        assert_eq!(
273            iter.nth(1).map(|v| v.get::<String>().unwrap()),
274            Some("1".into())
275        );
276        assert_eq!(iter.len(), 4);
277        assert_eq!(
278            iter.next().map(|v| v.get::<String>().unwrap()),
279            Some("2".into())
280        );
281        assert_eq!(
282            iter.nth_back(2).map(|v| v.get::<String>().unwrap()),
283            Some("3".into())
284        );
285        assert_eq!(iter.len(), 0);
286        assert_eq!(iter.next(), None);
287        assert_eq!(iter.next_back(), None);
288    }
289
290    #[test]
291    fn test_variant_iter_count() {
292        let v = Variant::array_from_iter::<String>([
293            "0".to_string().to_variant(),
294            "1".to_string().to_variant(),
295            "2".to_string().to_variant(),
296        ]);
297
298        let iter = v.iter();
299
300        assert_eq!(iter.len(), 3);
301        assert_eq!(iter.count(), 3);
302    }
303
304    #[test]
305    fn test_variant_iter_last() {
306        let v = Variant::array_from_iter::<String>([
307            "0".to_string().to_variant(),
308            "1".to_string().to_variant(),
309            "2".to_string().to_variant(),
310        ]);
311
312        let iter = v.iter();
313
314        assert_eq!(iter.len(), 3);
315        assert_eq!(
316            iter.last().map(|v| v.get::<String>().unwrap()),
317            Some("2".into())
318        );
319    }
320
321    #[test]
322    fn test_variant_str_iter_nth() {
323        let v = Variant::array_from_iter::<String>([
324            "0".to_string().to_variant(),
325            "1".to_string().to_variant(),
326            "2".to_string().to_variant(),
327            "3".to_string().to_variant(),
328            "4".to_string().to_variant(),
329            "5".to_string().to_variant(),
330        ]);
331
332        let mut iter = v.array_iter_str().unwrap();
333
334        assert_eq!(iter.len(), 6);
335        assert_eq!(iter.nth(1), Some("1"));
336        assert_eq!(iter.len(), 4);
337        assert_eq!(iter.next(), Some("2"));
338        assert_eq!(iter.nth_back(2), Some("3"));
339        assert_eq!(iter.len(), 0);
340        assert_eq!(iter.next(), None);
341        assert_eq!(iter.next_back(), None);
342    }
343
344    #[test]
345    fn test_variant_str_iter_count() {
346        let v = Variant::array_from_iter::<String>([
347            "0".to_string().to_variant(),
348            "1".to_string().to_variant(),
349            "2".to_string().to_variant(),
350        ]);
351
352        let iter = v.array_iter_str().unwrap();
353
354        assert_eq!(iter.len(), 3);
355        assert_eq!(iter.count(), 3);
356    }
357
358    #[test]
359    fn test_variant_str_iter_last() {
360        let v = Variant::array_from_iter::<String>([
361            "0".to_string().to_variant(),
362            "1".to_string().to_variant(),
363            "2".to_string().to_variant(),
364        ]);
365
366        let iter = v.array_iter_str().unwrap();
367
368        assert_eq!(iter.len(), 3);
369        assert_eq!(iter.last(), Some("2"));
370    }
371}