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 SList<T: TransparentPtrType> {
13 ptr: Option<ptr::NonNull<ffi::GSList>>,
14 phantom: PhantomData<T>,
15}
16
17#[doc(hidden)]
18unsafe impl<T: TransparentPtrType> TransparentPtrType for SList<T> {}
19
20#[doc(hidden)]
21impl<T: TransparentPtrType> GlibPtrDefault for SList<T> {
22 type GlibType = *mut ffi::GSList;
23}
24
25unsafe impl<T: Send + TransparentPtrType> Send for SList<T> {}
26
27unsafe impl<T: Sync + TransparentPtrType> Sync for SList<T> {}
28
29impl<T: TransparentPtrType> SList<T> {
30 // rustdoc-stripper-ignore-next
31 /// Create a new `SList` around a list.
32 #[inline]
33 pub unsafe fn from_glib_none(list: *const ffi::GSList) -> SList<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_slist_copy_deep(mut_override(list), Some(copy_item::<T>), ptr::null_mut())
48 } else {
49 ffi::g_slist_copy(mut_override(list))
50 };
51
52 SList {
53 ptr: ptr::NonNull::new(list),
54 phantom: PhantomData,
55 }
56 }
57
58 // rustdoc-stripper-ignore-next
59 /// Create a new `SList` around a list.
60 #[inline]
61 pub unsafe fn from_glib_container(list: *mut ffi::GSList) -> SList<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_slist_foreach(list, Some(copy_item::<T>), ptr::null_mut());
73 }
74
75 SList {
76 ptr: ptr::NonNull::new(list),
77 phantom: PhantomData,
78 }
79 }
80
81 // rustdoc-stripper-ignore-next
82 /// Create a new `SList` around a list.
83 #[inline]
84 pub unsafe fn from_glib_full(list: *mut ffi::GSList) -> SList<T> {
85 SList {
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 SList {
96 ptr: None,
97 phantom: PhantomData,
98 }
99 }
100
101 // rustdoc-stripper-ignore-next
102 /// Create a non-destructive iterator over the `SList`.
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 `SList`.
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_slist_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_slist_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_slist_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 let item = ptr::read(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
177 ffi::g_slist_free_1(cur.as_ptr());
178
179 Some(item)
180 },
181 }
182 }
183
184 // rustdoc-stripper-ignore-next
185 /// Prepends the new item to the front of the list.
186 ///
187 /// This operation is `O(1)`.
188 #[inline]
189 #[doc(alias = "g_slist_prepend")]
190 pub fn push_front(&mut self, item: T) {
191 unsafe {
192 let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut());
193 self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_prepend(
194 ptr,
195 *(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType)
196 as ffi::gpointer,
197 )));
198 }
199 }
200
201 // rustdoc-stripper-ignore-next
202 /// Returns a reference to the last item of the list, if any.
203 ///
204 /// This operation is `O(n)`.
205 #[inline]
206 #[doc(alias = "g_slist_last")]
207 pub fn back(&self) -> Option<&T> {
208 unsafe {
209 let ptr = match self.ptr {
210 None => return None,
211 Some(ptr) => ptr.as_ptr(),
212 };
213 let last_ptr = ffi::g_slist_last(ptr);
214 let item = &*(&(*last_ptr).data as *const ffi::gpointer as *const T);
215 Some(item)
216 }
217 }
218
219 // rustdoc-stripper-ignore-next
220 /// Returns a mutable reference to the last item of the list, if any.
221 ///
222 /// This operation is `O(n)`.
223 #[inline]
224 #[doc(alias = "g_slist_last")]
225 pub fn back_mut(&mut self) -> Option<&mut T> {
226 unsafe {
227 let ptr = match self.ptr {
228 None => return None,
229 Some(ptr) => ptr.as_ptr(),
230 };
231 let last_ptr = ffi::g_slist_last(ptr);
232 let item = &mut *(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T);
233 Some(item)
234 }
235 }
236
237 // rustdoc-stripper-ignore-next
238 /// Removes the back item from the list, if any.
239 ///
240 /// This operation is `O(n)`.
241 #[inline]
242 pub fn pop_back(&mut self) -> Option<T> {
243 unsafe {
244 let ptr = match self.ptr {
245 None => return None,
246 Some(ptr) => ptr.as_ptr(),
247 };
248 let last_ptr = ffi::g_slist_last(ptr);
249 let item = ptr::read(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T);
250 self.ptr = ptr::NonNull::new(ffi::g_slist_delete_link(ptr, last_ptr));
251
252 Some(item)
253 }
254 }
255
256 // rustdoc-stripper-ignore-next
257 /// Appends the new item to the back of the list.
258 ///
259 /// this operation is `O(n)`.
260 #[inline]
261 #[doc(alias = "g_slist_append")]
262 pub fn push_back(&mut self, item: T) {
263 unsafe {
264 let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut());
265 self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_append(
266 ptr,
267 *(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType)
268 as ffi::gpointer,
269 )));
270 }
271 }
272
273 // rustdoc-stripper-ignore-next
274 /// Reverse the list.
275 ///
276 /// This operation is `O(n)`.
277 #[inline]
278 #[doc(alias = "g_slist_reverse")]
279 pub fn reverse(&mut self) {
280 unsafe {
281 let ptr = match self.ptr {
282 None => return,
283 Some(ptr) => ptr.as_ptr(),
284 };
285
286 self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_reverse(ptr)));
287 }
288 }
289
290 // rustdoc-stripper-ignore-next
291 /// Sorts the list.
292 ///
293 /// This operation is `O(n * log n)`.
294 #[inline]
295 #[doc(alias = "g_slist_sort")]
296 pub fn sort(&mut self)
297 where
298 T: Ord,
299 {
300 self.sort_by(|a, b| a.cmp(b));
301 }
302
303 // rustdoc-stripper-ignore-next
304 /// Sorts the list.
305 ///
306 /// This operation is `O(n * log n)`.
307 #[inline]
308 #[doc(alias = "g_slist_sort")]
309 pub fn sort_by<F: FnMut(&T, &T) -> std::cmp::Ordering>(&mut self, mut f: F) {
310 unsafe {
311 let ptr = match self.ptr {
312 None => return,
313 Some(ptr) => ptr.as_ptr(),
314 };
315
316 unsafe extern "C" fn func<
317 T: TransparentPtrType,
318 F: FnMut(&T, &T) -> std::cmp::Ordering,
319 >(
320 a: ffi::gconstpointer,
321 b: ffi::gconstpointer,
322 user_data: ffi::gpointer,
323 ) -> i32 {
324 let f = &mut *(user_data as *mut F);
325 let a = &*(&a as *const ffi::gconstpointer as *const T);
326 let b = &*(&b as *const ffi::gconstpointer as *const T);
327 f(a, b).into_glib()
328 }
329
330 self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_sort_with_data(
331 ptr,
332 Some(func::<T, F>),
333 &mut f as *mut F as ffi::gpointer,
334 )));
335 }
336 }
337
338 // rustdoc-stripper-ignore-next
339 /// Removes all items from the list.
340 #[inline]
341 pub fn clear(&mut self) {
342 *self = Self::new();
343 }
344
345 // rustdoc-stripper-ignore-next
346 /// Only keeps the item in the list for which `f` returns `true`.
347 #[inline]
348 pub fn retain(&mut self, mut f: impl FnMut(&T) -> bool) {
349 if let Some(head) = self.ptr {
350 unsafe {
351 let mut ptr = head.as_ptr();
352 while !ptr.is_null() {
353 let item = &*((*ptr).data as *const ffi::gpointer as *const T);
354 let next = (*ptr).next;
355 if !f(item) {
356 ptr::drop_in_place(&mut (*ptr).data as *mut ffi::gpointer as *mut T);
357 self.ptr = ptr::NonNull::new(ffi::g_slist_delete_link(head.as_ptr(), ptr));
358 }
359 ptr = next;
360 }
361 }
362 }
363 }
364
365 // rustdoc-stripper-ignore-next
366 /// Returns the underlying pointer.
367 #[inline]
368 pub fn as_ptr(&self) -> *const ffi::GSList {
369 self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
370 }
371
372 // rustdoc-stripper-ignore-next
373 /// Returns the underlying pointer.
374 #[inline]
375 pub fn as_mut_ptr(&mut self) -> *mut ffi::GSList {
376 self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
377 }
378
379 // rustdoc-stripper-ignore-next
380 /// Consumes the list and returns the underlying pointer.
381 #[inline]
382 pub fn into_raw(mut self) -> *mut ffi::GSList {
383 self.ptr
384 .take()
385 .map(|p| p.as_ptr())
386 .unwrap_or(ptr::null_mut())
387 }
388}
389
390impl<T: TransparentPtrType> Default for SList<T> {
391 fn default() -> Self {
392 Self::new()
393 }
394}
395
396impl<T: TransparentPtrType> Clone for SList<T> {
397 fn clone(&self) -> Self {
398 unsafe { Self::from_glib_none(self.ptr.map(|p| p.as_ptr()).unwrap_or(default:ptr::null_mut())) }
399 }
400}
401
402impl<T: TransparentPtrType> Drop for SList<T> {
403 #[inline]
404 fn drop(&mut self) {
405 if let Some(ptr: NonNull) = self.ptr {
406 unsafe {
407 if mem::needs_drop::<T>() {
408 unsafe extern "C" fn drop_item<T: TransparentPtrType>(mut ptr: ffi::gpointer) {
409 ptr::drop_in_place(&mut ptr as *mut ffi::gpointer as *mut T);
410 }
411
412 ffi::g_slist_free_full(list:ptr.as_ptr(), free_func:Some(drop_item::<T>));
413 } else {
414 ffi::g_slist_free(list:ptr.as_ptr());
415 }
416 }
417 }
418 }
419}
420
421impl<T: TransparentPtrType> std::iter::FromIterator<T> for SList<T> {
422 #[inline]
423 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
424 unsafe {
425 let mut iter = iter.into_iter();
426
427 let first = match iter.next() {
428 None => return Self::new(),
429 Some(first) => first,
430 };
431
432 let list = ffi::g_slist_prepend(
433 ptr::null_mut(),
434 *(&mut *mem::ManuallyDrop::new(first) as *mut T as *mut *mut T::GlibType)
435 as ffi::gpointer,
436 );
437 let mut tail = list;
438 for item in iter {
439 let new_tail = ffi::g_slist_alloc();
440
441 (*new_tail).data = *(&mut *mem::ManuallyDrop::new(item) as *mut T
442 as *mut *mut T::GlibType) as ffi::gpointer;
443 (*new_tail).next = ptr::null_mut();
444 (*tail).next = new_tail;
445 tail = new_tail;
446 }
447
448 Self::from_glib_full(list)
449 }
450 }
451}
452
453impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a SList<T> {
454 type Item = &'a T;
455 type IntoIter = Iter<'a, T>;
456
457 #[inline]
458 fn into_iter(self) -> Self::IntoIter {
459 self.iter()
460 }
461}
462
463impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a mut SList<T> {
464 type Item = &'a mut T;
465 type IntoIter = IterMut<'a, T>;
466
467 #[inline]
468 fn into_iter(self) -> Self::IntoIter {
469 self.iter_mut()
470 }
471}
472
473impl<T: TransparentPtrType> std::iter::IntoIterator for SList<T> {
474 type Item = T;
475 type IntoIter = IntoIter<T>;
476
477 #[inline]
478 fn into_iter(self) -> Self::IntoIter {
479 IntoIter::new(self)
480 }
481}
482
483impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList>
484 for SList<T>
485{
486 #[inline]
487 unsafe fn from_glib_none_num(ptr: *mut ffi::GSList, _num: usize) -> Self {
488 Self::from_glib_none(list:ptr)
489 }
490
491 #[inline]
492 unsafe fn from_glib_container_num(ptr: *mut ffi::GSList, _num: usize) -> Self {
493 Self::from_glib_container(list:ptr)
494 }
495
496 #[inline]
497 unsafe fn from_glib_full_num(ptr: *mut ffi::GSList, _num: usize) -> Self {
498 Self::from_glib_full(list:ptr)
499 }
500}
501
502impl<T: TransparentPtrType> FromGlibContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GSList>
503 for SList<T>
504{
505 #[inline]
506 unsafe fn from_glib_none_num(ptr: *const ffi::GSList, _num: usize) -> Self {
507 Self::from_glib_none(list:ptr)
508 }
509
510 unsafe fn from_glib_container_num(_ptr: *const ffi::GSList, _num: usize) -> Self {
511 unimplemented!();
512 }
513
514 unsafe fn from_glib_full_num(_ptr: *const ffi::GSList, _num: usize) -> Self {
515 unimplemented!();
516 }
517}
518
519impl<T: TransparentPtrType> FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *mut ffi::GSList>
520 for SList<T>
521{
522 #[inline]
523 unsafe fn from_glib_none(ptr: *mut ffi::GSList) -> Self {
524 Self::from_glib_none(list:ptr)
525 }
526
527 #[inline]
528 unsafe fn from_glib_container(ptr: *mut ffi::GSList) -> Self {
529 Self::from_glib_container(list:ptr)
530 }
531
532 #[inline]
533 unsafe fn from_glib_full(ptr: *mut ffi::GSList) -> Self {
534 Self::from_glib_full(list:ptr)
535 }
536}
537
538impl<T: TransparentPtrType>
539 FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *const ffi::GSList> for SList<T>
540{
541 #[inline]
542 unsafe fn from_glib_none(ptr: *const ffi::GSList) -> Self {
543 Self::from_glib_none(list:ptr)
544 }
545
546 unsafe fn from_glib_container(_ptr: *const ffi::GSList) -> Self {
547 unimplemented!();
548 }
549
550 unsafe fn from_glib_full(_ptr: *const ffi::GSList) -> Self {
551 unimplemented!();
552 }
553}
554
555impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut ffi::GSList> for SList<T> {
556 type Storage = PhantomData<&'a Self>;
557
558 #[inline]
559 fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GSList, Self> {
560 Stash(self.as_ptr() as *mut _, PhantomData)
561 }
562
563 #[inline]
564 fn to_glib_container(&'a self) -> Stash<'a, *mut ffi::GSList, Self> {
565 unsafe {
566 let ptr: *mut GSList = ffi::g_malloc(n_bytes:mem::size_of::<T>().checked_mul(self.len() + 1).unwrap())
567 as *mut ffi::GSList;
568 ptr::copy_nonoverlapping(self.as_ptr(), dst:ptr, self.len() + 1);
569 Stash(ptr, PhantomData)
570 }
571 }
572
573 #[inline]
574 fn to_glib_full(&self) -> *mut ffi::GSList {
575 self.clone().into_raw()
576 }
577}
578
579impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const ffi::GSList> for SList<T> {
580 type Storage = PhantomData<&'a Self>;
581
582 #[inline]
583 fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GSList, Self> {
584 Stash(self.as_ptr(), PhantomData)
585 }
586}
587
588impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut ffi::GSList> for SList<T> {
589 type Storage = PhantomData<&'a mut Self>;
590
591 #[inline]
592 fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GSList, Self> {
593 StashMut(self.as_mut_ptr(), PhantomData)
594 }
595}
596
597impl<T: TransparentPtrType> IntoGlibPtr<*mut ffi::GSList> for SList<T> {
598 #[inline]
599 unsafe fn into_glib_ptr(self) -> *mut ffi::GSList {
600 self.into_raw()
601 }
602}
603
604// rustdoc-stripper-ignore-next
605/// A non-destructive iterator over a [`SList`].
606pub struct Iter<'a, T: TransparentPtrType> {
607 ptr: Option<ptr::NonNull<ffi::GSList>>,
608 phantom: PhantomData<&'a T>,
609}
610
611impl<'a, T: TransparentPtrType> Iter<'a, T> {
612 #[inline]
613 fn new(list: &'a SList<T>) -> Iter<'a, T> {
614 debug_assert_eq!(
615 mem::size_of::<T>(),
616 mem::size_of::<<T as GlibPtrDefault>::GlibType>()
617 );
618
619 Iter {
620 ptr: list.ptr,
621 phantom: PhantomData,
622 }
623 }
624}
625
626impl<'a, T: TransparentPtrType> Iterator for Iter<'a, T> {
627 type Item = &'a T;
628
629 #[inline]
630 fn next(&mut self) -> Option<&'a T> {
631 match self.ptr {
632 None => None,
633 Some(cur: NonNull) => unsafe {
634 self.ptr = ptr::NonNull::new(ptr:cur.as_ref().next);
635
636 let item: &T = &*(&cur.as_ref().data as *const ffi::gpointer as *const T);
637
638 Some(item)
639 },
640 }
641 }
642}
643
644impl<'a, T: TransparentPtrType> FusedIterator for Iter<'a, T> {}
645
646// rustdoc-stripper-ignore-next
647/// A non-destructive iterator over a [`SList`].
648pub struct IterMut<'a, T: TransparentPtrType> {
649 ptr: Option<ptr::NonNull<ffi::GSList>>,
650 phantom: PhantomData<&'a mut T>,
651}
652
653impl<'a, T: TransparentPtrType> IterMut<'a, T> {
654 #[inline]
655 fn new(list: &'a mut SList<T>) -> IterMut<'a, T> {
656 debug_assert_eq!(
657 mem::size_of::<T>(),
658 mem::size_of::<<T as GlibPtrDefault>::GlibType>()
659 );
660
661 IterMut {
662 ptr: list.ptr,
663 phantom: PhantomData,
664 }
665 }
666}
667
668impl<'a, T: TransparentPtrType> Iterator for IterMut<'a, T> {
669 type Item = &'a mut T;
670
671 #[inline]
672 fn next(&mut self) -> Option<&'a mut T> {
673 match self.ptr {
674 None => None,
675 Some(mut cur: NonNull) => unsafe {
676 self.ptr = ptr::NonNull::new(ptr:cur.as_ref().next);
677
678 let item: &mut T = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T);
679
680 Some(item)
681 },
682 }
683 }
684}
685
686impl<'a, T: TransparentPtrType> FusedIterator for IterMut<'a, T> {}
687
688// rustdoc-stripper-ignore-next
689/// A destructive iterator over a [`SList`].
690pub struct IntoIter<T: TransparentPtrType> {
691 list: SList<T>,
692}
693
694impl<T: TransparentPtrType> IntoIter<T> {
695 #[inline]
696 fn new(list: SList<T>) -> IntoIter<T> {
697 debug_assert_eq!(
698 mem::size_of::<T>(),
699 mem::size_of::<<T as GlibPtrDefault>::GlibType>()
700 );
701
702 IntoIter { list }
703 }
704}
705
706impl<T: TransparentPtrType> Iterator for IntoIter<T> {
707 type Item = T;
708
709 #[inline]
710 fn next(&mut self) -> Option<T> {
711 self.list.pop_front()
712 }
713}
714
715impl<T: TransparentPtrType> FusedIterator for IntoIter<T> {}
716
717#[cfg(test)]
718mod test {
719 use super::*;
720
721 #[test]
722 // checker-ignore-item
723 fn from_glib_full() {
724 let items = [
725 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
726 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
727 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
728 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
729 ];
730 let mut list = unsafe {
731 let mut list = ffi::g_slist_append(
732 ptr::null_mut(),
733 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[0]) as ffi::gpointer,
734 );
735 list = ffi::g_slist_append(
736 list,
737 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[1]) as ffi::gpointer,
738 );
739 list = ffi::g_slist_append(
740 list,
741 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[2]) as ffi::gpointer,
742 );
743 list = ffi::g_slist_append(
744 list,
745 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[3]) as ffi::gpointer,
746 );
747 SList::<crate::DateTime>::from_glib_full(list)
748 };
749 assert!(!list.is_empty());
750
751 let list_items = list.iter().cloned().collect::<Vec<_>>();
752 assert_eq!(&items[..], &list_items);
753
754 let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
755 assert_eq!(&items[..], &list_items);
756
757 let list_items = list.into_iter().collect::<Vec<_>>();
758 assert_eq!(&items[..], &list_items);
759
760 let list = unsafe { SList::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
761 assert!(list.is_empty());
762 }
763
764 #[test]
765 // checker-ignore-item
766 fn from_glib_container() {
767 let items = [
768 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
769 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
770 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
771 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
772 ];
773 let mut list = unsafe {
774 let mut list = ffi::g_slist_append(
775 ptr::null_mut(),
776 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
777 );
778 list = ffi::g_slist_append(
779 list,
780 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
781 );
782 list = ffi::g_slist_append(
783 list,
784 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
785 );
786 list = ffi::g_slist_append(
787 list,
788 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
789 );
790 SList::<crate::DateTime>::from_glib_container(list)
791 };
792 assert!(!list.is_empty());
793
794 let list_items = list.iter().cloned().collect::<Vec<_>>();
795 assert_eq!(&items[..], &list_items);
796
797 let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
798 assert_eq!(&items[..], &list_items);
799
800 let list_items = list.into_iter().collect::<Vec<_>>();
801 assert_eq!(&items[..], &list_items);
802
803 let list = unsafe { SList::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
804 assert!(list.is_empty());
805 }
806
807 #[test]
808 // checker-ignore-item
809 fn from_glib_none() {
810 let items = [
811 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
812 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
813 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
814 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
815 ];
816 let mut list = unsafe {
817 let mut list = ffi::g_slist_append(
818 ptr::null_mut(),
819 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer,
820 );
821 list = ffi::g_slist_append(
822 list,
823 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer,
824 );
825 list = ffi::g_slist_append(
826 list,
827 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer,
828 );
829 list = ffi::g_slist_append(
830 list,
831 ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer,
832 );
833 let res = SList::<crate::DateTime>::from_glib_none(list);
834 ffi::g_slist_free(list);
835 res
836 };
837 assert!(!list.is_empty());
838
839 let list_items = list.iter().cloned().collect::<Vec<_>>();
840 assert_eq!(&items[..], &list_items);
841
842 let list_items = list.iter_mut().map(|d| d.clone()).collect::<Vec<_>>();
843 assert_eq!(&items[..], &list_items);
844
845 let list_items = list.into_iter().collect::<Vec<_>>();
846 assert_eq!(&items[..], &list_items);
847
848 let list = unsafe { SList::<crate::DateTime>::from_glib_full(ptr::null_mut()) };
849 assert!(list.is_empty());
850 }
851
852 #[test]
853 // checker-ignore-item
854 fn safe_api() {
855 let items = [
856 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(),
857 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(),
858 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(),
859 crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(),
860 ];
861
862 let mut list = items[1..3].iter().cloned().collect::<SList<_>>();
863 assert_eq!(list.len(), 2);
864 list.push_front(items[0].clone());
865 assert_eq!(list.len(), 3);
866 list.push_back(items[3].clone());
867 assert_eq!(list.len(), 4);
868
869 let list_items = list.iter().cloned().collect::<Vec<_>>();
870 assert_eq!(&items[..], &list_items);
871
872 assert_eq!(list.front(), Some(&items[0]));
873 assert_eq!(list.back(), Some(&items[3]));
874 assert_eq!(list.pop_front().as_ref(), Some(&items[0]));
875 assert_eq!(list.len(), 3);
876
877 list.reverse();
878 let mut list_items = list.iter().cloned().collect::<Vec<_>>();
879 list_items.reverse();
880 assert_eq!(&items[1..], &list_items);
881
882 let list2 = list.clone();
883 let mut list_items = list2.iter().cloned().collect::<Vec<_>>();
884 list_items.reverse();
885 assert_eq!(&items[1..], &list_items);
886 }
887}
888