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 | |
7 | use std::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator}; |
8 | |
9 | use crate::{translate::*, Variant}; |
10 | |
11 | // rustdoc-stripper-ignore-next |
12 | /// Iterator over items in a variant. |
13 | #[derive (Debug)] |
14 | pub struct VariantIter { |
15 | variant: Variant, |
16 | head: usize, |
17 | tail: usize, |
18 | } |
19 | |
20 | impl 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 | |
31 | impl 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 | |
73 | impl 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 | |
95 | impl ExactSizeIterator for VariantIter {} |
96 | |
97 | impl FusedIterator for VariantIter {} |
98 | |
99 | // rustdoc-stripper-ignore-next |
100 | /// Iterator over items in a variant of type `as`. |
101 | #[derive (Debug)] |
102 | pub struct VariantStrIter<'a> { |
103 | variant: &'a Variant, |
104 | head: usize, |
105 | tail: usize, |
106 | } |
107 | |
108 | impl<'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 | |
135 | impl<'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 | |
177 | impl<'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 | |
199 | impl<'a> ExactSizeIterator for VariantStrIter<'a> {} |
200 | |
201 | impl<'a> FusedIterator for VariantStrIter<'a> {} |
202 | |
203 | #[cfg (test)] |
204 | mod 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 | |