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