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