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