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 = match self.ptr {
223                None => return None,
224                Some(ptr) => ptr.as_ptr(),
225            };
226            let last_ptr = ffi::g_list_last(ptr);
227            let item = &*(&(*last_ptr).data as *const ffi::gpointer as *const T);
228            Some(item)
229        }
230    }
231
232    // rustdoc-stripper-ignore-next
233    /// Returns a mutable reference to the last item of the list, if any.
234    ///
235    /// This operation is `O(n)`.
236    #[inline]
237    #[doc(alias = "g_list_last")]
238    pub fn back_mut(&mut self) -> Option<&mut T> {
239        unsafe {
240            let ptr = match self.ptr {
241                None => return None,
242                Some(ptr) => ptr.as_ptr(),
243            };
244            let last_ptr = ffi::g_list_last(ptr);
245            let item = &mut *(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T);
246            Some(item)
247        }
248    }
249
250    // rustdoc-stripper-ignore-next
251    /// Removes the back item from the list, if any.
252    ///
253    /// This operation is `O(n)`.
254    #[inline]
255    pub fn pop_back(&mut self) -> Option<T> {
256        unsafe {
257            let ptr = match self.ptr {
258                None => return None,
259                Some(ptr) => ptr.as_ptr(),
260            };
261            let last_ptr = ffi::g_list_last(ptr);
262            let item = ptr::read(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T);
263            self.ptr = ptr::NonNull::new(ffi::g_list_delete_link(ptr, last_ptr));
264
265            Some(item)
266        }
267    }
268
269    // rustdoc-stripper-ignore-next
270    /// Appends the new item to the back of the list.
271    ///
272    /// this operation is `O(n)`.
273    #[inline]
274    #[doc(alias = "g_list_append")]
275    pub fn push_back(&mut self, item: T) {
276        unsafe {
277            let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut());
278            self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_append(
279                ptr,
280                *(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType)
281                    as ffi::gpointer,
282            )));
283        }
284    }
285
286    // rustdoc-stripper-ignore-next
287    /// Reverse the list.
288    ///
289    /// This operation is `O(n)`.
290    #[inline]
291    #[doc(alias = "g_list_reverse")]
292    pub fn reverse(&mut self) {
293        unsafe {
294            let ptr = match self.ptr {
295                None => return,
296                Some(ptr) => ptr.as_ptr(),
297            };
298
299            self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_reverse(ptr)));
300        }
301    }
302
303    // rustdoc-stripper-ignore-next
304    /// Sorts the list.
305    ///
306    /// This operation is `O(n * log n)`.
307    #[inline]
308    #[doc(alias = "g_list_sort")]
309    pub fn sort(&mut self)
310    where
311        T: Ord,
312    {
313        self.sort_by(|a, b| a.cmp(b));
314    }
315
316    // rustdoc-stripper-ignore-next
317    /// Sorts the list.
318    ///
319    /// This operation is `O(n * log n)`.
320    #[inline]
321    #[doc(alias = "g_list_sort")]
322    pub fn sort_by<F: FnMut(&T, &T) -> std::cmp::Ordering>(&mut self, mut f: F) {
323        unsafe {
324            let ptr = match self.ptr {
325                None => return,
326                Some(ptr) => ptr.as_ptr(),
327            };
328
329            unsafe extern "C" fn func<
330                T: TransparentPtrType,
331                F: FnMut(&T, &T) -> std::cmp::Ordering,
332            >(
333                a: ffi::gconstpointer,
334                b: ffi::gconstpointer,
335                user_data: ffi::gpointer,
336            ) -> i32 {
337                unsafe {
338                    let f = &mut *(user_data as *mut F);
339                    let a = &*(&a as *const ffi::gconstpointer as *const T);
340                    let b = &*(&b as *const ffi::gconstpointer as *const T);
341                    f(a, b).into_glib()
342                }
343            }
344
345            self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_sort_with_data(
346                ptr,
347                Some(func::<T, F>),
348                &mut f as *mut F as ffi::gpointer,
349            )));
350        }
351    }
352
353    // rustdoc-stripper-ignore-next
354    /// Removes all items from the list.
355    #[inline]
356    pub fn clear(&mut self) {
357        *self = Self::new();
358    }
359
360    // rustdoc-stripper-ignore-next
361    /// Only keeps the item in the list for which `f` returns `true`.
362    #[inline]
363    pub fn retain(&mut self, mut f: impl FnMut(&T) -> bool) {
364        if let Some(head) = self.ptr {
365            unsafe {
366                let mut ptr = head.as_ptr();
367                while !ptr.is_null() {
368                    let item = &*(&(*ptr).data as *const ffi::gpointer as *const T);
369                    let next = (*ptr).next;
370                    if !f(item) {
371                        ptr::drop_in_place(&mut (*ptr).data as *mut ffi::gpointer as *mut T);
372                        self.ptr = ptr::NonNull::new(ffi::g_list_delete_link(head.as_ptr(), ptr));
373                    }
374                    ptr = next;
375                }
376            }
377        }
378    }
379
380    // rustdoc-stripper-ignore-next
381    /// Returns the underlying pointer.
382    #[inline]
383    pub fn as_ptr(&self) -> *const ffi::GList {
384        self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
385    }
386
387    // rustdoc-stripper-ignore-next
388    /// Returns the underlying pointer.
389    #[inline]
390    pub fn as_mut_ptr(&mut self) -> *mut ffi::GList {
391        self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
392    }
393
394    // rustdoc-stripper-ignore-next
395    /// Consumes the list and returns the underlying pointer.
396    #[inline]
397    pub fn into_raw(mut self) -> *mut ffi::GList {
398        self.ptr
399            .take()
400            .map(|p| p.as_ptr())
401            .unwrap_or(ptr::null_mut())
402    }
403}
404
405impl<T: TransparentPtrType> Default for List<T> {
406    fn default() -> Self {
407        Self::new()
408    }
409}
410
411impl<T: TransparentPtrType> Clone for List<T> {
412    fn clone(&self) -> Self {
413        unsafe { Self::from_glib_none(self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())) }
414    }
415}
416
417impl<T: TransparentPtrType> Drop for List<T> {
418    #[inline]
419    fn drop(&mut self) {
420        if let Some(ptr) = self.ptr {
421            unsafe {
422                if mem::needs_drop::<T>() {
423                    unsafe extern "C" fn drop_item<T: TransparentPtrType>(mut ptr: ffi::gpointer) {
424                        unsafe {
425                            ptr::drop_in_place(&mut ptr as *mut ffi::gpointer as *mut T);
426                        }
427                    }
428
429                    ffi::g_list_free_full(ptr.as_ptr(), Some(drop_item::<T>));
430                } else {
431                    ffi::g_list_free(ptr.as_ptr());
432                }
433            }
434        }
435    }
436}
437
438impl<T: TransparentPtrType> std::iter::FromIterator<T> for List<T> {
439    #[inline]
440    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
441        unsafe {
442            let mut iter = iter.into_iter();
443
444            let first = match iter.next() {
445                None => return Self::new(),
446                Some(first) => first,
447            };
448
449            let list = ffi::g_list_prepend(
450                ptr::null_mut(),
451                *(&mut *mem::ManuallyDrop::new(first) as *mut T as *mut *mut T::GlibType)
452                    as ffi::gpointer,
453            );
454            let mut tail = list;
455            for item in iter {
456                let new_tail = ffi::g_list_alloc();
457
458                (*new_tail).data = *(&mut *mem::ManuallyDrop::new(item) as *mut T
459                    as *mut *mut T::GlibType) as ffi::gpointer;
460                (*new_tail).prev = tail;
461                (*new_tail).next = ptr::null_mut();
462                (*tail).next = new_tail;
463                tail = new_tail;
464            }
465
466            Self::from_glib_full(list)
467        }
468    }
469}
470
471impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a List<T> {
472    type Item = &'a T;
473    type IntoIter = Iter<'a, T>;
474
475    #[inline]
476    fn into_iter(self) -> Self::IntoIter {
477        self.iter()
478    }
479}
480
481impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a mut List<T> {
482    type Item = &'a mut T;
483    type IntoIter = IterMut<'a, T>;
484
485    #[inline]
486    fn into_iter(self) -> Self::IntoIter {
487        self.iter_mut()
488    }
489}
490
491impl<T: TransparentPtrType> std::iter::IntoIterator for List<T> {
492    type Item = T;
493    type IntoIter = IntoIter<T>;
494
495    #[inline]
496    fn into_iter(self) -> Self::IntoIter {
497        IntoIter::new(self)
498    }
499}
500
501impl<T: TransparentPtrType> std::iter::Extend<T> for List<T> {
502    #[inline]
503    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
504        let list = iter.into_iter().collect::<Self>();
505        if list.is_empty() {
506            return;
507        }
508        match self.ptr.map(|p| p.as_ptr()) {
509            Some(ptr1) => {
510                let ptr2 = list.into_raw();
511                let _ = unsafe { ffi::g_list_concat(ptr1, ptr2) };
512            }
513            None => {
514                self.ptr = ptr::NonNull::new(list.into_raw());
515            }
516        }
517    }
518}
519
520impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GList>
521    for List<T>
522{
523    #[inline]
524    unsafe fn from_glib_none_num(ptr: *mut ffi::GList, _num: usize) -> Self {
525        unsafe { Self::from_glib_none(ptr) }
526    }
527
528    #[inline]
529    unsafe fn from_glib_container_num(ptr: *mut ffi::GList, _num: usize) -> Self {
530        unsafe { Self::from_glib_container(ptr) }
531    }
532
533    #[inline]
534    unsafe fn from_glib_full_num(ptr: *mut ffi::GList, _num: usize) -> Self {
535        unsafe { Self::from_glib_full(ptr) }
536    }
537}
538
539impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GList>
540    for List<T>
541{
542    #[inline]
543    unsafe fn from_glib_none_num(ptr: *const ffi::GList, _num: usize) -> Self {
544        unsafe { Self::from_glib_none(ptr) }
545    }
546
547    unsafe fn from_glib_container_num(_ptr: *const ffi::GList, _num: usize) -> Self {
548        unimplemented!();
549    }
550
551    unsafe fn from_glib_full_num(_ptr: *const ffi::GList, _num: usize) -> Self {
552        unimplemented!();
553    }
554}
555
556impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GList>
557    for List<T>
558{
559    #[inline]
560    unsafe fn from_glib_none(ptr: *mut ffi::GList) -> Self {
561        unsafe { Self::from_glib_none(ptr) }
562    }
563
564    #[inline]
565    unsafe fn from_glib_container(ptr: *mut ffi::GList) -> Self {
566        unsafe { Self::from_glib_container(ptr) }
567    }
568
569    #[inline]
570    unsafe fn from_glib_full(ptr: *mut ffi::GList) -> Self {
571        unsafe { Self::from_glib_full(ptr) }
572    }
573}
574
575impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GList>
576    for List<T>
577{
578    #[inline]
579    unsafe fn from_glib_none(ptr: *const ffi::GList) -> Self {
580        unsafe { Self::from_glib_none(ptr) }
581    }
582
583    unsafe fn from_glib_container(_ptr: *const ffi::GList) -> Self {
584        unimplemented!();
585    }
586
587    unsafe fn from_glib_full(_ptr: *const ffi::GList) -> Self {
588        unimplemented!();
589    }
590}
591
592impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut ffi::GList> for List<T> {
593    type Storage = PhantomData<&'a Self>;
594
595    #[inline]
596    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GList, Self> {
597        Stash(self.as_ptr() as *mut _, PhantomData)
598    }
599
600    #[inline]
601    fn to_glib_container(&'a self) -> Stash<'a, *mut ffi::GList, Self> {
602        unsafe {
603            let ptr = ffi::g_malloc(mem::size_of::<T>().checked_mul(self.len() + 1).unwrap())
604                as *mut ffi::GList;
605            ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1);
606            Stash(ptr, PhantomData)
607        }
608    }
609
610    #[inline]
611    fn to_glib_full(&self) -> *mut ffi::GList {
612        self.clone().into_raw()
613    }
614}
615
616impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const ffi::GList> for List<T> {
617    type Storage = PhantomData<&'a Self>;
618
619    #[inline]
620    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GList, Self> {
621        Stash(self.as_ptr(), PhantomData)
622    }
623}
624
625impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut ffi::GList> for List<T> {
626    type Storage = PhantomData<&'a mut Self>;
627
628    #[inline]
629    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GList, Self> {
630        StashMut(self.as_mut_ptr(), PhantomData)
631    }
632}
633
634impl<T: TransparentPtrType> IntoGlibPtr<*mut ffi::GList> for List<T> {
635    #[inline]
636    fn into_glib_ptr(self) -> *mut ffi::GList {
637        self.into_raw()
638    }
639}
640
641// rustdoc-stripper-ignore-next
642/// A non-destructive iterator over a [`List`].
643pub struct Iter<'a, T: TransparentPtrType> {
644    ptr: Option<ptr::NonNull<ffi::GList>>,
645    phantom: PhantomData<&'a T>,
646}
647
648impl<'a, T: TransparentPtrType> Iter<'a, T> {
649    #[inline]
650    fn new(list: &'a List<T>) -> Iter<'a, T> {
651        debug_assert_eq!(
652            mem::size_of::<T>(),
653            mem::size_of::<<T as GlibPtrDefault>::GlibType>()
654        );
655
656        Iter {
657            ptr: list.ptr,
658            phantom: PhantomData,
659        }
660    }
661}
662
663impl<'a, T: TransparentPtrType> Iterator for Iter<'a, T> {
664    type Item = &'a T;
665
666    #[inline]
667    fn next(&mut self) -> Option<&'a T> {
668        match self.ptr {
669            None => None,
670            Some(cur) => unsafe {
671                self.ptr = ptr::NonNull::new(cur.as_ref().next);
672
673                let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T);
674
675                Some(item)
676            },
677        }
678    }
679}
680
681impl<T: TransparentPtrType> FusedIterator for Iter<'_, T> {}
682
683// rustdoc-stripper-ignore-next
684/// A non-destructive iterator over a [`List`].
685pub struct IterMut<'a, T: TransparentPtrType> {
686    ptr: Option<ptr::NonNull<ffi::GList>>,
687    phantom: PhantomData<&'a mut T>,
688}
689
690impl<'a, T: TransparentPtrType> IterMut<'a, T> {
691    #[inline]
692    fn new(list: &'a mut List<T>) -> IterMut<'a, T> {
693        debug_assert_eq!(
694            mem::size_of::<T>(),
695            mem::size_of::<<T as GlibPtrDefault>::GlibType>()
696        );
697
698        IterMut {
699            ptr: list.ptr,
700            phantom: PhantomData,
701        }
702    }
703}
704
705impl<'a, T: TransparentPtrType> Iterator for IterMut<'a, T> {
706    type Item = &'a mut T;
707
708    #[inline]
709    fn next(&mut self) -> Option<&'a mut T> {
710        match self.ptr {
711            None => None,
712            Some(mut cur) => unsafe {
713                self.ptr = ptr::NonNull::new(cur.as_ref().next);
714
715                let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
716
717                Some(item)
718            },
719        }
720    }
721}
722
723impl<T: TransparentPtrType> FusedIterator for IterMut<'_, T> {}
724
725// rustdoc-stripper-ignore-next
726/// A destructive iterator over a [`List`].
727pub struct IntoIter<T: TransparentPtrType> {
728    list: List<T>,
729}
730
731impl<T: TransparentPtrType> IntoIter<T> {
732    #[inline]
733    fn new(list: List<T>) -> IntoIter<T> {
734        debug_assert_eq!(
735            mem::size_of::<T>(),
736            mem::size_of::<<T as GlibPtrDefault>::GlibType>()
737        );
738
739        IntoIter { list }
740    }
741}
742
743impl<T: TransparentPtrType> Iterator for IntoIter<T> {
744    type Item = T;
745
746    #[inline]
747    fn next(&mut self) -> Option<T> {
748        self.list.pop_front()
749    }
750}
751
752impl<T: TransparentPtrType> FusedIterator for IntoIter<T> {}
753
754#[cfg(test)]
755mod test {
756    use super::*;
757
758    #[test]
759    // checker-ignore-item
760    fn from_glib_full() {
761        let items = [
762            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
763            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
764            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
765            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
766        ];
767        let mut list = unsafe {
768            let mut list = ffi::g_list_append(
769                ptr::null_mut(),
770                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[0]) as ffi::gpointer,
771            );
772            list = ffi::g_list_append(
773                list,
774                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[1]) as ffi::gpointer,
775            );
776            list = ffi::g_list_append(
777                list,
778                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[2]) as ffi::gpointer,
779            );
780            list = ffi::g_list_append(
781                list,
782                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[3]) as ffi::gpointer,
783            );
784            List::<crate::DateTime>::from_glib_full(list)
785        };
786        assert!(!list.is_empty());
787
788        let list_items = list.iter().cloned().collect::<Vec<_>>();
789        assert_eq!(&items[..], &list_items);
790
791        let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
792        assert_eq!(&items[..], &list_items);
793
794        let list_items = list.into_iter().collect::<Vec<_>>();
795        assert_eq!(&items[..], &list_items);
796
797        let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
798        assert!(list.is_empty());
799    }
800
801    #[test]
802    // checker-ignore-item
803    fn from_glib_container() {
804        let items = [
805            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
806            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
807            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
808            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
809        ];
810        let mut list = unsafe {
811            let mut list = ffi::g_list_append(
812                ptr::null_mut(),
813                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
814            );
815            list = ffi::g_list_append(
816                list,
817                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
818            );
819            list = ffi::g_list_append(
820                list,
821                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
822            );
823            list = ffi::g_list_append(
824                list,
825                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
826            );
827            List::<crate::DateTime>::from_glib_container(list)
828        };
829        assert!(!list.is_empty());
830
831        let list_items = list.iter().cloned().collect::<Vec<_>>();
832        assert_eq!(&items[..], &list_items);
833
834        let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
835        assert_eq!(&items[..], &list_items);
836
837        let list_items = list.into_iter().collect::<Vec<_>>();
838        assert_eq!(&items[..], &list_items);
839
840        let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
841        assert!(list.is_empty());
842    }
843
844    #[test]
845    // checker-ignore-item
846    fn from_glib_none() {
847        let items = [
848            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
849            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
850            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
851            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
852        ];
853        let mut list = unsafe {
854            let mut list = ffi::g_list_append(
855                ptr::null_mut(),
856                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
857            );
858            list = ffi::g_list_append(
859                list,
860                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
861            );
862            list = ffi::g_list_append(
863                list,
864                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
865            );
866            list = ffi::g_list_append(
867                list,
868                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
869            );
870            let res = List::<crate::DateTime>::from_glib_none(list);
871            ffi::g_list_free(list);
872
873            res
874        };
875        assert!(!list.is_empty());
876
877        let list_items = list.iter().cloned().collect::<Vec<_>>();
878        assert_eq!(&items[..], &list_items);
879
880        let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
881        assert_eq!(&items[..], &list_items);
882
883        let list_items = list.into_iter().collect::<Vec<_>>();
884        assert_eq!(&items[..], &list_items);
885
886        let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
887        assert!(list.is_empty());
888    }
889
890    #[test]
891    // checker-ignore-item
892    fn safe_api() {
893        let items = [
894            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
895            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
896            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
897            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
898        ];
899
900        let mut list = items[1..3].iter().cloned().collect::<List<_>>();
901        assert_eq!(list.len(), 2);
902        list.push_front(items[0].clone());
903        assert_eq!(list.len(), 3);
904        list.push_back(items[3].clone());
905        assert_eq!(list.len(), 4);
906
907        let list_items = list.iter().cloned().collect::<Vec<_>>();
908        assert_eq!(&items[..], &list_items);
909
910        assert_eq!(list.front(), Some(&items[0]));
911        assert_eq!(list.back(), Some(&items[3]));
912        assert_eq!(list.pop_front().as_ref(), Some(&items[0]));
913        assert_eq!(list.len(), 3);
914
915        list.reverse();
916        let mut list_items = list.iter().cloned().collect::<Vec<_>>();
917        list_items.reverse();
918        assert_eq!(&items[1..], &list_items);
919
920        let list2 = list.clone();
921        let mut list_items = list2.iter().cloned().collect::<Vec<_>>();
922        list_items.reverse();
923        assert_eq!(&items[1..], &list_items);
924
925        list.reverse();
926        let mut list3 = list.clone();
927        list3.retain(|item| item.seconds() >= 14.0);
928        let list_items = list3.iter().cloned().collect::<Vec<_>>();
929        assert_eq!(&items[2..], &list_items);
930    }
931
932    #[test]
933    fn extend() {
934        let mut list = List::<crate::DateTime>::new();
935        list.push_back(crate::DateTime::from_unix_utc(11).unwrap());
936        list.push_back(crate::DateTime::from_unix_utc(12).unwrap());
937        list.push_back(crate::DateTime::from_unix_utc(13).unwrap());
938
939        list.extend(vec![
940            crate::DateTime::from_unix_utc(21).unwrap(),
941            crate::DateTime::from_unix_utc(22).unwrap(),
942        ]);
943
944        assert_eq!(
945            list.iter().map(|dt| dt.to_unix()).collect::<Vec<_>>(),
946            vec![11, 12, 13, 21, 22]
947        );
948    }
949
950    #[test]
951    fn extend_empty_with_empty() {
952        let mut list1 = List::<crate::DateTime>::new();
953        list1.extend(vec![]);
954        assert!(list1.is_empty());
955    }
956
957    #[test]
958    fn extend_with_empty() {
959        let mut list = List::<crate::DateTime>::new();
960        list.push_back(crate::DateTime::from_unix_utc(11).unwrap());
961        list.push_back(crate::DateTime::from_unix_utc(12).unwrap());
962        list.push_back(crate::DateTime::from_unix_utc(13).unwrap());
963
964        list.extend(vec![]);
965
966        assert_eq!(
967            list.iter().map(|dt| dt.to_unix()).collect::<Vec<_>>(),
968            vec![11, 12, 13]
969        );
970    }
971
972    #[test]
973    fn extend_empty() {
974        let mut list = List::<crate::DateTime>::new();
975
976        list.extend(vec![
977            crate::DateTime::from_unix_utc(21).unwrap(),
978            crate::DateTime::from_unix_utc(22).unwrap(),
979        ]);
980
981        assert_eq!(
982            list.iter().map(|dt| dt.to_unix()).collect::<Vec<_>>(),
983            vec![21, 22]
984        );
985    }
986}