1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{iter::FusedIterator, marker::PhantomData, mem, ptr};
4
5use crate::translate::*;
6
7// rustdoc-stripper-ignore-next
8/// A list of items of type `T`.
9///
10/// Behaves like an `Iterator<Item = T>` but allows modifications.
11#[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 // rustdoc-stripper-ignore-next
31 /// Create a new `List` around a list.
32 #[inline]
33 pub unsafe fn from_glib_none(list: *const ffi::GList) -> List<T> {
34 // Need to copy the whole list
35 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 // rustdoc-stripper-ignore-next
59 /// Create a new `List` around a list.
60 #[inline]
61 pub unsafe fn from_glib_container(list: *mut ffi::GList) -> List<T> {
62 // Need to copy all items as we only own the container
63 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 // rustdoc-stripper-ignore-next
82 /// Create a new `List` around a list.
83 #[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 // rustdoc-stripper-ignore-next
92 /// Creates a new empty list.
93 #[inline]
94 pub fn new() -> Self {
95 List {
96 ptr: None,
97 phantom: PhantomData,
98 }
99 }
100
101 // rustdoc-stripper-ignore-next
102 /// Create a non-destructive iterator over the `List`.
103 #[inline]
104 pub fn iter(&self) -> Iter<T> {
105 Iter::new(self)
106 }
107
108 // rustdoc-stripper-ignore-next
109 /// Create a non-destructive mutable iterator over the `List`.
110 #[inline]
111 pub fn iter_mut(&mut self) -> IterMut<T> {
112 IterMut::new(self)
113 }
114
115 // rustdoc-stripper-ignore-next
116 /// Check if the list is empty.
117 ///
118 /// This operation is `O(1)`.
119 #[inline]
120 pub fn is_empty(&self) -> bool {
121 self.ptr.is_none()
122 }
123
124 // rustdoc-stripper-ignore-next
125 /// Returns the length of the list.
126 ///
127 /// This operation is `O(n)`.
128 #[inline]
129 #[doc(alias = "g_list_length")]
130 pub fn len(&self) -> usize {
131 self.iter().count()
132 }
133
134 // rustdoc-stripper-ignore-next
135 /// Returns a reference to the first item of the list, if any.
136 ///
137 /// This operation is `O(1)`.
138 #[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 // rustdoc-stripper-ignore-next
151 /// Returns a mutable reference to the first item of the list, if any.
152 ///
153 /// This operation is `O(1)`.
154 #[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 // rustdoc-stripper-ignore-next
167 /// Removes the front item from the list, if any.
168 ///
169 /// This operation is `O(1)`.
170 #[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 // rustdoc-stripper-ignore-next
190 /// Prepends the new item to the front of the list.
191 ///
192 /// This operation is `O(1)`.
193 #[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 // rustdoc-stripper-ignore-next
207 /// Returns a reference to the last item of the list, if any.
208 ///
209 /// This operation is `O(n)`.
210 #[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 // rustdoc-stripper-ignore-next
225 /// Returns a mutable reference to the last item of the list, if any.
226 ///
227 /// This operation is `O(n)`.
228 #[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 // rustdoc-stripper-ignore-next
243 /// Removes the back item from the list, if any.
244 ///
245 /// This operation is `O(n)`.
246 #[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 // rustdoc-stripper-ignore-next
262 /// Appends the new item to the back of the list.
263 ///
264 /// this operation is `O(n)`.
265 #[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 // rustdoc-stripper-ignore-next
279 /// Reverse the list.
280 ///
281 /// This operation is `O(n)`.
282 #[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 // rustdoc-stripper-ignore-next
296 /// Sorts the list.
297 ///
298 /// This operation is `O(n * log n)`.
299 #[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 // rustdoc-stripper-ignore-next
309 /// Sorts the list.
310 ///
311 /// This operation is `O(n * log n)`.
312 #[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 // rustdoc-stripper-ignore-next
344 /// Removes all items from the list.
345 #[inline]
346 pub fn clear(&mut self) {
347 *self = Self::new();
348 }
349
350 // rustdoc-stripper-ignore-next
351 /// Only keeps the item in the list for which `f` returns `true`.
352 #[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 // rustdoc-stripper-ignore-next
371 /// Returns the underlying pointer.
372 #[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 // rustdoc-stripper-ignore-next
378 /// Returns the underlying pointer.
379 #[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 // rustdoc-stripper-ignore-next
385 /// Consumes the list and returns the underlying pointer.
386 #[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(default: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: NonNull) = 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(list:ptr.as_ptr(), free_func:Some(drop_item::<T>));
418 } else {
419 ffi::g_list_free(list: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> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GList>
490 for List<T>
491{
492 #[inline]
493 unsafe fn from_glib_none_num(ptr: *mut ffi::GList, _num: usize) -> Self {
494 Self::from_glib_none(list:ptr)
495 }
496
497 #[inline]
498 unsafe fn from_glib_container_num(ptr: *mut ffi::GList, _num: usize) -> Self {
499 Self::from_glib_container(list:ptr)
500 }
501
502 #[inline]
503 unsafe fn from_glib_full_num(ptr: *mut ffi::GList, _num: usize) -> Self {
504 Self::from_glib_full(list:ptr)
505 }
506}
507
508impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GList>
509 for List<T>
510{
511 #[inline]
512 unsafe fn from_glib_none_num(ptr: *const ffi::GList, _num: usize) -> Self {
513 Self::from_glib_none(list:ptr)
514 }
515
516 unsafe fn from_glib_container_num(_ptr: *const ffi::GList, _num: usize) -> Self {
517 unimplemented!();
518 }
519
520 unsafe fn from_glib_full_num(_ptr: *const ffi::GList, _num: usize) -> Self {
521 unimplemented!();
522 }
523}
524
525impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GList>
526 for List<T>
527{
528 #[inline]
529 unsafe fn from_glib_none(ptr: *mut ffi::GList) -> Self {
530 Self::from_glib_none(list:ptr)
531 }
532
533 #[inline]
534 unsafe fn from_glib_container(ptr: *mut ffi::GList) -> Self {
535 Self::from_glib_container(list:ptr)
536 }
537
538 #[inline]
539 unsafe fn from_glib_full(ptr: *mut ffi::GList) -> Self {
540 Self::from_glib_full(list:ptr)
541 }
542}
543
544impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GList>
545 for List<T>
546{
547 #[inline]
548 unsafe fn from_glib_none(ptr: *const ffi::GList) -> Self {
549 Self::from_glib_none(list:ptr)
550 }
551
552 unsafe fn from_glib_container(_ptr: *const ffi::GList) -> Self {
553 unimplemented!();
554 }
555
556 unsafe fn from_glib_full(_ptr: *const ffi::GList) -> Self {
557 unimplemented!();
558 }
559}
560
561impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut ffi::GList> for List<T> {
562 type Storage = PhantomData<&'a Self>;
563
564 #[inline]
565 fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GList, Self> {
566 Stash(self.as_ptr() as *mut _, PhantomData)
567 }
568
569 #[inline]
570 fn to_glib_container(&'a self) -> Stash<'a, *mut ffi::GList, Self> {
571 unsafe {
572 let ptr: *mut GList = ffi::g_malloc(n_bytes:mem::size_of::<T>().checked_mul(self.len() + 1).unwrap())
573 as *mut ffi::GList;
574 ptr::copy_nonoverlapping(self.as_ptr(), dst:ptr, self.len() + 1);
575 Stash(ptr, PhantomData)
576 }
577 }
578
579 #[inline]
580 fn to_glib_full(&self) -> *mut ffi::GList {
581 self.clone().into_raw()
582 }
583}
584
585impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const ffi::GList> for List<T> {
586 type Storage = PhantomData<&'a Self>;
587
588 #[inline]
589 fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GList, Self> {
590 Stash(self.as_ptr(), PhantomData)
591 }
592}
593
594impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut ffi::GList> for List<T> {
595 type Storage = PhantomData<&'a mut Self>;
596
597 #[inline]
598 fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GList, Self> {
599 StashMut(self.as_mut_ptr(), PhantomData)
600 }
601}
602
603impl<T: TransparentPtrType> IntoGlibPtr<*mut ffi::GList> for List<T> {
604 #[inline]
605 unsafe fn into_glib_ptr(self) -> *mut ffi::GList {
606 self.into_raw()
607 }
608}
609
610// rustdoc-stripper-ignore-next
611/// A non-destructive iterator over a [`List`].
612pub struct Iter<'a, T: TransparentPtrType> {
613 ptr: Option<ptr::NonNull<ffi::GList>>,
614 phantom: PhantomData<&'a T>,
615}
616
617impl<'a, T: TransparentPtrType> Iter<'a, T> {
618 #[inline]
619 fn new(list: &'a List<T>) -> Iter<'a, T> {
620 debug_assert_eq!(
621 mem::size_of::<T>(),
622 mem::size_of::<<T as GlibPtrDefault>::GlibType>()
623 );
624
625 Iter {
626 ptr: list.ptr,
627 phantom: PhantomData,
628 }
629 }
630}
631
632impl<'a, T: TransparentPtrType> Iterator for Iter<'a, T> {
633 type Item = &'a T;
634
635 #[inline]
636 fn next(&mut self) -> Option<&'a T> {
637 match self.ptr {
638 None => None,
639 Some(cur: NonNull) => unsafe {
640 self.ptr = ptr::NonNull::new(ptr:cur.as_ref().next);
641
642 let item: &T = &*(&cur.as_ref().data as *const ffi::gpointer as *const T);
643
644 Some(item)
645 },
646 }
647 }
648}
649
650impl<'a, T: TransparentPtrType> FusedIterator for Iter<'a, T> {}
651
652// rustdoc-stripper-ignore-next
653/// A non-destructive iterator over a [`List`].
654pub struct IterMut<'a, T: TransparentPtrType> {
655 ptr: Option<ptr::NonNull<ffi::GList>>,
656 phantom: PhantomData<&'a mut T>,
657}
658
659impl<'a, T: TransparentPtrType> IterMut<'a, T> {
660 #[inline]
661 fn new(list: &'a mut List<T>) -> IterMut<'a, T> {
662 debug_assert_eq!(
663 mem::size_of::<T>(),
664 mem::size_of::<<T as GlibPtrDefault>::GlibType>()
665 );
666
667 IterMut {
668 ptr: list.ptr,
669 phantom: PhantomData,
670 }
671 }
672}
673
674impl<'a, T: TransparentPtrType> Iterator for IterMut<'a, T> {
675 type Item = &'a mut T;
676
677 #[inline]
678 fn next(&mut self) -> Option<&'a mut T> {
679 match self.ptr {
680 None => None,
681 Some(mut cur: NonNull) => unsafe {
682 self.ptr = ptr::NonNull::new(ptr:cur.as_ref().next);
683
684 let item: &mut T = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
685
686 Some(item)
687 },
688 }
689 }
690}
691
692impl<'a, T: TransparentPtrType> FusedIterator for IterMut<'a, T> {}
693
694// rustdoc-stripper-ignore-next
695/// A destructive iterator over a [`List`].
696pub struct IntoIter<T: TransparentPtrType> {
697 list: List<T>,
698}
699
700impl<T: TransparentPtrType> IntoIter<T> {
701 #[inline]
702 fn new(list: List<T>) -> IntoIter<T> {
703 debug_assert_eq!(
704 mem::size_of::<T>(),
705 mem::size_of::<<T as GlibPtrDefault>::GlibType>()
706 );
707
708 IntoIter { list }
709 }
710}
711
712impl<T: TransparentPtrType> Iterator for IntoIter<T> {
713 type Item = T;
714
715 #[inline]
716 fn next(&mut self) -> Option<T> {
717 self.list.pop_front()
718 }
719}
720
721impl<T: TransparentPtrType> FusedIterator for IntoIter<T> {}
722
723#[cfg(test)]
724mod test {
725 use super::*;
726
727 #[test]
728 // checker-ignore-item
729 fn from_glib_full() {
730 let items = [
731 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
732 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
733 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
734 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
735 ];
736 let mut list = unsafe {
737 let mut list = ffi::g_list_append(
738 ptr::null_mut(),
739 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[0]) as ffi::gpointer,
740 );
741 list = ffi::g_list_append(
742 list,
743 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[1]) as ffi::gpointer,
744 );
745 list = ffi::g_list_append(
746 list,
747 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[2]) as ffi::gpointer,
748 );
749 list = ffi::g_list_append(
750 list,
751 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[3]) as ffi::gpointer,
752 );
753 List::<crate::DateTime>::from_glib_full(list)
754 };
755 assert!(!list.is_empty());
756
757 let list_items = list.iter().cloned().collect::<Vec<_>>();
758 assert_eq!(&items[..], &list_items);
759
760 let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
761 assert_eq!(&items[..], &list_items);
762
763 let list_items = list.into_iter().collect::<Vec<_>>();
764 assert_eq!(&items[..], &list_items);
765
766 let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
767 assert!(list.is_empty());
768 }
769
770 #[test]
771 // checker-ignore-item
772 fn from_glib_container() {
773 let items = [
774 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
775 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
776 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
777 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
778 ];
779 let mut list = unsafe {
780 let mut list = ffi::g_list_append(
781 ptr::null_mut(),
782 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
783 );
784 list = ffi::g_list_append(
785 list,
786 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
787 );
788 list = ffi::g_list_append(
789 list,
790 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
791 );
792 list = ffi::g_list_append(
793 list,
794 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
795 );
796 List::<crate::DateTime>::from_glib_container(list)
797 };
798 assert!(!list.is_empty());
799
800 let list_items = list.iter().cloned().collect::<Vec<_>>();
801 assert_eq!(&items[..], &list_items);
802
803 let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
804 assert_eq!(&items[..], &list_items);
805
806 let list_items = list.into_iter().collect::<Vec<_>>();
807 assert_eq!(&items[..], &list_items);
808
809 let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
810 assert!(list.is_empty());
811 }
812
813 #[test]
814 // checker-ignore-item
815 fn from_glib_none() {
816 let items = [
817 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
818 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
819 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
820 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
821 ];
822 let mut list = unsafe {
823 let mut list = ffi::g_list_append(
824 ptr::null_mut(),
825 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
826 );
827 list = ffi::g_list_append(
828 list,
829 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
830 );
831 list = ffi::g_list_append(
832 list,
833 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
834 );
835 list = ffi::g_list_append(
836 list,
837 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
838 );
839 let res = List::<crate::DateTime>::from_glib_none(list);
840 ffi::g_list_free(list);
841
842 res
843 };
844 assert!(!list.is_empty());
845
846 let list_items = list.iter().cloned().collect::<Vec<_>>();
847 assert_eq!(&items[..], &list_items);
848
849 let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
850 assert_eq!(&items[..], &list_items);
851
852 let list_items = list.into_iter().collect::<Vec<_>>();
853 assert_eq!(&items[..], &list_items);
854
855 let list = unsafe { List::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
856 assert!(list.is_empty());
857 }
858
859 #[test]
860 // checker-ignore-item
861 fn safe_api() {
862 let items = [
863 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
864 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
865 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
866 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
867 ];
868
869 let mut list = items[1..3].iter().cloned().collect::<List<_>>();
870 assert_eq!(list.len(), 2);
871 list.push_front(items[0].clone());
872 assert_eq!(list.len(), 3);
873 list.push_back(items[3].clone());
874 assert_eq!(list.len(), 4);
875
876 let list_items = list.iter().cloned().collect::<Vec<_>>();
877 assert_eq!(&items[..], &list_items);
878
879 assert_eq!(list.front(), Some(&items[0]));
880 assert_eq!(list.back(), Some(&items[3]));
881 assert_eq!(list.pop_front().as_ref(), Some(&items[0]));
882 assert_eq!(list.len(), 3);
883
884 list.reverse();
885 let mut list_items = list.iter().cloned().collect::<Vec<_>>();
886 list_items.reverse();
887 assert_eq!(&items[1..], &list_items);
888
889 let list2 = list.clone();
890 let mut list_items = list2.iter().cloned().collect::<Vec<_>>();
891 list_items.reverse();
892 assert_eq!(&items[1..], &list_items);
893 }
894}
895