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