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::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>`]
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: usize in 0..self.len {
88 ptr::drop_in_place::<T>(self.ptr.as_ptr().add(count: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: ::IntoIter = iter.into_iter();
154 self.reserve(additional:iter.size_hint().0);
155
156 for item: T 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: ::IntoIter = iter.into_iter();
166 self.reserve(additional:iter.size_hint().0);
167
168 for item: &T 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: ::IntoIter = iter.into_iter();
178 let mut s: PtrSlice = Self::with_capacity(iter.size_hint().0);
179 for item: T 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: usize in 0..self.len {
268 ptr::drop_in_place::<T>(self.idx.as_ptr().add(count: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 = Vec::with_capacity(value.len);
338 ptr::copy_nonoverlapping(src:value.ptr.as_ptr() as *const T, dst:s.as_mut_ptr(), count:value.len);
339 s.set_len(new_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: PtrSlice = Self::with_capacity(value.len());
351 ptr::copy_nonoverlapping(src:value.as_ptr(), dst:s.ptr.as_ptr() as *mut T, count:value.len());
352 s.len = value.len();
353 value.set_len(new_len:0);
354 ptr::write(
355 dst:s.ptr.as_ptr().add(s.len),
356 src:Ptr::from(ptr: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: ManuallyDrop<[T; N]> = mem::ManuallyDrop::new(value);
368 let len: usize = value.len();
369 let mut s: PtrSlice = Self::with_capacity(len);
370 ptr::copy_nonoverlapping(src:value.as_ptr(), dst:s.ptr.as_ptr() as *mut T, count:len);
371 s.len = len;
372 ptr::write(
373 dst:s.ptr.as_ptr().add(len),
374 src:Ptr::from(ptr: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: PtrSlice = Self::with_capacity(value.len());
386 for (i: usize, item: &T) in value.iter().enumerate() {
387 ptr::write(dst:s.ptr.as_ptr().add(i) as *mut T, src:item.clone());
388 }
389 s.len = value.len();
390 ptr::write(
391 dst:s.ptr.as_ptr().add(s.len),
392 src:Ptr::from(ptr: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: PtrSlice = Self::with_capacity(value.len());
404 for (i: usize, item: &&T) in value.iter().enumerate() {
405 ptr::write(dst:s.ptr.as_ptr().add(i) as *mut T, (*item).clone());
406 }
407 s.len = value.len();
408 ptr::write(
409 dst:s.ptr.as_ptr().add(s.len),
410 src:Ptr::from(ptr: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 PtrSlice {
605 ptr: ptr::NonNull::dangling(),
606 len: 0,
607 capacity: 0,
608 }
609 }
610
611 // rustdoc-stripper-ignore-next
612 /// Creates a new empty slice with the given capacity.
613 #[inline]
614 pub fn with_capacity(capacity: usize) -> Self {
615 let mut s = Self::new();
616 s.reserve(capacity);
617 s
618 }
619
620 // rustdoc-stripper-ignore-next
621 /// Returns the underlying pointer.
622 ///
623 /// This is guaranteed to be `NULL`-terminated.
624 #[inline]
625 pub fn as_ptr(&self) -> *const <T as GlibPtrDefault>::GlibType {
626 if self.len == 0 {
627 static EMPTY: [usize; 1] = [0];
628
629 EMPTY.as_ptr() as *const _
630 } else {
631 self.ptr.as_ptr()
632 }
633 }
634
635 // rustdoc-stripper-ignore-next
636 /// Returns the underlying pointer.
637 ///
638 /// This is guaranteed to be `NULL`-terminated.
639 #[inline]
640 pub fn as_mut_ptr(&mut self) -> *mut <T as GlibPtrDefault>::GlibType {
641 if self.len == 0 {
642 static EMPTY: [usize; 1] = [0];
643
644 EMPTY.as_ptr() as *mut _
645 } else {
646 self.ptr.as_ptr()
647 }
648 }
649
650 // rustdoc-stripper-ignore-next
651 /// Consumes the slice and returns the underlying pointer.
652 ///
653 /// This is guaranteed to be `NULL`-terminated.
654 #[inline]
655 pub fn into_raw(mut self) -> *mut <T as GlibPtrDefault>::GlibType {
656 if self.len == 0 {
657 ptr::null_mut()
658 } else {
659 self.len = 0;
660 self.capacity = 0;
661 self.ptr.as_ptr()
662 }
663 }
664
665 // rustdoc-stripper-ignore-next
666 /// Gets the length of the slice.
667 #[inline]
668 pub fn len(&self) -> usize {
669 self.len
670 }
671
672 // rustdoc-stripper-ignore-next
673 /// Returns `true` if the slice is empty.
674 #[inline]
675 pub fn is_empty(&self) -> bool {
676 self.len == 0
677 }
678
679 // rustdoc-stripper-ignore-next
680 /// Returns the capacity of the slice.
681 ///
682 /// This includes the space that is reserved for the `NULL`-terminator.
683 #[inline]
684 pub fn capacity(&self) -> usize {
685 self.capacity
686 }
687
688 // rustdoc-stripper-ignore-next
689 /// Sets the length of the slice to `len`.
690 ///
691 /// # SAFETY
692 ///
693 /// There must be at least `len` valid items and a `NULL`-terminator after the last item.
694 pub unsafe fn set_len(&mut self, len: usize) {
695 self.len = len;
696 }
697
698 // rustdoc-stripper-ignore-next
699 /// Reserves at least this much additional capacity.
700 #[allow(clippy::int_plus_one)]
701 pub fn reserve(&mut self, additional: usize) {
702 // Nothing new to reserve as there's still enough space
703 if self.len + additional + 1 <= self.capacity {
704 return;
705 }
706
707 let new_capacity =
708 usize::next_power_of_two(std::cmp::max(self.len + additional, MIN_SIZE) + 1);
709 assert_ne!(new_capacity, 0);
710 assert!(new_capacity > self.capacity);
711
712 unsafe {
713 let ptr = if self.capacity == 0 {
714 ptr::null_mut()
715 } else {
716 self.ptr.as_ptr() as *mut _
717 };
718 let new_ptr =
719 ffi::g_realloc(ptr, mem::size_of::<T>().checked_mul(new_capacity).unwrap())
720 as *mut <T as GlibPtrDefault>::GlibType;
721 self.ptr = ptr::NonNull::new_unchecked(new_ptr);
722 self.capacity = new_capacity;
723 }
724 }
725
726 // rustdoc-stripper-ignore-next
727 /// Borrows this slice as a `&[T]`.
728 #[inline]
729 pub fn as_slice(&self) -> &[T] {
730 unsafe {
731 if self.len == 0 {
732 &[]
733 } else {
734 std::slice::from_raw_parts(self.ptr.as_ptr() as *const T, self.len)
735 }
736 }
737 }
738
739 // rustdoc-stripper-ignore-next
740 /// Borrows this slice as a `&mut [T]`.
741 #[inline]
742 pub fn as_mut_slice(&mut self) -> &mut [T] {
743 unsafe {
744 if self.len == 0 {
745 &mut []
746 } else {
747 std::slice::from_raw_parts_mut(self.ptr.as_ptr() as *mut T, self.len)
748 }
749 }
750 }
751
752 // rustdoc-stripper-ignore-next
753 /// Removes all items from the slice.
754 #[inline]
755 pub fn clear(&mut self) {
756 unsafe {
757 if mem::needs_drop::<T>() {
758 for i in 0..self.len {
759 ptr::drop_in_place::<T>(self.ptr.as_ptr().add(i) as *mut T);
760 }
761 }
762
763 self.len = 0;
764 }
765 }
766
767 // rustdoc-stripper-ignore-next
768 /// Clones and appends all elements in `slice` to the slice.
769 #[inline]
770 pub fn extend_from_slice(&mut self, other: &[T]) {
771 // Nothing new to reserve as there's still enough space
772 if self.len + other.len() + 1 > self.capacity {
773 self.reserve(other.len());
774 }
775
776 unsafe {
777 for item in other {
778 ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item.clone());
779 self.len += 1;
780 }
781
782 ptr::write(
783 self.ptr.as_ptr().add(self.len),
784 Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
785 );
786 }
787 }
788
789 // rustdoc-stripper-ignore-next
790 /// Inserts `item` at position `index` of the slice, shifting all elements after it to the
791 /// right.
792 #[inline]
793 pub fn insert(&mut self, index: usize, item: T) {
794 assert!(index <= self.len);
795
796 // Nothing new to reserve as there's still enough space
797 if self.len + 1 + 1 > self.capacity {
798 self.reserve(1);
799 }
800
801 unsafe {
802 if index == self.len {
803 ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item);
804 } else {
805 let p = self.ptr.as_ptr().add(index);
806 ptr::copy(p, p.add(1), self.len - index);
807 ptr::write(self.ptr.as_ptr().add(index) as *mut T, item);
808 }
809
810 self.len += 1;
811
812 ptr::write(
813 self.ptr.as_ptr().add(self.len),
814 Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
815 );
816 }
817 }
818
819 // rustdoc-stripper-ignore-next
820 /// Pushes `item` to the end of the slice.
821 #[inline]
822 pub fn push(&mut self, item: T) {
823 // Nothing new to reserve as there's still enough space
824 if self.len + 1 + 1 > self.capacity {
825 self.reserve(1);
826 }
827
828 unsafe {
829 ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item);
830 self.len += 1;
831
832 ptr::write(
833 self.ptr.as_ptr().add(self.len),
834 Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
835 );
836 }
837 }
838
839 // rustdoc-stripper-ignore-next
840 /// Removes item from position `index` of the slice, shifting all elements after it to the
841 /// left.
842 #[inline]
843 pub fn remove(&mut self, index: usize) -> T {
844 assert!(index < self.len);
845
846 unsafe {
847 let p = self.ptr.as_ptr().add(index);
848 let item = ptr::read(p as *mut T);
849 ptr::copy(p.add(1), p, self.len - index - 1);
850
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 item
859 }
860 }
861
862 // rustdoc-stripper-ignore-next
863 /// Removes the last item of the slice and returns it.
864 #[inline]
865 pub fn pop(&mut self) -> Option<T> {
866 if self.len == 0 {
867 return None;
868 }
869
870 unsafe {
871 self.len -= 1;
872 let p = self.ptr.as_ptr().add(self.len);
873 let item = ptr::read(p as *mut T);
874
875 ptr::write(
876 self.ptr.as_ptr().add(self.len),
877 Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
878 );
879
880 Some(item)
881 }
882 }
883
884 // rustdoc-stripper-ignore-next
885 /// Shortens the slice by keeping the last `len` items.
886 ///
887 /// If there are fewer than `len` items then this has no effect.
888 #[inline]
889 pub fn truncate(&mut self, len: usize) {
890 if self.len <= len {
891 return;
892 }
893
894 unsafe {
895 while self.len > len {
896 self.len -= 1;
897 let p = self.ptr.as_ptr().add(self.len);
898 ptr::drop_in_place::<T>(p as *mut T);
899 ptr::write(
900 p,
901 Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
902 );
903 }
904 }
905 }
906}
907
908impl<T: TransparentPtrType>
909 FromGlibContainer<<T as GlibPtrDefault>::GlibType, *mut <T as GlibPtrDefault>::GlibType>
910 for PtrSlice<T>
911{
912 #[inline]
913 unsafe fn from_glib_none_num(ptr: *mut <T as GlibPtrDefault>::GlibType, num: usize) -> Self {
914 Self::from_glib_none_num(ptr, len:num, _null_terminated:false)
915 }
916
917 #[inline]
918 unsafe fn from_glib_container_num(
919 ptr: *mut <T as GlibPtrDefault>::GlibType,
920 num: usize,
921 ) -> Self {
922 Self::from_glib_container_num(ptr, len:num, null_terminated:false)
923 }
924
925 #[inline]
926 unsafe fn from_glib_full_num(ptr: *mut <T as GlibPtrDefault>::GlibType, num: usize) -> Self {
927 Self::from_glib_full_num(ptr, len:num, null_terminated:false)
928 }
929}
930
931impl<T: TransparentPtrType>
932 FromGlibContainer<<T as GlibPtrDefault>::GlibType, *const <T as GlibPtrDefault>::GlibType>
933 for PtrSlice<T>
934{
935 unsafe fn from_glib_none_num(ptr: *const <T as GlibPtrDefault>::GlibType, num: usize) -> Self {
936 Self::from_glib_none_num(ptr, len:num, _null_terminated:false)
937 }
938
939 unsafe fn from_glib_container_num(
940 _ptr: *const <T as GlibPtrDefault>::GlibType,
941 _num: usize,
942 ) -> Self {
943 unimplemented!();
944 }
945
946 unsafe fn from_glib_full_num(
947 _ptr: *const <T as GlibPtrDefault>::GlibType,
948 _num: usize,
949 ) -> Self {
950 unimplemented!();
951 }
952}
953
954impl<T: TransparentPtrType>
955 FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *mut <T as GlibPtrDefault>::GlibType>
956 for PtrSlice<T>
957{
958 #[inline]
959 unsafe fn from_glib_none(ptr: *mut <T as GlibPtrDefault>::GlibType) -> Self {
960 Self::from_glib_none(ptr)
961 }
962
963 #[inline]
964 unsafe fn from_glib_container(ptr: *mut <T as GlibPtrDefault>::GlibType) -> Self {
965 Self::from_glib_container(ptr)
966 }
967
968 #[inline]
969 unsafe fn from_glib_full(ptr: *mut <T as GlibPtrDefault>::GlibType) -> Self {
970 Self::from_glib_full(ptr)
971 }
972}
973
974impl<T: TransparentPtrType>
975 FromGlibPtrContainer<<T as GlibPtrDefault>::GlibType, *const <T as GlibPtrDefault>::GlibType>
976 for PtrSlice<T>
977{
978 #[inline]
979 unsafe fn from_glib_none(ptr: *const <T as GlibPtrDefault>::GlibType) -> Self {
980 Self::from_glib_none(ptr)
981 }
982
983 unsafe fn from_glib_container(_ptr: *const <T as GlibPtrDefault>::GlibType) -> Self {
984 unimplemented!();
985 }
986
987 unsafe fn from_glib_full(_ptr: *const <T as GlibPtrDefault>::GlibType) -> Self {
988 unimplemented!();
989 }
990}
991
992impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut <T as GlibPtrDefault>::GlibType>
993 for PtrSlice<T>
994{
995 type Storage = PhantomData<&'a Self>;
996
997 #[inline]
998 fn to_glib_none(&'a self) -> Stash<'a, *mut <T as GlibPtrDefault>::GlibType, Self> {
999 Stash(self.as_ptr() as *mut _, PhantomData)
1000 }
1001
1002 #[inline]
1003 fn to_glib_container(&'a self) -> Stash<'a, *mut <T as GlibPtrDefault>::GlibType, Self> {
1004 unsafe {
1005 let ptr: *mut ::GlibType = ffi::g_malloc(n_bytes:mem::size_of::<T>().checked_mul(self.len() + 1).unwrap())
1006 as *mut <T as GlibPtrDefault>::GlibType;
1007 ptr::copy_nonoverlapping(self.as_ptr(), dst:ptr, self.len() + 1);
1008 Stash(ptr, PhantomData)
1009 }
1010 }
1011
1012 #[inline]
1013 fn to_glib_full(&self) -> *mut <T as GlibPtrDefault>::GlibType {
1014 self.clone().into_raw()
1015 }
1016}
1017
1018impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const <T as GlibPtrDefault>::GlibType>
1019 for PtrSlice<T>
1020{
1021 type Storage = PhantomData<&'a Self>;
1022
1023 #[inline]
1024 fn to_glib_none(&'a self) -> Stash<'a, *const <T as GlibPtrDefault>::GlibType, Self> {
1025 Stash(self.as_ptr(), PhantomData)
1026 }
1027}
1028
1029impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut <T as GlibPtrDefault>::GlibType>
1030 for PtrSlice<T>
1031{
1032 type Storage = PhantomData<&'a mut Self>;
1033
1034 #[inline]
1035 fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut <T as GlibPtrDefault>::GlibType, Self> {
1036 StashMut(self.as_mut_ptr(), PhantomData)
1037 }
1038}
1039
1040impl<T: TransparentPtrType> IntoGlibPtr<*mut <T as GlibPtrDefault>::GlibType> for PtrSlice<T> {
1041 #[inline]
1042 unsafe fn into_glib_ptr(self) -> *mut <T as GlibPtrDefault>::GlibType {
1043 self.into_raw()
1044 }
1045}
1046
1047impl<T: TransparentPtrType> From<super::Slice<T>> for PtrSlice<T> {
1048 fn from(value: super::Slice<T>) -> Self {
1049 let len = value.len();
1050 let capacity = value.capacity();
1051 unsafe {
1052 let ptr = value.into_raw();
1053 let mut s = PtrSlice::<T> {
1054 ptr: ptr::NonNull::new_unchecked(ptr),
1055 len,
1056 capacity,
1057 };
1058
1059 // Reserve space for the `NULL`-terminator if needed
1060 if len == capacity {
1061 s.reserve(0);
1062 }
1063
1064 ptr::write(
1065 s.ptr.as_ptr().add(s.len()),
1066 Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
1067 );
1068
1069 s
1070 }
1071 }
1072}
1073
1074// rustdoc-stripper-ignore-next
1075/// A trait to accept both `&[T]` or `PtrSlice<T>` as an argument.
1076pub trait IntoPtrSlice<T: TransparentPtrType> {
1077 // rustdoc-stripper-ignore-next
1078 /// Runs the given closure with a `NULL`-terminated array.
1079 fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R;
1080}
1081
1082impl<T: TransparentPtrType> IntoPtrSlice<T> for PtrSlice<T> {
1083 #[inline]
1084 fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R {
1085 <&Self>::run_with_ptr_slice(&self, f)
1086 }
1087}
1088
1089impl<'a, T: TransparentPtrType> IntoPtrSlice<T> for &'a PtrSlice<T> {
1090 #[inline]
1091 fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R {
1092 f(unsafe { std::slice::from_raw_parts(self.as_ptr() as *mut _, self.len() + 1) })
1093 }
1094}
1095
1096// rustdoc-stripper-ignore-next
1097/// Maximum number of pointers to stack-allocate before falling back to a heap allocation.
1098const MAX_STACK_ALLOCATION: usize = 16;
1099
1100impl<T: TransparentPtrType> IntoPtrSlice<T> for Vec<T> {
1101 #[inline]
1102 fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R {
1103 if self.len() < MAX_STACK_ALLOCATION {
1104 unsafe {
1105 let mut s = mem::MaybeUninit::<
1106 [<T as GlibPtrDefault>::GlibType; MAX_STACK_ALLOCATION],
1107 >::uninit();
1108 let ptr = s.as_mut_ptr() as *mut <T as GlibPtrDefault>::GlibType;
1109 ptr::copy_nonoverlapping(
1110 self.as_ptr() as *mut <T as GlibPtrDefault>::GlibType,
1111 ptr,
1112 self.len(),
1113 );
1114 ptr::write(
1115 ptr.add(self.len()),
1116 Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
1117 );
1118 f(std::slice::from_raw_parts(ptr, self.len() + 1))
1119 }
1120 } else {
1121 PtrSlice::<T>::from(self).run_with_ptr_slice(f)
1122 }
1123 }
1124}
1125
1126impl<T: TransparentPtrType, const N: usize> IntoPtrSlice<T> for [T; N] {
1127 #[inline]
1128 fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R {
1129 if self.len() < MAX_STACK_ALLOCATION {
1130 unsafe {
1131 let mut s = mem::MaybeUninit::<
1132 [<T as GlibPtrDefault>::GlibType; MAX_STACK_ALLOCATION],
1133 >::uninit();
1134 let ptr = s.as_mut_ptr() as *mut <T as GlibPtrDefault>::GlibType;
1135 ptr::copy_nonoverlapping(
1136 self.as_ptr() as *mut <T as GlibPtrDefault>::GlibType,
1137 ptr,
1138 self.len(),
1139 );
1140 ptr::write(
1141 ptr.add(self.len()),
1142 Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
1143 );
1144 f(std::slice::from_raw_parts(ptr, self.len() + 1))
1145 }
1146 } else {
1147 PtrSlice::<T>::from(self).run_with_ptr_slice(f)
1148 }
1149 }
1150}
1151
1152impl<'a, T: TransparentPtrType> IntoPtrSlice<T> for &'a [T] {
1153 #[inline]
1154 fn run_with_ptr_slice<R, F: FnOnce(&[<T as GlibPtrDefault>::GlibType]) -> R>(self, f: F) -> R {
1155 if self.len() < MAX_STACK_ALLOCATION {
1156 unsafe {
1157 let mut s = mem::MaybeUninit::<
1158 [<T as GlibPtrDefault>::GlibType; MAX_STACK_ALLOCATION],
1159 >::uninit();
1160 let ptr = s.as_mut_ptr() as *mut <T as GlibPtrDefault>::GlibType;
1161 ptr::copy_nonoverlapping(
1162 self.as_ptr() as *mut <T as GlibPtrDefault>::GlibType,
1163 ptr,
1164 self.len(),
1165 );
1166 ptr::write(
1167 ptr.add(self.len()),
1168 Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
1169 );
1170 f(std::slice::from_raw_parts(ptr, self.len() + 1))
1171 }
1172 } else {
1173 PtrSlice::<T>::from(self).run_with_ptr_slice(f)
1174 }
1175 }
1176}
1177
1178#[cfg(test)]
1179mod test {
1180 use super::*;
1181
1182 #[test]
1183 fn test_from_glib_full() {
1184 let items = [
1185 crate::Error::new(crate::FileError::Failed, "Failed 1"),
1186 crate::Error::new(crate::FileError::Noent, "Failed 2"),
1187 crate::Error::new(crate::FileError::Io, "Failed 3"),
1188 crate::Error::new(crate::FileError::Perm, "Failed 4"),
1189 ];
1190
1191 let slice = unsafe {
1192 let ptr = ffi::g_malloc(mem::size_of::<ffi::GDate>() * 4) as *mut *mut ffi::GError;
1193 ptr::write(ptr.add(0), items[0].to_glib_full());
1194 ptr::write(ptr.add(1), items[1].to_glib_full());
1195 ptr::write(ptr.add(2), items[2].to_glib_full());
1196 ptr::write(ptr.add(3), items[3].to_glib_full());
1197
1198 PtrSlice::<crate::Error>::from_glib_full_num(ptr, 4, false)
1199 };
1200
1201 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1202 assert_eq!(a.message(), b.message());
1203 assert_eq!(
1204 a.kind::<crate::FileError>().unwrap(),
1205 b.kind::<crate::FileError>().unwrap()
1206 );
1207 }
1208 }
1209
1210 #[test]
1211 fn test_from_glib_none() {
1212 let items = [
1213 crate::Error::new(crate::FileError::Failed, "Failed 1"),
1214 crate::Error::new(crate::FileError::Noent, "Failed 2"),
1215 crate::Error::new(crate::FileError::Io, "Failed 3"),
1216 crate::Error::new(crate::FileError::Perm, "Failed 4"),
1217 ];
1218
1219 let slice = unsafe {
1220 PtrSlice::<crate::Error>::from_glib_none_num(
1221 items.as_ptr() as *const *mut ffi::GError,
1222 4,
1223 false,
1224 )
1225 };
1226
1227 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1228 assert_eq!(a.message(), b.message());
1229 assert_eq!(
1230 a.kind::<crate::FileError>().unwrap(),
1231 b.kind::<crate::FileError>().unwrap()
1232 );
1233 }
1234 }
1235
1236 #[test]
1237 fn test_safe_api() {
1238 let items = [
1239 crate::Error::new(crate::FileError::Failed, "Failed 1"),
1240 crate::Error::new(crate::FileError::Noent, "Failed 2"),
1241 crate::Error::new(crate::FileError::Io, "Failed 3"),
1242 ];
1243
1244 let mut slice = PtrSlice::from(&items[..]);
1245 assert_eq!(slice.len(), 3);
1246 slice.push(crate::Error::new(crate::FileError::Perm, "Failed 4"));
1247 assert_eq!(slice.len(), 4);
1248
1249 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1250 assert_eq!(a.message(), b.message());
1251 assert_eq!(
1252 a.kind::<crate::FileError>().unwrap(),
1253 b.kind::<crate::FileError>().unwrap()
1254 );
1255 }
1256 assert_eq!(slice[3].message(), "Failed 4");
1257
1258 let vec = Vec::from(slice);
1259 assert_eq!(vec.len(), 4);
1260 for (a, b) in Iterator::zip(items.iter(), vec.iter()) {
1261 assert_eq!(a.message(), b.message());
1262 assert_eq!(
1263 a.kind::<crate::FileError>().unwrap(),
1264 b.kind::<crate::FileError>().unwrap()
1265 );
1266 }
1267 assert_eq!(vec[3].message(), "Failed 4");
1268
1269 let mut slice = PtrSlice::from(vec);
1270 assert_eq!(slice.len(), 4);
1271 let e = slice.pop().unwrap();
1272 assert_eq!(e.message(), "Failed 4");
1273 assert_eq!(slice.len(), 3);
1274 slice.insert(2, e);
1275 assert_eq!(slice.len(), 4);
1276 assert_eq!(slice[0].message(), "Failed 1");
1277 assert_eq!(slice[1].message(), "Failed 2");
1278 assert_eq!(slice[2].message(), "Failed 4");
1279 assert_eq!(slice[3].message(), "Failed 3");
1280 let e = slice.remove(2);
1281 assert_eq!(e.message(), "Failed 4");
1282 assert_eq!(slice.len(), 3);
1283 slice.push(e);
1284 assert_eq!(slice.len(), 4);
1285
1286 let slice2 = crate::Slice::from(slice.clone());
1287
1288 for (a, b) in Iterator::zip(items.iter(), slice.into_iter()) {
1289 assert_eq!(a.message(), b.message());
1290 assert_eq!(
1291 a.kind::<crate::FileError>().unwrap(),
1292 b.kind::<crate::FileError>().unwrap()
1293 );
1294 }
1295
1296 let slice3 = crate::PtrSlice::from(slice2.clone());
1297
1298 for (a, b) in Iterator::zip(items.iter(), slice2.into_iter()) {
1299 assert_eq!(a.message(), b.message());
1300 assert_eq!(
1301 a.kind::<crate::FileError>().unwrap(),
1302 b.kind::<crate::FileError>().unwrap()
1303 );
1304 }
1305
1306 for (a, b) in Iterator::zip(items.iter(), slice3.into_iter()) {
1307 assert_eq!(a.message(), b.message());
1308 assert_eq!(
1309 a.kind::<crate::FileError>().unwrap(),
1310 b.kind::<crate::FileError>().unwrap()
1311 );
1312 }
1313 }
1314
1315 #[test]
1316 fn test_into_ptrslice() {
1317 let items = [
1318 crate::Error::new(crate::FileError::Failed, "Failed 1"),
1319 crate::Error::new(crate::FileError::Noent, "Failed 2"),
1320 crate::Error::new(crate::FileError::Io, "Failed 3"),
1321 crate::Error::new(crate::FileError::Perm, "Failed 4"),
1322 ];
1323
1324 items[..].run_with_ptr_slice(|s| unsafe {
1325 assert!(s[4].is_null());
1326 assert_eq!(s.len(), items.len() + 1);
1327 let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, items.len());
1328 assert_eq!(s, items);
1329 });
1330
1331 Vec::from(&items[..]).run_with_ptr_slice(|s| unsafe {
1332 assert!(s[4].is_null());
1333 assert_eq!(s.len(), items.len() + 1);
1334 let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, items.len());
1335 for (a, b) in Iterator::zip(items.iter(), s.iter()) {
1336 assert_eq!(a.message(), b.message());
1337 assert_eq!(
1338 a.kind::<crate::FileError>().unwrap(),
1339 b.kind::<crate::FileError>().unwrap()
1340 );
1341 }
1342 });
1343
1344 PtrSlice::<crate::Error>::from(&items[..]).run_with_ptr_slice(|s| unsafe {
1345 assert!(s[4].is_null());
1346 assert_eq!(s.len(), items.len() + 1);
1347 let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, items.len());
1348 for (a, b) in Iterator::zip(items.iter(), s.iter()) {
1349 assert_eq!(a.message(), b.message());
1350 assert_eq!(
1351 a.kind::<crate::FileError>().unwrap(),
1352 b.kind::<crate::FileError>().unwrap()
1353 );
1354 }
1355 });
1356
1357 let v = Vec::from(&items[..]);
1358 items.run_with_ptr_slice(|s| unsafe {
1359 assert!(s[4].is_null());
1360 assert_eq!(s.len(), v.len() + 1);
1361 let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, v.len());
1362 for (a, b) in Iterator::zip(v.iter(), s.iter()) {
1363 assert_eq!(a.message(), b.message());
1364 assert_eq!(
1365 a.kind::<crate::FileError>().unwrap(),
1366 b.kind::<crate::FileError>().unwrap()
1367 );
1368 }
1369 });
1370 }
1371}
1372