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 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 #[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 #[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 #[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
636pub 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
678pub 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
720pub 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 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 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 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 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 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}