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 if self.capacity != 0 {
803 *self.ptr.as_ptr().add(0) = ptr::null_mut();
804 }
805
806 self.len = 0;
807 }
808 }
809
810 #[inline]
813 pub fn extend_from_slice<S: AsRef<str>>(&mut self, other: &[S]) {
814 if other.len() >= self.capacity - self.len {
816 self.reserve(other.len());
817 }
818
819 unsafe {
820 for item in other {
821 *self.ptr.as_ptr().add(self.len) = GString::from(item.as_ref()).into_glib_ptr();
822 self.len += 1;
823
824 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
827 }
828 }
829 }
830
831 #[inline]
835 pub fn insert(&mut self, index: usize, item: GString) {
836 assert!(index <= self.len);
837
838 if 1 >= self.capacity - self.len {
840 self.reserve(1);
841 }
842
843 unsafe {
844 if index == self.len {
845 *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr();
846 } else {
847 let p = self.ptr.as_ptr().add(index);
848 ptr::copy(p, p.add(1), self.len - index);
849 *self.ptr.as_ptr().add(index) = item.into_glib_ptr();
850 }
851
852 self.len += 1;
853
854 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
855 }
856 }
857
858 #[inline]
861 pub fn push(&mut self, item: GString) {
862 if 1 >= self.capacity - self.len {
864 self.reserve(1);
865 }
866
867 unsafe {
868 *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr();
869 self.len += 1;
870
871 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
872 }
873 }
874
875 #[inline]
879 pub fn remove(&mut self, index: usize) -> GString {
880 assert!(index < self.len);
881
882 unsafe {
883 let p = self.ptr.as_ptr().add(index);
884 let item = *p;
885 ptr::copy(p.add(1), p, self.len - index - 1);
886
887 self.len -= 1;
888
889 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
890
891 GString::from_glib_full(item)
892 }
893 }
894
895 #[inline]
898 pub fn swap(&mut self, index: usize, new_item: GString) -> GString {
899 assert!(index < self.len);
900
901 unsafe {
902 let p = self.ptr.as_ptr().add(index);
903 let item = *p;
904 *p = new_item.into_glib_ptr();
905
906 GString::from_glib_full(item)
907 }
908 }
909
910 #[inline]
913 pub fn pop(&mut self) -> Option<GString> {
914 if self.len == 0 {
915 return None;
916 }
917
918 unsafe {
919 self.len -= 1;
920 let p = self.ptr.as_ptr().add(self.len);
921 let item = *p;
922
923 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
924
925 Some(GString::from_glib_full(item))
926 }
927 }
928
929 #[inline]
934 pub fn truncate(&mut self, len: usize) {
935 if self.len <= len {
936 return;
937 }
938
939 unsafe {
940 while self.len > len {
941 self.len -= 1;
942 let p = self.ptr.as_ptr().add(self.len);
943 ffi::g_free(*p as ffi::gpointer);
944 *p = ptr::null_mut();
945 }
946 }
947 }
948
949 #[inline]
952 #[doc(alias = "g_strjoinv")]
953 pub fn join(&self, separator: Option<impl IntoGStr>) -> GString {
954 separator.run_with_gstr(|separator| unsafe {
955 from_glib_full(ffi::g_strjoinv(
956 separator.to_glib_none().0,
957 self.as_ptr() as *mut _,
958 ))
959 })
960 }
961
962 #[inline]
965 #[doc(alias = "g_strv_contains")]
966 pub fn contains(&self, s: impl IntoGStr) -> bool {
967 s.run_with_gstr(|s| unsafe {
968 from_glib(ffi::g_strv_contains(
969 self.as_ptr() as *const _,
970 s.to_glib_none().0,
971 ))
972 })
973 }
974}
975
976impl FromGlibContainer<*mut c_char, *mut *mut c_char> for StrV {
977 #[inline]
978 unsafe fn from_glib_none_num(ptr: *mut *mut c_char, num: usize) -> Self {
979 unsafe { Self::from_glib_none_num(ptr as *const *const c_char, num, false) }
980 }
981
982 #[inline]
983 unsafe fn from_glib_container_num(ptr: *mut *mut c_char, num: usize) -> Self {
984 unsafe { Self::from_glib_container_num(ptr as *mut *const c_char, num, false) }
985 }
986
987 #[inline]
988 unsafe fn from_glib_full_num(ptr: *mut *mut c_char, num: usize) -> Self {
989 unsafe { Self::from_glib_full_num(ptr, num, false) }
990 }
991}
992
993impl FromGlibContainer<*mut c_char, *const *mut c_char> for StrV {
994 unsafe fn from_glib_none_num(ptr: *const *mut c_char, num: usize) -> Self {
995 unsafe { Self::from_glib_none_num(ptr as *const *const c_char, num, false) }
996 }
997
998 unsafe fn from_glib_container_num(_ptr: *const *mut c_char, _num: usize) -> Self {
999 unimplemented!();
1000 }
1001
1002 unsafe fn from_glib_full_num(_ptr: *const *mut c_char, _num: usize) -> Self {
1003 unimplemented!();
1004 }
1005}
1006
1007impl FromGlibPtrContainer<*mut c_char, *mut *mut c_char> for StrV {
1008 #[inline]
1009 unsafe fn from_glib_none(ptr: *mut *mut c_char) -> Self {
1010 unsafe { Self::from_glib_none(ptr as *const *const c_char) }
1011 }
1012
1013 #[inline]
1014 unsafe fn from_glib_container(ptr: *mut *mut c_char) -> Self {
1015 unsafe { Self::from_glib_container(ptr as *mut *const c_char) }
1016 }
1017
1018 #[inline]
1019 unsafe fn from_glib_full(ptr: *mut *mut c_char) -> Self {
1020 unsafe { Self::from_glib_full(ptr) }
1021 }
1022}
1023
1024impl FromGlibPtrContainer<*mut c_char, *const *mut c_char> for StrV {
1025 #[inline]
1026 unsafe fn from_glib_none(ptr: *const *mut c_char) -> Self {
1027 unsafe { Self::from_glib_none(ptr as *const *const c_char) }
1028 }
1029
1030 unsafe fn from_glib_container(_ptr: *const *mut c_char) -> Self {
1031 unimplemented!();
1032 }
1033
1034 unsafe fn from_glib_full(_ptr: *const *mut c_char) -> Self {
1035 unimplemented!();
1036 }
1037}
1038
1039impl<'a> ToGlibPtr<'a, *mut *mut c_char> for StrV {
1040 type Storage = PhantomData<&'a Self>;
1041
1042 #[inline]
1043 fn to_glib_none(&'a self) -> Stash<'a, *mut *mut c_char, Self> {
1044 Stash(self.as_ptr() as *mut _, PhantomData)
1045 }
1046
1047 #[inline]
1048 fn to_glib_container(&'a self) -> Stash<'a, *mut *mut c_char, Self> {
1049 unsafe {
1050 let ptr =
1051 ffi::g_malloc(mem::size_of::<*mut c_char>() * (self.len() + 1)) as *mut *mut c_char;
1052 ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1);
1053 Stash(ptr, PhantomData)
1054 }
1055 }
1056
1057 #[inline]
1058 fn to_glib_full(&self) -> *mut *mut c_char {
1059 self.clone().into_raw()
1060 }
1061}
1062
1063impl<'a> ToGlibPtr<'a, *const *mut c_char> for StrV {
1064 type Storage = PhantomData<&'a Self>;
1065
1066 #[inline]
1067 fn to_glib_none(&'a self) -> Stash<'a, *const *mut c_char, Self> {
1068 Stash(self.as_ptr(), PhantomData)
1069 }
1070}
1071
1072impl IntoGlibPtr<*mut *mut c_char> for StrV {
1073 #[inline]
1074 fn into_glib_ptr(self) -> *mut *mut c_char {
1075 self.into_raw()
1076 }
1077}
1078
1079impl StaticType for StrV {
1080 #[inline]
1081 fn static_type() -> crate::Type {
1082 <Vec<String>>::static_type()
1083 }
1084}
1085
1086impl StaticType for &'_ [GStringPtr] {
1087 #[inline]
1088 fn static_type() -> crate::Type {
1089 <Vec<String>>::static_type()
1090 }
1091}
1092
1093impl crate::value::ValueType for StrV {
1094 type Type = Vec<String>;
1095}
1096
1097unsafe impl<'a> crate::value::FromValue<'a> for StrV {
1098 type Checker = crate::value::GenericValueTypeChecker<Self>;
1099
1100 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1101 unsafe {
1102 let ptr = gobject_ffi::g_value_dup_boxed(value.to_glib_none().0) as *mut *mut c_char;
1103 FromGlibPtrContainer::from_glib_full(ptr)
1104 }
1105 }
1106}
1107
1108unsafe impl<'a> crate::value::FromValue<'a> for &'a [GStringPtr] {
1109 type Checker = crate::value::GenericValueTypeChecker<Self>;
1110
1111 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1112 unsafe {
1113 let ptr =
1114 gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
1115 StrV::from_glib_borrow(ptr)
1116 }
1117 }
1118}
1119
1120impl crate::value::ToValue for StrV {
1121 fn to_value(&self) -> crate::value::Value {
1122 unsafe {
1123 let mut value = crate::value::Value::for_value_type::<Self>();
1124 gobject_ffi::g_value_set_boxed(
1125 value.to_glib_none_mut().0,
1126 self.as_ptr() as ffi::gpointer,
1127 );
1128 value
1129 }
1130 }
1131
1132 fn value_type(&self) -> crate::Type {
1133 <StrV as StaticType>::static_type()
1134 }
1135}
1136
1137impl From<StrV> for crate::Value {
1138 #[inline]
1139 fn from(s: StrV) -> Self {
1140 unsafe {
1141 let mut value = crate::value::Value::for_value_type::<StrV>();
1142 gobject_ffi::g_value_take_boxed(
1143 value.to_glib_none_mut().0,
1144 s.into_raw() as ffi::gpointer,
1145 );
1146 value
1147 }
1148 }
1149}
1150
1151pub trait IntoStrV {
1154 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R;
1157}
1158
1159impl IntoStrV for StrV {
1160 #[inline]
1161 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1162 <&Self>::run_with_strv(&self, f)
1163 }
1164}
1165
1166impl IntoStrV for &'_ StrV {
1167 #[inline]
1168 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1169 f(unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) })
1170 }
1171}
1172
1173const MAX_STACK_ALLOCATION: usize = 16;
1178
1179impl IntoStrV for Vec<GString> {
1180 #[inline]
1181 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1182 self.as_slice().run_with_strv(f)
1183 }
1184}
1185
1186impl IntoStrV for Vec<&'_ GString> {
1187 #[inline]
1188 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1189 self.as_slice().run_with_strv(f)
1190 }
1191}
1192
1193impl IntoStrV for Vec<&'_ GStr> {
1194 #[inline]
1195 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1196 self.as_slice().run_with_strv(f)
1197 }
1198}
1199
1200impl IntoStrV for Vec<&'_ str> {
1201 #[inline]
1202 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1203 self.as_slice().run_with_strv(f)
1204 }
1205}
1206
1207impl IntoStrV for Vec<String> {
1208 #[inline]
1209 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1210 self.as_slice().run_with_strv(f)
1211 }
1212}
1213
1214impl IntoStrV for Vec<&'_ String> {
1215 #[inline]
1216 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1217 self.as_slice().run_with_strv(f)
1218 }
1219}
1220
1221impl IntoStrV for &[GString] {
1222 #[inline]
1223 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1224 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1225
1226 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1227 unsafe {
1228 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1229 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1230
1231 for (i, item) in self.iter().enumerate() {
1232 *ptrs.add(i) = item.as_ptr() as *mut _;
1233 }
1234 *ptrs.add(self.len()) = ptr::null_mut();
1235
1236 f(std::slice::from_raw_parts(ptrs, self.len()))
1237 }
1238 } else {
1239 let mut s = StrV::with_capacity(self.len());
1240 s.extend_from_slice(self);
1241 s.run_with_strv(f)
1242 }
1243 }
1244}
1245
1246impl IntoStrV for &[&GString] {
1247 #[inline]
1248 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1249 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1250
1251 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1252 unsafe {
1253 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1254 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1255
1256 for (i, item) in self.iter().enumerate() {
1257 *ptrs.add(i) = item.as_ptr() as *mut _;
1258 }
1259 *ptrs.add(self.len()) = ptr::null_mut();
1260
1261 f(std::slice::from_raw_parts(ptrs, self.len()))
1262 }
1263 } else {
1264 let mut s = StrV::with_capacity(self.len());
1265 s.extend_from_slice(self);
1266 s.run_with_strv(f)
1267 }
1268 }
1269}
1270
1271impl IntoStrV for &[&GStr] {
1272 #[inline]
1273 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1274 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1275
1276 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1277 unsafe {
1278 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1279 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1280
1281 for (i, item) in self.iter().enumerate() {
1282 *ptrs.add(i) = item.as_ptr() as *mut _;
1283 }
1284 *ptrs.add(self.len()) = ptr::null_mut();
1285
1286 f(std::slice::from_raw_parts(ptrs, self.len()))
1287 }
1288 } else {
1289 let mut s = StrV::with_capacity(self.len());
1290 s.extend_from_slice(self);
1291 s.run_with_strv(f)
1292 }
1293 }
1294}
1295
1296impl IntoStrV for &[&str] {
1297 #[inline]
1298 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1299 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1300 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1301
1302 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1303 unsafe {
1304 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1305 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1306 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1307
1308 for (i, item) in self.iter().enumerate() {
1309 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1310 *strs.add(item.len()) = 0;
1311 *ptrs.add(i) = strs;
1312 strs = strs.add(item.len() + 1);
1313 }
1314 *ptrs.add(self.len()) = ptr::null_mut();
1315
1316 f(std::slice::from_raw_parts(ptrs, self.len()))
1317 }
1318 } else {
1319 let mut s = StrV::with_capacity(self.len());
1320 s.extend_from_slice(self);
1321 s.run_with_strv(f)
1322 }
1323 }
1324}
1325
1326impl IntoStrV for &[String] {
1327 #[inline]
1328 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1329 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1330 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1331
1332 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1333 unsafe {
1334 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1335 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1336 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1337
1338 for (i, item) in self.iter().enumerate() {
1339 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1340 *strs.add(item.len()) = 0;
1341 *ptrs.add(i) = strs;
1342 strs = strs.add(item.len() + 1);
1343 }
1344 *ptrs.add(self.len()) = ptr::null_mut();
1345
1346 f(std::slice::from_raw_parts(ptrs, self.len()))
1347 }
1348 } else {
1349 let mut s = StrV::with_capacity(self.len());
1350 s.extend_from_slice(self);
1351 s.run_with_strv(f)
1352 }
1353 }
1354}
1355
1356impl IntoStrV for &[&String] {
1357 #[inline]
1358 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1359 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1360 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1361
1362 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1363 unsafe {
1364 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1365 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1366 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1367
1368 for (i, item) in self.iter().enumerate() {
1369 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1370 *strs.add(item.len()) = 0;
1371 *ptrs.add(i) = strs;
1372 strs = strs.add(item.len() + 1);
1373 }
1374 *ptrs.add(self.len()) = ptr::null_mut();
1375
1376 f(std::slice::from_raw_parts(ptrs, self.len()))
1377 }
1378 } else {
1379 let mut s = StrV::with_capacity(self.len());
1380 s.extend_from_slice(self);
1381 s.run_with_strv(f)
1382 }
1383 }
1384}
1385
1386impl<const N: usize> IntoStrV for [GString; N] {
1387 #[inline]
1388 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1389 self.as_slice().run_with_strv(f)
1390 }
1391}
1392
1393impl<const N: usize> IntoStrV for [&'_ GString; N] {
1394 #[inline]
1395 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1396 self.as_slice().run_with_strv(f)
1397 }
1398}
1399
1400impl<const N: usize> IntoStrV for [&'_ GStr; N] {
1401 #[inline]
1402 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1403 self.as_slice().run_with_strv(f)
1404 }
1405}
1406
1407impl<const N: usize> IntoStrV for [&'_ str; N] {
1408 #[inline]
1409 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1410 self.as_slice().run_with_strv(f)
1411 }
1412}
1413
1414impl<const N: usize> IntoStrV for [String; N] {
1415 #[inline]
1416 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1417 self.as_slice().run_with_strv(f)
1418 }
1419}
1420
1421impl<const N: usize> IntoStrV for [&'_ String; N] {
1422 #[inline]
1423 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1424 self.as_slice().run_with_strv(f)
1425 }
1426}
1427
1428#[repr(transparent)]
1434pub struct StrVRef {
1435 inner: [GStringPtr],
1436}
1437
1438impl StrVRef {
1439 #[inline]
1446 pub unsafe fn from_glib_borrow<'a>(ptr: *const *const c_char) -> &'a StrVRef {
1447 unsafe {
1448 let slice = StrV::from_glib_borrow(ptr);
1449 &*(slice as *const [GStringPtr] as *const StrVRef)
1450 }
1451 }
1452
1453 #[inline]
1460 pub unsafe fn from_glib_borrow_num<'a>(ptr: *const *const c_char, len: usize) -> &'a StrVRef {
1461 unsafe {
1462 let slice = StrV::from_glib_borrow_num(ptr, len);
1463 &*(slice as *const [GStringPtr] as *const StrVRef)
1464 }
1465 }
1466
1467 #[inline]
1472 pub const fn as_ptr(&self) -> *const *const c_char {
1473 self.inner.as_ptr() as *const *const _
1474 }
1475}
1476
1477impl fmt::Debug for StrVRef {
1478 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1479 self.inner.fmt(f)
1480 }
1481}
1482
1483unsafe impl Send for StrVRef {}
1484
1485unsafe impl Sync for StrVRef {}
1486
1487impl PartialEq for StrVRef {
1488 #[inline]
1489 fn eq(&self, other: &Self) -> bool {
1490 self.inner == other.inner
1491 }
1492}
1493
1494impl Eq for StrVRef {}
1495
1496impl PartialOrd for StrVRef {
1497 #[inline]
1498 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1499 Some(self.cmp(other))
1500 }
1501}
1502
1503impl Ord for StrVRef {
1504 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1505 self.inner.cmp(&other.inner)
1506 }
1507}
1508
1509impl std::hash::Hash for StrVRef {
1510 #[inline]
1511 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1512 self.inner.hash(state)
1513 }
1514}
1515
1516impl PartialEq<[&'_ str]> for StrVRef {
1517 fn eq(&self, other: &[&'_ str]) -> bool {
1518 if self.len() != other.len() {
1519 return false;
1520 }
1521
1522 for (a, b) in Iterator::zip(self.iter(), other.iter()) {
1523 if a != b {
1524 return false;
1525 }
1526 }
1527
1528 true
1529 }
1530}
1531
1532impl PartialEq<StrVRef> for [&'_ str] {
1533 #[inline]
1534 fn eq(&self, other: &StrVRef) -> bool {
1535 other.eq(self)
1536 }
1537}
1538
1539impl Default for &StrVRef {
1540 #[inline]
1541 fn default() -> Self {
1542 const SLICE: &[*const c_char] = &[ptr::null()];
1543 unsafe { StrVRef::from_glib_borrow(SLICE.as_ptr()) }
1545 }
1546}
1547
1548impl std::ops::Deref for StrVRef {
1549 type Target = [GStringPtr];
1550
1551 #[inline]
1552 fn deref(&self) -> &[GStringPtr] {
1553 &self.inner
1554 }
1555}
1556
1557impl<'a> std::iter::IntoIterator for &'a StrVRef {
1558 type Item = &'a GStringPtr;
1559 type IntoIter = std::slice::Iter<'a, GStringPtr>;
1560
1561 #[inline]
1562 fn into_iter(self) -> Self::IntoIter {
1563 self.inner.iter()
1564 }
1565}
1566
1567impl<'a> From<&'a StrV> for &'a StrVRef {
1568 fn from(value: &'a StrV) -> Self {
1569 let slice = value.as_slice();
1570 unsafe { &*(slice as *const [GStringPtr] as *const StrVRef) }
1574 }
1575}
1576
1577impl FromGlibContainer<*mut c_char, *const *const c_char> for &StrVRef {
1578 unsafe fn from_glib_none_num(ptr: *const *const c_char, num: usize) -> Self {
1579 unsafe { StrVRef::from_glib_borrow_num(ptr, num) }
1580 }
1581
1582 unsafe fn from_glib_container_num(_ptr: *const *const c_char, _num: usize) -> Self {
1583 unimplemented!();
1584 }
1585
1586 unsafe fn from_glib_full_num(_ptr: *const *const c_char, _num: usize) -> Self {
1587 unimplemented!();
1588 }
1589}
1590
1591impl FromGlibPtrContainer<*mut c_char, *const *const c_char> for &StrVRef {
1592 #[inline]
1593 unsafe fn from_glib_none(ptr: *const *const c_char) -> Self {
1594 unsafe { StrVRef::from_glib_borrow(ptr) }
1595 }
1596
1597 unsafe fn from_glib_container(_ptr: *const *const c_char) -> Self {
1598 unimplemented!();
1599 }
1600
1601 unsafe fn from_glib_full(_ptr: *const *const c_char) -> Self {
1602 unimplemented!();
1603 }
1604}
1605
1606impl<'a> ToGlibPtr<'a, *const *const c_char> for StrVRef {
1607 type Storage = PhantomData<&'a Self>;
1608
1609 #[inline]
1610 fn to_glib_none(&'a self) -> Stash<'a, *const *const c_char, Self> {
1611 Stash(self.as_ptr(), PhantomData)
1612 }
1613}
1614
1615impl IntoGlibPtr<*const *const c_char> for &StrVRef {
1616 #[inline]
1617 fn into_glib_ptr(self) -> *const *const c_char {
1618 self.as_ptr()
1619 }
1620}
1621
1622impl StaticType for StrVRef {
1623 #[inline]
1624 fn static_type() -> crate::Type {
1625 <Vec<String>>::static_type()
1626 }
1627}
1628
1629unsafe impl<'a> crate::value::FromValue<'a> for &'a StrVRef {
1630 type Checker = crate::value::GenericValueTypeChecker<Self>;
1631
1632 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1633 unsafe {
1634 let ptr =
1635 gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
1636 StrVRef::from_glib_borrow(ptr)
1637 }
1638 }
1639}
1640
1641#[cfg(test)]
1642mod test {
1643 use super::*;
1644
1645 #[test]
1646 fn test_from_glib_full() {
1647 let items = ["str1", "str2", "str3", "str4"];
1648
1649 let slice = unsafe {
1650 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *mut c_char;
1651 *ptr.add(0) = items[0].to_glib_full();
1652 *ptr.add(1) = items[1].to_glib_full();
1653 *ptr.add(2) = items[2].to_glib_full();
1654 *ptr.add(3) = items[3].to_glib_full();
1655
1656 StrV::from_glib_full_num(ptr, 4, false)
1657 };
1658
1659 assert_eq!(items.len(), slice.len());
1660 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1661 assert_eq!(a, b);
1662 }
1663 }
1664
1665 #[test]
1666 fn test_from_glib_container() {
1667 let items = [
1668 crate::gstr!("str1"),
1669 crate::gstr!("str2"),
1670 crate::gstr!("str3"),
1671 crate::gstr!("str4"),
1672 ];
1673
1674 let slice = unsafe {
1675 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char;
1676 *ptr.add(0) = items[0].as_ptr();
1677 *ptr.add(1) = items[1].as_ptr();
1678 *ptr.add(2) = items[2].as_ptr();
1679 *ptr.add(3) = items[3].as_ptr();
1680
1681 StrV::from_glib_container_num(ptr, 4, false)
1682 };
1683
1684 assert_eq!(items.len(), slice.len());
1685 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1686 assert_eq!(a, b);
1687 }
1688 }
1689
1690 #[test]
1691 fn test_from_glib_none() {
1692 let items = [
1693 crate::gstr!("str1"),
1694 crate::gstr!("str2"),
1695 crate::gstr!("str3"),
1696 crate::gstr!("str4"),
1697 ];
1698
1699 let slice = unsafe {
1700 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char;
1701 *ptr.add(0) = items[0].as_ptr();
1702 *ptr.add(1) = items[1].as_ptr();
1703 *ptr.add(2) = items[2].as_ptr();
1704 *ptr.add(3) = items[3].as_ptr();
1705
1706 let res = StrV::from_glib_none_num(ptr, 4, false);
1707 ffi::g_free(ptr as ffi::gpointer);
1708 res
1709 };
1710
1711 assert_eq!(items.len(), slice.len());
1712 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1713 assert_eq!(a, b);
1714 }
1715 }
1716
1717 #[test]
1718 fn test_from_slice() {
1719 let items = [
1720 crate::gstr!("str1"),
1721 crate::gstr!("str2"),
1722 crate::gstr!("str3"),
1723 ];
1724
1725 let slice1 = StrV::from(&items[..]);
1726 let slice2 = StrV::from(items);
1727 assert_eq!(slice1.len(), 3);
1728 assert_eq!(slice1, slice2);
1729 }
1730
1731 #[test]
1732 fn test_safe_api() {
1733 let items = [
1734 crate::gstr!("str1"),
1735 crate::gstr!("str2"),
1736 crate::gstr!("str3"),
1737 ];
1738
1739 let mut slice = StrV::from(&items[..]);
1740 assert_eq!(slice.len(), 3);
1741 slice.push(GString::from("str4"));
1742 assert_eq!(slice.len(), 4);
1743
1744 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1745 assert_eq!(a, b);
1746 }
1747 assert_eq!(slice[3], "str4");
1748
1749 let vec = Vec::from(slice);
1750 assert_eq!(vec.len(), 4);
1751 for (a, b) in Iterator::zip(items.iter(), vec.iter()) {
1752 assert_eq!(a, b);
1753 }
1754 assert_eq!(vec[3], "str4");
1755
1756 let mut slice = StrV::from(vec);
1757 assert_eq!(slice.len(), 4);
1758 let e = slice.pop().unwrap();
1759 assert_eq!(e, "str4");
1760 assert_eq!(slice.len(), 3);
1761 slice.insert(2, e);
1762 assert_eq!(slice.len(), 4);
1763 assert_eq!(slice[0], "str1");
1764 assert_eq!(slice[1], "str2");
1765 assert_eq!(slice[2], "str4");
1766 assert_eq!(slice[3], "str3");
1767 let e = slice.remove(2);
1768 assert_eq!(e, "str4");
1769 assert_eq!(slice.len(), 3);
1770 slice.push(e);
1771 assert_eq!(slice.len(), 4);
1772
1773 for (a, b) in Iterator::zip(items.iter(), slice) {
1774 assert_eq!(*a, b);
1775 }
1776 }
1777
1778 #[test]
1779 fn test_into_strv() {
1780 let items = ["str1", "str2", "str3", "str4"];
1781
1782 items[..].run_with_strv(|s| unsafe {
1783 assert!((*s.as_ptr().add(4)).is_null());
1784 assert_eq!(s.len(), items.len());
1785 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1786 assert_eq!(s, items);
1787 });
1788
1789 Vec::from(&items[..]).run_with_strv(|s| unsafe {
1790 assert!((*s.as_ptr().add(4)).is_null());
1791 assert_eq!(s.len(), items.len());
1792 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1793 assert_eq!(s, items);
1794 });
1795
1796 StrV::from(&items[..]).run_with_strv(|s| unsafe {
1797 assert!((*s.as_ptr().add(4)).is_null());
1798 assert_eq!(s.len(), items.len());
1799 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1800 assert_eq!(s, items);
1801 });
1802
1803 let v = items.iter().copied().map(String::from).collect::<Vec<_>>();
1804 items.run_with_strv(|s| unsafe {
1805 assert!((*s.as_ptr().add(4)).is_null());
1806 assert_eq!(s.len(), v.len());
1807 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1808 assert_eq!(s, items);
1809 });
1810
1811 let v = items.iter().copied().map(GString::from).collect::<Vec<_>>();
1812 items.run_with_strv(|s| unsafe {
1813 assert!((*s.as_ptr().add(4)).is_null());
1814 assert_eq!(s.len(), v.len());
1815 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1816 assert_eq!(s, items);
1817 });
1818 }
1819
1820 #[test]
1821 fn test_join() {
1822 let items = [
1823 crate::gstr!("str1"),
1824 crate::gstr!("str2"),
1825 crate::gstr!("str3"),
1826 ];
1827
1828 let strv = StrV::from(&items[..]);
1829 assert_eq!(strv.join(None::<&str>), "str1str2str3");
1830 assert_eq!(strv.join(Some(",")), "str1,str2,str3");
1831 }
1832
1833 #[test]
1834 fn test_contains() {
1835 let items = [
1836 crate::gstr!("str1"),
1837 crate::gstr!("str2"),
1838 crate::gstr!("str3"),
1839 ];
1840
1841 let strv = StrV::from(&items[..]);
1842 assert!(strv.contains("str2"));
1843 assert!(!strv.contains("str4"));
1844 }
1845
1846 #[test]
1847 #[should_panic]
1848 fn test_reserve_overflow() {
1849 let mut strv = StrV::from(&[crate::gstr!("foo"); 3][..]);
1850
1851 strv.reserve(usize::MAX - 3);
1854 }
1855
1856 #[test]
1857 #[should_panic]
1858 fn test_extend_from_slice_overflow() {
1859 #[derive(Clone, Copy)]
1862 struct ImplicitStr;
1863
1864 impl AsRef<str> for ImplicitStr {
1865 fn as_ref(&self) -> &str {
1866 ""
1867 }
1868 }
1869
1870 let mut strv = StrV::from(&[crate::gstr!(""); 3][..]);
1871
1872 strv.extend_from_slice(&[ImplicitStr; usize::MAX - 3]);
1876 }
1877
1878 #[test]
1879 fn test_extend_from_slice_panic_safe() {
1880 struct MayPanic(bool);
1881
1882 impl AsRef<str> for MayPanic {
1883 fn as_ref(&self) -> &str {
1884 if self.0 {
1885 panic!("panicking as per request");
1886 } else {
1887 ""
1888 }
1889 }
1890 }
1891
1892 let mut strv = StrV::from(&[crate::gstr!(""); 3][..]);
1893 strv.clear();
1894
1895 _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1897 strv.extend_from_slice(&[MayPanic(false), MayPanic(true)]);
1898 }));
1899
1900 assert!(strv.len() <= 1);
1902 unsafe {
1903 for i in 0..strv.len() {
1904 assert!(!(*strv.as_ptr().add(i)).is_null());
1905 }
1906 assert!((*strv.as_ptr().add(strv.len())).is_null());
1907 }
1908 }
1909
1910 #[test]
1911 fn test_strv_ref_eq_str_slice() {
1912 let strv = StrV::from(&[crate::gstr!("a")][..]);
1913 let strv_ref: &StrVRef = strv.as_ref();
1914
1915 assert_eq!(strv_ref, &["a"][..]);
1917 assert_ne!(strv_ref, &[][..]);
1918 assert_ne!(strv_ref, &["a", "b"][..]);
1919 assert_ne!(strv_ref, &["b"][..]);
1920 }
1921
1922 #[test]
1923 fn test_from_ptr_slice() {
1924 let items = [
1925 GStringPtr::from("a"),
1926 GStringPtr::from("b"),
1927 GStringPtr::from("c"),
1928 ];
1929 let ptr_slice: crate::PtrSlice<GStringPtr> = crate::PtrSlice::from(&items[..]);
1930 let strv: StrV = ptr_slice.into();
1931
1932 for (i, item) in items.into_iter().enumerate() {
1933 assert_eq!(strv[i], item);
1934 }
1935 }
1936
1937 #[test]
1938 fn test_into_ptr_slice() {
1939 let items = [crate::gstr!("a"), crate::gstr!("b"), crate::gstr!("c")];
1940 let strv: StrV = StrV::from(&items[..]);
1941 let ptr_slice: crate::PtrSlice<GStringPtr> = strv.into();
1942
1943 for (i, item) in items.into_iter().enumerate() {
1944 assert_eq!(ptr_slice[i], item);
1945 }
1946 }
1947
1948 #[test]
1949 fn test_clear_no_double_free() {
1950 let mut strv = StrV::from(&["one", "two", "three"][..]);
1951 assert_eq!(strv.len(), 3);
1952 strv.clear();
1953 assert_eq!(strv.len(), 0);
1954 }
1956}