1use std::{ffi::c_char, fmt, marker::PhantomData, mem, ptr};
4
5use crate::{GStr, GString, GStringPtr, ffi, gobject_ffi, prelude::*, translate::*};
6
7const MIN_SIZE: usize = 16;
10
11pub struct StrV {
18 ptr: ptr::NonNull<*mut c_char>,
19 len: usize,
22 capacity: usize,
25}
26
27impl fmt::Debug for StrV {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 self.as_slice().fmt(f)
30 }
31}
32
33unsafe impl Send for StrV {}
34
35unsafe impl Sync for StrV {}
36
37impl PartialEq for StrV {
38 #[inline]
39 fn eq(&self, other: &Self) -> bool {
40 self.as_slice() == other.as_slice()
41 }
42}
43
44impl Eq for StrV {}
45
46impl PartialOrd for StrV {
47 #[inline]
48 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
49 Some(self.cmp(other))
50 }
51}
52
53impl Ord for StrV {
54 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
55 self.as_slice().cmp(other.as_slice())
56 }
57}
58
59impl std::hash::Hash for StrV {
60 #[inline]
61 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
62 self.as_slice().hash(state)
63 }
64}
65
66impl PartialEq<[&'_ str]> for StrV {
67 fn eq(&self, other: &[&'_ str]) -> bool {
68 if self.len() != other.len() {
69 return false;
70 }
71
72 for (a, b) in Iterator::zip(self.iter(), other.iter()) {
73 if a != b {
74 return false;
75 }
76 }
77
78 true
79 }
80}
81
82impl PartialEq<StrV> for [&'_ str] {
83 #[inline]
84 fn eq(&self, other: &StrV) -> bool {
85 other.eq(self)
86 }
87}
88
89impl Drop for StrV {
90 #[inline]
91 fn drop(&mut self) {
92 unsafe {
93 if self.capacity != 0 {
94 ffi::g_strfreev(self.ptr.as_ptr());
95 }
96 }
97 }
98}
99
100impl Default for StrV {
101 #[inline]
102 fn default() -> Self {
103 Self::new()
104 }
105}
106
107impl AsRef<[GStringPtr]> for StrV {
108 #[inline]
109 fn as_ref(&self) -> &[GStringPtr] {
110 self.as_slice()
111 }
112}
113
114impl std::borrow::Borrow<[GStringPtr]> for StrV {
115 #[inline]
116 fn borrow(&self) -> &[GStringPtr] {
117 self.as_slice()
118 }
119}
120
121impl AsRef<StrVRef> for StrV {
122 #[inline]
123 fn as_ref(&self) -> &StrVRef {
124 self.into()
125 }
126}
127
128impl std::borrow::Borrow<StrVRef> for StrV {
129 #[inline]
130 fn borrow(&self) -> &StrVRef {
131 self.into()
132 }
133}
134
135impl std::ops::Deref for StrV {
136 type Target = StrVRef;
137
138 #[inline]
139 fn deref(&self) -> &StrVRef {
140 self.into()
141 }
142}
143
144impl std::iter::Extend<GString> for StrV {
145 #[inline]
146 fn extend<I: IntoIterator<Item = GString>>(&mut self, iter: I) {
147 let iter = iter.into_iter();
148 self.reserve(iter.size_hint().0);
149
150 for item in iter {
151 self.push(item);
152 }
153 }
154}
155
156impl<'a> std::iter::Extend<&'a str> for StrV {
157 #[inline]
158 fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
159 let iter = iter.into_iter();
160 self.reserve(iter.size_hint().0);
161
162 for item in iter {
163 self.push(GString::from(item));
164 }
165 }
166}
167
168impl std::iter::FromIterator<GString> for StrV {
169 #[inline]
170 fn from_iter<I: IntoIterator<Item = GString>>(iter: I) -> Self {
171 let iter = iter.into_iter();
172 let mut s = Self::with_capacity(iter.size_hint().0);
173 for item in iter {
174 s.push(item);
175 }
176 s
177 }
178}
179
180impl<'a> std::iter::IntoIterator for &'a StrV {
181 type Item = &'a GStringPtr;
182 type IntoIter = std::slice::Iter<'a, GStringPtr>;
183
184 #[inline]
185 fn into_iter(self) -> Self::IntoIter {
186 self.as_slice().iter()
187 }
188}
189
190impl std::iter::IntoIterator for StrV {
191 type Item = GString;
192 type IntoIter = IntoIter;
193
194 #[inline]
195 fn into_iter(self) -> Self::IntoIter {
196 IntoIter::new(self)
197 }
198}
199
200pub struct IntoIter {
201 ptr: ptr::NonNull<*mut c_char>,
202 idx: ptr::NonNull<*mut c_char>,
203 len: usize,
204 empty: bool,
205}
206
207impl IntoIter {
208 #[inline]
209 fn new(slice: StrV) -> Self {
210 let slice = mem::ManuallyDrop::new(slice);
211 IntoIter {
212 ptr: slice.ptr,
213 idx: slice.ptr,
214 len: slice.len,
215 empty: slice.capacity == 0,
216 }
217 }
218
219 #[inline]
222 pub const fn as_slice(&self) -> &[GStringPtr] {
223 unsafe {
224 if self.len == 0 {
225 &[]
226 } else {
227 std::slice::from_raw_parts(self.idx.as_ptr() as *const GStringPtr, self.len)
228 }
229 }
230 }
231}
232
233impl Drop for IntoIter {
234 #[inline]
235 fn drop(&mut self) {
236 unsafe {
237 for i in 0..self.len {
238 ffi::g_free(*self.idx.as_ptr().add(i) as ffi::gpointer);
239 }
240
241 if !self.empty {
242 ffi::g_free(self.ptr.as_ptr() as ffi::gpointer);
243 }
244 }
245 }
246}
247
248impl Iterator for IntoIter {
249 type Item = GString;
250
251 #[inline]
252 fn next(&mut self) -> Option<Self::Item> {
253 if self.len == 0 {
254 return None;
255 }
256
257 unsafe {
258 let p = self.idx.as_ptr();
259 self.len -= 1;
260 self.idx = ptr::NonNull::new_unchecked(p.add(1));
261 Some(GString::from_glib_full(*p))
262 }
263 }
264
265 #[inline]
266 fn size_hint(&self) -> (usize, Option<usize>) {
267 (self.len, Some(self.len))
268 }
269
270 #[inline]
271 fn count(self) -> usize {
272 self.len
273 }
274
275 #[inline]
276 fn last(mut self) -> Option<GString> {
277 if self.len == 0 {
278 None
279 } else {
280 self.len -= 1;
281 Some(unsafe { GString::from_glib_full(*self.idx.as_ptr().add(self.len)) })
282 }
283 }
284}
285
286impl DoubleEndedIterator for IntoIter {
287 #[inline]
288 fn next_back(&mut self) -> Option<GString> {
289 if self.len == 0 {
290 None
291 } else {
292 self.len -= 1;
293 Some(unsafe { GString::from_glib_full(*self.idx.as_ptr().add(self.len)) })
294 }
295 }
296}
297
298impl ExactSizeIterator for IntoIter {}
299
300impl std::iter::FusedIterator for IntoIter {}
301
302impl From<StrV> for Vec<GString> {
303 #[inline]
304 fn from(value: StrV) -> Self {
305 value.into_iter().collect()
306 }
307}
308
309impl From<Vec<String>> for StrV {
310 #[inline]
311 fn from(value: Vec<String>) -> Self {
312 unsafe {
313 let len = value.len();
314 let mut s = Self::with_capacity(len);
315 for (i, item) in value.into_iter().enumerate() {
316 *s.ptr.as_ptr().add(i) = GString::from(item).into_glib_ptr();
317 }
318 s.len = len;
319 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
320 s
321 }
322 }
323}
324
325impl From<Vec<&'_ str>> for StrV {
326 #[inline]
327 fn from(value: Vec<&'_ str>) -> Self {
328 value.as_slice().into()
329 }
330}
331
332impl From<Vec<GString>> for StrV {
333 #[inline]
334 fn from(value: Vec<GString>) -> Self {
335 unsafe {
336 let len = value.len();
337 let mut s = Self::with_capacity(len);
338 for (i, v) in value.into_iter().enumerate() {
339 *s.ptr.as_ptr().add(i) = v.into_glib_ptr();
340 }
341 s.len = len;
342 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
343 s
344 }
345 }
346}
347
348impl<const N: usize> From<[GString; N]> for StrV {
349 #[inline]
350 fn from(value: [GString; N]) -> Self {
351 unsafe {
352 let len = value.len();
353 let mut s = Self::with_capacity(len);
354 for (i, v) in value.into_iter().enumerate() {
355 *s.ptr.as_ptr().add(i) = v.into_glib_ptr();
356 }
357 s.len = len;
358 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
359 s
360 }
361 }
362}
363
364impl<const N: usize> From<[String; N]> for StrV {
365 #[inline]
366 fn from(value: [String; N]) -> Self {
367 unsafe {
368 let len = value.len();
369 let mut s = Self::with_capacity(len);
370 for (i, v) in value.into_iter().enumerate() {
371 *s.ptr.as_ptr().add(i) = GString::from(v).into_glib_ptr();
372 }
373 s.len = len;
374 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
375 s
376 }
377 }
378}
379
380impl<const N: usize> From<[&'_ str; N]> for StrV {
381 #[inline]
382 fn from(value: [&'_ str; N]) -> Self {
383 unsafe {
384 let mut s = Self::with_capacity(value.len());
385 for (i, item) in value.iter().enumerate() {
386 *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr();
387 }
388 s.len = value.len();
389 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
390 s
391 }
392 }
393}
394
395impl<const N: usize> From<[&'_ GStr; N]> for StrV {
396 #[inline]
397 fn from(value: [&'_ GStr; N]) -> Self {
398 unsafe {
399 let mut s = Self::with_capacity(value.len());
400 for (i, item) in value.iter().enumerate() {
401 *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr();
402 }
403 s.len = value.len();
404 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
405 s
406 }
407 }
408}
409
410impl From<&'_ [&'_ str]> for StrV {
411 #[inline]
412 fn from(value: &'_ [&'_ str]) -> Self {
413 unsafe {
414 let mut s = Self::with_capacity(value.len());
415 for (i, item) in value.iter().enumerate() {
416 *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr();
417 }
418 s.len = value.len();
419 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
420 s
421 }
422 }
423}
424
425impl From<&'_ [&'_ GStr]> for StrV {
426 #[inline]
427 fn from(value: &'_ [&'_ GStr]) -> Self {
428 unsafe {
429 let mut s = Self::with_capacity(value.len());
430 for (i, item) in value.iter().enumerate() {
431 *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr();
432 }
433 s.len = value.len();
434 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
435 s
436 }
437 }
438}
439
440impl From<crate::PtrSlice<GStringPtr>> for StrV {
441 #[inline]
442 fn from(value: crate::PtrSlice<GStringPtr>) -> Self {
443 let len = value.len();
444 unsafe { Self::from_glib_full_num(value.into_glib_ptr(), len, true) }
445 }
446}
447
448impl From<StrV> for crate::PtrSlice<GStringPtr> {
449 #[inline]
450 fn from(value: StrV) -> Self {
451 let len = value.len();
452 unsafe { Self::from_glib_full_num(value.into_glib_ptr(), len, true) }
453 }
454}
455
456impl Clone for StrV {
457 #[inline]
458 fn clone(&self) -> Self {
459 unsafe {
460 let mut s = Self::with_capacity(self.len());
461 for (i, item) in self.iter().enumerate() {
462 *s.ptr.as_ptr().add(i) = GString::from(item.as_str()).into_glib_ptr();
463 }
464 s.len = self.len();
465 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
466 s
467 }
468 }
469}
470
471impl StrV {
472 #[inline]
475 pub unsafe fn from_glib_borrow<'a>(ptr: *const *const c_char) -> &'a [GStringPtr] {
476 unsafe {
477 let mut len = 0;
478 if !ptr.is_null() {
479 while !(*ptr.add(len)).is_null() {
480 len += 1;
481 }
482 }
483 Self::from_glib_borrow_num(ptr, len)
484 }
485 }
486
487 #[inline]
490 pub unsafe fn from_glib_borrow_num<'a>(
491 ptr: *const *const c_char,
492 len: usize,
493 ) -> &'a [GStringPtr] {
494 unsafe {
495 debug_assert!(!ptr.is_null() || len == 0);
496
497 if len == 0 {
498 &[]
499 } else {
500 std::slice::from_raw_parts(ptr as *const GStringPtr, len)
501 }
502 }
503 }
504
505 #[inline]
508 pub unsafe fn from_glib_none_num(
509 ptr: *const *const c_char,
510 len: usize,
511 _null_terminated: bool,
512 ) -> Self {
513 unsafe {
514 debug_assert!(!ptr.is_null() || len == 0);
515
516 if len == 0 {
517 StrV::default()
518 } else {
519 let new_ptr =
522 ffi::g_malloc(mem::size_of::<*mut c_char>() * (len + 1)) as *mut *mut c_char;
523
524 for i in 0..len {
526 let p = ptr.add(i) as *mut *const c_char;
527 let q = new_ptr.add(i) as *mut *const c_char;
528 *q = ffi::g_strdup(*p);
529 }
530
531 *new_ptr.add(len) = ptr::null_mut();
532
533 StrV {
534 ptr: ptr::NonNull::new_unchecked(new_ptr),
535 len,
536 capacity: len + 1,
537 }
538 }
539 }
540 }
541
542 #[inline]
545 pub unsafe fn from_glib_container_num(
546 ptr: *mut *const c_char,
547 len: usize,
548 null_terminated: bool,
549 ) -> Self {
550 unsafe {
551 debug_assert!(!ptr.is_null() || len == 0);
552
553 if len == 0 {
554 ffi::g_free(ptr as ffi::gpointer);
555 StrV::default()
556 } else {
557 for i in 0..len {
559 let p = ptr.add(i);
560 *p = ffi::g_strdup(*p);
561 }
562
563 Self::from_glib_full_num(ptr as *mut *mut c_char, len, null_terminated)
565 }
566 }
567 }
568
569 #[inline]
572 pub unsafe fn from_glib_full_num(
573 ptr: *mut *mut c_char,
574 len: usize,
575 null_terminated: bool,
576 ) -> Self {
577 unsafe {
578 debug_assert!(!ptr.is_null() || len == 0);
579
580 if len == 0 {
581 ffi::g_free(ptr as ffi::gpointer);
582 StrV::default()
583 } else {
584 if null_terminated {
585 return StrV {
586 ptr: ptr::NonNull::new_unchecked(ptr),
587 len,
588 capacity: len + 1,
589 };
590 }
591
592 let capacity = len + 1;
594 assert_ne!(capacity, 0);
595 let ptr = ffi::g_realloc(
596 ptr as *mut _,
597 mem::size_of::<*mut c_char>().checked_mul(capacity).unwrap(),
598 ) as *mut *mut c_char;
599 *ptr.add(len) = ptr::null_mut();
600
601 StrV {
602 ptr: ptr::NonNull::new_unchecked(ptr),
603 len,
604 capacity,
605 }
606 }
607 }
608 }
609
610 #[inline]
613 pub unsafe fn from_glib_none(ptr: *const *const c_char) -> Self {
614 unsafe {
615 let mut len = 0;
616 if !ptr.is_null() {
617 while !(*ptr.add(len)).is_null() {
618 len += 1;
619 }
620 }
621
622 StrV::from_glib_none_num(ptr, len, true)
623 }
624 }
625
626 #[inline]
629 pub unsafe fn from_glib_container(ptr: *mut *const c_char) -> Self {
630 unsafe {
631 let mut len = 0;
632 if !ptr.is_null() {
633 while !(*ptr.add(len)).is_null() {
634 len += 1;
635 }
636 }
637
638 StrV::from_glib_container_num(ptr, len, true)
639 }
640 }
641
642 #[inline]
645 pub unsafe fn from_glib_full(ptr: *mut *mut c_char) -> Self {
646 unsafe {
647 let mut len = 0;
648 if !ptr.is_null() {
649 while !(*ptr.add(len)).is_null() {
650 len += 1;
651 }
652 }
653
654 StrV::from_glib_full_num(ptr, len, true)
655 }
656 }
657
658 #[inline]
661 pub fn new() -> Self {
662 StrV {
663 ptr: ptr::NonNull::dangling(),
664 len: 0,
665 capacity: 0,
666 }
667 }
668
669 #[inline]
672 pub fn with_capacity(capacity: usize) -> Self {
673 let mut s = Self::new();
674 s.reserve(capacity);
675 s
676 }
677
678 #[inline]
683 pub fn as_ptr(&self) -> *const *mut c_char {
684 if self.len == 0 {
685 static EMPTY: [usize; 1] = [0];
686
687 EMPTY.as_ptr() as *const _
688 } else {
689 self.ptr.as_ptr()
690 }
691 }
692
693 #[inline]
698 pub fn into_raw(mut self) -> *mut *mut c_char {
699 if self.len == 0 {
702 self.reserve(0);
703 unsafe {
704 *self.ptr.as_ptr().add(0) = ptr::null_mut();
705 }
706 }
707
708 self.len = 0;
709 self.capacity = 0;
710 self.ptr.as_ptr()
711 }
712
713 #[inline]
716 pub fn len(&self) -> usize {
717 self.len
718 }
719
720 #[inline]
723 pub fn is_empty(&self) -> bool {
724 self.len == 0
725 }
726
727 #[inline]
732 pub fn capacity(&self) -> usize {
733 self.capacity
734 }
735
736 pub unsafe fn set_len(&mut self, len: usize) {
743 self.len = len;
744 }
745
746 #[allow(clippy::int_plus_one)]
749 pub fn reserve(&mut self, additional: usize) {
750 if additional < self.capacity - self.len {
752 return;
753 }
754
755 let new_capacity =
756 usize::next_power_of_two(std::cmp::max(self.len + additional, MIN_SIZE) + 1);
757 assert_ne!(new_capacity, 0);
758 assert!(new_capacity > self.capacity);
759
760 unsafe {
761 let ptr = if self.capacity == 0 {
762 ptr::null_mut()
763 } else {
764 self.ptr.as_ptr() as *mut _
765 };
766 let new_ptr = ffi::g_realloc(
767 ptr,
768 mem::size_of::<*mut c_char>()
769 .checked_mul(new_capacity)
770 .unwrap(),
771 ) as *mut *mut c_char;
772 if self.capacity == 0 {
773 *new_ptr = ptr::null_mut();
774 }
775 self.ptr = ptr::NonNull::new_unchecked(new_ptr);
776 self.capacity = new_capacity;
777 }
778 }
779
780 #[inline]
783 pub const fn as_slice(&self) -> &[GStringPtr] {
784 unsafe {
785 if self.len == 0 {
786 &[]
787 } else {
788 std::slice::from_raw_parts(self.ptr.as_ptr() as *const GStringPtr, self.len)
789 }
790 }
791 }
792
793 #[inline]
796 pub fn clear(&mut self) {
797 unsafe {
798 for i in 0..self.len {
799 ffi::g_free(*self.ptr.as_ptr().add(i) as ffi::gpointer);
800 }
801
802 self.len = 0;
803 }
804 }
805
806 #[inline]
809 pub fn extend_from_slice<S: AsRef<str>>(&mut self, other: &[S]) {
810 if other.len() >= self.capacity - self.len {
812 self.reserve(other.len());
813 }
814
815 unsafe {
816 for item in other {
817 *self.ptr.as_ptr().add(self.len) = GString::from(item.as_ref()).into_glib_ptr();
818 self.len += 1;
819
820 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
823 }
824 }
825 }
826
827 #[inline]
831 pub fn insert(&mut self, index: usize, item: GString) {
832 assert!(index <= self.len);
833
834 if 1 >= self.capacity - self.len {
836 self.reserve(1);
837 }
838
839 unsafe {
840 if index == self.len {
841 *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr();
842 } else {
843 let p = self.ptr.as_ptr().add(index);
844 ptr::copy(p, p.add(1), self.len - index);
845 *self.ptr.as_ptr().add(index) = item.into_glib_ptr();
846 }
847
848 self.len += 1;
849
850 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
851 }
852 }
853
854 #[inline]
857 pub fn push(&mut self, item: GString) {
858 if 1 >= self.capacity - self.len {
860 self.reserve(1);
861 }
862
863 unsafe {
864 *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr();
865 self.len += 1;
866
867 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
868 }
869 }
870
871 #[inline]
875 pub fn remove(&mut self, index: usize) -> GString {
876 assert!(index < self.len);
877
878 unsafe {
879 let p = self.ptr.as_ptr().add(index);
880 let item = *p;
881 ptr::copy(p.add(1), p, self.len - index - 1);
882
883 self.len -= 1;
884
885 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
886
887 GString::from_glib_full(item)
888 }
889 }
890
891 #[inline]
894 pub fn swap(&mut self, index: usize, new_item: GString) -> GString {
895 assert!(index < self.len);
896
897 unsafe {
898 let p = self.ptr.as_ptr().add(index);
899 let item = *p;
900 *p = new_item.into_glib_ptr();
901
902 GString::from_glib_full(item)
903 }
904 }
905
906 #[inline]
909 pub fn pop(&mut self) -> Option<GString> {
910 if self.len == 0 {
911 return None;
912 }
913
914 unsafe {
915 self.len -= 1;
916 let p = self.ptr.as_ptr().add(self.len);
917 let item = *p;
918
919 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
920
921 Some(GString::from_glib_full(item))
922 }
923 }
924
925 #[inline]
930 pub fn truncate(&mut self, len: usize) {
931 if self.len <= len {
932 return;
933 }
934
935 unsafe {
936 while self.len > len {
937 self.len -= 1;
938 let p = self.ptr.as_ptr().add(self.len);
939 ffi::g_free(*p as ffi::gpointer);
940 *p = ptr::null_mut();
941 }
942 }
943 }
944
945 #[inline]
948 #[doc(alias = "g_strjoinv")]
949 pub fn join(&self, separator: Option<impl IntoGStr>) -> GString {
950 separator.run_with_gstr(|separator| unsafe {
951 from_glib_full(ffi::g_strjoinv(
952 separator.to_glib_none().0,
953 self.as_ptr() as *mut _,
954 ))
955 })
956 }
957
958 #[inline]
961 #[doc(alias = "g_strv_contains")]
962 pub fn contains(&self, s: impl IntoGStr) -> bool {
963 s.run_with_gstr(|s| unsafe {
964 from_glib(ffi::g_strv_contains(
965 self.as_ptr() as *const _,
966 s.to_glib_none().0,
967 ))
968 })
969 }
970}
971
972impl FromGlibContainer<*mut c_char, *mut *mut c_char> for StrV {
973 #[inline]
974 unsafe fn from_glib_none_num(ptr: *mut *mut c_char, num: usize) -> Self {
975 unsafe { Self::from_glib_none_num(ptr as *const *const c_char, num, false) }
976 }
977
978 #[inline]
979 unsafe fn from_glib_container_num(ptr: *mut *mut c_char, num: usize) -> Self {
980 unsafe { Self::from_glib_container_num(ptr as *mut *const c_char, num, false) }
981 }
982
983 #[inline]
984 unsafe fn from_glib_full_num(ptr: *mut *mut c_char, num: usize) -> Self {
985 unsafe { Self::from_glib_full_num(ptr, num, false) }
986 }
987}
988
989impl FromGlibContainer<*mut c_char, *const *mut c_char> for StrV {
990 unsafe fn from_glib_none_num(ptr: *const *mut c_char, num: usize) -> Self {
991 unsafe { Self::from_glib_none_num(ptr as *const *const c_char, num, false) }
992 }
993
994 unsafe fn from_glib_container_num(_ptr: *const *mut c_char, _num: usize) -> Self {
995 unimplemented!();
996 }
997
998 unsafe fn from_glib_full_num(_ptr: *const *mut c_char, _num: usize) -> Self {
999 unimplemented!();
1000 }
1001}
1002
1003impl FromGlibPtrContainer<*mut c_char, *mut *mut c_char> for StrV {
1004 #[inline]
1005 unsafe fn from_glib_none(ptr: *mut *mut c_char) -> Self {
1006 unsafe { Self::from_glib_none(ptr as *const *const c_char) }
1007 }
1008
1009 #[inline]
1010 unsafe fn from_glib_container(ptr: *mut *mut c_char) -> Self {
1011 unsafe { Self::from_glib_container(ptr as *mut *const c_char) }
1012 }
1013
1014 #[inline]
1015 unsafe fn from_glib_full(ptr: *mut *mut c_char) -> Self {
1016 unsafe { Self::from_glib_full(ptr) }
1017 }
1018}
1019
1020impl FromGlibPtrContainer<*mut c_char, *const *mut c_char> for StrV {
1021 #[inline]
1022 unsafe fn from_glib_none(ptr: *const *mut c_char) -> Self {
1023 unsafe { Self::from_glib_none(ptr as *const *const c_char) }
1024 }
1025
1026 unsafe fn from_glib_container(_ptr: *const *mut c_char) -> Self {
1027 unimplemented!();
1028 }
1029
1030 unsafe fn from_glib_full(_ptr: *const *mut c_char) -> Self {
1031 unimplemented!();
1032 }
1033}
1034
1035impl<'a> ToGlibPtr<'a, *mut *mut c_char> for StrV {
1036 type Storage = PhantomData<&'a Self>;
1037
1038 #[inline]
1039 fn to_glib_none(&'a self) -> Stash<'a, *mut *mut c_char, Self> {
1040 Stash(self.as_ptr() as *mut _, PhantomData)
1041 }
1042
1043 #[inline]
1044 fn to_glib_container(&'a self) -> Stash<'a, *mut *mut c_char, Self> {
1045 unsafe {
1046 let ptr =
1047 ffi::g_malloc(mem::size_of::<*mut c_char>() * (self.len() + 1)) as *mut *mut c_char;
1048 ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1);
1049 Stash(ptr, PhantomData)
1050 }
1051 }
1052
1053 #[inline]
1054 fn to_glib_full(&self) -> *mut *mut c_char {
1055 self.clone().into_raw()
1056 }
1057}
1058
1059impl<'a> ToGlibPtr<'a, *const *mut c_char> for StrV {
1060 type Storage = PhantomData<&'a Self>;
1061
1062 #[inline]
1063 fn to_glib_none(&'a self) -> Stash<'a, *const *mut c_char, Self> {
1064 Stash(self.as_ptr(), PhantomData)
1065 }
1066}
1067
1068impl IntoGlibPtr<*mut *mut c_char> for StrV {
1069 #[inline]
1070 fn into_glib_ptr(self) -> *mut *mut c_char {
1071 self.into_raw()
1072 }
1073}
1074
1075impl StaticType for StrV {
1076 #[inline]
1077 fn static_type() -> crate::Type {
1078 <Vec<String>>::static_type()
1079 }
1080}
1081
1082impl StaticType for &'_ [GStringPtr] {
1083 #[inline]
1084 fn static_type() -> crate::Type {
1085 <Vec<String>>::static_type()
1086 }
1087}
1088
1089impl crate::value::ValueType for StrV {
1090 type Type = Vec<String>;
1091}
1092
1093unsafe impl<'a> crate::value::FromValue<'a> for StrV {
1094 type Checker = crate::value::GenericValueTypeChecker<Self>;
1095
1096 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1097 unsafe {
1098 let ptr = gobject_ffi::g_value_dup_boxed(value.to_glib_none().0) as *mut *mut c_char;
1099 FromGlibPtrContainer::from_glib_full(ptr)
1100 }
1101 }
1102}
1103
1104unsafe impl<'a> crate::value::FromValue<'a> for &'a [GStringPtr] {
1105 type Checker = crate::value::GenericValueTypeChecker<Self>;
1106
1107 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1108 unsafe {
1109 let ptr =
1110 gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
1111 StrV::from_glib_borrow(ptr)
1112 }
1113 }
1114}
1115
1116impl crate::value::ToValue for StrV {
1117 fn to_value(&self) -> crate::value::Value {
1118 unsafe {
1119 let mut value = crate::value::Value::for_value_type::<Self>();
1120 gobject_ffi::g_value_set_boxed(
1121 value.to_glib_none_mut().0,
1122 self.as_ptr() as ffi::gpointer,
1123 );
1124 value
1125 }
1126 }
1127
1128 fn value_type(&self) -> crate::Type {
1129 <StrV as StaticType>::static_type()
1130 }
1131}
1132
1133impl From<StrV> for crate::Value {
1134 #[inline]
1135 fn from(s: StrV) -> Self {
1136 unsafe {
1137 let mut value = crate::value::Value::for_value_type::<StrV>();
1138 gobject_ffi::g_value_take_boxed(
1139 value.to_glib_none_mut().0,
1140 s.into_raw() as ffi::gpointer,
1141 );
1142 value
1143 }
1144 }
1145}
1146
1147pub trait IntoStrV {
1150 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R;
1153}
1154
1155impl IntoStrV for StrV {
1156 #[inline]
1157 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1158 <&Self>::run_with_strv(&self, f)
1159 }
1160}
1161
1162impl IntoStrV for &'_ StrV {
1163 #[inline]
1164 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1165 f(unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) })
1166 }
1167}
1168
1169const MAX_STACK_ALLOCATION: usize = 16;
1174
1175impl IntoStrV for Vec<GString> {
1176 #[inline]
1177 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1178 self.as_slice().run_with_strv(f)
1179 }
1180}
1181
1182impl IntoStrV for Vec<&'_ GString> {
1183 #[inline]
1184 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1185 self.as_slice().run_with_strv(f)
1186 }
1187}
1188
1189impl IntoStrV for Vec<&'_ GStr> {
1190 #[inline]
1191 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1192 self.as_slice().run_with_strv(f)
1193 }
1194}
1195
1196impl IntoStrV for Vec<&'_ str> {
1197 #[inline]
1198 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1199 self.as_slice().run_with_strv(f)
1200 }
1201}
1202
1203impl IntoStrV for Vec<String> {
1204 #[inline]
1205 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1206 self.as_slice().run_with_strv(f)
1207 }
1208}
1209
1210impl IntoStrV for Vec<&'_ String> {
1211 #[inline]
1212 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1213 self.as_slice().run_with_strv(f)
1214 }
1215}
1216
1217impl IntoStrV for &[GString] {
1218 #[inline]
1219 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1220 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1221
1222 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1223 unsafe {
1224 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1225 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1226
1227 for (i, item) in self.iter().enumerate() {
1228 *ptrs.add(i) = item.as_ptr() as *mut _;
1229 }
1230 *ptrs.add(self.len()) = ptr::null_mut();
1231
1232 f(std::slice::from_raw_parts(ptrs, self.len()))
1233 }
1234 } else {
1235 let mut s = StrV::with_capacity(self.len());
1236 s.extend_from_slice(self);
1237 s.run_with_strv(f)
1238 }
1239 }
1240}
1241
1242impl IntoStrV for &[&GString] {
1243 #[inline]
1244 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1245 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1246
1247 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1248 unsafe {
1249 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1250 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1251
1252 for (i, item) in self.iter().enumerate() {
1253 *ptrs.add(i) = item.as_ptr() as *mut _;
1254 }
1255 *ptrs.add(self.len()) = ptr::null_mut();
1256
1257 f(std::slice::from_raw_parts(ptrs, self.len()))
1258 }
1259 } else {
1260 let mut s = StrV::with_capacity(self.len());
1261 s.extend_from_slice(self);
1262 s.run_with_strv(f)
1263 }
1264 }
1265}
1266
1267impl IntoStrV for &[&GStr] {
1268 #[inline]
1269 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1270 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1271
1272 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1273 unsafe {
1274 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1275 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1276
1277 for (i, item) in self.iter().enumerate() {
1278 *ptrs.add(i) = item.as_ptr() as *mut _;
1279 }
1280 *ptrs.add(self.len()) = ptr::null_mut();
1281
1282 f(std::slice::from_raw_parts(ptrs, self.len()))
1283 }
1284 } else {
1285 let mut s = StrV::with_capacity(self.len());
1286 s.extend_from_slice(self);
1287 s.run_with_strv(f)
1288 }
1289 }
1290}
1291
1292impl IntoStrV for &[&str] {
1293 #[inline]
1294 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1295 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1296 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1297
1298 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1299 unsafe {
1300 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1301 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1302 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1303
1304 for (i, item) in self.iter().enumerate() {
1305 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1306 *strs.add(item.len()) = 0;
1307 *ptrs.add(i) = strs;
1308 strs = strs.add(item.len() + 1);
1309 }
1310 *ptrs.add(self.len()) = ptr::null_mut();
1311
1312 f(std::slice::from_raw_parts(ptrs, self.len()))
1313 }
1314 } else {
1315 let mut s = StrV::with_capacity(self.len());
1316 s.extend_from_slice(self);
1317 s.run_with_strv(f)
1318 }
1319 }
1320}
1321
1322impl IntoStrV for &[String] {
1323 #[inline]
1324 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1325 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1326 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1327
1328 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1329 unsafe {
1330 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1331 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1332 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1333
1334 for (i, item) in self.iter().enumerate() {
1335 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1336 *strs.add(item.len()) = 0;
1337 *ptrs.add(i) = strs;
1338 strs = strs.add(item.len() + 1);
1339 }
1340 *ptrs.add(self.len()) = ptr::null_mut();
1341
1342 f(std::slice::from_raw_parts(ptrs, self.len()))
1343 }
1344 } else {
1345 let mut s = StrV::with_capacity(self.len());
1346 s.extend_from_slice(self);
1347 s.run_with_strv(f)
1348 }
1349 }
1350}
1351
1352impl IntoStrV for &[&String] {
1353 #[inline]
1354 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1355 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1356 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1357
1358 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1359 unsafe {
1360 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1361 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1362 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1363
1364 for (i, item) in self.iter().enumerate() {
1365 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1366 *strs.add(item.len()) = 0;
1367 *ptrs.add(i) = strs;
1368 strs = strs.add(item.len() + 1);
1369 }
1370 *ptrs.add(self.len()) = ptr::null_mut();
1371
1372 f(std::slice::from_raw_parts(ptrs, self.len()))
1373 }
1374 } else {
1375 let mut s = StrV::with_capacity(self.len());
1376 s.extend_from_slice(self);
1377 s.run_with_strv(f)
1378 }
1379 }
1380}
1381
1382impl<const N: usize> IntoStrV for [GString; N] {
1383 #[inline]
1384 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1385 self.as_slice().run_with_strv(f)
1386 }
1387}
1388
1389impl<const N: usize> IntoStrV for [&'_ GString; N] {
1390 #[inline]
1391 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1392 self.as_slice().run_with_strv(f)
1393 }
1394}
1395
1396impl<const N: usize> IntoStrV for [&'_ GStr; N] {
1397 #[inline]
1398 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1399 self.as_slice().run_with_strv(f)
1400 }
1401}
1402
1403impl<const N: usize> IntoStrV for [&'_ str; N] {
1404 #[inline]
1405 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1406 self.as_slice().run_with_strv(f)
1407 }
1408}
1409
1410impl<const N: usize> IntoStrV for [String; N] {
1411 #[inline]
1412 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1413 self.as_slice().run_with_strv(f)
1414 }
1415}
1416
1417impl<const N: usize> IntoStrV for [&'_ String; N] {
1418 #[inline]
1419 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1420 self.as_slice().run_with_strv(f)
1421 }
1422}
1423
1424#[repr(transparent)]
1430pub struct StrVRef {
1431 inner: [GStringPtr],
1432}
1433
1434impl StrVRef {
1435 #[inline]
1442 pub unsafe fn from_glib_borrow<'a>(ptr: *const *const c_char) -> &'a StrVRef {
1443 unsafe {
1444 let slice = StrV::from_glib_borrow(ptr);
1445 &*(slice as *const [GStringPtr] as *const StrVRef)
1446 }
1447 }
1448
1449 #[inline]
1456 pub unsafe fn from_glib_borrow_num<'a>(ptr: *const *const c_char, len: usize) -> &'a StrVRef {
1457 unsafe {
1458 let slice = StrV::from_glib_borrow_num(ptr, len);
1459 &*(slice as *const [GStringPtr] as *const StrVRef)
1460 }
1461 }
1462
1463 #[inline]
1468 pub const fn as_ptr(&self) -> *const *const c_char {
1469 self.inner.as_ptr() as *const *const _
1470 }
1471}
1472
1473impl fmt::Debug for StrVRef {
1474 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1475 self.inner.fmt(f)
1476 }
1477}
1478
1479unsafe impl Send for StrVRef {}
1480
1481unsafe impl Sync for StrVRef {}
1482
1483impl PartialEq for StrVRef {
1484 #[inline]
1485 fn eq(&self, other: &Self) -> bool {
1486 self.inner == other.inner
1487 }
1488}
1489
1490impl Eq for StrVRef {}
1491
1492impl PartialOrd for StrVRef {
1493 #[inline]
1494 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1495 Some(self.cmp(other))
1496 }
1497}
1498
1499impl Ord for StrVRef {
1500 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1501 self.inner.cmp(&other.inner)
1502 }
1503}
1504
1505impl std::hash::Hash for StrVRef {
1506 #[inline]
1507 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1508 self.inner.hash(state)
1509 }
1510}
1511
1512impl PartialEq<[&'_ str]> for StrVRef {
1513 fn eq(&self, other: &[&'_ str]) -> bool {
1514 if self.len() != other.len() {
1515 return false;
1516 }
1517
1518 for (a, b) in Iterator::zip(self.iter(), other.iter()) {
1519 if a != b {
1520 return false;
1521 }
1522 }
1523
1524 true
1525 }
1526}
1527
1528impl PartialEq<StrVRef> for [&'_ str] {
1529 #[inline]
1530 fn eq(&self, other: &StrVRef) -> bool {
1531 other.eq(self)
1532 }
1533}
1534
1535impl Default for &StrVRef {
1536 #[inline]
1537 fn default() -> Self {
1538 const SLICE: &[*const c_char] = &[ptr::null()];
1539 unsafe { StrVRef::from_glib_borrow(SLICE.as_ptr()) }
1541 }
1542}
1543
1544impl std::ops::Deref for StrVRef {
1545 type Target = [GStringPtr];
1546
1547 #[inline]
1548 fn deref(&self) -> &[GStringPtr] {
1549 &self.inner
1550 }
1551}
1552
1553impl<'a> std::iter::IntoIterator for &'a StrVRef {
1554 type Item = &'a GStringPtr;
1555 type IntoIter = std::slice::Iter<'a, GStringPtr>;
1556
1557 #[inline]
1558 fn into_iter(self) -> Self::IntoIter {
1559 self.inner.iter()
1560 }
1561}
1562
1563impl<'a> From<&'a StrV> for &'a StrVRef {
1564 fn from(value: &'a StrV) -> Self {
1565 let slice = value.as_slice();
1566 unsafe { &*(slice as *const [GStringPtr] as *const StrVRef) }
1570 }
1571}
1572
1573impl FromGlibContainer<*mut c_char, *const *const c_char> for &StrVRef {
1574 unsafe fn from_glib_none_num(ptr: *const *const c_char, num: usize) -> Self {
1575 unsafe { StrVRef::from_glib_borrow_num(ptr, num) }
1576 }
1577
1578 unsafe fn from_glib_container_num(_ptr: *const *const c_char, _num: usize) -> Self {
1579 unimplemented!();
1580 }
1581
1582 unsafe fn from_glib_full_num(_ptr: *const *const c_char, _num: usize) -> Self {
1583 unimplemented!();
1584 }
1585}
1586
1587impl FromGlibPtrContainer<*mut c_char, *const *const c_char> for &StrVRef {
1588 #[inline]
1589 unsafe fn from_glib_none(ptr: *const *const c_char) -> Self {
1590 unsafe { StrVRef::from_glib_borrow(ptr) }
1591 }
1592
1593 unsafe fn from_glib_container(_ptr: *const *const c_char) -> Self {
1594 unimplemented!();
1595 }
1596
1597 unsafe fn from_glib_full(_ptr: *const *const c_char) -> Self {
1598 unimplemented!();
1599 }
1600}
1601
1602impl<'a> ToGlibPtr<'a, *const *const c_char> for StrVRef {
1603 type Storage = PhantomData<&'a Self>;
1604
1605 #[inline]
1606 fn to_glib_none(&'a self) -> Stash<'a, *const *const c_char, Self> {
1607 Stash(self.as_ptr(), PhantomData)
1608 }
1609}
1610
1611impl IntoGlibPtr<*const *const c_char> for &StrVRef {
1612 #[inline]
1613 fn into_glib_ptr(self) -> *const *const c_char {
1614 self.as_ptr()
1615 }
1616}
1617
1618impl StaticType for StrVRef {
1619 #[inline]
1620 fn static_type() -> crate::Type {
1621 <Vec<String>>::static_type()
1622 }
1623}
1624
1625unsafe impl<'a> crate::value::FromValue<'a> for &'a StrVRef {
1626 type Checker = crate::value::GenericValueTypeChecker<Self>;
1627
1628 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1629 unsafe {
1630 let ptr =
1631 gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
1632 StrVRef::from_glib_borrow(ptr)
1633 }
1634 }
1635}
1636
1637#[cfg(test)]
1638mod test {
1639 use super::*;
1640
1641 #[test]
1642 fn test_from_glib_full() {
1643 let items = ["str1", "str2", "str3", "str4"];
1644
1645 let slice = unsafe {
1646 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *mut c_char;
1647 *ptr.add(0) = items[0].to_glib_full();
1648 *ptr.add(1) = items[1].to_glib_full();
1649 *ptr.add(2) = items[2].to_glib_full();
1650 *ptr.add(3) = items[3].to_glib_full();
1651
1652 StrV::from_glib_full_num(ptr, 4, false)
1653 };
1654
1655 assert_eq!(items.len(), slice.len());
1656 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1657 assert_eq!(a, b);
1658 }
1659 }
1660
1661 #[test]
1662 fn test_from_glib_container() {
1663 let items = [
1664 crate::gstr!("str1"),
1665 crate::gstr!("str2"),
1666 crate::gstr!("str3"),
1667 crate::gstr!("str4"),
1668 ];
1669
1670 let slice = unsafe {
1671 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char;
1672 *ptr.add(0) = items[0].as_ptr();
1673 *ptr.add(1) = items[1].as_ptr();
1674 *ptr.add(2) = items[2].as_ptr();
1675 *ptr.add(3) = items[3].as_ptr();
1676
1677 StrV::from_glib_container_num(ptr, 4, false)
1678 };
1679
1680 assert_eq!(items.len(), slice.len());
1681 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1682 assert_eq!(a, b);
1683 }
1684 }
1685
1686 #[test]
1687 fn test_from_glib_none() {
1688 let items = [
1689 crate::gstr!("str1"),
1690 crate::gstr!("str2"),
1691 crate::gstr!("str3"),
1692 crate::gstr!("str4"),
1693 ];
1694
1695 let slice = unsafe {
1696 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char;
1697 *ptr.add(0) = items[0].as_ptr();
1698 *ptr.add(1) = items[1].as_ptr();
1699 *ptr.add(2) = items[2].as_ptr();
1700 *ptr.add(3) = items[3].as_ptr();
1701
1702 let res = StrV::from_glib_none_num(ptr, 4, false);
1703 ffi::g_free(ptr as ffi::gpointer);
1704 res
1705 };
1706
1707 assert_eq!(items.len(), slice.len());
1708 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1709 assert_eq!(a, b);
1710 }
1711 }
1712
1713 #[test]
1714 fn test_from_slice() {
1715 let items = [
1716 crate::gstr!("str1"),
1717 crate::gstr!("str2"),
1718 crate::gstr!("str3"),
1719 ];
1720
1721 let slice1 = StrV::from(&items[..]);
1722 let slice2 = StrV::from(items);
1723 assert_eq!(slice1.len(), 3);
1724 assert_eq!(slice1, slice2);
1725 }
1726
1727 #[test]
1728 fn test_safe_api() {
1729 let items = [
1730 crate::gstr!("str1"),
1731 crate::gstr!("str2"),
1732 crate::gstr!("str3"),
1733 ];
1734
1735 let mut slice = StrV::from(&items[..]);
1736 assert_eq!(slice.len(), 3);
1737 slice.push(GString::from("str4"));
1738 assert_eq!(slice.len(), 4);
1739
1740 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1741 assert_eq!(a, b);
1742 }
1743 assert_eq!(slice[3], "str4");
1744
1745 let vec = Vec::from(slice);
1746 assert_eq!(vec.len(), 4);
1747 for (a, b) in Iterator::zip(items.iter(), vec.iter()) {
1748 assert_eq!(a, b);
1749 }
1750 assert_eq!(vec[3], "str4");
1751
1752 let mut slice = StrV::from(vec);
1753 assert_eq!(slice.len(), 4);
1754 let e = slice.pop().unwrap();
1755 assert_eq!(e, "str4");
1756 assert_eq!(slice.len(), 3);
1757 slice.insert(2, e);
1758 assert_eq!(slice.len(), 4);
1759 assert_eq!(slice[0], "str1");
1760 assert_eq!(slice[1], "str2");
1761 assert_eq!(slice[2], "str4");
1762 assert_eq!(slice[3], "str3");
1763 let e = slice.remove(2);
1764 assert_eq!(e, "str4");
1765 assert_eq!(slice.len(), 3);
1766 slice.push(e);
1767 assert_eq!(slice.len(), 4);
1768
1769 for (a, b) in Iterator::zip(items.iter(), slice.into_iter()) {
1770 assert_eq!(*a, b);
1771 }
1772 }
1773
1774 #[test]
1775 fn test_into_strv() {
1776 let items = ["str1", "str2", "str3", "str4"];
1777
1778 items[..].run_with_strv(|s| unsafe {
1779 assert!((*s.as_ptr().add(4)).is_null());
1780 assert_eq!(s.len(), items.len());
1781 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1782 assert_eq!(s, items);
1783 });
1784
1785 Vec::from(&items[..]).run_with_strv(|s| unsafe {
1786 assert!((*s.as_ptr().add(4)).is_null());
1787 assert_eq!(s.len(), items.len());
1788 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1789 assert_eq!(s, items);
1790 });
1791
1792 StrV::from(&items[..]).run_with_strv(|s| unsafe {
1793 assert!((*s.as_ptr().add(4)).is_null());
1794 assert_eq!(s.len(), items.len());
1795 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1796 assert_eq!(s, items);
1797 });
1798
1799 let v = items.iter().copied().map(String::from).collect::<Vec<_>>();
1800 items.run_with_strv(|s| unsafe {
1801 assert!((*s.as_ptr().add(4)).is_null());
1802 assert_eq!(s.len(), v.len());
1803 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1804 assert_eq!(s, items);
1805 });
1806
1807 let v = items.iter().copied().map(GString::from).collect::<Vec<_>>();
1808 items.run_with_strv(|s| unsafe {
1809 assert!((*s.as_ptr().add(4)).is_null());
1810 assert_eq!(s.len(), v.len());
1811 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1812 assert_eq!(s, items);
1813 });
1814 }
1815
1816 #[test]
1817 fn test_join() {
1818 let items = [
1819 crate::gstr!("str1"),
1820 crate::gstr!("str2"),
1821 crate::gstr!("str3"),
1822 ];
1823
1824 let strv = StrV::from(&items[..]);
1825 assert_eq!(strv.join(None::<&str>), "str1str2str3");
1826 assert_eq!(strv.join(Some(",")), "str1,str2,str3");
1827 }
1828
1829 #[test]
1830 fn test_contains() {
1831 let items = [
1832 crate::gstr!("str1"),
1833 crate::gstr!("str2"),
1834 crate::gstr!("str3"),
1835 ];
1836
1837 let strv = StrV::from(&items[..]);
1838 assert!(strv.contains("str2"));
1839 assert!(!strv.contains("str4"));
1840 }
1841
1842 #[test]
1843 #[should_panic]
1844 fn test_reserve_overflow() {
1845 let mut strv = StrV::from(&[crate::gstr!("foo"); 3][..]);
1846
1847 strv.reserve(usize::MAX - 3);
1850 }
1851
1852 #[test]
1853 #[should_panic]
1854 fn test_extend_from_slice_overflow() {
1855 #[derive(Clone, Copy)]
1858 struct ImplicitStr;
1859
1860 impl AsRef<str> for ImplicitStr {
1861 fn as_ref(&self) -> &str {
1862 ""
1863 }
1864 }
1865
1866 let mut strv = StrV::from(&[crate::gstr!(""); 3][..]);
1867
1868 strv.extend_from_slice(&[ImplicitStr; usize::MAX - 3]);
1872 }
1873
1874 #[test]
1875 fn test_extend_from_slice_panic_safe() {
1876 struct MayPanic(bool);
1877
1878 impl AsRef<str> for MayPanic {
1879 fn as_ref(&self) -> &str {
1880 if self.0 {
1881 panic!("panicking as per request");
1882 } else {
1883 ""
1884 }
1885 }
1886 }
1887
1888 let mut strv = StrV::from(&[crate::gstr!(""); 3][..]);
1889 strv.clear();
1890
1891 _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1893 strv.extend_from_slice(&[MayPanic(false), MayPanic(true)]);
1894 }));
1895
1896 assert!(strv.len() <= 1);
1898 unsafe {
1899 for i in 0..strv.len() {
1900 assert!(!(*strv.as_ptr().add(i)).is_null());
1901 }
1902 assert!((*strv.as_ptr().add(strv.len())).is_null());
1903 }
1904 }
1905
1906 #[test]
1907 fn test_strv_ref_eq_str_slice() {
1908 let strv = StrV::from(&[crate::gstr!("a")][..]);
1909 let strv_ref: &StrVRef = strv.as_ref();
1910
1911 assert_eq!(strv_ref, &["a"][..]);
1913 assert_ne!(strv_ref, &[][..]);
1914 assert_ne!(strv_ref, &["a", "b"][..]);
1915 assert_ne!(strv_ref, &["b"][..]);
1916 }
1917
1918 #[test]
1919 fn test_from_ptr_slice() {
1920 let items = [
1921 GStringPtr::from("a"),
1922 GStringPtr::from("b"),
1923 GStringPtr::from("c"),
1924 ];
1925 let ptr_slice: crate::PtrSlice<GStringPtr> = crate::PtrSlice::from(&items[..]);
1926 let strv: StrV = ptr_slice.into();
1927
1928 for (i, item) in items.into_iter().enumerate() {
1929 assert_eq!(strv[i], item);
1930 }
1931 }
1932
1933 #[test]
1934 fn test_into_ptr_slice() {
1935 let items = [crate::gstr!("a"), crate::gstr!("b"), crate::gstr!("c")];
1936 let strv: StrV = StrV::from(&items[..]);
1937 let ptr_slice: crate::PtrSlice<GStringPtr> = strv.into();
1938
1939 for (i, item) in items.into_iter().enumerate() {
1940 assert_eq!(ptr_slice[i], item);
1941 }
1942 }
1943}