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