1use std::{ffi::c_char, fmt, marker::PhantomData, mem, ptr};
4
5use crate::{ffi, gobject_ffi, prelude::*, translate::*, GStr, GString, GStringPtr};
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 Clone for StrV {
441 #[inline]
442 fn clone(&self) -> Self {
443 unsafe {
444 let mut s = Self::with_capacity(self.len());
445 for (i, item) in self.iter().enumerate() {
446 *s.ptr.as_ptr().add(i) = GString::from(item.as_str()).into_glib_ptr();
447 }
448 s.len = self.len();
449 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
450 s
451 }
452 }
453}
454
455impl StrV {
456 #[inline]
459 pub unsafe fn from_glib_borrow<'a>(ptr: *const *const c_char) -> &'a [GStringPtr] {
460 let mut len = 0;
461 if !ptr.is_null() {
462 while !(*ptr.add(len)).is_null() {
463 len += 1;
464 }
465 }
466 Self::from_glib_borrow_num(ptr, len)
467 }
468
469 #[inline]
472 pub unsafe fn from_glib_borrow_num<'a>(
473 ptr: *const *const c_char,
474 len: usize,
475 ) -> &'a [GStringPtr] {
476 debug_assert!(!ptr.is_null() || len == 0);
477
478 if len == 0 {
479 &[]
480 } else {
481 std::slice::from_raw_parts(ptr as *const GStringPtr, len)
482 }
483 }
484
485 #[inline]
488 pub unsafe fn from_glib_none_num(
489 ptr: *const *const c_char,
490 len: usize,
491 _null_terminated: bool,
492 ) -> Self {
493 debug_assert!(!ptr.is_null() || len == 0);
494
495 if len == 0 {
496 StrV::default()
497 } else {
498 let new_ptr =
501 ffi::g_malloc(mem::size_of::<*mut c_char>() * (len + 1)) as *mut *mut c_char;
502
503 for i in 0..len {
505 let p = ptr.add(i) as *mut *const c_char;
506 let q = new_ptr.add(i) as *mut *const c_char;
507 *q = ffi::g_strdup(*p);
508 }
509
510 *new_ptr.add(len) = ptr::null_mut();
511
512 StrV {
513 ptr: ptr::NonNull::new_unchecked(new_ptr),
514 len,
515 capacity: len + 1,
516 }
517 }
518 }
519
520 #[inline]
523 pub unsafe fn from_glib_container_num(
524 ptr: *mut *const c_char,
525 len: usize,
526 null_terminated: bool,
527 ) -> Self {
528 debug_assert!(!ptr.is_null() || len == 0);
529
530 if len == 0 {
531 ffi::g_free(ptr as ffi::gpointer);
532 StrV::default()
533 } else {
534 for i in 0..len {
536 let p = ptr.add(i);
537 *p = ffi::g_strdup(*p);
538 }
539
540 Self::from_glib_full_num(ptr as *mut *mut c_char, len, null_terminated)
542 }
543 }
544
545 #[inline]
548 pub unsafe fn from_glib_full_num(
549 ptr: *mut *mut c_char,
550 len: usize,
551 null_terminated: bool,
552 ) -> Self {
553 debug_assert!(!ptr.is_null() || len == 0);
554
555 if len == 0 {
556 ffi::g_free(ptr as ffi::gpointer);
557 StrV::default()
558 } else {
559 if null_terminated {
560 return StrV {
561 ptr: ptr::NonNull::new_unchecked(ptr),
562 len,
563 capacity: len + 1,
564 };
565 }
566
567 let capacity = len + 1;
569 assert_ne!(capacity, 0);
570 let ptr = ffi::g_realloc(
571 ptr as *mut _,
572 mem::size_of::<*mut c_char>().checked_mul(capacity).unwrap(),
573 ) as *mut *mut c_char;
574 *ptr.add(len) = ptr::null_mut();
575
576 StrV {
577 ptr: ptr::NonNull::new_unchecked(ptr),
578 len,
579 capacity,
580 }
581 }
582 }
583
584 #[inline]
587 pub unsafe fn from_glib_none(ptr: *const *const c_char) -> Self {
588 let mut len = 0;
589 if !ptr.is_null() {
590 while !(*ptr.add(len)).is_null() {
591 len += 1;
592 }
593 }
594
595 StrV::from_glib_none_num(ptr, len, true)
596 }
597
598 #[inline]
601 pub unsafe fn from_glib_container(ptr: *mut *const c_char) -> Self {
602 let mut len = 0;
603 if !ptr.is_null() {
604 while !(*ptr.add(len)).is_null() {
605 len += 1;
606 }
607 }
608
609 StrV::from_glib_container_num(ptr, len, true)
610 }
611
612 #[inline]
615 pub unsafe fn from_glib_full(ptr: *mut *mut c_char) -> Self {
616 let mut len = 0;
617 if !ptr.is_null() {
618 while !(*ptr.add(len)).is_null() {
619 len += 1;
620 }
621 }
622
623 StrV::from_glib_full_num(ptr, len, true)
624 }
625
626 #[inline]
629 pub fn new() -> Self {
630 StrV {
631 ptr: ptr::NonNull::dangling(),
632 len: 0,
633 capacity: 0,
634 }
635 }
636
637 #[inline]
640 pub fn with_capacity(capacity: usize) -> Self {
641 let mut s = Self::new();
642 s.reserve(capacity);
643 s
644 }
645
646 #[inline]
651 pub fn as_ptr(&self) -> *const *mut c_char {
652 if self.len == 0 {
653 static EMPTY: [usize; 1] = [0];
654
655 EMPTY.as_ptr() as *const _
656 } else {
657 self.ptr.as_ptr()
658 }
659 }
660
661 #[inline]
666 pub fn into_raw(mut self) -> *mut *mut c_char {
667 if self.len == 0 {
670 self.reserve(0);
671 unsafe {
672 *self.ptr.as_ptr().add(0) = ptr::null_mut();
673 }
674 }
675
676 self.len = 0;
677 self.capacity = 0;
678 self.ptr.as_ptr()
679 }
680
681 #[inline]
684 pub fn len(&self) -> usize {
685 self.len
686 }
687
688 #[inline]
691 pub fn is_empty(&self) -> bool {
692 self.len == 0
693 }
694
695 #[inline]
700 pub fn capacity(&self) -> usize {
701 self.capacity
702 }
703
704 pub unsafe fn set_len(&mut self, len: usize) {
711 self.len = len;
712 }
713
714 #[allow(clippy::int_plus_one)]
717 pub fn reserve(&mut self, additional: usize) {
718 if additional < self.capacity - self.len {
720 return;
721 }
722
723 let new_capacity =
724 usize::next_power_of_two(std::cmp::max(self.len + additional, MIN_SIZE) + 1);
725 assert_ne!(new_capacity, 0);
726 assert!(new_capacity > self.capacity);
727
728 unsafe {
729 let ptr = if self.capacity == 0 {
730 ptr::null_mut()
731 } else {
732 self.ptr.as_ptr() as *mut _
733 };
734 let new_ptr = ffi::g_realloc(
735 ptr,
736 mem::size_of::<*mut c_char>()
737 .checked_mul(new_capacity)
738 .unwrap(),
739 ) as *mut *mut c_char;
740 if self.capacity == 0 {
741 *new_ptr = ptr::null_mut();
742 }
743 self.ptr = ptr::NonNull::new_unchecked(new_ptr);
744 self.capacity = new_capacity;
745 }
746 }
747
748 #[inline]
751 pub const fn as_slice(&self) -> &[GStringPtr] {
752 unsafe {
753 if self.len == 0 {
754 &[]
755 } else {
756 std::slice::from_raw_parts(self.ptr.as_ptr() as *const GStringPtr, self.len)
757 }
758 }
759 }
760
761 #[inline]
764 pub fn clear(&mut self) {
765 unsafe {
766 for i in 0..self.len {
767 ffi::g_free(*self.ptr.as_ptr().add(i) as ffi::gpointer);
768 }
769
770 self.len = 0;
771 }
772 }
773
774 #[inline]
777 pub fn extend_from_slice<S: AsRef<str>>(&mut self, other: &[S]) {
778 if other.len() >= self.capacity - self.len {
780 self.reserve(other.len());
781 }
782
783 unsafe {
784 for item in other {
785 *self.ptr.as_ptr().add(self.len) = GString::from(item.as_ref()).into_glib_ptr();
786 self.len += 1;
787
788 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
791 }
792 }
793 }
794
795 #[inline]
799 pub fn insert(&mut self, index: usize, item: GString) {
800 assert!(index <= self.len);
801
802 if 1 >= self.capacity - self.len {
804 self.reserve(1);
805 }
806
807 unsafe {
808 if index == self.len {
809 *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr();
810 } else {
811 let p = self.ptr.as_ptr().add(index);
812 ptr::copy(p, p.add(1), self.len - index);
813 *self.ptr.as_ptr().add(index) = item.into_glib_ptr();
814 }
815
816 self.len += 1;
817
818 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
819 }
820 }
821
822 #[inline]
825 pub fn push(&mut self, item: GString) {
826 if 1 >= self.capacity - self.len {
828 self.reserve(1);
829 }
830
831 unsafe {
832 *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr();
833 self.len += 1;
834
835 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
836 }
837 }
838
839 #[inline]
843 pub fn remove(&mut self, index: usize) -> GString {
844 assert!(index < self.len);
845
846 unsafe {
847 let p = self.ptr.as_ptr().add(index);
848 let item = *p;
849 ptr::copy(p.add(1), p, self.len - index - 1);
850
851 self.len -= 1;
852
853 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
854
855 GString::from_glib_full(item)
856 }
857 }
858
859 #[inline]
862 pub fn swap(&mut self, index: usize, new_item: GString) -> GString {
863 assert!(index < self.len);
864
865 unsafe {
866 let p = self.ptr.as_ptr().add(index);
867 let item = *p;
868 *p = new_item.into_glib_ptr();
869
870 GString::from_glib_full(item)
871 }
872 }
873
874 #[inline]
877 pub fn pop(&mut self) -> Option<GString> {
878 if self.len == 0 {
879 return None;
880 }
881
882 unsafe {
883 self.len -= 1;
884 let p = self.ptr.as_ptr().add(self.len);
885 let item = *p;
886
887 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
888
889 Some(GString::from_glib_full(item))
890 }
891 }
892
893 #[inline]
898 pub fn truncate(&mut self, len: usize) {
899 if self.len <= len {
900 return;
901 }
902
903 unsafe {
904 while self.len > len {
905 self.len -= 1;
906 let p = self.ptr.as_ptr().add(self.len);
907 ffi::g_free(*p as ffi::gpointer);
908 *p = ptr::null_mut();
909 }
910 }
911 }
912
913 #[inline]
916 #[doc(alias = "g_strjoinv")]
917 pub fn join(&self, separator: Option<impl IntoGStr>) -> GString {
918 separator.run_with_gstr(|separator| unsafe {
919 from_glib_full(ffi::g_strjoinv(
920 separator.to_glib_none().0,
921 self.as_ptr() as *mut _,
922 ))
923 })
924 }
925
926 #[inline]
929 #[doc(alias = "g_strv_contains")]
930 pub fn contains(&self, s: impl IntoGStr) -> bool {
931 s.run_with_gstr(|s| unsafe {
932 from_glib(ffi::g_strv_contains(
933 self.as_ptr() as *const _,
934 s.to_glib_none().0,
935 ))
936 })
937 }
938}
939
940impl FromGlibContainer<*mut c_char, *mut *mut c_char> for StrV {
941 #[inline]
942 unsafe fn from_glib_none_num(ptr: *mut *mut c_char, num: usize) -> Self {
943 Self::from_glib_none_num(ptr as *const *const c_char, num, false)
944 }
945
946 #[inline]
947 unsafe fn from_glib_container_num(ptr: *mut *mut c_char, num: usize) -> Self {
948 Self::from_glib_container_num(ptr as *mut *const c_char, num, false)
949 }
950
951 #[inline]
952 unsafe fn from_glib_full_num(ptr: *mut *mut c_char, num: usize) -> Self {
953 Self::from_glib_full_num(ptr, num, false)
954 }
955}
956
957impl FromGlibContainer<*mut c_char, *const *mut c_char> for StrV {
958 unsafe fn from_glib_none_num(ptr: *const *mut c_char, num: usize) -> Self {
959 Self::from_glib_none_num(ptr as *const *const c_char, num, false)
960 }
961
962 unsafe fn from_glib_container_num(_ptr: *const *mut c_char, _num: usize) -> Self {
963 unimplemented!();
964 }
965
966 unsafe fn from_glib_full_num(_ptr: *const *mut c_char, _num: usize) -> Self {
967 unimplemented!();
968 }
969}
970
971impl FromGlibPtrContainer<*mut c_char, *mut *mut c_char> for StrV {
972 #[inline]
973 unsafe fn from_glib_none(ptr: *mut *mut c_char) -> Self {
974 Self::from_glib_none(ptr as *const *const c_char)
975 }
976
977 #[inline]
978 unsafe fn from_glib_container(ptr: *mut *mut c_char) -> Self {
979 Self::from_glib_container(ptr as *mut *const c_char)
980 }
981
982 #[inline]
983 unsafe fn from_glib_full(ptr: *mut *mut c_char) -> Self {
984 Self::from_glib_full(ptr)
985 }
986}
987
988impl FromGlibPtrContainer<*mut c_char, *const *mut c_char> for StrV {
989 #[inline]
990 unsafe fn from_glib_none(ptr: *const *mut c_char) -> Self {
991 Self::from_glib_none(ptr as *const *const c_char)
992 }
993
994 unsafe fn from_glib_container(_ptr: *const *mut c_char) -> Self {
995 unimplemented!();
996 }
997
998 unsafe fn from_glib_full(_ptr: *const *mut c_char) -> Self {
999 unimplemented!();
1000 }
1001}
1002
1003impl<'a> ToGlibPtr<'a, *mut *mut c_char> for StrV {
1004 type Storage = PhantomData<&'a Self>;
1005
1006 #[inline]
1007 fn to_glib_none(&'a self) -> Stash<'a, *mut *mut c_char, Self> {
1008 Stash(self.as_ptr() as *mut _, PhantomData)
1009 }
1010
1011 #[inline]
1012 fn to_glib_container(&'a self) -> Stash<'a, *mut *mut c_char, Self> {
1013 unsafe {
1014 let ptr =
1015 ffi::g_malloc(mem::size_of::<*mut c_char>() * (self.len() + 1)) as *mut *mut c_char;
1016 ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1);
1017 Stash(ptr, PhantomData)
1018 }
1019 }
1020
1021 #[inline]
1022 fn to_glib_full(&self) -> *mut *mut c_char {
1023 self.clone().into_raw()
1024 }
1025}
1026
1027impl<'a> ToGlibPtr<'a, *const *mut c_char> for StrV {
1028 type Storage = PhantomData<&'a Self>;
1029
1030 #[inline]
1031 fn to_glib_none(&'a self) -> Stash<'a, *const *mut c_char, Self> {
1032 Stash(self.as_ptr(), PhantomData)
1033 }
1034}
1035
1036impl IntoGlibPtr<*mut *mut c_char> for StrV {
1037 #[inline]
1038 fn into_glib_ptr(self) -> *mut *mut c_char {
1039 self.into_raw()
1040 }
1041}
1042
1043impl StaticType for StrV {
1044 #[inline]
1045 fn static_type() -> crate::Type {
1046 <Vec<String>>::static_type()
1047 }
1048}
1049
1050impl StaticType for &'_ [GStringPtr] {
1051 #[inline]
1052 fn static_type() -> crate::Type {
1053 <Vec<String>>::static_type()
1054 }
1055}
1056
1057impl crate::value::ValueType for StrV {
1058 type Type = Vec<String>;
1059}
1060
1061unsafe impl<'a> crate::value::FromValue<'a> for StrV {
1062 type Checker = crate::value::GenericValueTypeChecker<Self>;
1063
1064 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1065 let ptr = gobject_ffi::g_value_dup_boxed(value.to_glib_none().0) as *mut *mut c_char;
1066 FromGlibPtrContainer::from_glib_full(ptr)
1067 }
1068}
1069
1070unsafe impl<'a> crate::value::FromValue<'a> for &'a [GStringPtr] {
1071 type Checker = crate::value::GenericValueTypeChecker<Self>;
1072
1073 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1074 let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
1075 StrV::from_glib_borrow(ptr)
1076 }
1077}
1078
1079impl crate::value::ToValue for StrV {
1080 fn to_value(&self) -> crate::value::Value {
1081 unsafe {
1082 let mut value = crate::value::Value::for_value_type::<Self>();
1083 gobject_ffi::g_value_set_boxed(
1084 value.to_glib_none_mut().0,
1085 self.as_ptr() as ffi::gpointer,
1086 );
1087 value
1088 }
1089 }
1090
1091 fn value_type(&self) -> crate::Type {
1092 <StrV as StaticType>::static_type()
1093 }
1094}
1095
1096impl From<StrV> for crate::Value {
1097 #[inline]
1098 fn from(s: StrV) -> Self {
1099 unsafe {
1100 let mut value = crate::value::Value::for_value_type::<StrV>();
1101 gobject_ffi::g_value_take_boxed(
1102 value.to_glib_none_mut().0,
1103 s.into_raw() as ffi::gpointer,
1104 );
1105 value
1106 }
1107 }
1108}
1109
1110pub trait IntoStrV {
1113 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R;
1116}
1117
1118impl IntoStrV for StrV {
1119 #[inline]
1120 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1121 <&Self>::run_with_strv(&self, f)
1122 }
1123}
1124
1125impl IntoStrV for &'_ StrV {
1126 #[inline]
1127 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1128 f(unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) })
1129 }
1130}
1131
1132const MAX_STACK_ALLOCATION: usize = 16;
1137
1138impl IntoStrV for Vec<GString> {
1139 #[inline]
1140 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1141 self.as_slice().run_with_strv(f)
1142 }
1143}
1144
1145impl IntoStrV for Vec<&'_ GString> {
1146 #[inline]
1147 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1148 self.as_slice().run_with_strv(f)
1149 }
1150}
1151
1152impl IntoStrV for Vec<&'_ GStr> {
1153 #[inline]
1154 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1155 self.as_slice().run_with_strv(f)
1156 }
1157}
1158
1159impl IntoStrV for Vec<&'_ str> {
1160 #[inline]
1161 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1162 self.as_slice().run_with_strv(f)
1163 }
1164}
1165
1166impl IntoStrV for Vec<String> {
1167 #[inline]
1168 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1169 self.as_slice().run_with_strv(f)
1170 }
1171}
1172
1173impl IntoStrV for Vec<&'_ String> {
1174 #[inline]
1175 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1176 self.as_slice().run_with_strv(f)
1177 }
1178}
1179
1180impl IntoStrV for &[GString] {
1181 #[inline]
1182 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1183 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1184
1185 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1186 unsafe {
1187 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1188 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1189
1190 for (i, item) in self.iter().enumerate() {
1191 *ptrs.add(i) = item.as_ptr() as *mut _;
1192 }
1193 *ptrs.add(self.len()) = ptr::null_mut();
1194
1195 f(std::slice::from_raw_parts(ptrs, self.len()))
1196 }
1197 } else {
1198 let mut s = StrV::with_capacity(self.len());
1199 s.extend_from_slice(self);
1200 s.run_with_strv(f)
1201 }
1202 }
1203}
1204
1205impl IntoStrV for &[&GString] {
1206 #[inline]
1207 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1208 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1209
1210 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1211 unsafe {
1212 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1213 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1214
1215 for (i, item) in self.iter().enumerate() {
1216 *ptrs.add(i) = item.as_ptr() as *mut _;
1217 }
1218 *ptrs.add(self.len()) = ptr::null_mut();
1219
1220 f(std::slice::from_raw_parts(ptrs, self.len()))
1221 }
1222 } else {
1223 let mut s = StrV::with_capacity(self.len());
1224 s.extend_from_slice(self);
1225 s.run_with_strv(f)
1226 }
1227 }
1228}
1229
1230impl IntoStrV for &[&GStr] {
1231 #[inline]
1232 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1233 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1234
1235 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1236 unsafe {
1237 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1238 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1239
1240 for (i, item) in self.iter().enumerate() {
1241 *ptrs.add(i) = item.as_ptr() as *mut _;
1242 }
1243 *ptrs.add(self.len()) = ptr::null_mut();
1244
1245 f(std::slice::from_raw_parts(ptrs, self.len()))
1246 }
1247 } else {
1248 let mut s = StrV::with_capacity(self.len());
1249 s.extend_from_slice(self);
1250 s.run_with_strv(f)
1251 }
1252 }
1253}
1254
1255impl IntoStrV for &[&str] {
1256 #[inline]
1257 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1258 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1259 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1260
1261 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1262 unsafe {
1263 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1264 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1265 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1266
1267 for (i, item) in self.iter().enumerate() {
1268 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1269 *strs.add(item.len()) = 0;
1270 *ptrs.add(i) = strs;
1271 strs = strs.add(item.len() + 1);
1272 }
1273 *ptrs.add(self.len()) = ptr::null_mut();
1274
1275 f(std::slice::from_raw_parts(ptrs, self.len()))
1276 }
1277 } else {
1278 let mut s = StrV::with_capacity(self.len());
1279 s.extend_from_slice(self);
1280 s.run_with_strv(f)
1281 }
1282 }
1283}
1284
1285impl IntoStrV for &[String] {
1286 #[inline]
1287 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1288 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1289 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1290
1291 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1292 unsafe {
1293 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1294 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1295 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1296
1297 for (i, item) in self.iter().enumerate() {
1298 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1299 *strs.add(item.len()) = 0;
1300 *ptrs.add(i) = strs;
1301 strs = strs.add(item.len() + 1);
1302 }
1303 *ptrs.add(self.len()) = ptr::null_mut();
1304
1305 f(std::slice::from_raw_parts(ptrs, self.len()))
1306 }
1307 } else {
1308 let mut s = StrV::with_capacity(self.len());
1309 s.extend_from_slice(self);
1310 s.run_with_strv(f)
1311 }
1312 }
1313}
1314
1315impl IntoStrV for &[&String] {
1316 #[inline]
1317 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1318 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1319 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1320
1321 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1322 unsafe {
1323 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1324 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1325 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1326
1327 for (i, item) in self.iter().enumerate() {
1328 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1329 *strs.add(item.len()) = 0;
1330 *ptrs.add(i) = strs;
1331 strs = strs.add(item.len() + 1);
1332 }
1333 *ptrs.add(self.len()) = ptr::null_mut();
1334
1335 f(std::slice::from_raw_parts(ptrs, self.len()))
1336 }
1337 } else {
1338 let mut s = StrV::with_capacity(self.len());
1339 s.extend_from_slice(self);
1340 s.run_with_strv(f)
1341 }
1342 }
1343}
1344
1345impl<const N: usize> IntoStrV for [GString; N] {
1346 #[inline]
1347 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1348 self.as_slice().run_with_strv(f)
1349 }
1350}
1351
1352impl<const N: usize> IntoStrV for [&'_ GString; N] {
1353 #[inline]
1354 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1355 self.as_slice().run_with_strv(f)
1356 }
1357}
1358
1359impl<const N: usize> IntoStrV for [&'_ GStr; N] {
1360 #[inline]
1361 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1362 self.as_slice().run_with_strv(f)
1363 }
1364}
1365
1366impl<const N: usize> IntoStrV for [&'_ str; N] {
1367 #[inline]
1368 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1369 self.as_slice().run_with_strv(f)
1370 }
1371}
1372
1373impl<const N: usize> IntoStrV for [String; N] {
1374 #[inline]
1375 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1376 self.as_slice().run_with_strv(f)
1377 }
1378}
1379
1380impl<const N: usize> IntoStrV for [&'_ String; N] {
1381 #[inline]
1382 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1383 self.as_slice().run_with_strv(f)
1384 }
1385}
1386
1387#[repr(transparent)]
1393pub struct StrVRef {
1394 inner: [GStringPtr],
1395}
1396
1397impl StrVRef {
1398 #[inline]
1405 pub unsafe fn from_glib_borrow<'a>(ptr: *const *const c_char) -> &'a StrVRef {
1406 let slice = StrV::from_glib_borrow(ptr);
1407 &*(slice as *const [GStringPtr] as *const StrVRef)
1408 }
1409
1410 #[inline]
1417 pub unsafe fn from_glib_borrow_num<'a>(ptr: *const *const c_char, len: usize) -> &'a StrVRef {
1418 let slice = StrV::from_glib_borrow_num(ptr, len);
1419 &*(slice as *const [GStringPtr] as *const StrVRef)
1420 }
1421
1422 #[inline]
1427 pub const fn as_ptr(&self) -> *const *const c_char {
1428 self.inner.as_ptr() as *const *const _
1429 }
1430}
1431
1432impl fmt::Debug for StrVRef {
1433 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1434 self.inner.fmt(f)
1435 }
1436}
1437
1438unsafe impl Send for StrVRef {}
1439
1440unsafe impl Sync for StrVRef {}
1441
1442impl PartialEq for StrVRef {
1443 #[inline]
1444 fn eq(&self, other: &Self) -> bool {
1445 self.inner == other.inner
1446 }
1447}
1448
1449impl Eq for StrVRef {}
1450
1451impl PartialOrd for StrVRef {
1452 #[inline]
1453 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1454 Some(self.cmp(other))
1455 }
1456}
1457
1458impl Ord for StrVRef {
1459 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1460 self.inner.cmp(&other.inner)
1461 }
1462}
1463
1464impl std::hash::Hash for StrVRef {
1465 #[inline]
1466 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1467 self.inner.hash(state)
1468 }
1469}
1470
1471impl PartialEq<[&'_ str]> for StrVRef {
1472 fn eq(&self, other: &[&'_ str]) -> bool {
1473 if self.len() != other.len() {
1474 return false;
1475 }
1476
1477 for (a, b) in Iterator::zip(self.iter(), other.iter()) {
1478 if a != b {
1479 return false;
1480 }
1481 }
1482
1483 true
1484 }
1485}
1486
1487impl PartialEq<StrVRef> for [&'_ str] {
1488 #[inline]
1489 fn eq(&self, other: &StrVRef) -> bool {
1490 other.eq(self)
1491 }
1492}
1493
1494impl Default for &StrVRef {
1495 #[inline]
1496 fn default() -> Self {
1497 const SLICE: &[*const c_char] = &[ptr::null()];
1498 unsafe { StrVRef::from_glib_borrow(SLICE.as_ptr()) }
1500 }
1501}
1502
1503impl std::ops::Deref for StrVRef {
1504 type Target = [GStringPtr];
1505
1506 #[inline]
1507 fn deref(&self) -> &[GStringPtr] {
1508 &self.inner
1509 }
1510}
1511
1512impl<'a> std::iter::IntoIterator for &'a StrVRef {
1513 type Item = &'a GStringPtr;
1514 type IntoIter = std::slice::Iter<'a, GStringPtr>;
1515
1516 #[inline]
1517 fn into_iter(self) -> Self::IntoIter {
1518 self.inner.iter()
1519 }
1520}
1521
1522impl<'a> From<&'a StrV> for &'a StrVRef {
1523 fn from(value: &'a StrV) -> Self {
1524 let slice = value.as_slice();
1525 unsafe { &*(slice as *const [GStringPtr] as *const StrVRef) }
1529 }
1530}
1531
1532impl FromGlibContainer<*mut c_char, *const *const c_char> for &StrVRef {
1533 unsafe fn from_glib_none_num(ptr: *const *const c_char, num: usize) -> Self {
1534 StrVRef::from_glib_borrow_num(ptr, num)
1535 }
1536
1537 unsafe fn from_glib_container_num(_ptr: *const *const c_char, _num: usize) -> Self {
1538 unimplemented!();
1539 }
1540
1541 unsafe fn from_glib_full_num(_ptr: *const *const c_char, _num: usize) -> Self {
1542 unimplemented!();
1543 }
1544}
1545
1546impl FromGlibPtrContainer<*mut c_char, *const *const c_char> for &StrVRef {
1547 #[inline]
1548 unsafe fn from_glib_none(ptr: *const *const c_char) -> Self {
1549 StrVRef::from_glib_borrow(ptr)
1550 }
1551
1552 unsafe fn from_glib_container(_ptr: *const *const c_char) -> Self {
1553 unimplemented!();
1554 }
1555
1556 unsafe fn from_glib_full(_ptr: *const *const c_char) -> Self {
1557 unimplemented!();
1558 }
1559}
1560
1561impl<'a> ToGlibPtr<'a, *const *const c_char> for StrVRef {
1562 type Storage = PhantomData<&'a Self>;
1563
1564 #[inline]
1565 fn to_glib_none(&'a self) -> Stash<'a, *const *const c_char, Self> {
1566 Stash(self.as_ptr(), PhantomData)
1567 }
1568}
1569
1570impl IntoGlibPtr<*const *const c_char> for &StrVRef {
1571 #[inline]
1572 fn into_glib_ptr(self) -> *const *const c_char {
1573 self.as_ptr()
1574 }
1575}
1576
1577impl StaticType for StrVRef {
1578 #[inline]
1579 fn static_type() -> crate::Type {
1580 <Vec<String>>::static_type()
1581 }
1582}
1583
1584unsafe impl<'a> crate::value::FromValue<'a> for &'a StrVRef {
1585 type Checker = crate::value::GenericValueTypeChecker<Self>;
1586
1587 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1588 let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
1589 StrVRef::from_glib_borrow(ptr)
1590 }
1591}
1592
1593#[cfg(test)]
1594mod test {
1595 use super::*;
1596
1597 #[test]
1598 fn test_from_glib_full() {
1599 let items = ["str1", "str2", "str3", "str4"];
1600
1601 let slice = unsafe {
1602 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *mut c_char;
1603 *ptr.add(0) = items[0].to_glib_full();
1604 *ptr.add(1) = items[1].to_glib_full();
1605 *ptr.add(2) = items[2].to_glib_full();
1606 *ptr.add(3) = items[3].to_glib_full();
1607
1608 StrV::from_glib_full_num(ptr, 4, false)
1609 };
1610
1611 assert_eq!(items.len(), slice.len());
1612 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1613 assert_eq!(a, b);
1614 }
1615 }
1616
1617 #[test]
1618 fn test_from_glib_container() {
1619 let items = [
1620 crate::gstr!("str1"),
1621 crate::gstr!("str2"),
1622 crate::gstr!("str3"),
1623 crate::gstr!("str4"),
1624 ];
1625
1626 let slice = unsafe {
1627 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char;
1628 *ptr.add(0) = items[0].as_ptr();
1629 *ptr.add(1) = items[1].as_ptr();
1630 *ptr.add(2) = items[2].as_ptr();
1631 *ptr.add(3) = items[3].as_ptr();
1632
1633 StrV::from_glib_container_num(ptr, 4, false)
1634 };
1635
1636 assert_eq!(items.len(), slice.len());
1637 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1638 assert_eq!(a, b);
1639 }
1640 }
1641
1642 #[test]
1643 fn test_from_glib_none() {
1644 let items = [
1645 crate::gstr!("str1"),
1646 crate::gstr!("str2"),
1647 crate::gstr!("str3"),
1648 crate::gstr!("str4"),
1649 ];
1650
1651 let slice = unsafe {
1652 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char;
1653 *ptr.add(0) = items[0].as_ptr();
1654 *ptr.add(1) = items[1].as_ptr();
1655 *ptr.add(2) = items[2].as_ptr();
1656 *ptr.add(3) = items[3].as_ptr();
1657
1658 let res = StrV::from_glib_none_num(ptr, 4, false);
1659 ffi::g_free(ptr as ffi::gpointer);
1660 res
1661 };
1662
1663 assert_eq!(items.len(), slice.len());
1664 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1665 assert_eq!(a, b);
1666 }
1667 }
1668
1669 #[test]
1670 fn test_from_slice() {
1671 let items = [
1672 crate::gstr!("str1"),
1673 crate::gstr!("str2"),
1674 crate::gstr!("str3"),
1675 ];
1676
1677 let slice1 = StrV::from(&items[..]);
1678 let slice2 = StrV::from(items);
1679 assert_eq!(slice1.len(), 3);
1680 assert_eq!(slice1, slice2);
1681 }
1682
1683 #[test]
1684 fn test_safe_api() {
1685 let items = [
1686 crate::gstr!("str1"),
1687 crate::gstr!("str2"),
1688 crate::gstr!("str3"),
1689 ];
1690
1691 let mut slice = StrV::from(&items[..]);
1692 assert_eq!(slice.len(), 3);
1693 slice.push(GString::from("str4"));
1694 assert_eq!(slice.len(), 4);
1695
1696 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1697 assert_eq!(a, b);
1698 }
1699 assert_eq!(slice[3], "str4");
1700
1701 let vec = Vec::from(slice);
1702 assert_eq!(vec.len(), 4);
1703 for (a, b) in Iterator::zip(items.iter(), vec.iter()) {
1704 assert_eq!(a, b);
1705 }
1706 assert_eq!(vec[3], "str4");
1707
1708 let mut slice = StrV::from(vec);
1709 assert_eq!(slice.len(), 4);
1710 let e = slice.pop().unwrap();
1711 assert_eq!(e, "str4");
1712 assert_eq!(slice.len(), 3);
1713 slice.insert(2, e);
1714 assert_eq!(slice.len(), 4);
1715 assert_eq!(slice[0], "str1");
1716 assert_eq!(slice[1], "str2");
1717 assert_eq!(slice[2], "str4");
1718 assert_eq!(slice[3], "str3");
1719 let e = slice.remove(2);
1720 assert_eq!(e, "str4");
1721 assert_eq!(slice.len(), 3);
1722 slice.push(e);
1723 assert_eq!(slice.len(), 4);
1724
1725 for (a, b) in Iterator::zip(items.iter(), slice.into_iter()) {
1726 assert_eq!(*a, b);
1727 }
1728 }
1729
1730 #[test]
1731 fn test_into_strv() {
1732 let items = ["str1", "str2", "str3", "str4"];
1733
1734 items[..].run_with_strv(|s| unsafe {
1735 assert!((*s.as_ptr().add(4)).is_null());
1736 assert_eq!(s.len(), items.len());
1737 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1738 assert_eq!(s, items);
1739 });
1740
1741 Vec::from(&items[..]).run_with_strv(|s| unsafe {
1742 assert!((*s.as_ptr().add(4)).is_null());
1743 assert_eq!(s.len(), items.len());
1744 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1745 assert_eq!(s, items);
1746 });
1747
1748 StrV::from(&items[..]).run_with_strv(|s| unsafe {
1749 assert!((*s.as_ptr().add(4)).is_null());
1750 assert_eq!(s.len(), items.len());
1751 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1752 assert_eq!(s, items);
1753 });
1754
1755 let v = items.iter().copied().map(String::from).collect::<Vec<_>>();
1756 items.run_with_strv(|s| unsafe {
1757 assert!((*s.as_ptr().add(4)).is_null());
1758 assert_eq!(s.len(), v.len());
1759 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1760 assert_eq!(s, items);
1761 });
1762
1763 let v = items.iter().copied().map(GString::from).collect::<Vec<_>>();
1764 items.run_with_strv(|s| unsafe {
1765 assert!((*s.as_ptr().add(4)).is_null());
1766 assert_eq!(s.len(), v.len());
1767 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1768 assert_eq!(s, items);
1769 });
1770 }
1771
1772 #[test]
1773 fn test_join() {
1774 let items = [
1775 crate::gstr!("str1"),
1776 crate::gstr!("str2"),
1777 crate::gstr!("str3"),
1778 ];
1779
1780 let strv = StrV::from(&items[..]);
1781 assert_eq!(strv.join(None::<&str>), "str1str2str3");
1782 assert_eq!(strv.join(Some(",")), "str1,str2,str3");
1783 }
1784
1785 #[test]
1786 fn test_contains() {
1787 let items = [
1788 crate::gstr!("str1"),
1789 crate::gstr!("str2"),
1790 crate::gstr!("str3"),
1791 ];
1792
1793 let strv = StrV::from(&items[..]);
1794 assert!(strv.contains("str2"));
1795 assert!(!strv.contains("str4"));
1796 }
1797
1798 #[test]
1799 #[should_panic]
1800 fn test_reserve_overflow() {
1801 let mut strv = StrV::from(&[crate::gstr!("foo"); 3][..]);
1802
1803 strv.reserve(usize::MAX - 3);
1806 }
1807
1808 #[test]
1809 #[should_panic]
1810 fn test_extend_from_slice_overflow() {
1811 #[derive(Clone, Copy)]
1814 struct ImplicitStr;
1815
1816 impl AsRef<str> for ImplicitStr {
1817 fn as_ref(&self) -> &str {
1818 ""
1819 }
1820 }
1821
1822 let mut strv = StrV::from(&[crate::gstr!(""); 3][..]);
1823
1824 strv.extend_from_slice(&[ImplicitStr; usize::MAX - 3]);
1828 }
1829
1830 #[test]
1831 fn test_extend_from_slice_panic_safe() {
1832 struct MayPanic(bool);
1833
1834 impl AsRef<str> for MayPanic {
1835 fn as_ref(&self) -> &str {
1836 if self.0 {
1837 panic!("panicking as per request");
1838 } else {
1839 ""
1840 }
1841 }
1842 }
1843
1844 let mut strv = StrV::from(&[crate::gstr!(""); 3][..]);
1845 strv.clear();
1846
1847 _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1849 strv.extend_from_slice(&[MayPanic(false), MayPanic(true)]);
1850 }));
1851
1852 assert!(strv.len() <= 1);
1854 unsafe {
1855 for i in 0..strv.len() {
1856 assert!(!(*strv.as_ptr().add(i)).is_null());
1857 }
1858 assert!((*strv.as_ptr().add(strv.len())).is_null());
1859 }
1860 }
1861
1862 #[test]
1863 fn test_strv_ref_eq_str_slice() {
1864 let strv = StrV::from(&[crate::gstr!("a")][..]);
1865 let strv_ref: &StrVRef = strv.as_ref();
1866
1867 assert_eq!(strv_ref, &["a"][..]);
1869 assert_ne!(strv_ref, &[][..]);
1870 assert_ne!(strv_ref, &["a", "b"][..]);
1871 assert_ne!(strv_ref, &["b"][..]);
1872 }
1873}