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