1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::{iter::FusedIterator, marker::PhantomData, mem, ptr}; |
4 | |
5 | use crate::translate::*; |
6 | |
7 | // rustdoc-stripper-ignore-next |
8 | /// A list of items of type `T`. |
9 | /// |
10 | /// Behaves like an `Iterator<Item = T>` but allows modifications. |
11 | #[repr (transparent)] |
12 | pub struct List<T: TransparentPtrType> { |
13 | ptr: Option<ptr::NonNull<ffi::GList>>, |
14 | phantom: PhantomData<T>, |
15 | } |
16 | |
17 | #[doc (hidden)] |
18 | unsafe impl<T: TransparentPtrType> TransparentPtrType for List<T> {} |
19 | |
20 | #[doc (hidden)] |
21 | impl<T: TransparentPtrType> GlibPtrDefault for List<T> { |
22 | type GlibType = *mut ffi::GList; |
23 | } |
24 | |
25 | unsafe impl<T: Send + TransparentPtrType> Send for List<T> {} |
26 | |
27 | unsafe impl<T: Sync + TransparentPtrType> Sync for List<T> {} |
28 | |
29 | impl<T: TransparentPtrType> List<T> { |
30 | // rustdoc-stripper-ignore-next |
31 | /// Create a new `List` around a list. |
32 | #[inline ] |
33 | pub unsafe fn from_glib_none(list: *const ffi::GList) -> List<T> { |
34 | // Need to copy the whole list |
35 | let list = if mem::needs_drop::<T>() { |
36 | unsafe extern "C" fn copy_item<T: TransparentPtrType>( |
37 | ptr: ffi::gconstpointer, |
38 | _user_data: ffi::gpointer, |
39 | ) -> ffi::gpointer { |
40 | let mut item = mem::ManuallyDrop::new( |
41 | (*(&ptr as *const ffi::gconstpointer as *const T)).clone(), |
42 | ); |
43 | |
44 | *(&mut *item as *mut T as *mut *mut T::GlibType) as ffi::gpointer |
45 | } |
46 | |
47 | ffi::g_list_copy_deep(mut_override(list), Some(copy_item::<T>), ptr::null_mut()) |
48 | } else { |
49 | ffi::g_list_copy(mut_override(list)) |
50 | }; |
51 | |
52 | List { |
53 | ptr: ptr::NonNull::new(list), |
54 | phantom: PhantomData, |
55 | } |
56 | } |
57 | |
58 | // rustdoc-stripper-ignore-next |
59 | /// Create a new `List` around a list. |
60 | #[inline ] |
61 | pub unsafe fn from_glib_container(list: *mut ffi::GList) -> List<T> { |
62 | // Need to copy all items as we only own the container |
63 | if mem::needs_drop::<T>() { |
64 | unsafe extern "C" fn copy_item<T: TransparentPtrType>( |
65 | ptr: ffi::gpointer, |
66 | _user_data: ffi::gpointer, |
67 | ) { |
68 | let item = (*(&ptr as *const ffi::gpointer as *const T)).clone(); |
69 | ptr::write(ptr as *mut T, item); |
70 | } |
71 | |
72 | ffi::g_list_foreach(list, Some(copy_item::<T>), ptr::null_mut()); |
73 | } |
74 | |
75 | List { |
76 | ptr: ptr::NonNull::new(list), |
77 | phantom: PhantomData, |
78 | } |
79 | } |
80 | |
81 | // rustdoc-stripper-ignore-next |
82 | /// Create a new `List` around a list. |
83 | #[inline ] |
84 | pub unsafe fn from_glib_full(list: *mut ffi::GList) -> List<T> { |
85 | List { |
86 | ptr: ptr::NonNull::new(list), |
87 | phantom: PhantomData, |
88 | } |
89 | } |
90 | |
91 | // rustdoc-stripper-ignore-next |
92 | /// Creates a new empty list. |
93 | #[inline ] |
94 | pub fn new() -> Self { |
95 | List { |
96 | ptr: None, |
97 | phantom: PhantomData, |
98 | } |
99 | } |
100 | |
101 | // rustdoc-stripper-ignore-next |
102 | /// Create a non-destructive iterator over the `List`. |
103 | #[inline ] |
104 | pub fn iter(&self) -> Iter<T> { |
105 | Iter::new(self) |
106 | } |
107 | |
108 | // rustdoc-stripper-ignore-next |
109 | /// Create a non-destructive mutable iterator over the `List`. |
110 | #[inline ] |
111 | pub fn iter_mut(&mut self) -> IterMut<T> { |
112 | IterMut::new(self) |
113 | } |
114 | |
115 | // rustdoc-stripper-ignore-next |
116 | /// Check if the list is empty. |
117 | /// |
118 | /// This operation is `O(1)`. |
119 | #[inline ] |
120 | pub fn is_empty(&self) -> bool { |
121 | self.ptr.is_none() |
122 | } |
123 | |
124 | // rustdoc-stripper-ignore-next |
125 | /// Returns the length of the list. |
126 | /// |
127 | /// This operation is `O(n)`. |
128 | #[inline ] |
129 | #[doc (alias = "g_list_length" )] |
130 | pub fn len(&self) -> usize { |
131 | self.iter().count() |
132 | } |
133 | |
134 | // rustdoc-stripper-ignore-next |
135 | /// Returns a reference to the first item of the list, if any. |
136 | /// |
137 | /// This operation is `O(1)`. |
138 | #[inline ] |
139 | #[doc (alias = "g_list_first" )] |
140 | pub fn front(&self) -> Option<&T> { |
141 | match self.ptr { |
142 | None => None, |
143 | Some(cur) => unsafe { |
144 | let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T); |
145 | Some(item) |
146 | }, |
147 | } |
148 | } |
149 | |
150 | // rustdoc-stripper-ignore-next |
151 | /// Returns a mutable reference to the first item of the list, if any. |
152 | /// |
153 | /// This operation is `O(1)`. |
154 | #[inline ] |
155 | #[doc (alias = "g_list_first" )] |
156 | pub fn front_mut(&mut self) -> Option<&mut T> { |
157 | match self.ptr { |
158 | None => None, |
159 | Some(mut cur) => unsafe { |
160 | let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T); |
161 | Some(item) |
162 | }, |
163 | } |
164 | } |
165 | |
166 | // rustdoc-stripper-ignore-next |
167 | /// Removes the front item from the list, if any. |
168 | /// |
169 | /// This operation is `O(1)`. |
170 | #[inline ] |
171 | pub fn pop_front(&mut self) -> Option<T> { |
172 | match self.ptr { |
173 | None => None, |
174 | Some(mut cur) => unsafe { |
175 | self.ptr = ptr::NonNull::new(cur.as_ref().next); |
176 | if let Some(mut next) = self.ptr { |
177 | next.as_mut().prev = ptr::null_mut(); |
178 | } |
179 | |
180 | let item = ptr::read(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T); |
181 | |
182 | ffi::g_list_free_1(cur.as_ptr()); |
183 | |
184 | Some(item) |
185 | }, |
186 | } |
187 | } |
188 | |
189 | // rustdoc-stripper-ignore-next |
190 | /// Prepends the new item to the front of the list. |
191 | /// |
192 | /// This operation is `O(1)`. |
193 | #[inline ] |
194 | #[doc (alias = "g_list_prepend" )] |
195 | pub fn push_front(&mut self, item: T) { |
196 | unsafe { |
197 | let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()); |
198 | self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_prepend( |
199 | ptr, |
200 | *(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType) |
201 | as ffi::gpointer, |
202 | ))); |
203 | } |
204 | } |
205 | |
206 | // rustdoc-stripper-ignore-next |
207 | /// Returns a reference to the last item of the list, if any. |
208 | /// |
209 | /// This operation is `O(n)`. |
210 | #[inline ] |
211 | #[doc (alias = "g_list_last" )] |
212 | pub fn back(&self) -> Option<&T> { |
213 | unsafe { |
214 | let ptr = match self.ptr { |
215 | None => return None, |
216 | Some(ptr) => ptr.as_ptr(), |
217 | }; |
218 | let last_ptr = ffi::g_list_last(ptr); |
219 | let item = &*(&(*last_ptr).data as *const ffi::gpointer as *const T); |
220 | Some(item) |
221 | } |
222 | } |
223 | |
224 | // rustdoc-stripper-ignore-next |
225 | /// Returns a mutable reference to the last item of the list, if any. |
226 | /// |
227 | /// This operation is `O(n)`. |
228 | #[inline ] |
229 | #[doc (alias = "g_list_last" )] |
230 | pub fn back_mut(&mut self) -> Option<&mut T> { |
231 | unsafe { |
232 | let ptr = match self.ptr { |
233 | None => return None, |
234 | Some(ptr) => ptr.as_ptr(), |
235 | }; |
236 | let last_ptr = ffi::g_list_last(ptr); |
237 | let item = &mut *(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T); |
238 | Some(item) |
239 | } |
240 | } |
241 | |
242 | // rustdoc-stripper-ignore-next |
243 | /// Removes the back item from the list, if any. |
244 | /// |
245 | /// This operation is `O(n)`. |
246 | #[inline ] |
247 | pub fn pop_back(&mut self) -> Option<T> { |
248 | unsafe { |
249 | let ptr = match self.ptr { |
250 | None => return None, |
251 | Some(ptr) => ptr.as_ptr(), |
252 | }; |
253 | let last_ptr = ffi::g_list_last(ptr); |
254 | let item = ptr::read(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T); |
255 | self.ptr = ptr::NonNull::new(ffi::g_list_delete_link(ptr, last_ptr)); |
256 | |
257 | Some(item) |
258 | } |
259 | } |
260 | |
261 | // rustdoc-stripper-ignore-next |
262 | /// Appends the new item to the back of the list. |
263 | /// |
264 | /// this operation is `O(n)`. |
265 | #[inline ] |
266 | #[doc (alias = "g_list_append" )] |
267 | pub fn push_back(&mut self, item: T) { |
268 | unsafe { |
269 | let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()); |
270 | self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_append( |
271 | ptr, |
272 | *(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType) |
273 | as ffi::gpointer, |
274 | ))); |
275 | } |
276 | } |
277 | |
278 | // rustdoc-stripper-ignore-next |
279 | /// Reverse the list. |
280 | /// |
281 | /// This operation is `O(n)`. |
282 | #[inline ] |
283 | #[doc (alias = "g_list_reverse" )] |
284 | pub fn reverse(&mut self) { |
285 | unsafe { |
286 | let ptr = match self.ptr { |
287 | None => return, |
288 | Some(ptr) => ptr.as_ptr(), |
289 | }; |
290 | |
291 | self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_reverse(ptr))); |
292 | } |
293 | } |
294 | |
295 | // rustdoc-stripper-ignore-next |
296 | /// Sorts the list. |
297 | /// |
298 | /// This operation is `O(n * log n)`. |
299 | #[inline ] |
300 | #[doc (alias = "g_list_sort" )] |
301 | pub fn sort(&mut self) |
302 | where |
303 | T: Ord, |
304 | { |
305 | self.sort_by(|a, b| a.cmp(b)); |
306 | } |
307 | |
308 | // rustdoc-stripper-ignore-next |
309 | /// Sorts the list. |
310 | /// |
311 | /// This operation is `O(n * log n)`. |
312 | #[inline ] |
313 | #[doc (alias = "g_list_sort" )] |
314 | pub fn sort_by<F: FnMut(&T, &T) -> std::cmp::Ordering>(&mut self, mut f: F) { |
315 | unsafe { |
316 | let ptr = match self.ptr { |
317 | None => return, |
318 | Some(ptr) => ptr.as_ptr(), |
319 | }; |
320 | |
321 | unsafe extern "C" fn func< |
322 | T: TransparentPtrType, |
323 | F: FnMut(&T, &T) -> std::cmp::Ordering, |
324 | >( |
325 | a: ffi::gconstpointer, |
326 | b: ffi::gconstpointer, |
327 | user_data: ffi::gpointer, |
328 | ) -> i32 { |
329 | let f = &mut *(user_data as *mut F); |
330 | let a = &*(&a as *const ffi::gconstpointer as *const T); |
331 | let b = &*(&b as *const ffi::gconstpointer as *const T); |
332 | f(a, b).into_glib() |
333 | } |
334 | |
335 | self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_sort_with_data( |
336 | ptr, |
337 | Some(func::<T, F>), |
338 | &mut f as *mut F as ffi::gpointer, |
339 | ))); |
340 | } |
341 | } |
342 | |
343 | // rustdoc-stripper-ignore-next |
344 | /// Removes all items from the list. |
345 | #[inline ] |
346 | pub fn clear(&mut self) { |
347 | *self = Self::new(); |
348 | } |
349 | |
350 | // rustdoc-stripper-ignore-next |
351 | /// Only keeps the item in the list for which `f` returns `true`. |
352 | #[inline ] |
353 | pub fn retain(&mut self, mut f: impl FnMut(&T) -> bool) { |
354 | if let Some(head) = self.ptr { |
355 | unsafe { |
356 | let mut ptr = head.as_ptr(); |
357 | while !ptr.is_null() { |
358 | let item = &*((*ptr).data as *const ffi::gpointer as *const T); |
359 | let next = (*ptr).next; |
360 | if !f(item) { |
361 | ptr::drop_in_place(&mut (*ptr).data as *mut ffi::gpointer as *mut T); |
362 | self.ptr = ptr::NonNull::new(ffi::g_list_delete_link(head.as_ptr(), ptr)); |
363 | } |
364 | ptr = next; |
365 | } |
366 | } |
367 | } |
368 | } |
369 | |
370 | // rustdoc-stripper-ignore-next |
371 | /// Returns the underlying pointer. |
372 | #[inline ] |
373 | pub fn as_ptr(&self) -> *const ffi::GList { |
374 | self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()) |
375 | } |
376 | |
377 | // rustdoc-stripper-ignore-next |
378 | /// Returns the underlying pointer. |
379 | #[inline ] |
380 | pub fn as_mut_ptr(&mut self) -> *mut ffi::GList { |
381 | self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()) |
382 | } |
383 | |
384 | // rustdoc-stripper-ignore-next |
385 | /// Consumes the list and returns the underlying pointer. |
386 | #[inline ] |
387 | pub fn into_raw(mut self) -> *mut ffi::GList { |
388 | self.ptr |
389 | .take() |
390 | .map(|p| p.as_ptr()) |
391 | .unwrap_or(ptr::null_mut()) |
392 | } |
393 | } |
394 | |
395 | impl<T: TransparentPtrType> Default for List<T> { |
396 | fn default() -> Self { |
397 | Self::new() |
398 | } |
399 | } |
400 | |
401 | impl<T: TransparentPtrType> Clone for List<T> { |
402 | fn clone(&self) -> Self { |
403 | unsafe { Self::from_glib_none(self.ptr.map(|p| p.as_ptr()).unwrap_or(default:ptr::null_mut())) } |
404 | } |
405 | } |
406 | |
407 | impl<T: TransparentPtrType> Drop for List<T> { |
408 | #[inline ] |
409 | fn drop(&mut self) { |
410 | if let Some(ptr: NonNull) = self.ptr { |
411 | unsafe { |
412 | if mem::needs_drop::<T>() { |
413 | unsafe extern "C" fn drop_item<T: TransparentPtrType>(mut ptr: ffi::gpointer) { |
414 | ptr::drop_in_place(&mut ptr as *mut ffi::gpointer as *mut T); |
415 | } |
416 | |
417 | ffi::g_list_free_full(list:ptr.as_ptr(), free_func:Some(drop_item::<T>)); |
418 | } else { |
419 | ffi::g_list_free(list:ptr.as_ptr()); |
420 | } |
421 | } |
422 | } |
423 | } |
424 | } |
425 | |
426 | impl<T: TransparentPtrType> std::iter::FromIterator<T> for List<T> { |
427 | #[inline ] |
428 | fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { |
429 | unsafe { |
430 | let mut iter = iter.into_iter(); |
431 | |
432 | let first = match iter.next() { |
433 | None => return Self::new(), |
434 | Some(first) => first, |
435 | }; |
436 | |
437 | let list = ffi::g_list_prepend( |
438 | ptr::null_mut(), |
439 | *(&mut *mem::ManuallyDrop::new(first) as *mut T as *mut *mut T::GlibType) |
440 | as ffi::gpointer, |
441 | ); |
442 | let mut tail = list; |
443 | for item in iter { |
444 | let new_tail = ffi::g_list_alloc(); |
445 | |
446 | (*new_tail).data = *(&mut *mem::ManuallyDrop::new(item) as *mut T |
447 | as *mut *mut T::GlibType) as ffi::gpointer; |
448 | (*new_tail).prev = tail; |
449 | (*new_tail).next = ptr::null_mut(); |
450 | (*tail).next = new_tail; |
451 | tail = new_tail; |
452 | } |
453 | |
454 | Self::from_glib_full(list) |
455 | } |
456 | } |
457 | } |
458 | |
459 | impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a List<T> { |
460 | type Item = &'a T; |
461 | type IntoIter = Iter<'a, T>; |
462 | |
463 | #[inline ] |
464 | fn into_iter(self) -> Self::IntoIter { |
465 | self.iter() |
466 | } |
467 | } |
468 | |
469 | impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a mut List<T> { |
470 | type Item = &'a mut T; |
471 | type IntoIter = IterMut<'a, T>; |
472 | |
473 | #[inline ] |
474 | fn into_iter(self) -> Self::IntoIter { |
475 | self.iter_mut() |
476 | } |
477 | } |
478 | |
479 | impl<T: TransparentPtrType> std::iter::IntoIterator for List<T> { |
480 | type Item = T; |
481 | type IntoIter = IntoIter<T>; |
482 | |
483 | #[inline ] |
484 | fn into_iter(self) -> Self::IntoIter { |
485 | IntoIter::new(self) |
486 | } |
487 | } |
488 | |
489 | impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GList> |
490 | for List<T> |
491 | { |
492 | #[inline ] |
493 | unsafe fn from_glib_none_num(ptr: *mut ffi::GList, _num: usize) -> Self { |
494 | Self::from_glib_none(list:ptr) |
495 | } |
496 | |
497 | #[inline ] |
498 | unsafe fn from_glib_container_num(ptr: *mut ffi::GList, _num: usize) -> Self { |
499 | Self::from_glib_container(list:ptr) |
500 | } |
501 | |
502 | #[inline ] |
503 | unsafe fn from_glib_full_num(ptr: *mut ffi::GList, _num: usize) -> Self { |
504 | Self::from_glib_full(list:ptr) |
505 | } |
506 | } |
507 | |
508 | impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GList> |
509 | for List<T> |
510 | { |
511 | #[inline ] |
512 | unsafe fn from_glib_none_num(ptr: *const ffi::GList, _num: usize) -> Self { |
513 | Self::from_glib_none(list:ptr) |
514 | } |
515 | |
516 | unsafe fn from_glib_container_num(_ptr: *const ffi::GList, _num: usize) -> Self { |
517 | unimplemented!(); |
518 | } |
519 | |
520 | unsafe fn from_glib_full_num(_ptr: *const ffi::GList, _num: usize) -> Self { |
521 | unimplemented!(); |
522 | } |
523 | } |
524 | |
525 | impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GList> |
526 | for List<T> |
527 | { |
528 | #[inline ] |
529 | unsafe fn from_glib_none(ptr: *mut ffi::GList) -> Self { |
530 | Self::from_glib_none(list:ptr) |
531 | } |
532 | |
533 | #[inline ] |
534 | unsafe fn from_glib_container(ptr: *mut ffi::GList) -> Self { |
535 | Self::from_glib_container(list:ptr) |
536 | } |
537 | |
538 | #[inline ] |
539 | unsafe fn from_glib_full(ptr: *mut ffi::GList) -> Self { |
540 | Self::from_glib_full(list:ptr) |
541 | } |
542 | } |
543 | |
544 | impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GList> |
545 | for List<T> |
546 | { |
547 | #[inline ] |
548 | unsafe fn from_glib_none(ptr: *const ffi::GList) -> Self { |
549 | Self::from_glib_none(list:ptr) |
550 | } |
551 | |
552 | unsafe fn from_glib_container(_ptr: *const ffi::GList) -> Self { |
553 | unimplemented!(); |
554 | } |
555 | |
556 | unsafe fn from_glib_full(_ptr: *const ffi::GList) -> Self { |
557 | unimplemented!(); |
558 | } |
559 | } |
560 | |
561 | impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut ffi::GList> for List<T> { |
562 | type Storage = PhantomData<&'a Self>; |
563 | |
564 | #[inline ] |
565 | fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GList, Self> { |
566 | Stash(self.as_ptr() as *mut _, PhantomData) |
567 | } |
568 | |
569 | #[inline ] |
570 | fn to_glib_container(&'a self) -> Stash<'a, *mut ffi::GList, Self> { |
571 | unsafe { |
572 | let ptr: *mut GList = ffi::g_malloc(n_bytes:mem::size_of::<T>().checked_mul(self.len() + 1).unwrap()) |
573 | as *mut ffi::GList; |
574 | ptr::copy_nonoverlapping(self.as_ptr(), dst:ptr, self.len() + 1); |
575 | Stash(ptr, PhantomData) |
576 | } |
577 | } |
578 | |
579 | #[inline ] |
580 | fn to_glib_full(&self) -> *mut ffi::GList { |
581 | self.clone().into_raw() |
582 | } |
583 | } |
584 | |
585 | impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const ffi::GList> for List<T> { |
586 | type Storage = PhantomData<&'a Self>; |
587 | |
588 | #[inline ] |
589 | fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GList, Self> { |
590 | Stash(self.as_ptr(), PhantomData) |
591 | } |
592 | } |
593 | |
594 | impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut ffi::GList> for List<T> { |
595 | type Storage = PhantomData<&'a mut Self>; |
596 | |
597 | #[inline ] |
598 | fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GList, Self> { |
599 | StashMut(self.as_mut_ptr(), PhantomData) |
600 | } |
601 | } |
602 | |
603 | impl<T: TransparentPtrType> IntoGlibPtr<*mut ffi::GList> for List<T> { |
604 | #[inline ] |
605 | unsafe fn into_glib_ptr(self) -> *mut ffi::GList { |
606 | self.into_raw() |
607 | } |
608 | } |
609 | |
610 | // rustdoc-stripper-ignore-next |
611 | /// A non-destructive iterator over a [`List`]. |
612 | pub struct Iter<'a, T: TransparentPtrType> { |
613 | ptr: Option<ptr::NonNull<ffi::GList>>, |
614 | phantom: PhantomData<&'a T>, |
615 | } |
616 | |
617 | impl<'a, T: TransparentPtrType> Iter<'a, T> { |
618 | #[inline ] |
619 | fn new(list: &'a List<T>) -> Iter<'a, T> { |
620 | debug_assert_eq!( |
621 | mem::size_of::<T>(), |
622 | mem::size_of::<<T as GlibPtrDefault>::GlibType>() |
623 | ); |
624 | |
625 | Iter { |
626 | ptr: list.ptr, |
627 | phantom: PhantomData, |
628 | } |
629 | } |
630 | } |
631 | |
632 | impl<'a, T: TransparentPtrType> Iterator for Iter<'a, T> { |
633 | type Item = &'a T; |
634 | |
635 | #[inline ] |
636 | fn next(&mut self) -> Option<&'a T> { |
637 | match self.ptr { |
638 | None => None, |
639 | Some(cur: NonNull) => unsafe { |
640 | self.ptr = ptr::NonNull::new(ptr:cur.as_ref().next); |
641 | |
642 | let item: &T = &*(&cur.as_ref().data as *const ffi::gpointer as *const T); |
643 | |
644 | Some(item) |
645 | }, |
646 | } |
647 | } |
648 | } |
649 | |
650 | impl<'a, T: TransparentPtrType> FusedIterator for Iter<'a, T> {} |
651 | |
652 | // rustdoc-stripper-ignore-next |
653 | /// A non-destructive iterator over a [`List`]. |
654 | pub struct IterMut<'a, T: TransparentPtrType> { |
655 | ptr: Option<ptr::NonNull<ffi::GList>>, |
656 | phantom: PhantomData<&'a mut T>, |
657 | } |
658 | |
659 | impl<'a, T: TransparentPtrType> IterMut<'a, T> { |
660 | #[inline ] |
661 | fn new(list: &'a mut List<T>) -> IterMut<'a, T> { |
662 | debug_assert_eq!( |
663 | mem::size_of::<T>(), |
664 | mem::size_of::<<T as GlibPtrDefault>::GlibType>() |
665 | ); |
666 | |
667 | IterMut { |
668 | ptr: list.ptr, |
669 | phantom: PhantomData, |
670 | } |
671 | } |
672 | } |
673 | |
674 | impl<'a, T: TransparentPtrType> Iterator for IterMut<'a, T> { |
675 | type Item = &'a mut T; |
676 | |
677 | #[inline ] |
678 | fn next(&mut self) -> Option<&'a mut T> { |
679 | match self.ptr { |
680 | None => None, |
681 | Some(mut cur: NonNull) => unsafe { |
682 | self.ptr = ptr::NonNull::new(ptr:cur.as_ref().next); |
683 | |
684 | let item: &mut T = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T); |
685 | |
686 | Some(item) |
687 | }, |
688 | } |
689 | } |
690 | } |
691 | |
692 | impl<'a, T: TransparentPtrType> FusedIterator for IterMut<'a, T> {} |
693 | |
694 | // rustdoc-stripper-ignore-next |
695 | /// A destructive iterator over a [`List`]. |
696 | pub struct IntoIter<T: TransparentPtrType> { |
697 | list: List<T>, |
698 | } |
699 | |
700 | impl<T: TransparentPtrType> IntoIter<T> { |
701 | #[inline ] |
702 | fn new(list: List<T>) -> IntoIter<T> { |
703 | debug_assert_eq!( |
704 | mem::size_of::<T>(), |
705 | mem::size_of::<<T as GlibPtrDefault>::GlibType>() |
706 | ); |
707 | |
708 | IntoIter { list } |
709 | } |
710 | } |
711 | |
712 | impl<T: TransparentPtrType> Iterator for IntoIter<T> { |
713 | type Item = T; |
714 | |
715 | #[inline ] |
716 | fn next(&mut self) -> Option<T> { |
717 | self.list.pop_front() |
718 | } |
719 | } |
720 | |
721 | impl<T: TransparentPtrType> FusedIterator for IntoIter<T> {} |
722 | |
723 | #[cfg (test)] |
724 | mod test { |
725 | use super::*; |
726 | |
727 | #[test ] |
728 | // checker-ignore-item |
729 | fn from_glib_full() { |
730 | let items = [ |
731 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), |
732 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), |
733 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), |
734 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), |
735 | ]; |
736 | let mut list = unsafe { |
737 | let mut list = ffi::g_list_append( |
738 | ptr::null_mut(), |
739 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[0]) as ffi::gpointer, |
740 | ); |
741 | list = ffi::g_list_append( |
742 | list, |
743 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[1]) as ffi::gpointer, |
744 | ); |
745 | list = ffi::g_list_append( |
746 | list, |
747 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[2]) as ffi::gpointer, |
748 | ); |
749 | list = ffi::g_list_append( |
750 | list, |
751 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[3]) as ffi::gpointer, |
752 | ); |
753 | List::<crate::DateTime>::from_glib_full(list) |
754 | }; |
755 | assert!(!list.is_empty()); |
756 | |
757 | let list_items = list.iter().cloned().collect::<Vec<_>>(); |
758 | assert_eq!(&items[..], &list_items); |
759 | |
760 | let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>(); |
761 | assert_eq!(&items[..], &list_items); |
762 | |
763 | let list_items = list.into_iter().collect::<Vec<_>>(); |
764 | assert_eq!(&items[..], &list_items); |
765 | |
766 | let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) }; |
767 | assert!(list.is_empty()); |
768 | } |
769 | |
770 | #[test ] |
771 | // checker-ignore-item |
772 | fn from_glib_container() { |
773 | let items = [ |
774 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), |
775 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), |
776 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), |
777 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), |
778 | ]; |
779 | let mut list = unsafe { |
780 | let mut list = ffi::g_list_append( |
781 | ptr::null_mut(), |
782 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer, |
783 | ); |
784 | list = ffi::g_list_append( |
785 | list, |
786 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer, |
787 | ); |
788 | list = ffi::g_list_append( |
789 | list, |
790 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer, |
791 | ); |
792 | list = ffi::g_list_append( |
793 | list, |
794 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer, |
795 | ); |
796 | List::<crate::DateTime>::from_glib_container(list) |
797 | }; |
798 | assert!(!list.is_empty()); |
799 | |
800 | let list_items = list.iter().cloned().collect::<Vec<_>>(); |
801 | assert_eq!(&items[..], &list_items); |
802 | |
803 | let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>(); |
804 | assert_eq!(&items[..], &list_items); |
805 | |
806 | let list_items = list.into_iter().collect::<Vec<_>>(); |
807 | assert_eq!(&items[..], &list_items); |
808 | |
809 | let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) }; |
810 | assert!(list.is_empty()); |
811 | } |
812 | |
813 | #[test ] |
814 | // checker-ignore-item |
815 | fn from_glib_none() { |
816 | let items = [ |
817 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), |
818 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), |
819 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), |
820 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), |
821 | ]; |
822 | let mut list = unsafe { |
823 | let mut list = ffi::g_list_append( |
824 | ptr::null_mut(), |
825 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer, |
826 | ); |
827 | list = ffi::g_list_append( |
828 | list, |
829 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer, |
830 | ); |
831 | list = ffi::g_list_append( |
832 | list, |
833 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer, |
834 | ); |
835 | list = ffi::g_list_append( |
836 | list, |
837 | ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer, |
838 | ); |
839 | let res = List::<crate::DateTime>::from_glib_none(list); |
840 | ffi::g_list_free(list); |
841 | |
842 | res |
843 | }; |
844 | assert!(!list.is_empty()); |
845 | |
846 | let list_items = list.iter().cloned().collect::<Vec<_>>(); |
847 | assert_eq!(&items[..], &list_items); |
848 | |
849 | let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>(); |
850 | assert_eq!(&items[..], &list_items); |
851 | |
852 | let list_items = list.into_iter().collect::<Vec<_>>(); |
853 | assert_eq!(&items[..], &list_items); |
854 | |
855 | let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) }; |
856 | assert!(list.is_empty()); |
857 | } |
858 | |
859 | #[test ] |
860 | // checker-ignore-item |
861 | fn safe_api() { |
862 | let items = [ |
863 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), |
864 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), |
865 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), |
866 | crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), |
867 | ]; |
868 | |
869 | let mut list = items[1..3].iter().cloned().collect::<List<_>>(); |
870 | assert_eq!(list.len(), 2); |
871 | list.push_front(items[0].clone()); |
872 | assert_eq!(list.len(), 3); |
873 | list.push_back(items[3].clone()); |
874 | assert_eq!(list.len(), 4); |
875 | |
876 | let list_items = list.iter().cloned().collect::<Vec<_>>(); |
877 | assert_eq!(&items[..], &list_items); |
878 | |
879 | assert_eq!(list.front(), Some(&items[0])); |
880 | assert_eq!(list.back(), Some(&items[3])); |
881 | assert_eq!(list.pop_front().as_ref(), Some(&items[0])); |
882 | assert_eq!(list.len(), 3); |
883 | |
884 | list.reverse(); |
885 | let mut list_items = list.iter().cloned().collect::<Vec<_>>(); |
886 | list_items.reverse(); |
887 | assert_eq!(&items[1..], &list_items); |
888 | |
889 | let list2 = list.clone(); |
890 | let mut list_items = list2.iter().cloned().collect::<Vec<_>>(); |
891 | list_items.reverse(); |
892 | assert_eq!(&items[1..], &list_items); |
893 | } |
894 | } |
895 | |