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 std::ops::Deref for StrV {
118 type Target = [GStringPtr];
119
120 #[inline]
121 fn deref(&self) -> &[GStringPtr] {
122 self.as_slice()
123 }
124}
125
126impl std::iter::Extend<GString> for StrV {
127 #[inline]
128 fn extend<I: IntoIterator<Item = GString>>(&mut self, iter: I) {
129 let iter = iter.into_iter();
130 self.reserve(iter.size_hint().0);
131
132 for item in iter {
133 self.push(item);
134 }
135 }
136}
137
138impl<'a> std::iter::Extend<&'a str> for StrV {
139 #[inline]
140 fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
141 let iter = iter.into_iter();
142 self.reserve(iter.size_hint().0);
143
144 for item in iter {
145 self.push(GString::from(item));
146 }
147 }
148}
149
150impl std::iter::FromIterator<GString> for StrV {
151 #[inline]
152 fn from_iter<I: IntoIterator<Item = GString>>(iter: I) -> Self {
153 let iter = iter.into_iter();
154 let mut s = Self::with_capacity(iter.size_hint().0);
155 for item in iter {
156 s.push(item);
157 }
158 s
159 }
160}
161
162impl<'a> std::iter::IntoIterator for &'a StrV {
163 type Item = &'a GStringPtr;
164 type IntoIter = std::slice::Iter<'a, GStringPtr>;
165
166 #[inline]
167 fn into_iter(self) -> Self::IntoIter {
168 self.as_slice().iter()
169 }
170}
171
172impl std::iter::IntoIterator for StrV {
173 type Item = GString;
174 type IntoIter = IntoIter;
175
176 #[inline]
177 fn into_iter(self) -> Self::IntoIter {
178 IntoIter::new(self)
179 }
180}
181
182pub struct IntoIter {
183 ptr: ptr::NonNull<*mut c_char>,
184 idx: ptr::NonNull<*mut c_char>,
185 len: usize,
186 empty: bool,
187}
188
189impl IntoIter {
190 #[inline]
191 fn new(slice: StrV) -> Self {
192 let slice = mem::ManuallyDrop::new(slice);
193 IntoIter {
194 ptr: slice.ptr,
195 idx: slice.ptr,
196 len: slice.len,
197 empty: slice.capacity == 0,
198 }
199 }
200
201 #[inline]
204 pub const fn as_slice(&self) -> &[GStringPtr] {
205 unsafe {
206 if self.len == 0 {
207 &[]
208 } else {
209 std::slice::from_raw_parts(self.idx.as_ptr() as *const GStringPtr, self.len)
210 }
211 }
212 }
213}
214
215impl Drop for IntoIter {
216 #[inline]
217 fn drop(&mut self) {
218 unsafe {
219 for i in 0..self.len {
220 ffi::g_free(*self.idx.as_ptr().add(i) as ffi::gpointer);
221 }
222
223 if !self.empty {
224 ffi::g_free(self.ptr.as_ptr() as ffi::gpointer);
225 }
226 }
227 }
228}
229
230impl Iterator for IntoIter {
231 type Item = GString;
232
233 #[inline]
234 fn next(&mut self) -> Option<Self::Item> {
235 if self.len == 0 {
236 return None;
237 }
238
239 unsafe {
240 let p = self.idx.as_ptr();
241 self.len -= 1;
242 self.idx = ptr::NonNull::new_unchecked(p.add(1));
243 Some(GString::from_glib_full(*p))
244 }
245 }
246
247 #[inline]
248 fn size_hint(&self) -> (usize, Option<usize>) {
249 (self.len, Some(self.len))
250 }
251
252 #[inline]
253 fn count(self) -> usize {
254 self.len
255 }
256
257 #[inline]
258 fn last(mut self) -> Option<GString> {
259 if self.len == 0 {
260 None
261 } else {
262 self.len -= 1;
263 Some(unsafe { GString::from_glib_full(*self.idx.as_ptr().add(self.len)) })
264 }
265 }
266}
267
268impl DoubleEndedIterator for IntoIter {
269 #[inline]
270 fn next_back(&mut self) -> Option<GString> {
271 if self.len == 0 {
272 None
273 } else {
274 self.len -= 1;
275 Some(unsafe { GString::from_glib_full(*self.idx.as_ptr().add(self.len)) })
276 }
277 }
278}
279
280impl ExactSizeIterator for IntoIter {}
281
282impl std::iter::FusedIterator for IntoIter {}
283
284impl From<StrV> for Vec<GString> {
285 #[inline]
286 fn from(value: StrV) -> Self {
287 value.into_iter().collect()
288 }
289}
290
291impl From<Vec<String>> for StrV {
292 #[inline]
293 fn from(value: Vec<String>) -> Self {
294 unsafe {
295 let len = value.len();
296 let mut s = Self::with_capacity(len);
297 for (i, item) in value.into_iter().enumerate() {
298 *s.ptr.as_ptr().add(i) = GString::from(item).into_glib_ptr();
299 }
300 s.len = len;
301 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
302 s
303 }
304 }
305}
306
307impl From<Vec<&'_ str>> for StrV {
308 #[inline]
309 fn from(value: Vec<&'_ str>) -> Self {
310 value.as_slice().into()
311 }
312}
313
314impl From<Vec<GString>> for StrV {
315 #[inline]
316 fn from(value: Vec<GString>) -> Self {
317 unsafe {
318 let len = value.len();
319 let mut s = Self::with_capacity(len);
320 for (i, v) in value.into_iter().enumerate() {
321 *s.ptr.as_ptr().add(i) = v.into_glib_ptr();
322 }
323 s.len = len;
324 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
325 s
326 }
327 }
328}
329
330impl<const N: usize> From<[GString; N]> for StrV {
331 #[inline]
332 fn from(value: [GString; N]) -> Self {
333 unsafe {
334 let len = value.len();
335 let mut s = Self::with_capacity(len);
336 for (i, v) in value.into_iter().enumerate() {
337 *s.ptr.as_ptr().add(i) = v.into_glib_ptr();
338 }
339 s.len = len;
340 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
341 s
342 }
343 }
344}
345
346impl<const N: usize> From<[String; N]> for StrV {
347 #[inline]
348 fn from(value: [String; N]) -> Self {
349 unsafe {
350 let len = value.len();
351 let mut s = Self::with_capacity(len);
352 for (i, v) in value.into_iter().enumerate() {
353 *s.ptr.as_ptr().add(i) = GString::from(v).into_glib_ptr();
354 }
355 s.len = len;
356 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
357 s
358 }
359 }
360}
361
362impl<const N: usize> From<[&'_ str; N]> for StrV {
363 #[inline]
364 fn from(value: [&'_ str; N]) -> Self {
365 unsafe {
366 let mut s = Self::with_capacity(value.len());
367 for (i, item) in value.iter().enumerate() {
368 *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr();
369 }
370 s.len = value.len();
371 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
372 s
373 }
374 }
375}
376
377impl<const N: usize> From<[&'_ GStr; N]> for StrV {
378 #[inline]
379 fn from(value: [&'_ GStr; N]) -> Self {
380 unsafe {
381 let mut s = Self::with_capacity(value.len());
382 for (i, item) in value.iter().enumerate() {
383 *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr();
384 }
385 s.len = value.len();
386 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
387 s
388 }
389 }
390}
391
392impl From<&'_ [&'_ str]> for StrV {
393 #[inline]
394 fn from(value: &'_ [&'_ str]) -> Self {
395 unsafe {
396 let mut s = Self::with_capacity(value.len());
397 for (i, item) in value.iter().enumerate() {
398 *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr();
399 }
400 s.len = value.len();
401 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
402 s
403 }
404 }
405}
406
407impl From<&'_ [&'_ GStr]> for StrV {
408 #[inline]
409 fn from(value: &'_ [&'_ GStr]) -> Self {
410 unsafe {
411 let mut s = Self::with_capacity(value.len());
412 for (i, item) in value.iter().enumerate() {
413 *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr();
414 }
415 s.len = value.len();
416 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
417 s
418 }
419 }
420}
421
422impl Clone for StrV {
423 #[inline]
424 fn clone(&self) -> Self {
425 unsafe {
426 let mut s = Self::with_capacity(self.len());
427 for (i, item) in self.iter().enumerate() {
428 *s.ptr.as_ptr().add(i) = GString::from(item.as_str()).into_glib_ptr();
429 }
430 s.len = self.len();
431 *s.ptr.as_ptr().add(s.len) = ptr::null_mut();
432 s
433 }
434 }
435}
436
437impl StrV {
438 #[inline]
441 pub unsafe fn from_glib_borrow<'a>(ptr: *const *const c_char) -> &'a [GStringPtr] {
442 let mut len = 0;
443 if !ptr.is_null() {
444 while !(*ptr.add(len)).is_null() {
445 len += 1;
446 }
447 }
448 Self::from_glib_borrow_num(ptr, len)
449 }
450
451 #[inline]
454 pub unsafe fn from_glib_borrow_num<'a>(
455 ptr: *const *const c_char,
456 len: usize,
457 ) -> &'a [GStringPtr] {
458 debug_assert!(!ptr.is_null() || len == 0);
459
460 if len == 0 {
461 &[]
462 } else {
463 std::slice::from_raw_parts(ptr as *const GStringPtr, len)
464 }
465 }
466
467 #[inline]
470 pub unsafe fn from_glib_none_num(
471 ptr: *const *const c_char,
472 len: usize,
473 _null_terminated: bool,
474 ) -> Self {
475 debug_assert!(!ptr.is_null() || len == 0);
476
477 if len == 0 {
478 StrV::default()
479 } else {
480 let new_ptr =
483 ffi::g_malloc(mem::size_of::<*mut c_char>() * (len + 1)) as *mut *mut c_char;
484
485 for i in 0..len {
487 let p = ptr.add(i) as *mut *const c_char;
488 let q = new_ptr.add(i) as *mut *const c_char;
489 *q = ffi::g_strdup(*p);
490 }
491
492 *new_ptr.add(len) = ptr::null_mut();
493
494 StrV {
495 ptr: ptr::NonNull::new_unchecked(new_ptr),
496 len,
497 capacity: len + 1,
498 }
499 }
500 }
501
502 #[inline]
505 pub unsafe fn from_glib_container_num(
506 ptr: *mut *const c_char,
507 len: usize,
508 null_terminated: bool,
509 ) -> Self {
510 debug_assert!(!ptr.is_null() || len == 0);
511
512 if len == 0 {
513 ffi::g_free(ptr as ffi::gpointer);
514 StrV::default()
515 } else {
516 for i in 0..len {
518 let p = ptr.add(i);
519 *p = ffi::g_strdup(*p);
520 }
521
522 Self::from_glib_full_num(ptr as *mut *mut c_char, len, null_terminated)
524 }
525 }
526
527 #[inline]
530 pub unsafe fn from_glib_full_num(
531 ptr: *mut *mut c_char,
532 len: usize,
533 null_terminated: bool,
534 ) -> Self {
535 debug_assert!(!ptr.is_null() || len == 0);
536
537 if len == 0 {
538 ffi::g_free(ptr as ffi::gpointer);
539 StrV::default()
540 } else {
541 if null_terminated {
542 return StrV {
543 ptr: ptr::NonNull::new_unchecked(ptr),
544 len,
545 capacity: len + 1,
546 };
547 }
548
549 let capacity = len + 1;
551 assert_ne!(capacity, 0);
552 let ptr = ffi::g_realloc(
553 ptr as *mut _,
554 mem::size_of::<*mut c_char>().checked_mul(capacity).unwrap(),
555 ) as *mut *mut c_char;
556 *ptr.add(len) = ptr::null_mut();
557
558 StrV {
559 ptr: ptr::NonNull::new_unchecked(ptr),
560 len,
561 capacity,
562 }
563 }
564 }
565
566 #[inline]
569 pub unsafe fn from_glib_none(ptr: *const *const c_char) -> Self {
570 let mut len = 0;
571 if !ptr.is_null() {
572 while !(*ptr.add(len)).is_null() {
573 len += 1;
574 }
575 }
576
577 StrV::from_glib_none_num(ptr, len, true)
578 }
579
580 #[inline]
583 pub unsafe fn from_glib_container(ptr: *mut *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_container_num(ptr, len, true)
592 }
593
594 #[inline]
597 pub unsafe fn from_glib_full(ptr: *mut *mut 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_full_num(ptr, len, true)
606 }
607
608 #[inline]
611 pub fn new() -> Self {
612 StrV {
613 ptr: ptr::NonNull::dangling(),
614 len: 0,
615 capacity: 0,
616 }
617 }
618
619 #[inline]
622 pub fn with_capacity(capacity: usize) -> Self {
623 let mut s = Self::new();
624 s.reserve(capacity);
625 s
626 }
627
628 #[inline]
633 pub fn as_ptr(&self) -> *const *mut c_char {
634 if self.len == 0 {
635 static EMPTY: [usize; 1] = [0];
636
637 EMPTY.as_ptr() as *const _
638 } else {
639 self.ptr.as_ptr()
640 }
641 }
642
643 #[inline]
648 pub fn into_raw(mut self) -> *mut *mut c_char {
649 if self.len == 0 {
652 self.reserve(0);
653 unsafe {
654 *self.ptr.as_ptr().add(0) = ptr::null_mut();
655 }
656 }
657
658 self.len = 0;
659 self.capacity = 0;
660 self.ptr.as_ptr()
661 }
662
663 #[inline]
666 pub fn len(&self) -> usize {
667 self.len
668 }
669
670 #[inline]
673 pub fn is_empty(&self) -> bool {
674 self.len == 0
675 }
676
677 #[inline]
682 pub fn capacity(&self) -> usize {
683 self.capacity
684 }
685
686 pub unsafe fn set_len(&mut self, len: usize) {
693 self.len = len;
694 }
695
696 #[allow(clippy::int_plus_one)]
699 pub fn reserve(&mut self, additional: usize) {
700 if self.len + additional + 1 <= self.capacity {
702 return;
703 }
704
705 let new_capacity =
706 usize::next_power_of_two(std::cmp::max(self.len + additional, MIN_SIZE) + 1);
707 assert_ne!(new_capacity, 0);
708 assert!(new_capacity > self.capacity);
709
710 unsafe {
711 let ptr = if self.capacity == 0 {
712 ptr::null_mut()
713 } else {
714 self.ptr.as_ptr() as *mut _
715 };
716 let new_ptr = ffi::g_realloc(
717 ptr,
718 mem::size_of::<*mut c_char>()
719 .checked_mul(new_capacity)
720 .unwrap(),
721 ) as *mut *mut c_char;
722 if self.capacity == 0 {
723 *new_ptr = ptr::null_mut();
724 }
725 self.ptr = ptr::NonNull::new_unchecked(new_ptr);
726 self.capacity = new_capacity;
727 }
728 }
729
730 #[inline]
733 pub const fn as_slice(&self) -> &[GStringPtr] {
734 unsafe {
735 if self.len == 0 {
736 &[]
737 } else {
738 std::slice::from_raw_parts(self.ptr.as_ptr() as *const GStringPtr, self.len)
739 }
740 }
741 }
742
743 #[inline]
746 pub fn clear(&mut self) {
747 unsafe {
748 for i in 0..self.len {
749 ffi::g_free(*self.ptr.as_ptr().add(i) as ffi::gpointer);
750 }
751
752 self.len = 0;
753 }
754 }
755
756 #[inline]
759 pub fn extend_from_slice<S: AsRef<str>>(&mut self, other: &[S]) {
760 if self.len + other.len() + 1 > self.capacity {
762 self.reserve(other.len());
763 }
764
765 unsafe {
766 for item in other {
767 *self.ptr.as_ptr().add(self.len) = GString::from(item.as_ref()).into_glib_ptr();
768 self.len += 1;
769 }
770
771 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
772 }
773 }
774
775 #[inline]
779 pub fn insert(&mut self, index: usize, item: GString) {
780 assert!(index <= self.len);
781
782 if self.len + 1 + 1 > self.capacity {
784 self.reserve(1);
785 }
786
787 unsafe {
788 if index == self.len {
789 *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr();
790 } else {
791 let p = self.ptr.as_ptr().add(index);
792 ptr::copy(p, p.add(1), self.len - index);
793 *self.ptr.as_ptr().add(index) = item.into_glib_ptr();
794 }
795
796 self.len += 1;
797
798 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
799 }
800 }
801
802 #[inline]
805 pub fn push(&mut self, item: GString) {
806 if self.len + 1 + 1 > self.capacity {
808 self.reserve(1);
809 }
810
811 unsafe {
812 *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr();
813 self.len += 1;
814
815 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
816 }
817 }
818
819 #[inline]
823 pub fn remove(&mut self, index: usize) -> GString {
824 assert!(index < self.len);
825
826 unsafe {
827 let p = self.ptr.as_ptr().add(index);
828 let item = *p;
829 ptr::copy(p.add(1), p, self.len - index - 1);
830
831 self.len -= 1;
832
833 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
834
835 GString::from_glib_full(item)
836 }
837 }
838
839 #[inline]
842 pub fn swap(&mut self, index: usize, new_item: GString) -> GString {
843 assert!(index < self.len);
844
845 unsafe {
846 let p = self.ptr.as_ptr().add(index);
847 let item = *p;
848 *p = new_item.into_glib_ptr();
849
850 GString::from_glib_full(item)
851 }
852 }
853
854 #[inline]
857 pub fn pop(&mut self) -> Option<GString> {
858 if self.len == 0 {
859 return None;
860 }
861
862 unsafe {
863 self.len -= 1;
864 let p = self.ptr.as_ptr().add(self.len);
865 let item = *p;
866
867 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
868
869 Some(GString::from_glib_full(item))
870 }
871 }
872
873 #[inline]
878 pub fn truncate(&mut self, len: usize) {
879 if self.len <= len {
880 return;
881 }
882
883 unsafe {
884 while self.len > len {
885 self.len -= 1;
886 let p = self.ptr.as_ptr().add(self.len);
887 ffi::g_free(*p as ffi::gpointer);
888 *p = ptr::null_mut();
889 }
890 }
891 }
892
893 #[inline]
896 #[doc(alias = "g_strjoinv")]
897 pub fn join(&self, separator: Option<impl IntoGStr>) -> GString {
898 separator.run_with_gstr(|separator| unsafe {
899 from_glib_full(ffi::g_strjoinv(
900 separator.to_glib_none().0,
901 self.as_ptr() as *mut _,
902 ))
903 })
904 }
905
906 #[inline]
909 #[doc(alias = "g_strv_contains")]
910 pub fn contains(&self, s: impl IntoGStr) -> bool {
911 s.run_with_gstr(|s| unsafe {
912 from_glib(ffi::g_strv_contains(
913 self.as_ptr() as *const _,
914 s.to_glib_none().0,
915 ))
916 })
917 }
918}
919
920impl FromGlibContainer<*mut c_char, *mut *mut c_char> for StrV {
921 #[inline]
922 unsafe fn from_glib_none_num(ptr: *mut *mut c_char, num: usize) -> Self {
923 Self::from_glib_none_num(ptr as *const *const c_char, num, false)
924 }
925
926 #[inline]
927 unsafe fn from_glib_container_num(ptr: *mut *mut c_char, num: usize) -> Self {
928 Self::from_glib_container_num(ptr as *mut *const c_char, num, false)
929 }
930
931 #[inline]
932 unsafe fn from_glib_full_num(ptr: *mut *mut c_char, num: usize) -> Self {
933 Self::from_glib_full_num(ptr, num, false)
934 }
935}
936
937impl FromGlibContainer<*mut c_char, *const *mut c_char> for StrV {
938 unsafe fn from_glib_none_num(ptr: *const *mut c_char, num: usize) -> Self {
939 Self::from_glib_none_num(ptr as *const *const c_char, num, false)
940 }
941
942 unsafe fn from_glib_container_num(_ptr: *const *mut c_char, _num: usize) -> Self {
943 unimplemented!();
944 }
945
946 unsafe fn from_glib_full_num(_ptr: *const *mut c_char, _num: usize) -> Self {
947 unimplemented!();
948 }
949}
950
951impl FromGlibPtrContainer<*mut c_char, *mut *mut c_char> for StrV {
952 #[inline]
953 unsafe fn from_glib_none(ptr: *mut *mut c_char) -> Self {
954 Self::from_glib_none(ptr as *const *const c_char)
955 }
956
957 #[inline]
958 unsafe fn from_glib_container(ptr: *mut *mut c_char) -> Self {
959 Self::from_glib_container(ptr as *mut *const c_char)
960 }
961
962 #[inline]
963 unsafe fn from_glib_full(ptr: *mut *mut c_char) -> Self {
964 Self::from_glib_full(ptr)
965 }
966}
967
968impl FromGlibPtrContainer<*mut c_char, *const *mut c_char> for StrV {
969 #[inline]
970 unsafe fn from_glib_none(ptr: *const *mut c_char) -> Self {
971 Self::from_glib_none(ptr as *const *const c_char)
972 }
973
974 unsafe fn from_glib_container(_ptr: *const *mut c_char) -> Self {
975 unimplemented!();
976 }
977
978 unsafe fn from_glib_full(_ptr: *const *mut c_char) -> Self {
979 unimplemented!();
980 }
981}
982
983impl<'a> ToGlibPtr<'a, *mut *mut c_char> for StrV {
984 type Storage = PhantomData<&'a Self>;
985
986 #[inline]
987 fn to_glib_none(&'a self) -> Stash<'a, *mut *mut c_char, Self> {
988 Stash(self.as_ptr() as *mut _, PhantomData)
989 }
990
991 #[inline]
992 fn to_glib_container(&'a self) -> Stash<'a, *mut *mut c_char, Self> {
993 unsafe {
994 let ptr =
995 ffi::g_malloc(mem::size_of::<*mut c_char>() * (self.len() + 1)) as *mut *mut c_char;
996 ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1);
997 Stash(ptr, PhantomData)
998 }
999 }
1000
1001 #[inline]
1002 fn to_glib_full(&self) -> *mut *mut c_char {
1003 self.clone().into_raw()
1004 }
1005}
1006
1007impl<'a> ToGlibPtr<'a, *const *mut c_char> for StrV {
1008 type Storage = PhantomData<&'a Self>;
1009
1010 #[inline]
1011 fn to_glib_none(&'a self) -> Stash<'a, *const *mut c_char, Self> {
1012 Stash(self.as_ptr(), PhantomData)
1013 }
1014}
1015
1016impl IntoGlibPtr<*mut *mut c_char> for StrV {
1017 #[inline]
1018 unsafe fn into_glib_ptr(self) -> *mut *mut c_char {
1019 self.into_raw()
1020 }
1021}
1022
1023impl StaticType for StrV {
1024 #[inline]
1025 fn static_type() -> crate::Type {
1026 <Vec<String>>::static_type()
1027 }
1028}
1029
1030impl StaticType for &'_ [GStringPtr] {
1031 #[inline]
1032 fn static_type() -> crate::Type {
1033 <Vec<String>>::static_type()
1034 }
1035}
1036
1037impl crate::value::ValueType for StrV {
1038 type Type = Vec<String>;
1039}
1040
1041unsafe impl<'a> crate::value::FromValue<'a> for StrV {
1042 type Checker = crate::value::GenericValueTypeChecker<Self>;
1043
1044 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1045 let ptr = gobject_ffi::g_value_dup_boxed(value.to_glib_none().0) as *mut *mut c_char;
1046 FromGlibPtrContainer::from_glib_full(ptr)
1047 }
1048}
1049
1050unsafe impl<'a> crate::value::FromValue<'a> for &'a [GStringPtr] {
1051 type Checker = crate::value::GenericValueTypeChecker<Self>;
1052
1053 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1054 let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
1055 StrV::from_glib_borrow(ptr)
1056 }
1057}
1058
1059impl crate::value::ToValue for StrV {
1060 fn to_value(&self) -> crate::value::Value {
1061 unsafe {
1062 let mut value = crate::value::Value::for_value_type::<Self>();
1063 gobject_ffi::g_value_set_boxed(
1064 value.to_glib_none_mut().0,
1065 self.as_ptr() as ffi::gpointer,
1066 );
1067 value
1068 }
1069 }
1070
1071 fn value_type(&self) -> crate::Type {
1072 <StrV as StaticType>::static_type()
1073 }
1074}
1075
1076impl From<StrV> for crate::Value {
1077 #[inline]
1078 fn from(s: StrV) -> Self {
1079 unsafe {
1080 let mut value = crate::value::Value::for_value_type::<StrV>();
1081 gobject_ffi::g_value_take_boxed(
1082 value.to_glib_none_mut().0,
1083 s.into_raw() as ffi::gpointer,
1084 );
1085 value
1086 }
1087 }
1088}
1089
1090pub trait IntoStrV {
1093 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R;
1096}
1097
1098impl IntoStrV for StrV {
1099 #[inline]
1100 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1101 <&Self>::run_with_strv(&self, f)
1102 }
1103}
1104
1105impl IntoStrV for &'_ StrV {
1106 #[inline]
1107 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1108 f(unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) })
1109 }
1110}
1111
1112const MAX_STACK_ALLOCATION: usize = 16;
1117
1118impl IntoStrV for Vec<GString> {
1119 #[inline]
1120 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1121 self.as_slice().run_with_strv(f)
1122 }
1123}
1124
1125impl IntoStrV for Vec<&'_ GString> {
1126 #[inline]
1127 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1128 self.as_slice().run_with_strv(f)
1129 }
1130}
1131
1132impl IntoStrV for Vec<&'_ GStr> {
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<&'_ str> {
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<String> {
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<&'_ String> {
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 &[GString] {
1161 #[inline]
1162 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1163 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1164
1165 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1166 unsafe {
1167 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1168 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1169
1170 for (i, item) in self.iter().enumerate() {
1171 *ptrs.add(i) = item.as_ptr() as *mut _;
1172 }
1173 *ptrs.add(self.len()) = ptr::null_mut();
1174
1175 f(std::slice::from_raw_parts(ptrs, self.len()))
1176 }
1177 } else {
1178 let mut s = StrV::with_capacity(self.len());
1179 s.extend_from_slice(self);
1180 s.run_with_strv(f)
1181 }
1182 }
1183}
1184
1185impl IntoStrV for &[&GString] {
1186 #[inline]
1187 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1188 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1189
1190 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1191 unsafe {
1192 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1193 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1194
1195 for (i, item) in self.iter().enumerate() {
1196 *ptrs.add(i) = item.as_ptr() as *mut _;
1197 }
1198 *ptrs.add(self.len()) = ptr::null_mut();
1199
1200 f(std::slice::from_raw_parts(ptrs, self.len()))
1201 }
1202 } else {
1203 let mut s = StrV::with_capacity(self.len());
1204 s.extend_from_slice(self);
1205 s.run_with_strv(f)
1206 }
1207 }
1208}
1209
1210impl IntoStrV for &[&GStr] {
1211 #[inline]
1212 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1213 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1214
1215 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1216 unsafe {
1217 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1218 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1219
1220 for (i, item) in self.iter().enumerate() {
1221 *ptrs.add(i) = item.as_ptr() as *mut _;
1222 }
1223 *ptrs.add(self.len()) = ptr::null_mut();
1224
1225 f(std::slice::from_raw_parts(ptrs, self.len()))
1226 }
1227 } else {
1228 let mut s = StrV::with_capacity(self.len());
1229 s.extend_from_slice(self);
1230 s.run_with_strv(f)
1231 }
1232 }
1233}
1234
1235impl IntoStrV for &[&str] {
1236 #[inline]
1237 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1238 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1239 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1240
1241 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1242 unsafe {
1243 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1244 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1245 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1246
1247 for (i, item) in self.iter().enumerate() {
1248 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1249 *strs.add(item.len()) = 0;
1250 *ptrs.add(i) = strs;
1251 strs = strs.add(item.len() + 1);
1252 }
1253 *ptrs.add(self.len()) = ptr::null_mut();
1254
1255 f(std::slice::from_raw_parts(ptrs, self.len()))
1256 }
1257 } else {
1258 let mut s = StrV::with_capacity(self.len());
1259 s.extend_from_slice(self);
1260 s.run_with_strv(f)
1261 }
1262 }
1263}
1264
1265impl IntoStrV for &[String] {
1266 #[inline]
1267 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1268 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1269 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1270
1271 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1272 unsafe {
1273 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1274 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1275 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1276
1277 for (i, item) in self.iter().enumerate() {
1278 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1279 *strs.add(item.len()) = 0;
1280 *ptrs.add(i) = strs;
1281 strs = strs.add(item.len() + 1);
1282 }
1283 *ptrs.add(self.len()) = ptr::null_mut();
1284
1285 f(std::slice::from_raw_parts(ptrs, self.len()))
1286 }
1287 } else {
1288 let mut s = StrV::with_capacity(self.len());
1289 s.extend_from_slice(self);
1290 s.run_with_strv(f)
1291 }
1292 }
1293}
1294
1295impl IntoStrV for &[&String] {
1296 #[inline]
1297 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1298 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1299 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1300
1301 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1302 unsafe {
1303 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1304 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1305 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1306
1307 for (i, item) in self.iter().enumerate() {
1308 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1309 *strs.add(item.len()) = 0;
1310 *ptrs.add(i) = strs;
1311 strs = strs.add(item.len() + 1);
1312 }
1313 *ptrs.add(self.len()) = ptr::null_mut();
1314
1315 f(std::slice::from_raw_parts(ptrs, self.len()))
1316 }
1317 } else {
1318 let mut s = StrV::with_capacity(self.len());
1319 s.extend_from_slice(self);
1320 s.run_with_strv(f)
1321 }
1322 }
1323}
1324
1325impl<const N: usize> IntoStrV for [GString; N] {
1326 #[inline]
1327 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1328 self.as_slice().run_with_strv(f)
1329 }
1330}
1331
1332impl<const N: usize> IntoStrV for [&'_ GString; N] {
1333 #[inline]
1334 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1335 self.as_slice().run_with_strv(f)
1336 }
1337}
1338
1339impl<const N: usize> IntoStrV for [&'_ GStr; 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 [&'_ str; 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 [String; 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 [&'_ String; 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
1367#[cfg(test)]
1368mod test {
1369 use super::*;
1370
1371 #[test]
1372 fn test_from_glib_full() {
1373 let items = ["str1", "str2", "str3", "str4"];
1374
1375 let slice = unsafe {
1376 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *mut c_char;
1377 *ptr.add(0) = items[0].to_glib_full();
1378 *ptr.add(1) = items[1].to_glib_full();
1379 *ptr.add(2) = items[2].to_glib_full();
1380 *ptr.add(3) = items[3].to_glib_full();
1381
1382 StrV::from_glib_full_num(ptr, 4, false)
1383 };
1384
1385 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1386 assert_eq!(a, b);
1387 }
1388 }
1389
1390 #[test]
1391 fn test_from_glib_container() {
1392 let items = [
1393 crate::gstr!("str1"),
1394 crate::gstr!("str2"),
1395 crate::gstr!("str3"),
1396 crate::gstr!("str4"),
1397 ];
1398
1399 let slice = unsafe {
1400 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char;
1401 *ptr.add(0) = items[0].as_ptr();
1402 *ptr.add(1) = items[1].as_ptr();
1403 *ptr.add(2) = items[2].as_ptr();
1404 *ptr.add(3) = items[3].as_ptr();
1405
1406 StrV::from_glib_container_num(ptr, 4, false)
1407 };
1408
1409 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1410 assert_eq!(a, b);
1411 }
1412 }
1413
1414 #[test]
1415 fn test_from_glib_none() {
1416 let items = [
1417 crate::gstr!("str1"),
1418 crate::gstr!("str2"),
1419 crate::gstr!("str3"),
1420 crate::gstr!("str4"),
1421 ];
1422
1423 let slice = unsafe {
1424 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char;
1425 *ptr.add(0) = items[0].as_ptr();
1426 *ptr.add(1) = items[1].as_ptr();
1427 *ptr.add(2) = items[2].as_ptr();
1428 *ptr.add(3) = items[3].as_ptr();
1429
1430 let res = StrV::from_glib_none_num(ptr, 4, false);
1431 ffi::g_free(ptr as ffi::gpointer);
1432 res
1433 };
1434
1435 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1436 assert_eq!(a, b);
1437 }
1438 }
1439
1440 #[test]
1441 fn test_from_slice() {
1442 let items = [
1443 crate::gstr!("str1"),
1444 crate::gstr!("str2"),
1445 crate::gstr!("str3"),
1446 ];
1447
1448 let slice1 = StrV::from(&items[..]);
1449 let slice2 = StrV::from(items);
1450 assert_eq!(slice1.len(), 3);
1451 assert_eq!(slice1, slice2);
1452 }
1453
1454 #[test]
1455 fn test_safe_api() {
1456 let items = [
1457 crate::gstr!("str1"),
1458 crate::gstr!("str2"),
1459 crate::gstr!("str3"),
1460 ];
1461
1462 let mut slice = StrV::from(&items[..]);
1463 assert_eq!(slice.len(), 3);
1464 slice.push(GString::from("str4"));
1465 assert_eq!(slice.len(), 4);
1466
1467 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1468 assert_eq!(a, b);
1469 }
1470 assert_eq!(slice[3], "str4");
1471
1472 let vec = Vec::from(slice);
1473 assert_eq!(vec.len(), 4);
1474 for (a, b) in Iterator::zip(items.iter(), vec.iter()) {
1475 assert_eq!(a, b);
1476 }
1477 assert_eq!(vec[3], "str4");
1478
1479 let mut slice = StrV::from(vec);
1480 assert_eq!(slice.len(), 4);
1481 let e = slice.pop().unwrap();
1482 assert_eq!(e, "str4");
1483 assert_eq!(slice.len(), 3);
1484 slice.insert(2, e);
1485 assert_eq!(slice.len(), 4);
1486 assert_eq!(slice[0], "str1");
1487 assert_eq!(slice[1], "str2");
1488 assert_eq!(slice[2], "str4");
1489 assert_eq!(slice[3], "str3");
1490 let e = slice.remove(2);
1491 assert_eq!(e, "str4");
1492 assert_eq!(slice.len(), 3);
1493 slice.push(e);
1494 assert_eq!(slice.len(), 4);
1495
1496 for (a, b) in Iterator::zip(items.iter(), slice.into_iter()) {
1497 assert_eq!(*a, b);
1498 }
1499 }
1500
1501 #[test]
1502 fn test_into_strv() {
1503 let items = ["str1", "str2", "str3", "str4"];
1504
1505 items[..].run_with_strv(|s| unsafe {
1506 assert!((*s.as_ptr().add(4)).is_null());
1507 assert_eq!(s.len(), items.len());
1508 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1509 assert_eq!(s, items);
1510 });
1511
1512 Vec::from(&items[..]).run_with_strv(|s| unsafe {
1513 assert!((*s.as_ptr().add(4)).is_null());
1514 assert_eq!(s.len(), items.len());
1515 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1516 assert_eq!(s, items);
1517 });
1518
1519 StrV::from(&items[..]).run_with_strv(|s| unsafe {
1520 assert!((*s.as_ptr().add(4)).is_null());
1521 assert_eq!(s.len(), items.len());
1522 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1523 assert_eq!(s, items);
1524 });
1525
1526 let v = items.iter().copied().map(String::from).collect::<Vec<_>>();
1527 items.run_with_strv(|s| unsafe {
1528 assert!((*s.as_ptr().add(4)).is_null());
1529 assert_eq!(s.len(), v.len());
1530 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1531 assert_eq!(s, items);
1532 });
1533
1534 let v = items.iter().copied().map(GString::from).collect::<Vec<_>>();
1535 items.run_with_strv(|s| unsafe {
1536 assert!((*s.as_ptr().add(4)).is_null());
1537 assert_eq!(s.len(), v.len());
1538 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1539 assert_eq!(s, items);
1540 });
1541 }
1542
1543 #[test]
1544 fn test_join() {
1545 let items = [
1546 crate::gstr!("str1"),
1547 crate::gstr!("str2"),
1548 crate::gstr!("str3"),
1549 ];
1550
1551 let strv = StrV::from(&items[..]);
1552 assert_eq!(strv.join(None::<&str>), "str1str2str3");
1553 assert_eq!(strv.join(Some(",")), "str1,str2,str3");
1554 }
1555
1556 #[test]
1557 fn test_contains() {
1558 let items = [
1559 crate::gstr!("str1"),
1560 crate::gstr!("str2"),
1561 crate::gstr!("str3"),
1562 ];
1563
1564 let strv = StrV::from(&items[..]);
1565 assert!(strv.contains("str2"));
1566 assert!(!strv.contains("str4"));
1567 }
1568}