Skip to main content

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