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