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 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 #[inline]
61 pub unsafe fn from_glib_container(list: *mut ffi::GSList) -> SList<T> {
62 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 #[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 #[inline]
94 pub fn new() -> Self {
95 SList {
96 ptr: None,
97 phantom: PhantomData,
98 }
99 }
100
101 #[inline]
104 pub fn iter(&self) -> Iter<T> {
105 Iter::new(self)
106 }
107
108 #[inline]
111 pub fn iter_mut(&mut self) -> IterMut<T> {
112 IterMut::new(self)
113 }
114
115 #[inline]
120 pub fn is_empty(&self) -> bool {
121 self.ptr.is_none()
122 }
123
124 #[inline]
129 #[doc(alias = "g_slist_length")]
130 pub fn len(&self) -> usize {
131 self.iter().count()
132 }
133
134 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[inline]
341 pub fn clear(&mut self) {
342 *self = Self::new();
343 }
344
345 #[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 #[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 #[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 #[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
623pub 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
665pub 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
707pub 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 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 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 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 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}