Skip to main content

glib/collections/
list.rs

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