| 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::FusedIterator; |
| 8 | |
| 9 | use crate::{ffi, 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 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 | |
| 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 ExactSizeIterator for VariantStrIter<'_> {} |
| 200 | |
| 201 | impl FusedIterator for VariantStrIter<'_> {} |
| 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 | |