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_list_copy(mut_override(self.as_ptr()));
596            Stash(ptr, PhantomData)
597        }
598    }
599
600    #[inline]
601    fn to_glib_full(&self) -> *mut ffi::GList {
602        self.clone().into_raw()
603    }
604}
605
606impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const ffi::GList> for List<T> {
607    type Storage = PhantomData<&'a Self>;
608
609    #[inline]
610    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GList, Self> {
611        Stash(self.as_ptr(), PhantomData)
612    }
613}
614
615impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut ffi::GList> for List<T> {
616    type Storage = PhantomData<&'a mut Self>;
617
618    #[inline]
619    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GList, Self> {
620        StashMut(self.as_mut_ptr(), PhantomData)
621    }
622}
623
624impl<T: TransparentPtrType> IntoGlibPtr<*mut ffi::GList> for List<T> {
625    #[inline]
626    fn into_glib_ptr(self) -> *mut ffi::GList {
627        self.into_raw()
628    }
629}
630
631// rustdoc-stripper-ignore-next
632/// A non-destructive iterator over a [`List`].
633pub struct Iter<'a, T: TransparentPtrType> {
634    ptr: Option<ptr::NonNull<ffi::GList>>,
635    phantom: PhantomData<&'a T>,
636}
637
638impl<'a, T: TransparentPtrType> Iter<'a, T> {
639    #[inline]
640    fn new(list: &'a List<T>) -> Iter<'a, T> {
641        debug_assert_eq!(
642            mem::size_of::<T>(),
643            mem::size_of::<<T as GlibPtrDefault>::GlibType>()
644        );
645
646        Iter {
647            ptr: list.ptr,
648            phantom: PhantomData,
649        }
650    }
651}
652
653impl<'a, T: TransparentPtrType> Iterator for Iter<'a, T> {
654    type Item = &'a T;
655
656    #[inline]
657    fn next(&mut self) -> Option<&'a T> {
658        match self.ptr {
659            None => None,
660            Some(cur) => unsafe {
661                self.ptr = ptr::NonNull::new(cur.as_ref().next);
662
663                let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T);
664
665                Some(item)
666            },
667        }
668    }
669}
670
671impl<T: TransparentPtrType> FusedIterator for Iter<'_, T> {}
672
673// rustdoc-stripper-ignore-next
674/// A non-destructive iterator over a [`List`].
675pub struct IterMut<'a, T: TransparentPtrType> {
676    ptr: Option<ptr::NonNull<ffi::GList>>,
677    phantom: PhantomData<&'a mut T>,
678}
679
680impl<'a, T: TransparentPtrType> IterMut<'a, T> {
681    #[inline]
682    fn new(list: &'a mut List<T>) -> IterMut<'a, T> {
683        debug_assert_eq!(
684            mem::size_of::<T>(),
685            mem::size_of::<<T as GlibPtrDefault>::GlibType>()
686        );
687
688        IterMut {
689            ptr: list.ptr,
690            phantom: PhantomData,
691        }
692    }
693}
694
695impl<'a, T: TransparentPtrType> Iterator for IterMut<'a, T> {
696    type Item = &'a mut T;
697
698    #[inline]
699    fn next(&mut self) -> Option<&'a mut T> {
700        match self.ptr {
701            None => None,
702            Some(mut cur) => unsafe {
703                self.ptr = ptr::NonNull::new(cur.as_ref().next);
704
705                let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
706
707                Some(item)
708            },
709        }
710    }
711}
712
713impl<T: TransparentPtrType> FusedIterator for IterMut<'_, T> {}
714
715// rustdoc-stripper-ignore-next
716/// A destructive iterator over a [`List`].
717pub struct IntoIter<T: TransparentPtrType> {
718    list: List<T>,
719}
720
721impl<T: TransparentPtrType> IntoIter<T> {
722    #[inline]
723    fn new(list: List<T>) -> IntoIter<T> {
724        debug_assert_eq!(
725            mem::size_of::<T>(),
726            mem::size_of::<<T as GlibPtrDefault>::GlibType>()
727        );
728
729        IntoIter { list }
730    }
731}
732
733impl<T: TransparentPtrType> Iterator for IntoIter<T> {
734    type Item = T;
735
736    #[inline]
737    fn next(&mut self) -> Option<T> {
738        self.list.pop_front()
739    }
740}
741
742impl<T: TransparentPtrType> FusedIterator for IntoIter<T> {}
743
744#[cfg(test)]
745mod test {
746    use super::*;
747
748    #[test]
749    // checker-ignore-item
750    fn from_glib_full() {
751        let items = [
752            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
753            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
754            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
755            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
756        ];
757        let mut list = unsafe {
758            let mut list = ffi::g_list_append(
759                ptr::null_mut(),
760                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[0]) as ffi::gpointer,
761            );
762            list = ffi::g_list_append(
763                list,
764                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[1]) as ffi::gpointer,
765            );
766            list = ffi::g_list_append(
767                list,
768                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[2]) as ffi::gpointer,
769            );
770            list = ffi::g_list_append(
771                list,
772                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[3]) as ffi::gpointer,
773            );
774            List::<crate::DateTime>::from_glib_full(list)
775        };
776        assert!(!list.is_empty());
777
778        let list_items = list.iter().cloned().collect::<Vec<_>>();
779        assert_eq!(&items[..], &list_items);
780
781        let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
782        assert_eq!(&items[..], &list_items);
783
784        let list_items = list.into_iter().collect::<Vec<_>>();
785        assert_eq!(&items[..], &list_items);
786
787        let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
788        assert!(list.is_empty());
789    }
790
791    #[test]
792    // checker-ignore-item
793    fn from_glib_container() {
794        let items = [
795            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
796            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
797            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
798            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
799        ];
800        let mut list = unsafe {
801            let mut list = ffi::g_list_append(
802                ptr::null_mut(),
803                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
804            );
805            list = ffi::g_list_append(
806                list,
807                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
808            );
809            list = ffi::g_list_append(
810                list,
811                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
812            );
813            list = ffi::g_list_append(
814                list,
815                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
816            );
817            List::<crate::DateTime>::from_glib_container(list)
818        };
819        assert!(!list.is_empty());
820
821        let list_items = list.iter().cloned().collect::<Vec<_>>();
822        assert_eq!(&items[..], &list_items);
823
824        let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
825        assert_eq!(&items[..], &list_items);
826
827        let list_items = list.into_iter().collect::<Vec<_>>();
828        assert_eq!(&items[..], &list_items);
829
830        let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
831        assert!(list.is_empty());
832    }
833
834    #[test]
835    // checker-ignore-item
836    fn from_glib_none() {
837        let items = [
838            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
839            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
840            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
841            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
842        ];
843        let mut list = unsafe {
844            let mut list = ffi::g_list_append(
845                ptr::null_mut(),
846                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
847            );
848            list = ffi::g_list_append(
849                list,
850                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
851            );
852            list = ffi::g_list_append(
853                list,
854                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
855            );
856            list = ffi::g_list_append(
857                list,
858                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
859            );
860            let res = List::<crate::DateTime>::from_glib_none(list);
861            ffi::g_list_free(list);
862
863            res
864        };
865        assert!(!list.is_empty());
866
867        let list_items = list.iter().cloned().collect::<Vec<_>>();
868        assert_eq!(&items[..], &list_items);
869
870        let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
871        assert_eq!(&items[..], &list_items);
872
873        let list_items = list.into_iter().collect::<Vec<_>>();
874        assert_eq!(&items[..], &list_items);
875
876        let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
877        assert!(list.is_empty());
878    }
879
880    #[test]
881    // checker-ignore-item
882    fn safe_api() {
883        let items = [
884            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
885            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
886            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
887            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
888        ];
889
890        let mut list = items[1..3].iter().cloned().collect::<List<_>>();
891        assert_eq!(list.len(), 2);
892        list.push_front(items[0].clone());
893        assert_eq!(list.len(), 3);
894        list.push_back(items[3].clone());
895        assert_eq!(list.len(), 4);
896
897        let list_items = list.iter().cloned().collect::<Vec<_>>();
898        assert_eq!(&items[..], &list_items);
899
900        assert_eq!(list.front(), Some(&items[0]));
901        assert_eq!(list.back(), Some(&items[3]));
902        assert_eq!(list.pop_front().as_ref(), Some(&items[0]));
903        assert_eq!(list.len(), 3);
904
905        list.reverse();
906        let mut list_items = list.iter().cloned().collect::<Vec<_>>();
907        list_items.reverse();
908        assert_eq!(&items[1..], &list_items);
909
910        let list2 = list.clone();
911        let mut list_items = list2.iter().cloned().collect::<Vec<_>>();
912        list_items.reverse();
913        assert_eq!(&items[1..], &list_items);
914
915        list.reverse();
916        let mut list3 = list.clone();
917        list3.retain(|item| item.seconds() >= 14.0);
918        let list_items = list3.iter().cloned().collect::<Vec<_>>();
919        assert_eq!(&items[2..], &list_items);
920    }
921
922    #[test]
923    fn extend() {
924        let mut list = List::<crate::DateTime>::new();
925        list.push_back(crate::DateTime::from_unix_utc(11).unwrap());
926        list.push_back(crate::DateTime::from_unix_utc(12).unwrap());
927        list.push_back(crate::DateTime::from_unix_utc(13).unwrap());
928
929        list.extend(vec![
930            crate::DateTime::from_unix_utc(21).unwrap(),
931            crate::DateTime::from_unix_utc(22).unwrap(),
932        ]);
933
934        assert_eq!(
935            list.iter().map(|dt| dt.to_unix()).collect::<Vec<_>>(),
936            vec![11, 12, 13, 21, 22]
937        );
938    }
939
940    #[test]
941    fn extend_empty_with_empty() {
942        let mut list1 = List::<crate::DateTime>::new();
943        list1.extend(vec![]);
944        assert!(list1.is_empty());
945    }
946
947    #[test]
948    fn extend_with_empty() {
949        let mut list = List::<crate::DateTime>::new();
950        list.push_back(crate::DateTime::from_unix_utc(11).unwrap());
951        list.push_back(crate::DateTime::from_unix_utc(12).unwrap());
952        list.push_back(crate::DateTime::from_unix_utc(13).unwrap());
953
954        list.extend(vec![]);
955
956        assert_eq!(
957            list.iter().map(|dt| dt.to_unix()).collect::<Vec<_>>(),
958            vec![11, 12, 13]
959        );
960    }
961
962    #[test]
963    fn extend_empty() {
964        let mut list = List::<crate::DateTime>::new();
965
966        list.extend(vec![
967            crate::DateTime::from_unix_utc(21).unwrap(),
968            crate::DateTime::from_unix_utc(22).unwrap(),
969        ]);
970
971        assert_eq!(
972            list.iter().map(|dt| dt.to_unix()).collect::<Vec<_>>(),
973            vec![21, 22]
974        );
975    }
976
977    #[test]
978    fn retain_deletes_head() {
979        let mut list = List::<crate::DateTime>::new();
980        let items = [
981            crate::DateTime::from_unix_utc(1).unwrap(),
982            crate::DateTime::from_unix_utc(2).unwrap(),
983            crate::DateTime::from_unix_utc(3).unwrap(),
984        ];
985        for item in &items {
986            list.push_back(item.clone());
987        }
988        assert_eq!(list.len(), 3);
989
990        // Delete first and second nodes, keep third
991        list.retain(|item| item.to_unix() >= 3);
992
993        assert_eq!(list.len(), 1);
994        assert_eq!(list.pop_front().unwrap().to_unix(), 3);
995    }
996
997    #[test]
998    fn to_glib_container() {
999        let items = [
1000            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
1001            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
1002            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
1003            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
1004        ];
1005        let list: List<crate::DateTime> = items.iter().cloned().collect();
1006
1007        let stash = <_ as ToGlibPtr<'_, *mut ffi::GList>>::to_glib_container(&list);
1008        assert!(!stash.0.is_null());
1009        // The copy must be a separate chain of nodes sharing the same data
1010        assert_ne!(stash.0, list.as_ptr() as *mut _);
1011        assert_eq!(unsafe { (*stash.0).data }, unsafe {
1012            (*(list.as_ptr() as *mut ffi::GList)).data
1013        },);
1014
1015        let list_items = unsafe { List::<crate::DateTime>::from_glib_container(stash.0) }
1016            .into_iter()
1017            .collect::<Vec<_>>();
1018        assert_eq!(&items[..], &list_items);
1019
1020        let empty = List::<crate::DateTime>::new();
1021        let stash = <_ as ToGlibPtr<'_, *mut ffi::GList>>::to_glib_container(&empty);
1022        assert!(stash.0.is_null());
1023    }
1024}