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