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::{DoubleEndedIterator, ExactSizeIterator, FusedIterator};
8
9use crate::{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: usize = 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: usize, overflow: bool) = 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(index: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 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 &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: usize, overflow: bool) = 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<'a> ExactSizeIterator for VariantStrIter<'a> {}
200
201impl<'a> FusedIterator for VariantStrIter<'a> {}
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}
372