Skip to main content

glib/collections/
ptr_slice.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, marker::PhantomData, mem, ptr};
4
5use crate::{ffi, translate::*};
6
7// rustdoc-stripper-ignore-next
8/// Minimum size of the `PtrSlice` allocation.
9const MIN_SIZE: usize = 16;
10
11// rustdoc-stripper-ignore-next
12/// Slice of elements of type `T` allocated by the GLib allocator.
13///
14/// The underlying memory is always `NULL`-terminated. [`Slice<T>`](crate::collections::slice::Slice)
15/// can be used for a non-`NULL`-terminated slice.
16///
17/// This can be used like a `&[T]`, `&mut [T]` and `Vec<T>`.
18pub struct PtrSlice<T: TransparentPtrType> {
19    ptr: ptr::NonNull<<T as GlibPtrDefault>::GlibType>,
20    // rustdoc-stripper-ignore-next
21    /// Length without the `NULL`-terminator.
22    len: usize,
23    // rustdoc-stripper-ignore-next
24    /// Capacity **with** the `NULL`-terminator, i.e. the actual allocation size.
25    capacity: usize,
26}
27
28impl<T: fmt::Debug + TransparentPtrType> fmt::Debug for PtrSlice<T> {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        self.as_slice().fmt(f)
31    }
32}
33
34unsafe impl<T: Send + TransparentPtrType> Send for PtrSlice<T> {}
35
36unsafe impl<T: Sync + TransparentPtrType> Sync for PtrSlice<T> {}
37
38impl<T: PartialEq + TransparentPtrType> PartialEq for PtrSlice<T> {
39    #[inline]
40    fn eq(&self, other: &Self) -> bool {
41        self.as_slice() == other.as_slice()
42    }
43}
44
45impl<T: Eq + TransparentPtrType> Eq for PtrSlice<T> {}
46
47impl<T: PartialOrd + TransparentPtrType> PartialOrd for PtrSlice<T> {
48    #[inline]
49    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
50        self.as_slice().partial_cmp(other.as_slice())
51    }
52}
53
54impl<T: Ord + TransparentPtrType> Ord for PtrSlice<T> {
55    #[inline]
56    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
57        self.as_slice().cmp(other.as_slice())
58    }
59}
60
61impl<T: std::hash::Hash + TransparentPtrType> std::hash::Hash for PtrSlice<T> {
62    #[inline]
63    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
64        self.as_slice().hash(state)
65    }
66}
67
68impl<T: PartialEq + TransparentPtrType> PartialEq<[T]> for PtrSlice<T> {
69    #[inline]
70    fn eq(&self, other: &[T]) -> bool {
71        self.as_slice() == other
72    }
73}
74
75impl<T: PartialEq + TransparentPtrType> PartialEq<PtrSlice<T>> for [T] {
76    #[inline]
77    fn eq(&self, other: &PtrSlice<T>) -> bool {
78        self == other.as_slice()
79    }
80}
81
82impl<T: TransparentPtrType> Drop for PtrSlice<T> {
83    #[inline]
84    fn drop(&mut self) {
85        unsafe {
86            let len = mem::replace(&mut self.len, 0);
87            if mem::needs_drop::<T>() {
88                for i in 0..len {
89                    ptr::drop_in_place::<T>(self.ptr.as_ptr().add(i) as *mut T);
90                }
91            }
92
93            let capacity = mem::replace(&mut self.capacity, 0);
94            if capacity != 0 {
95                ffi::g_free(self.ptr.as_ptr() as ffi::gpointer);
96            }
97        }
98    }
99}
100
101impl<T: TransparentPtrType> AsRef<[T]> for PtrSlice<T> {
102    #[inline]
103    fn as_ref(&self) -> &[T] {
104        self.as_slice()
105    }
106}
107
108impl<T: TransparentPtrType> AsMut<[T]> for PtrSlice<T> {
109    #[inline]
110    fn as_mut(&mut self) -> &mut [T] {
111        self.as_mut_slice()
112    }
113}
114
115impl<T: TransparentPtrType> std::borrow::Borrow<[T]> for PtrSlice<T> {
116    #[inline]
117    fn borrow(&self) -> &[T] {
118        self.as_slice()
119    }
120}
121
122impl<T: TransparentPtrType> std::borrow::BorrowMut<[T]> for PtrSlice<T> {
123    #[inline]
124    fn borrow_mut(&mut self) -> &mut [T] {
125        self.as_mut_slice()
126    }
127}
128
129impl<T: TransparentPtrType> std::ops::Deref for PtrSlice<T> {
130    type Target = [T];
131
132    #[inline]
133    fn deref(&self) -> &[T] {
134        self.as_slice()
135    }
136}
137
138impl<T: TransparentPtrType> std::ops::DerefMut for PtrSlice<T> {
139    #[inline]
140    fn deref_mut(&mut self) -> &mut [T] {
141        self.as_mut_slice()
142    }
143}
144
145impl<T: TransparentPtrType> Default for PtrSlice<T> {
146    #[inline]
147    fn default() -> Self {
148        Self::new()
149    }
150}
151
152impl<T: TransparentPtrType> std::iter::Extend<T> for PtrSlice<T> {
153    #[inline]
154    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
155        let iter = iter.into_iter();
156        self.reserve(iter.size_hint().0);
157
158        for item in iter {
159            self.push(item);
160        }
161    }
162}
163
164impl<'a, T: TransparentPtrType + 'a> std::iter::Extend<&'a T> for PtrSlice<T> {
165    #[inline]
166    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
167        let iter = iter.into_iter();
168        self.reserve(iter.size_hint().0);
169
170        for item in iter {
171            self.push(item.clone());
172        }
173    }
174}
175
176impl<T: TransparentPtrType> std::iter::FromIterator<T> for PtrSlice<T> {
177    #[inline]
178    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
179        let iter = iter.into_iter();
180        let mut s = Self::with_capacity(iter.size_hint().0);
181        for item in iter {
182            s.push(item);
183        }
184        s
185    }
186}
187
188impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a PtrSlice<T> {
189    type Item = &'a T;
190    type IntoIter = std::slice::Iter<'a, T>;
191
192    #[inline]
193    fn into_iter(self) -> Self::IntoIter {
194        self.as_slice().iter()
195    }
196}
197
198impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a mut PtrSlice<T> {
199    type Item = &'a mut T;
200    type IntoIter = std::slice::IterMut<'a, T>;
201
202    #[inline]
203    fn into_iter(self) -> Self::IntoIter {
204        self.as_mut_slice().iter_mut()
205    }
206}
207
208impl<T: TransparentPtrType> std::iter::IntoIterator for PtrSlice<T> {
209    type Item = T;
210    type IntoIter = IntoIter<T>;
211
212    #[inline]
213    fn into_iter(self) -> Self::IntoIter {
214        IntoIter::new(self)
215    }
216}
217
218pub struct IntoIter<T: TransparentPtrType> {
219    ptr: ptr::NonNull<<T as GlibPtrDefault>::GlibType>,
220    idx: ptr::NonNull<<T as GlibPtrDefault>::GlibType>,
221    len: usize,
222    empty: bool,
223}
224
225impl<T: TransparentPtrType> IntoIter<T> {
226    #[inline]
227    fn new(slice: PtrSlice<T>) -> Self {
228        let slice = mem::ManuallyDrop::new(slice);
229        IntoIter {
230            ptr: slice.ptr,
231            idx: slice.ptr,
232            len: slice.len,
233            empty: slice.capacity == 0,
234        }
235    }
236
237    // rustdoc-stripper-ignore-next
238    /// Returns the remaining items as slice.
239    #[inline]
240    pub fn as_slice(&self) -> &[T] {
241        unsafe {
242            if self.len == 0 {
243                &[]
244            } else {
245                std::slice::from_raw_parts(self.idx.as_ptr() as *mut T, self.len)
246            }
247        }
248    }
249
250    // rustdoc-stripper-ignore-next
251    /// Returns the remaining items as mutable slice.
252    #[inline]
253    pub fn as_mut_slice(&mut self) -> &mut [T] {
254        unsafe {
255            if self.len == 0 {
256                &mut []
257            } else {
258                std::slice::from_raw_parts_mut(self.idx.as_ptr() as *mut T, self.len)
259            }
260        }
261    }
262}
263
264impl<T: TransparentPtrType> Drop for IntoIter<T> {
265    #[inline]
266    fn drop(&mut self) {
267        unsafe {
268            let len = mem::replace(&mut self.len, 0);
269            if mem::needs_drop::<T>() {
270                for i in 0..len {
271                    ptr::drop_in_place::<T>(self.idx.as_ptr().add(i) as *mut T);
272                }
273            }
274
275            let empty = mem::replace(&mut self.empty, true);
276            if !empty {
277                ffi::g_free(self.ptr.as_ptr() as ffi::gpointer);
278            }
279        }
280    }
281}
282
283impl<T: TransparentPtrType> Iterator for IntoIter<T> {
284    type Item = T;
285
286    #[inline]
287    fn next(&mut self) -> Option<Self::Item> {
288        if self.len == 0 {
289            return None;
290        }
291
292        unsafe {
293            let p = self.idx.as_ptr();
294            self.len -= 1;
295            self.idx = ptr::NonNull::new_unchecked(p.add(1));
296            Some(ptr::read(p as *mut T))
297        }
298    }
299
300    #[inline]
301    fn size_hint(&self) -> (usize, Option<usize>) {
302        (self.len, Some(self.len))
303    }
304
305    #[inline]
306    fn count(self) -> usize {
307        self.len
308    }
309
310    #[inline]
311    fn last(mut self) -> Option<T> {
312        if self.len == 0 {
313            None
314        } else {
315            self.len -= 1;
316            Some(unsafe { ptr::read(self.idx.as_ptr().add(self.len) as *mut T) })
317        }
318    }
319}
320
321impl<T: TransparentPtrType> DoubleEndedIterator for IntoIter<T> {
322    #[inline]
323    fn next_back(&mut self) -> Option<T> {
324        if self.len == 0 {
325            None
326        } else {
327            self.len -= 1;
328            Some(unsafe { ptr::read(self.idx.as_ptr().add(self.len) as *mut T) })
329        }
330    }
331}
332
333impl<T: TransparentPtrType> ExactSizeIterator for IntoIter<T> {}
334
335impl<T: TransparentPtrType> std::iter::FusedIterator for IntoIter<T> {}
336
337impl<T: TransparentPtrType> From<PtrSlice<T>> for Vec<T> {
338    #[inline]
339    fn from(mut value: PtrSlice<T>) -> Self {
340        unsafe {
341            let mut s = Vec::with_capacity(value.len);
342            ptr::copy_nonoverlapping(value.ptr.as_ptr() as *const T, s.as_mut_ptr(), value.len);
343            s.set_len(value.len);
344            value.len = 0;
345            s
346        }
347    }
348}
349
350impl<T: TransparentPtrType> From<Vec<T>> for PtrSlice<T> {
351    #[inline]
352    fn from(mut value: Vec<T>) -> Self {
353        unsafe {
354            let mut s = Self::with_capacity(value.len());
355            ptr::copy_nonoverlapping(value.as_ptr(), s.ptr.as_ptr() as *mut T, value.len());
356            s.len = value.len();
357            value.set_len(0);
358            ptr::write(
359                s.ptr.as_ptr().add(s.len),
360                Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
361            );
362            s
363        }
364    }
365}
366
367impl<T: TransparentPtrType, const N: usize> From<[T; N]> for PtrSlice<T> {
368    #[inline]
369    fn from(value: [T; N]) -> Self {
370        unsafe {
371            let value = mem::ManuallyDrop::new(value);
372            let len = value.len();
373            let mut s = Self::with_capacity(len);
374            ptr::copy_nonoverlapping(value.as_ptr(), s.ptr.as_ptr() as *mut T, len);
375            s.len = len;
376            ptr::write(
377                s.ptr.as_ptr().add(len),
378                Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
379            );
380            s
381        }
382    }
383}
384
385impl<'a, T: TransparentPtrType> From<&'a [T]> for PtrSlice<T> {
386    #[inline]
387    fn from(value: &'a [T]) -> Self {
388        unsafe {
389            let mut s = Self::with_capacity(value.len());
390            for (i, item) in value.iter().enumerate() {
391                ptr::write(s.ptr.as_ptr().add(i) as *mut T, item.clone());
392            }
393            s.len = value.len();
394            ptr::write(
395                s.ptr.as_ptr().add(s.len),
396                Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
397            );
398            s
399        }
400    }
401}
402
403impl<'a, T: TransparentPtrType> From<&'a [&'a T]> for PtrSlice<T> {
404    #[inline]
405    fn from(value: &'a [&'a T]) -> Self {
406        unsafe {
407            let mut s = Self::with_capacity(value.len());
408            for (i, item) in value.iter().enumerate() {
409                ptr::write(s.ptr.as_ptr().add(i) as *mut T, (*item).clone());
410            }
411            s.len = value.len();
412            ptr::write(
413                s.ptr.as_ptr().add(s.len),
414                Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
415            );
416            s
417        }
418    }
419}
420
421impl<T: TransparentPtrType> Clone for PtrSlice<T> {
422    #[inline]
423    fn clone(&self) -> Self {
424        Self::from(self.as_slice())
425    }
426}
427
428impl<T: TransparentPtrType> PtrSlice<T> {
429    // rustdoc-stripper-ignore-next
430    /// Borrows a C array.
431    #[inline]
432    pub unsafe fn from_glib_borrow<'a>(ptr: *const <T as GlibPtrDefault>::GlibType) -> &'a [T] {
433        unsafe {
434            let mut len = 0;
435            if !ptr.is_null() {
436                while !(*ptr.add(len)).is_null() {
437                    len += 1;
438                }
439            }
440            Self::from_glib_borrow_num(ptr, len)
441        }
442    }
443
444    // rustdoc-stripper-ignore-next
445    /// Borrows a C array.
446    #[inline]
447    pub unsafe fn from_glib_borrow_num<'a>(
448        ptr: *const <T as GlibPtrDefault>::GlibType,
449        len: usize,
450    ) -> &'a [T] {
451        unsafe {
452            debug_assert_eq!(
453                mem::size_of::<T>(),
454                mem::size_of::<<T as GlibPtrDefault>::GlibType>()
455            );
456            debug_assert!(!ptr.is_null() || len == 0);
457
458            if len == 0 {
459                &[]
460            } else {
461                std::slice::from_raw_parts(ptr as *const T, len)
462            }
463        }
464    }
465
466    // rustdoc-stripper-ignore-next
467    /// Create a new `PtrSlice` around a C array.
468    #[inline]
469    pub unsafe fn from_glib_none_num(
470        ptr: *const <T as GlibPtrDefault>::GlibType,
471        len: usize,
472        _null_terminated: bool,
473    ) -> Self {
474        unsafe {
475            debug_assert_eq!(
476                mem::size_of::<T>(),
477                mem::size_of::<<T as GlibPtrDefault>::GlibType>()
478            );
479            debug_assert!(!ptr.is_null() || len == 0);
480
481            if len == 0 {
482                PtrSlice::default()
483            } else {
484                // Need to fully copy the array here.
485                let s = Self::from_glib_borrow_num(ptr, len);
486                Self::from(s)
487            }
488        }
489    }
490
491    // rustdoc-stripper-ignore-next
492    /// Create a new `PtrSlice` around a C array.
493    #[inline]
494    pub unsafe fn from_glib_container_num(
495        ptr: *mut <T as GlibPtrDefault>::GlibType,
496        len: usize,
497        null_terminated: bool,
498    ) -> Self {
499        unsafe {
500            debug_assert_eq!(
501                mem::size_of::<T>(),
502                mem::size_of::<<T as GlibPtrDefault>::GlibType>()
503            );
504            debug_assert!(!ptr.is_null() || len == 0);
505
506            if len == 0 {
507                ffi::g_free(ptr as ffi::gpointer);
508                PtrSlice::default()
509            } else {
510                // Need to clone every item because we don't own it here
511                for i in 0..len {
512                    let p = ptr.add(i) as *mut T;
513                    let clone: T = (*p).clone();
514                    ptr::write(p, clone);
515                }
516
517                // And now it can be handled exactly the same as `from_glib_full_num()`.
518                Self::from_glib_full_num(ptr, len, null_terminated)
519            }
520        }
521    }
522
523    // rustdoc-stripper-ignore-next
524    /// Create a new `PtrSlice` around a C array.
525    #[inline]
526    pub unsafe fn from_glib_full_num(
527        ptr: *mut <T as GlibPtrDefault>::GlibType,
528        len: usize,
529        null_terminated: bool,
530    ) -> Self {
531        unsafe {
532            debug_assert_eq!(
533                mem::size_of::<T>(),
534                mem::size_of::<<T as GlibPtrDefault>::GlibType>()
535            );
536            debug_assert!(!ptr.is_null() || len == 0);
537
538            if len == 0 {
539                ffi::g_free(ptr as ffi::gpointer);
540                PtrSlice::default()
541            } else {
542                if null_terminated {
543                    return PtrSlice {
544                        ptr: ptr::NonNull::new_unchecked(ptr),
545                        len,
546                        capacity: len + 1,
547                    };
548                }
549
550                // Need to re-allocate here for adding the NULL-terminator
551                let capacity = len + 1;
552                assert_ne!(capacity, 0);
553                let ptr = ffi::g_realloc(
554                    ptr as *mut _,
555                    mem::size_of::<T>().checked_mul(capacity).unwrap(),
556                ) as *mut <T as GlibPtrDefault>::GlibType;
557
558                ptr::write(
559                    ptr.add(len),
560                    Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
561                );
562
563                PtrSlice {
564                    ptr: ptr::NonNull::new_unchecked(ptr),
565                    len,
566                    capacity,
567                }
568            }
569        }
570    }
571
572    // rustdoc-stripper-ignore-next
573    /// Create a new `PtrSlice` around a `NULL`-terminated C array.
574    #[inline]
575    pub unsafe fn from_glib_none(ptr: *const <T as GlibPtrDefault>::GlibType) -> Self {
576        unsafe {
577            let mut len = 0;
578            if !ptr.is_null() {
579                while !(*ptr.add(len)).is_null() {
580                    len += 1;
581                }
582            }
583
584            PtrSlice::from_glib_none_num(ptr, len, true)
585        }
586    }
587
588    // rustdoc-stripper-ignore-next
589    /// Create a new `PtrSlice` around a `NULL`-terminated C array.
590    #[inline]
591    pub unsafe fn from_glib_container(ptr: *mut <T as GlibPtrDefault>::GlibType) -> Self {
592        unsafe {
593            let mut len = 0;
594            if !ptr.is_null() {
595                while !(*ptr.add(len)).is_null() {
596                    len += 1;
597                }
598            }
599
600            PtrSlice::from_glib_container_num(ptr, len, true)
601        }
602    }
603
604    // rustdoc-stripper-ignore-next
605    /// Create a new `PtrSlice` around a `NULL`-terminated C array.
606    #[inline]
607    pub unsafe fn from_glib_full(ptr: *mut <T as GlibPtrDefault>::GlibType) -> Self {
608        unsafe {
609            let mut len = 0;
610            if !ptr.is_null() {
611                while !(*ptr.add(len)).is_null() {
612                    len += 1;
613                }
614            }
615
616            PtrSlice::from_glib_full_num(ptr, len, true)
617        }
618    }
619
620    // rustdoc-stripper-ignore-next
621    /// Creates a new empty slice.
622    #[inline]
623    pub fn new() -> Self {
624        debug_assert_eq!(
625            mem::size_of::<T>(),
626            mem::size_of::<<T as GlibPtrDefault>::GlibType>()
627        );
628
629        PtrSlice {
630            ptr: ptr::NonNull::dangling(),
631            len: 0,
632            capacity: 0,
633        }
634    }
635
636    // rustdoc-stripper-ignore-next
637    /// Creates a new empty slice with the given capacity.
638    #[inline]
639    pub fn with_capacity(capacity: usize) -> Self {
640        let mut s = Self::new();
641        s.reserve(capacity);
642        s
643    }
644
645    // rustdoc-stripper-ignore-next
646    /// Returns the underlying pointer.
647    ///
648    /// This is guaranteed to be `NULL`-terminated.
649    #[inline]
650    pub fn as_ptr(&self) -> *const <T as GlibPtrDefault>::GlibType {
651        if self.len == 0 {
652            static EMPTY: [usize; 1] = [0];
653
654            EMPTY.as_ptr() as *const _
655        } else {
656            self.ptr.as_ptr()
657        }
658    }
659
660    // rustdoc-stripper-ignore-next
661    /// Returns the underlying pointer.
662    ///
663    /// This is guaranteed to be `NULL`-terminated.
664    #[inline]
665    pub fn as_mut_ptr(&mut self) -> *mut <T as GlibPtrDefault>::GlibType {
666        if self.len == 0 {
667            static EMPTY: [usize; 1] = [0];
668
669            EMPTY.as_ptr() as *mut _
670        } else {
671            self.ptr.as_ptr()
672        }
673    }
674
675    // rustdoc-stripper-ignore-next
676    /// Consumes the slice and returns the underlying pointer.
677    ///
678    /// This is guaranteed to be `NULL`-terminated.
679    #[inline]
680    pub fn into_raw(mut self) -> *mut <T as GlibPtrDefault>::GlibType {
681        // Make sure to allocate a valid pointer that points to a
682        // NULL-pointer.
683        if self.len == 0 {
684            self.reserve(0);
685            unsafe {
686                ptr::write(
687                    self.ptr.as_ptr().add(0),
688                    Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
689                );
690            }
691        }
692
693        self.len = 0;
694        self.capacity = 0;
695        self.ptr.as_ptr()
696    }
697
698    // rustdoc-stripper-ignore-next
699    /// Gets the length of the slice.
700    #[inline]
701    pub fn len(&self) -> usize {
702        self.len
703    }
704
705    // rustdoc-stripper-ignore-next
706    /// Returns `true` if the slice is empty.
707    #[inline]
708    pub fn is_empty(&self) -> bool {
709        self.len == 0
710    }
711
712    // rustdoc-stripper-ignore-next
713    /// Returns the capacity of the slice.
714    ///
715    /// This includes the space that is reserved for the `NULL`-terminator.
716    #[inline]
717    pub fn capacity(&self) -> usize {
718        self.capacity
719    }
720
721    // rustdoc-stripper-ignore-next
722    /// Sets the length of the slice to `len`.
723    ///
724    /// # SAFETY
725    ///
726    /// There must be at least `len` valid items and a `NULL`-terminator after the last item.
727    pub unsafe fn set_len(&mut self, len: usize) {
728        self.len = len;
729    }
730
731    // rustdoc-stripper-ignore-next
732    /// Reserves at least this much additional capacity.
733    #[allow(clippy::int_plus_one)]
734    pub fn reserve(&mut self, additional: usize) {
735        // Nothing new to reserve as there's still enough space
736        if additional < self.capacity - self.len {
737            return;
738        }
739
740        let new_capacity =
741            usize::next_power_of_two(std::cmp::max(self.len + additional, MIN_SIZE) + 1);
742        assert_ne!(new_capacity, 0);
743        assert!(new_capacity > self.capacity);
744
745        unsafe {
746            let ptr = if self.capacity == 0 {
747                ptr::null_mut()
748            } else {
749                self.ptr.as_ptr() as *mut _
750            };
751            let new_ptr =
752                ffi::g_realloc(ptr, mem::size_of::<T>().checked_mul(new_capacity).unwrap())
753                    as *mut <T as GlibPtrDefault>::GlibType;
754            if self.capacity == 0 {
755                ptr::write(
756                    new_ptr,
757                    Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
758                );
759            }
760            self.ptr = ptr::NonNull::new_unchecked(new_ptr);
761            self.capacity = new_capacity;
762        }
763    }
764
765    // rustdoc-stripper-ignore-next
766    /// Borrows this slice as a `&[T]`.
767    #[inline]
768    pub fn as_slice(&self) -> &[T] {
769        unsafe {
770            if self.len == 0 {
771                &[]
772            } else {
773                std::slice::from_raw_parts(self.ptr.as_ptr() as *const T, self.len)
774            }
775        }
776    }
777
778    // rustdoc-stripper-ignore-next
779    /// Borrows this slice as a `&mut [T]`.
780    #[inline]
781    pub fn as_mut_slice(&mut self) -> &mut [T] {
782        unsafe {
783            if self.len == 0 {
784                &mut []
785            } else {
786                std::slice::from_raw_parts_mut(self.ptr.as_ptr() as *mut T, self.len)
787            }
788        }
789    }
790
791    // rustdoc-stripper-ignore-next
792    /// Removes all items from the slice.
793    #[inline]
794    pub fn clear(&mut self) {
795        unsafe {
796            let len = mem::replace(&mut self.len, 0);
797            if mem::needs_drop::<T>() {
798                for i in 0..len {
799                    ptr::drop_in_place::<T>(self.ptr.as_ptr().add(i) as *mut T);
800                }
801            }
802        }
803    }
804
805    // rustdoc-stripper-ignore-next
806    /// Clones and appends all elements in `slice` to the slice.
807    #[inline]
808    pub fn extend_from_slice(&mut self, other: &[T]) {
809        // Nothing new to reserve as there's still enough space
810        if other.len() >= self.capacity - self.len {
811            self.reserve(other.len());
812        }
813
814        unsafe {
815            for item in other {
816                ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item.clone());
817                self.len += 1;
818
819                // Add null terminator on every iteration because `clone`
820                // may panic
821                ptr::write(
822                    self.ptr.as_ptr().add(self.len),
823                    Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
824                );
825            }
826        }
827    }
828
829    // rustdoc-stripper-ignore-next
830    /// Inserts `item` at position `index` of the slice, shifting all elements after it to the
831    /// right.
832    #[inline]
833    pub fn insert(&mut self, index: usize, item: T) {
834        assert!(index <= self.len);
835
836        // Nothing new to reserve as there's still enough space
837        if 1 >= self.capacity - self.len {
838            self.reserve(1);
839        }
840
841        unsafe {
842            if index == self.len {
843                ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item);
844            } else {
845                let p = self.ptr.as_ptr().add(index);
846                ptr::copy(p, p.add(1), self.len - index);
847                ptr::write(self.ptr.as_ptr().add(index) as *mut T, item);
848            }
849
850            self.len += 1;
851
852            ptr::write(
853                self.ptr.as_ptr().add(self.len),
854                Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
855            );
856        }
857    }
858
859    // rustdoc-stripper-ignore-next
860    /// Pushes `item` to the end of the slice.
861    #[inline]
862    pub fn push(&mut self, item: T) {
863        // Nothing new to reserve as there's still enough space
864        if 1 >= self.capacity - self.len {
865            self.reserve(1);
866        }
867
868        unsafe {
869            ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item);
870            self.len += 1;
871
872            ptr::write(
873                self.ptr.as_ptr().add(self.len),
874                Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
875            );
876        }
877    }
878
879    // rustdoc-stripper-ignore-next
880    /// Removes item from position `index` of the slice, shifting all elements after it to the
881    /// left.
882    #[inline]
883    pub fn remove(&mut self, index: usize) -> T {
884        assert!(index < self.len);
885
886        unsafe {
887            let p = self.ptr.as_ptr().add(index);
888            let item = ptr::read(p as *mut T);
889            ptr::copy(p.add(1), p, self.len - index - 1);
890
891            self.len -= 1;
892
893            ptr::write(
894                self.ptr.as_ptr().add(self.len),
895                Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
896            );
897
898            item
899        }
900    }
901
902    // rustdoc-stripper-ignore-next
903    /// Removes the last item of the slice and returns it.
904    #[inline]
905    pub fn pop(&mut self) -> Option<T> {
906        if self.len == 0 {
907            return None;
908        }
909
910        unsafe {
911            self.len -= 1;
912            let p = self.ptr.as_ptr().add(self.len);
913            let item = ptr::read(p as *mut T);
914
915            ptr::write(
916                self.ptr.as_ptr().add(self.len),
917                Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
918            );
919
920            Some(item)
921        }
922    }
923
924    // rustdoc-stripper-ignore-next
925    /// Shortens the slice by keeping the last `len` items.
926    ///
927    /// If there are fewer than `len` items then this has no effect.
928    #[inline]
929    pub fn truncate(&mut self, len: usize) {
930        if self.len <= len {
931            return;
932        }
933
934        unsafe {
935            if mem::needs_drop::<T>() {
936                while self.len > len {
937                    self.len -= 1;
938                    let p = self.ptr.as_ptr().add(self.len);
939                    ptr::drop_in_place::<T>(p as *mut T);
940                    ptr::write(
941                        p,
942                        Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
943                    );
944                }
945            } else {
946                self.len = len;
947            }
948        }
949    }
950}
951
952impl<T: TransparentPtrType>
953    FromGlibContainer<<T as GlibPtrDefault>::GlibType, *mut <T as GlibPtrDefault>::GlibType>
954    for PtrSlice<T>
955{
956    #[inline]
957    unsafe fn from_glib_none_num(ptr: *mut <T as GlibPtrDefault>::GlibType, num: usize) -> Self {
958        unsafe { Self::from_glib_none_num(ptr, num, false) }
959    }
960
961    #[inline]
962    unsafe fn from_glib_container_num(
963        ptr: *mut <T as GlibPtrDefault>::GlibType,
964        num: usize,
965    ) -> Self {
966        unsafe { Self::from_glib_container_num(ptr, num, false) }
967    }
968
969    #[inline]
970    unsafe fn from_glib_full_num(ptr: *mut <T as GlibPtrDefault>::GlibType, num: usize) -> Self {
971        unsafe { Self::from_glib_full_num(ptr, num, false) }
972    }
973}
974
975impl<T: TransparentPtrType>
976    FromGlibContainer<<T as GlibPtrDefault>::GlibType, *const <T as GlibPtrDefault>::GlibType>
977    for PtrSlice<T>
978{
979    unsafe fn from_glib_none_num(ptr: *const <T as GlibPtrDefault>::GlibType, num: usize) -> Self {
980        unsafe { Self::from_glib_none_num(ptr, num, false) }
981    }
982
983    unsafe fn from_glib_container_num(
984        _ptr: *const <T as GlibPtrDefault>::GlibType,
985        _num: usize,
986    ) -> Self {
987        unimplemented!();
988    }
989
990    unsafe fn from_glib_full_num(
991        _ptr: *const <T as GlibPtrDefault>::GlibType,
992        _num: usize,
993    ) -> Self {
994        unimplemented!();
995    }
996}
997
998impl<T: TransparentPtrType>
999    FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *mut <T as GlibPtrDefault>::GlibType>
1000    for PtrSlice<T>
1001{
1002    #[inline]
1003    unsafe fn from_glib_none(ptr: *mut <T as GlibPtrDefault>::GlibType) -> Self {
1004        unsafe { Self::from_glib_none(ptr) }
1005    }
1006
1007    #[inline]
1008    unsafe fn from_glib_container(ptr: *mut <T as GlibPtrDefault>::GlibType) -> Self {
1009        unsafe { Self::from_glib_container(ptr) }
1010    }
1011
1012    #[inline]
1013    unsafe fn from_glib_full(ptr: *mut <T as GlibPtrDefault>::GlibType) -> Self {
1014        unsafe { Self::from_glib_full(ptr) }
1015    }
1016}
1017
1018impl<T: TransparentPtrType>
1019    FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *const <T as GlibPtrDefault>::GlibType>
1020    for PtrSlice<T>
1021{
1022    #[inline]
1023    unsafe fn from_glib_none(ptr: *const <T as GlibPtrDefault>::GlibType) -> Self {
1024        unsafe { Self::from_glib_none(ptr) }
1025    }
1026
1027    unsafe fn from_glib_container(_ptr: *const <T as GlibPtrDefault>::GlibType) -> Self {
1028        unimplemented!();
1029    }
1030
1031    unsafe fn from_glib_full(_ptr: *const <T as GlibPtrDefault>::GlibType) -> Self {
1032        unimplemented!();
1033    }
1034}
1035
1036impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut <T as GlibPtrDefault>::GlibType>
1037    for PtrSlice<T>
1038{
1039    type Storage = PhantomData<&'a Self>;
1040
1041    #[inline]
1042    fn to_glib_none(&'a self) -> Stash<'a, *mut <T as GlibPtrDefault>::GlibType, Self> {
1043        Stash(self.as_ptr() as *mut _, PhantomData)
1044    }
1045
1046    #[inline]
1047    fn to_glib_container(&'a self) -> Stash<'a, *mut <T as GlibPtrDefault>::GlibType, Self> {
1048        unsafe {
1049            let ptr = ffi::g_malloc(mem::size_of::<T>().checked_mul(self.len() + 1).unwrap())
1050                as *mut <T as GlibPtrDefault>::GlibType;
1051            ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1);
1052            Stash(ptr, PhantomData)
1053        }
1054    }
1055
1056    #[inline]
1057    fn to_glib_full(&self) -> *mut <T as GlibPtrDefault>::GlibType {
1058        self.clone().into_raw()
1059    }
1060}
1061
1062impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const <T as GlibPtrDefault>::GlibType>
1063    for PtrSlice<T>
1064{
1065    type Storage = PhantomData<&'a Self>;
1066
1067    #[inline]
1068    fn to_glib_none(&'a self) -> Stash<'a, *const <T as GlibPtrDefault>::GlibType, Self> {
1069        Stash(self.as_ptr(), PhantomData)
1070    }
1071}
1072
1073impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut <T as GlibPtrDefault>::GlibType>
1074    for PtrSlice<T>
1075{
1076    type Storage = PhantomData<&'a mut Self>;
1077
1078    #[inline]
1079    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut <T as GlibPtrDefault>::GlibType, Self> {
1080        StashMut(self.as_mut_ptr(), PhantomData)
1081    }
1082}
1083
1084impl<T: TransparentPtrType> IntoGlibPtr<*mut <T as GlibPtrDefault>::GlibType> for PtrSlice<T> {
1085    #[inline]
1086    fn into_glib_ptr(self) -> *mut <T as GlibPtrDefault>::GlibType {
1087        self.into_raw()
1088    }
1089}
1090
1091impl<T: TransparentPtrType> From<super::Slice<T>> for PtrSlice<T> {
1092    fn from(value: super::Slice<T>) -> Self {
1093        let len = value.len();
1094        let capacity = value.capacity();
1095        unsafe {
1096            let ptr = value.into_raw();
1097            let mut s = PtrSlice::<T> {
1098                ptr: ptr::NonNull::new_unchecked(ptr),
1099                len,
1100                capacity,
1101            };
1102
1103            // Reserve space for the `NULL`-terminator if needed
1104            if len == capacity {
1105                s.reserve(0);
1106            }
1107
1108            ptr::write(
1109                s.ptr.as_ptr().add(s.len()),
1110                Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
1111            );
1112
1113            s
1114        }
1115    }
1116}
1117
1118// rustdoc-stripper-ignore-next
1119/// A trait to accept both `&[T]` or `PtrSlice<T>` as an argument.
1120pub trait IntoPtrSlice<T: TransparentPtrType> {
1121    // rustdoc-stripper-ignore-next
1122    /// Runs the given closure with a `NULL`-terminated array.
1123    fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R;
1124}
1125
1126impl<T: TransparentPtrType> IntoPtrSlice<T> for PtrSlice<T> {
1127    #[inline]
1128    fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R {
1129        <&Self>::run_with_ptr_slice(&self, f)
1130    }
1131}
1132
1133impl<T: TransparentPtrType> IntoPtrSlice<T> for &'_ PtrSlice<T> {
1134    #[inline]
1135    fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R {
1136        f(unsafe { std::slice::from_raw_parts(self.as_ptr() as *mut _, self.len() + 1) })
1137    }
1138}
1139
1140// rustdoc-stripper-ignore-next
1141/// Maximum number of pointers to stack-allocate before falling back to a heap allocation.
1142const MAX_STACK_ALLOCATION: usize = 16;
1143
1144impl<T: TransparentPtrType> IntoPtrSlice<T> for Vec<T> {
1145    #[inline]
1146    fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R {
1147        if self.len() < MAX_STACK_ALLOCATION {
1148            unsafe {
1149                let mut s = mem::MaybeUninit::<
1150                    [<T as GlibPtrDefault>::GlibType; MAX_STACK_ALLOCATION],
1151                >::uninit();
1152                let ptr = s.as_mut_ptr() as *mut <T as GlibPtrDefault>::GlibType;
1153                ptr::copy_nonoverlapping(
1154                    self.as_ptr() as *mut <T as GlibPtrDefault>::GlibType,
1155                    ptr,
1156                    self.len(),
1157                );
1158                ptr::write(
1159                    ptr.add(self.len()),
1160                    Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
1161                );
1162                f(std::slice::from_raw_parts(ptr, self.len() + 1))
1163            }
1164        } else {
1165            PtrSlice::<T>::from(self).run_with_ptr_slice(f)
1166        }
1167    }
1168}
1169
1170impl<T: TransparentPtrType, const N: usize> IntoPtrSlice<T> for [T; N] {
1171    #[inline]
1172    fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R {
1173        if self.len() < MAX_STACK_ALLOCATION {
1174            unsafe {
1175                let mut s = mem::MaybeUninit::<
1176                    [<T as GlibPtrDefault>::GlibType; MAX_STACK_ALLOCATION],
1177                >::uninit();
1178                let ptr = s.as_mut_ptr() as *mut <T as GlibPtrDefault>::GlibType;
1179                ptr::copy_nonoverlapping(
1180                    self.as_ptr() as *mut <T as GlibPtrDefault>::GlibType,
1181                    ptr,
1182                    self.len(),
1183                );
1184                ptr::write(
1185                    ptr.add(self.len()),
1186                    Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
1187                );
1188                f(std::slice::from_raw_parts(ptr, self.len() + 1))
1189            }
1190        } else {
1191            PtrSlice::<T>::from(self).run_with_ptr_slice(f)
1192        }
1193    }
1194}
1195
1196impl<T: TransparentPtrType> IntoPtrSlice<T> for &'_ [T] {
1197    #[inline]
1198    fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R {
1199        if self.len() < MAX_STACK_ALLOCATION {
1200            unsafe {
1201                let mut s = mem::MaybeUninit::<
1202                    [<T as GlibPtrDefault>::GlibType; MAX_STACK_ALLOCATION],
1203                >::uninit();
1204                let ptr = s.as_mut_ptr() as *mut <T as GlibPtrDefault>::GlibType;
1205                ptr::copy_nonoverlapping(
1206                    self.as_ptr() as *mut <T as GlibPtrDefault>::GlibType,
1207                    ptr,
1208                    self.len(),
1209                );
1210                ptr::write(
1211                    ptr.add(self.len()),
1212                    Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
1213                );
1214                f(std::slice::from_raw_parts(ptr, self.len() + 1))
1215            }
1216        } else {
1217            PtrSlice::<T>::from(self).run_with_ptr_slice(f)
1218        }
1219    }
1220}
1221
1222#[cfg(test)]
1223mod test {
1224    use super::*;
1225
1226    #[test]
1227    fn test_from_glib_full() {
1228        let items = [
1229            crate::Error::new(crate::FileError::Failed, "Failed 1"),
1230            crate::Error::new(crate::FileError::Noent, "Failed 2"),
1231            crate::Error::new(crate::FileError::Io, "Failed 3"),
1232            crate::Error::new(crate::FileError::Perm, "Failed 4"),
1233        ];
1234
1235        let slice = unsafe {
1236            let ptr = ffi::g_malloc(mem::size_of::<ffi::GDate>() * 4) as *mut *mut ffi::GError;
1237            ptr::write(ptr.add(0), items[0].to_glib_full());
1238            ptr::write(ptr.add(1), items[1].to_glib_full());
1239            ptr::write(ptr.add(2), items[2].to_glib_full());
1240            ptr::write(ptr.add(3), items[3].to_glib_full());
1241
1242            PtrSlice::<crate::Error>::from_glib_full_num(ptr, 4, false)
1243        };
1244
1245        for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1246            assert_eq!(a.message(), b.message());
1247            assert_eq!(
1248                a.kind::<crate::FileError>().unwrap(),
1249                b.kind::<crate::FileError>().unwrap()
1250            );
1251        }
1252    }
1253
1254    #[test]
1255    fn test_from_glib_none() {
1256        let items = [
1257            crate::Error::new(crate::FileError::Failed, "Failed 1"),
1258            crate::Error::new(crate::FileError::Noent, "Failed 2"),
1259            crate::Error::new(crate::FileError::Io, "Failed 3"),
1260            crate::Error::new(crate::FileError::Perm, "Failed 4"),
1261        ];
1262
1263        let slice = unsafe {
1264            PtrSlice::<crate::Error>::from_glib_none_num(
1265                items.as_ptr() as *const *mut ffi::GError,
1266                4,
1267                false,
1268            )
1269        };
1270
1271        for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1272            assert_eq!(a.message(), b.message());
1273            assert_eq!(
1274                a.kind::<crate::FileError>().unwrap(),
1275                b.kind::<crate::FileError>().unwrap()
1276            );
1277        }
1278    }
1279
1280    #[test]
1281    fn test_safe_api() {
1282        let items = [
1283            crate::Error::new(crate::FileError::Failed, "Failed 1"),
1284            crate::Error::new(crate::FileError::Noent, "Failed 2"),
1285            crate::Error::new(crate::FileError::Io, "Failed 3"),
1286        ];
1287
1288        let mut slice = PtrSlice::from(&items[..]);
1289        assert_eq!(slice.len(), 3);
1290        slice.push(crate::Error::new(crate::FileError::Perm, "Failed 4"));
1291        assert_eq!(slice.len(), 4);
1292
1293        for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1294            assert_eq!(a.message(), b.message());
1295            assert_eq!(
1296                a.kind::<crate::FileError>().unwrap(),
1297                b.kind::<crate::FileError>().unwrap()
1298            );
1299        }
1300        assert_eq!(slice[3].message(), "Failed 4");
1301
1302        let vec = Vec::from(slice);
1303        assert_eq!(vec.len(), 4);
1304        for (a, b) in Iterator::zip(items.iter(), vec.iter()) {
1305            assert_eq!(a.message(), b.message());
1306            assert_eq!(
1307                a.kind::<crate::FileError>().unwrap(),
1308                b.kind::<crate::FileError>().unwrap()
1309            );
1310        }
1311        assert_eq!(vec[3].message(), "Failed 4");
1312
1313        let mut slice = PtrSlice::from(vec);
1314        assert_eq!(slice.len(), 4);
1315        let e = slice.pop().unwrap();
1316        assert_eq!(e.message(), "Failed 4");
1317        assert_eq!(slice.len(), 3);
1318        slice.insert(2, e);
1319        assert_eq!(slice.len(), 4);
1320        assert_eq!(slice[0].message(), "Failed 1");
1321        assert_eq!(slice[1].message(), "Failed 2");
1322        assert_eq!(slice[2].message(), "Failed 4");
1323        assert_eq!(slice[3].message(), "Failed 3");
1324        let e = slice.remove(2);
1325        assert_eq!(e.message(), "Failed 4");
1326        assert_eq!(slice.len(), 3);
1327        slice.push(e);
1328        assert_eq!(slice.len(), 4);
1329
1330        let slice2 = crate::Slice::from(slice.clone());
1331
1332        for (a, b) in Iterator::zip(items.iter(), slice) {
1333            assert_eq!(a.message(), b.message());
1334            assert_eq!(
1335                a.kind::<crate::FileError>().unwrap(),
1336                b.kind::<crate::FileError>().unwrap()
1337            );
1338        }
1339
1340        let slice3 = crate::PtrSlice::from(slice2.clone());
1341
1342        for (a, b) in Iterator::zip(items.iter(), slice2) {
1343            assert_eq!(a.message(), b.message());
1344            assert_eq!(
1345                a.kind::<crate::FileError>().unwrap(),
1346                b.kind::<crate::FileError>().unwrap()
1347            );
1348        }
1349
1350        for (a, b) in Iterator::zip(items.iter(), slice3) {
1351            assert_eq!(a.message(), b.message());
1352            assert_eq!(
1353                a.kind::<crate::FileError>().unwrap(),
1354                b.kind::<crate::FileError>().unwrap()
1355            );
1356        }
1357    }
1358
1359    #[test]
1360    fn test_into_ptrslice() {
1361        let items = [
1362            crate::Error::new(crate::FileError::Failed, "Failed 1"),
1363            crate::Error::new(crate::FileError::Noent, "Failed 2"),
1364            crate::Error::new(crate::FileError::Io, "Failed 3"),
1365            crate::Error::new(crate::FileError::Perm, "Failed 4"),
1366        ];
1367
1368        items[..].run_with_ptr_slice(|s| unsafe {
1369            assert!(s[4].is_null());
1370            assert_eq!(s.len(), items.len() + 1);
1371            let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, items.len());
1372            assert_eq!(s, items);
1373        });
1374
1375        Vec::from(&items[..]).run_with_ptr_slice(|s| unsafe {
1376            assert!(s[4].is_null());
1377            assert_eq!(s.len(), items.len() + 1);
1378            let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, items.len());
1379            for (a, b) in Iterator::zip(items.iter(), s.iter()) {
1380                assert_eq!(a.message(), b.message());
1381                assert_eq!(
1382                    a.kind::<crate::FileError>().unwrap(),
1383                    b.kind::<crate::FileError>().unwrap()
1384                );
1385            }
1386        });
1387
1388        PtrSlice::<crate::Error>::from(&items[..]).run_with_ptr_slice(|s| unsafe {
1389            assert!(s[4].is_null());
1390            assert_eq!(s.len(), items.len() + 1);
1391            let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, items.len());
1392            for (a, b) in Iterator::zip(items.iter(), s.iter()) {
1393                assert_eq!(a.message(), b.message());
1394                assert_eq!(
1395                    a.kind::<crate::FileError>().unwrap(),
1396                    b.kind::<crate::FileError>().unwrap()
1397                );
1398            }
1399        });
1400
1401        let v = Vec::from(&items[..]);
1402        items.run_with_ptr_slice(|s| unsafe {
1403            assert!(s[4].is_null());
1404            assert_eq!(s.len(), v.len() + 1);
1405            let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, v.len());
1406            for (a, b) in Iterator::zip(v.iter(), s.iter()) {
1407                assert_eq!(a.message(), b.message());
1408                assert_eq!(
1409                    a.kind::<crate::FileError>().unwrap(),
1410                    b.kind::<crate::FileError>().unwrap()
1411                );
1412            }
1413        });
1414    }
1415}