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