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