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 = 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        let mut head = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut());
365        unsafe {
366            let mut ptr = head;
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                    let mut item_ptr = (*ptr).data;
372                    head = ffi::g_list_delete_link(head, ptr);
373                    self.ptr = ptr::NonNull::new(head);
374                    ptr::drop_in_place(&mut item_ptr as *mut ffi::gpointer as *mut T);
375                }
376                ptr = next;
377            }
378        }
379    }
380
381    // rustdoc-stripper-ignore-next
382    /// Returns the underlying pointer.
383    #[inline]
384    pub fn as_ptr(&self) -> *const ffi::GList {
385        self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
386    }
387
388    // rustdoc-stripper-ignore-next
389    /// Returns the underlying pointer.
390    #[inline]
391    pub fn as_mut_ptr(&mut self) -> *mut ffi::GList {
392        self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
393    }
394
395    // rustdoc-stripper-ignore-next
396    /// Consumes the list and returns the underlying pointer.
397    #[inline]
398    pub fn into_raw(mut self) -> *mut ffi::GList {
399        self.ptr
400            .take()
401            .map(|p| p.as_ptr())
402            .unwrap_or(ptr::null_mut())
403    }
404}
405
406impl<T: TransparentPtrType> Default for List<T> {
407    fn default() -> Self {
408        Self::new()
409    }
410}
411
412impl<T: TransparentPtrType> Clone for List<T> {
413    fn clone(&self) -> Self {
414        unsafe { Self::from_glib_none(self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())) }
415    }
416}
417
418impl<T: TransparentPtrType> Drop for List<T> {
419    #[inline]
420    fn drop(&mut self) {
421        if let Some(ptr) = self.ptr.take() {
422            unsafe {
423                if mem::needs_drop::<T>() {
424                    unsafe extern "C" fn drop_item<T: TransparentPtrType>(mut ptr: ffi::gpointer) {
425                        unsafe {
426                            ptr::drop_in_place(&mut ptr as *mut ffi::gpointer as *mut T);
427                        }
428                    }
429
430                    ffi::g_list_free_full(ptr.as_ptr(), Some(drop_item::<T>));
431                } else {
432                    ffi::g_list_free(ptr.as_ptr());
433                }
434            }
435        }
436    }
437}
438
439impl<T: TransparentPtrType> std::iter::FromIterator<T> for List<T> {
440    #[inline]
441    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
442        unsafe {
443            let mut iter = iter.into_iter();
444
445            let first = match iter.next() {
446                None => return Self::new(),
447                Some(first) => first,
448            };
449
450            let list = ffi::g_list_prepend(
451                ptr::null_mut(),
452                *(&mut *mem::ManuallyDrop::new(first) as *mut T as *mut *mut T::GlibType)
453                    as ffi::gpointer,
454            );
455            let mut tail = list;
456            for item in iter {
457                let new_tail = ffi::g_list_alloc();
458
459                (*new_tail).data = *(&mut *mem::ManuallyDrop::new(item) as *mut T
460                    as *mut *mut T::GlibType) as ffi::gpointer;
461                (*new_tail).prev = tail;
462                (*new_tail).next = ptr::null_mut();
463                (*tail).next = new_tail;
464                tail = new_tail;
465            }
466
467            Self::from_glib_full(list)
468        }
469    }
470}
471
472impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a List<T> {
473    type Item = &'a T;
474    type IntoIter = Iter<'a, T>;
475
476    #[inline]
477    fn into_iter(self) -> Self::IntoIter {
478        self.iter()
479    }
480}
481
482impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a mut List<T> {
483    type Item = &'a mut T;
484    type IntoIter = IterMut<'a, T>;
485
486    #[inline]
487    fn into_iter(self) -> Self::IntoIter {
488        self.iter_mut()
489    }
490}
491
492impl<T: TransparentPtrType> std::iter::IntoIterator for List<T> {
493    type Item = T;
494    type IntoIter = IntoIter<T>;
495
496    #[inline]
497    fn into_iter(self) -> Self::IntoIter {
498        IntoIter::new(self)
499    }
500}
501
502impl<T: TransparentPtrType> std::iter::Extend<T> for List<T> {
503    #[inline]
504    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
505        let list = iter.into_iter().collect::<Self>();
506        if list.is_empty() {
507            return;
508        }
509        match self.ptr.map(|p| p.as_ptr()) {
510            Some(ptr1) => {
511                let ptr2 = list.into_raw();
512                let _ = unsafe { ffi::g_list_concat(ptr1, ptr2) };
513            }
514            None => {
515                self.ptr = ptr::NonNull::new(list.into_raw());
516            }
517        }
518    }
519}
520
521impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GList>
522    for List<T>
523{
524    #[inline]
525    unsafe fn from_glib_none_num(ptr: *mut ffi::GList, _num: usize) -> Self {
526        unsafe { Self::from_glib_none(ptr) }
527    }
528
529    #[inline]
530    unsafe fn from_glib_container_num(ptr: *mut ffi::GList, _num: usize) -> Self {
531        unsafe { Self::from_glib_container(ptr) }
532    }
533
534    #[inline]
535    unsafe fn from_glib_full_num(ptr: *mut ffi::GList, _num: usize) -> Self {
536        unsafe { Self::from_glib_full(ptr) }
537    }
538}
539
540impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GList>
541    for List<T>
542{
543    #[inline]
544    unsafe fn from_glib_none_num(ptr: *const ffi::GList, _num: usize) -> Self {
545        unsafe { Self::from_glib_none(ptr) }
546    }
547
548    unsafe fn from_glib_container_num(_ptr: *const ffi::GList, _num: usize) -> Self {
549        unimplemented!();
550    }
551
552    unsafe fn from_glib_full_num(_ptr: *const ffi::GList, _num: usize) -> Self {
553        unimplemented!();
554    }
555}
556
557impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GList>
558    for List<T>
559{
560    #[inline]
561    unsafe fn from_glib_none(ptr: *mut ffi::GList) -> Self {
562        unsafe { Self::from_glib_none(ptr) }
563    }
564
565    #[inline]
566    unsafe fn from_glib_container(ptr: *mut ffi::GList) -> Self {
567        unsafe { Self::from_glib_container(ptr) }
568    }
569
570    #[inline]
571    unsafe fn from_glib_full(ptr: *mut ffi::GList) -> Self {
572        unsafe { Self::from_glib_full(ptr) }
573    }
574}
575
576impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GList>
577    for List<T>
578{
579    #[inline]
580    unsafe fn from_glib_none(ptr: *const ffi::GList) -> Self {
581        unsafe { Self::from_glib_none(ptr) }
582    }
583
584    unsafe fn from_glib_container(_ptr: *const ffi::GList) -> Self {
585        unimplemented!();
586    }
587
588    unsafe fn from_glib_full(_ptr: *const ffi::GList) -> Self {
589        unimplemented!();
590    }
591}
592
593impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut ffi::GList> for List<T> {
594    type Storage = PhantomData<&'a Self>;
595
596    #[inline]
597    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GList, Self> {
598        Stash(self.as_ptr() as *mut _, PhantomData)
599    }
600
601    #[inline]
602    fn to_glib_container(&'a self) -> Stash<'a, *mut ffi::GList, Self> {
603        unsafe {
604            let ptr = ffi::g_malloc(mem::size_of::<T>().checked_mul(self.len() + 1).unwrap())
605                as *mut ffi::GList;
606            ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1);
607            Stash(ptr, PhantomData)
608        }
609    }
610
611    #[inline]
612    fn to_glib_full(&self) -> *mut ffi::GList {
613        self.clone().into_raw()
614    }
615}
616
617impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const ffi::GList> for List<T> {
618    type Storage = PhantomData<&'a Self>;
619
620    #[inline]
621    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GList, Self> {
622        Stash(self.as_ptr(), PhantomData)
623    }
624}
625
626impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut ffi::GList> for List<T> {
627    type Storage = PhantomData<&'a mut Self>;
628
629    #[inline]
630    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GList, Self> {
631        StashMut(self.as_mut_ptr(), PhantomData)
632    }
633}
634
635impl<T: TransparentPtrType> IntoGlibPtr<*mut ffi::GList> for List<T> {
636    #[inline]
637    fn into_glib_ptr(self) -> *mut ffi::GList {
638        self.into_raw()
639    }
640}
641
642// rustdoc-stripper-ignore-next
643/// A non-destructive iterator over a [`List`].
644pub struct Iter<'a, T: TransparentPtrType> {
645    ptr: Option<ptr::NonNull<ffi::GList>>,
646    phantom: PhantomData<&'a T>,
647}
648
649impl<'a, T: TransparentPtrType> Iter<'a, T> {
650    #[inline]
651    fn new(list: &'a List<T>) -> Iter<'a, T> {
652        debug_assert_eq!(
653            mem::size_of::<T>(),
654            mem::size_of::<<T as GlibPtrDefault>::GlibType>()
655        );
656
657        Iter {
658            ptr: list.ptr,
659            phantom: PhantomData,
660        }
661    }
662}
663
664impl<'a, T: TransparentPtrType> Iterator for Iter<'a, T> {
665    type Item = &'a T;
666
667    #[inline]
668    fn next(&mut self) -> Option<&'a T> {
669        match self.ptr {
670            None => None,
671            Some(cur) => unsafe {
672                self.ptr = ptr::NonNull::new(cur.as_ref().next);
673
674                let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T);
675
676                Some(item)
677            },
678        }
679    }
680}
681
682impl<T: TransparentPtrType> FusedIterator for Iter<'_, T> {}
683
684// rustdoc-stripper-ignore-next
685/// A non-destructive iterator over a [`List`].
686pub struct IterMut<'a, T: TransparentPtrType> {
687    ptr: Option<ptr::NonNull<ffi::GList>>,
688    phantom: PhantomData<&'a mut T>,
689}
690
691impl<'a, T: TransparentPtrType> IterMut<'a, T> {
692    #[inline]
693    fn new(list: &'a mut List<T>) -> IterMut<'a, T> {
694        debug_assert_eq!(
695            mem::size_of::<T>(),
696            mem::size_of::<<T as GlibPtrDefault>::GlibType>()
697        );
698
699        IterMut {
700            ptr: list.ptr,
701            phantom: PhantomData,
702        }
703    }
704}
705
706impl<'a, T: TransparentPtrType> Iterator for IterMut<'a, T> {
707    type Item = &'a mut T;
708
709    #[inline]
710    fn next(&mut self) -> Option<&'a mut T> {
711        match self.ptr {
712            None => None,
713            Some(mut cur) => unsafe {
714                self.ptr = ptr::NonNull::new(cur.as_ref().next);
715
716                let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
717
718                Some(item)
719            },
720        }
721    }
722}
723
724impl<T: TransparentPtrType> FusedIterator for IterMut<'_, T> {}
725
726// rustdoc-stripper-ignore-next
727/// A destructive iterator over a [`List`].
728pub struct IntoIter<T: TransparentPtrType> {
729    list: List<T>,
730}
731
732impl<T: TransparentPtrType> IntoIter<T> {
733    #[inline]
734    fn new(list: List<T>) -> IntoIter<T> {
735        debug_assert_eq!(
736            mem::size_of::<T>(),
737            mem::size_of::<<T as GlibPtrDefault>::GlibType>()
738        );
739
740        IntoIter { list }
741    }
742}
743
744impl<T: TransparentPtrType> Iterator for IntoIter<T> {
745    type Item = T;
746
747    #[inline]
748    fn next(&mut self) -> Option<T> {
749        self.list.pop_front()
750    }
751}
752
753impl<T: TransparentPtrType> FusedIterator for IntoIter<T> {}
754
755#[cfg(test)]
756mod test {
757    use super::*;
758
759    #[test]
760    // checker-ignore-item
761    fn from_glib_full() {
762        let items = [
763            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
764            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
765            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
766            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
767        ];
768        let mut list = unsafe {
769            let mut list = ffi::g_list_append(
770                ptr::null_mut(),
771                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[0]) as ffi::gpointer,
772            );
773            list = ffi::g_list_append(
774                list,
775                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[1]) as ffi::gpointer,
776            );
777            list = ffi::g_list_append(
778                list,
779                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[2]) as ffi::gpointer,
780            );
781            list = ffi::g_list_append(
782                list,
783                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[3]) as ffi::gpointer,
784            );
785            List::<crate::DateTime>::from_glib_full(list)
786        };
787        assert!(!list.is_empty());
788
789        let list_items = list.iter().cloned().collect::<Vec<_>>();
790        assert_eq!(&items[..], &list_items);
791
792        let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
793        assert_eq!(&items[..], &list_items);
794
795        let list_items = list.into_iter().collect::<Vec<_>>();
796        assert_eq!(&items[..], &list_items);
797
798        let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
799        assert!(list.is_empty());
800    }
801
802    #[test]
803    // checker-ignore-item
804    fn from_glib_container() {
805        let items = [
806            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
807            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
808            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
809            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
810        ];
811        let mut list = unsafe {
812            let mut list = ffi::g_list_append(
813                ptr::null_mut(),
814                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
815            );
816            list = ffi::g_list_append(
817                list,
818                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
819            );
820            list = ffi::g_list_append(
821                list,
822                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
823            );
824            list = ffi::g_list_append(
825                list,
826                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
827            );
828            List::<crate::DateTime>::from_glib_container(list)
829        };
830        assert!(!list.is_empty());
831
832        let list_items = list.iter().cloned().collect::<Vec<_>>();
833        assert_eq!(&items[..], &list_items);
834
835        let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
836        assert_eq!(&items[..], &list_items);
837
838        let list_items = list.into_iter().collect::<Vec<_>>();
839        assert_eq!(&items[..], &list_items);
840
841        let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
842        assert!(list.is_empty());
843    }
844
845    #[test]
846    // checker-ignore-item
847    fn from_glib_none() {
848        let items = [
849            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
850            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
851            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
852            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
853        ];
854        let mut list = unsafe {
855            let mut list = ffi::g_list_append(
856                ptr::null_mut(),
857                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
858            );
859            list = ffi::g_list_append(
860                list,
861                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
862            );
863            list = ffi::g_list_append(
864                list,
865                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
866            );
867            list = ffi::g_list_append(
868                list,
869                ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
870            );
871            let res = List::<crate::DateTime>::from_glib_none(list);
872            ffi::g_list_free(list);
873
874            res
875        };
876        assert!(!list.is_empty());
877
878        let list_items = list.iter().cloned().collect::<Vec<_>>();
879        assert_eq!(&items[..], &list_items);
880
881        let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
882        assert_eq!(&items[..], &list_items);
883
884        let list_items = list.into_iter().collect::<Vec<_>>();
885        assert_eq!(&items[..], &list_items);
886
887        let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
888        assert!(list.is_empty());
889    }
890
891    #[test]
892    // checker-ignore-item
893    fn safe_api() {
894        let items = [
895            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
896            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
897            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
898            crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
899        ];
900
901        let mut list = items[1..3].iter().cloned().collect::<List<_>>();
902        assert_eq!(list.len(), 2);
903        list.push_front(items[0].clone());
904        assert_eq!(list.len(), 3);
905        list.push_back(items[3].clone());
906        assert_eq!(list.len(), 4);
907
908        let list_items = list.iter().cloned().collect::<Vec<_>>();
909        assert_eq!(&items[..], &list_items);
910
911        assert_eq!(list.front(), Some(&items[0]));
912        assert_eq!(list.back(), Some(&items[3]));
913        assert_eq!(list.pop_front().as_ref(), Some(&items[0]));
914        assert_eq!(list.len(), 3);
915
916        list.reverse();
917        let mut list_items = list.iter().cloned().collect::<Vec<_>>();
918        list_items.reverse();
919        assert_eq!(&items[1..], &list_items);
920
921        let list2 = list.clone();
922        let mut list_items = list2.iter().cloned().collect::<Vec<_>>();
923        list_items.reverse();
924        assert_eq!(&items[1..], &list_items);
925
926        list.reverse();
927        let mut list3 = list.clone();
928        list3.retain(|item| item.seconds() >= 14.0);
929        let list_items = list3.iter().cloned().collect::<Vec<_>>();
930        assert_eq!(&items[2..], &list_items);
931    }
932
933    #[test]
934    fn extend() {
935        let mut list = List::<crate::DateTime>::new();
936        list.push_back(crate::DateTime::from_unix_utc(11).unwrap());
937        list.push_back(crate::DateTime::from_unix_utc(12).unwrap());
938        list.push_back(crate::DateTime::from_unix_utc(13).unwrap());
939
940        list.extend(vec![
941            crate::DateTime::from_unix_utc(21).unwrap(),
942            crate::DateTime::from_unix_utc(22).unwrap(),
943        ]);
944
945        assert_eq!(
946            list.iter().map(|dt| dt.to_unix()).collect::<Vec<_>>(),
947            vec![11, 12, 13, 21, 22]
948        );
949    }
950
951    #[test]
952    fn extend_empty_with_empty() {
953        let mut list1 = List::<crate::DateTime>::new();
954        list1.extend(vec![]);
955        assert!(list1.is_empty());
956    }
957
958    #[test]
959    fn extend_with_empty() {
960        let mut list = List::<crate::DateTime>::new();
961        list.push_back(crate::DateTime::from_unix_utc(11).unwrap());
962        list.push_back(crate::DateTime::from_unix_utc(12).unwrap());
963        list.push_back(crate::DateTime::from_unix_utc(13).unwrap());
964
965        list.extend(vec![]);
966
967        assert_eq!(
968            list.iter().map(|dt| dt.to_unix()).collect::<Vec<_>>(),
969            vec![11, 12, 13]
970        );
971    }
972
973    #[test]
974    fn extend_empty() {
975        let mut list = List::<crate::DateTime>::new();
976
977        list.extend(vec![
978            crate::DateTime::from_unix_utc(21).unwrap(),
979            crate::DateTime::from_unix_utc(22).unwrap(),
980        ]);
981
982        assert_eq!(
983            list.iter().map(|dt| dt.to_unix()).collect::<Vec<_>>(),
984            vec![21, 22]
985        );
986    }
987
988    #[test]
989    fn retain_deletes_head() {
990        let mut list = List::<crate::DateTime>::new();
991        let items = [
992            crate::DateTime::from_unix_utc(1).unwrap(),
993            crate::DateTime::from_unix_utc(2).unwrap(),
994            crate::DateTime::from_unix_utc(3).unwrap(),
995        ];
996        for item in &items {
997            list.push_back(item.clone());
998        }
999        assert_eq!(list.len(), 3);
1000
1001        // Delete first and second nodes, keep third
1002        list.retain(|item| item.to_unix() >= 3);
1003
1004        assert_eq!(list.len(), 1);
1005        assert_eq!(list.pop_front().unwrap().to_unix(), 3);
1006    }
1007}