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 {
650 ptr::null_mut()
651 } else {
652 self.len = 0;
653 self.capacity = 0;
654 self.ptr.as_ptr()
655 }
656 }
657
658 #[inline]
661 pub fn len(&self) -> usize {
662 self.len
663 }
664
665 #[inline]
668 pub fn is_empty(&self) -> bool {
669 self.len == 0
670 }
671
672 #[inline]
677 pub fn capacity(&self) -> usize {
678 self.capacity
679 }
680
681 pub unsafe fn set_len(&mut self, len: usize) {
688 self.len = len;
689 }
690
691 #[allow(clippy::int_plus_one)]
694 pub fn reserve(&mut self, additional: usize) {
695 if self.len + additional + 1 <= self.capacity {
697 return;
698 }
699
700 let new_capacity =
701 usize::next_power_of_two(std::cmp::max(self.len + additional, MIN_SIZE) + 1);
702 assert_ne!(new_capacity, 0);
703 assert!(new_capacity > self.capacity);
704
705 unsafe {
706 let ptr = if self.capacity == 0 {
707 ptr::null_mut()
708 } else {
709 self.ptr.as_ptr() as *mut _
710 };
711 let new_ptr = ffi::g_realloc(
712 ptr,
713 mem::size_of::<*mut c_char>()
714 .checked_mul(new_capacity)
715 .unwrap(),
716 ) as *mut *mut c_char;
717 if self.capacity == 0 {
718 *new_ptr = ptr::null_mut();
719 }
720 self.ptr = ptr::NonNull::new_unchecked(new_ptr);
721 self.capacity = new_capacity;
722 }
723 }
724
725 #[inline]
728 pub const fn as_slice(&self) -> &[GStringPtr] {
729 unsafe {
730 if self.len == 0 {
731 &[]
732 } else {
733 std::slice::from_raw_parts(self.ptr.as_ptr() as *const GStringPtr, self.len)
734 }
735 }
736 }
737
738 #[inline]
741 pub fn clear(&mut self) {
742 unsafe {
743 for i in 0..self.len {
744 ffi::g_free(*self.ptr.as_ptr().add(i) as ffi::gpointer);
745 }
746
747 self.len = 0;
748 }
749 }
750
751 #[inline]
754 pub fn extend_from_slice<S: AsRef<str>>(&mut self, other: &[S]) {
755 if self.len + other.len() + 1 > self.capacity {
757 self.reserve(other.len());
758 }
759
760 unsafe {
761 for item in other {
762 *self.ptr.as_ptr().add(self.len) = GString::from(item.as_ref()).into_glib_ptr();
763 self.len += 1;
764 }
765
766 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
767 }
768 }
769
770 #[inline]
774 pub fn insert(&mut self, index: usize, item: GString) {
775 assert!(index <= self.len);
776
777 if self.len + 1 + 1 > self.capacity {
779 self.reserve(1);
780 }
781
782 unsafe {
783 if index == self.len {
784 *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr();
785 } else {
786 let p = self.ptr.as_ptr().add(index);
787 ptr::copy(p, p.add(1), self.len - index);
788 *self.ptr.as_ptr().add(index) = item.into_glib_ptr();
789 }
790
791 self.len += 1;
792
793 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
794 }
795 }
796
797 #[inline]
800 pub fn push(&mut self, item: GString) {
801 if self.len + 1 + 1 > self.capacity {
803 self.reserve(1);
804 }
805
806 unsafe {
807 *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr();
808 self.len += 1;
809
810 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
811 }
812 }
813
814 #[inline]
818 pub fn remove(&mut self, index: usize) -> GString {
819 assert!(index < self.len);
820
821 unsafe {
822 let p = self.ptr.as_ptr().add(index);
823 let item = *p;
824 ptr::copy(p.add(1), p, self.len - index - 1);
825
826 self.len -= 1;
827
828 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
829
830 GString::from_glib_full(item)
831 }
832 }
833
834 #[inline]
837 pub fn swap(&mut self, index: usize, new_item: GString) -> GString {
838 assert!(index < self.len);
839
840 unsafe {
841 let p = self.ptr.as_ptr().add(index);
842 let item = *p;
843 *p = new_item.into_glib_ptr();
844
845 GString::from_glib_full(item)
846 }
847 }
848
849 #[inline]
852 pub fn pop(&mut self) -> Option<GString> {
853 if self.len == 0 {
854 return None;
855 }
856
857 unsafe {
858 self.len -= 1;
859 let p = self.ptr.as_ptr().add(self.len);
860 let item = *p;
861
862 *self.ptr.as_ptr().add(self.len) = ptr::null_mut();
863
864 Some(GString::from_glib_full(item))
865 }
866 }
867
868 #[inline]
873 pub fn truncate(&mut self, len: usize) {
874 if self.len <= len {
875 return;
876 }
877
878 unsafe {
879 while self.len > len {
880 self.len -= 1;
881 let p = self.ptr.as_ptr().add(self.len);
882 ffi::g_free(*p as ffi::gpointer);
883 *p = ptr::null_mut();
884 }
885 }
886 }
887
888 #[inline]
891 #[doc(alias = "g_strjoinv")]
892 pub fn join(&self, separator: Option<impl IntoGStr>) -> GString {
893 separator.run_with_gstr(|separator| unsafe {
894 from_glib_full(ffi::g_strjoinv(
895 separator.to_glib_none().0,
896 self.as_ptr() as *mut _,
897 ))
898 })
899 }
900
901 #[inline]
904 #[doc(alias = "g_strv_contains")]
905 pub fn contains(&self, s: impl IntoGStr) -> bool {
906 s.run_with_gstr(|s| unsafe {
907 from_glib(ffi::g_strv_contains(
908 self.as_ptr() as *const _,
909 s.to_glib_none().0,
910 ))
911 })
912 }
913}
914
915impl FromGlibContainer<*mut c_char, *mut *mut c_char> for StrV {
916 #[inline]
917 unsafe fn from_glib_none_num(ptr: *mut *mut c_char, num: usize) -> Self {
918 Self::from_glib_none_num(ptr as *const *const c_char, num, false)
919 }
920
921 #[inline]
922 unsafe fn from_glib_container_num(ptr: *mut *mut c_char, num: usize) -> Self {
923 Self::from_glib_container_num(ptr as *mut *const c_char, num, false)
924 }
925
926 #[inline]
927 unsafe fn from_glib_full_num(ptr: *mut *mut c_char, num: usize) -> Self {
928 Self::from_glib_full_num(ptr, num, false)
929 }
930}
931
932impl FromGlibContainer<*mut c_char, *const *mut c_char> for StrV {
933 unsafe fn from_glib_none_num(ptr: *const *mut c_char, num: usize) -> Self {
934 Self::from_glib_none_num(ptr as *const *const c_char, num, false)
935 }
936
937 unsafe fn from_glib_container_num(_ptr: *const *mut c_char, _num: usize) -> Self {
938 unimplemented!();
939 }
940
941 unsafe fn from_glib_full_num(_ptr: *const *mut c_char, _num: usize) -> Self {
942 unimplemented!();
943 }
944}
945
946impl FromGlibPtrContainer<*mut c_char, *mut *mut c_char> for StrV {
947 #[inline]
948 unsafe fn from_glib_none(ptr: *mut *mut c_char) -> Self {
949 Self::from_glib_none(ptr as *const *const c_char)
950 }
951
952 #[inline]
953 unsafe fn from_glib_container(ptr: *mut *mut c_char) -> Self {
954 Self::from_glib_container(ptr as *mut *const c_char)
955 }
956
957 #[inline]
958 unsafe fn from_glib_full(ptr: *mut *mut c_char) -> Self {
959 Self::from_glib_full(ptr)
960 }
961}
962
963impl FromGlibPtrContainer<*mut c_char, *const *mut c_char> for StrV {
964 #[inline]
965 unsafe fn from_glib_none(ptr: *const *mut c_char) -> Self {
966 Self::from_glib_none(ptr as *const *const c_char)
967 }
968
969 unsafe fn from_glib_container(_ptr: *const *mut c_char) -> Self {
970 unimplemented!();
971 }
972
973 unsafe fn from_glib_full(_ptr: *const *mut c_char) -> Self {
974 unimplemented!();
975 }
976}
977
978impl<'a> ToGlibPtr<'a, *mut *mut c_char> for StrV {
979 type Storage = PhantomData<&'a Self>;
980
981 #[inline]
982 fn to_glib_none(&'a self) -> Stash<'a, *mut *mut c_char, Self> {
983 Stash(self.as_ptr() as *mut _, PhantomData)
984 }
985
986 #[inline]
987 fn to_glib_container(&'a self) -> Stash<'a, *mut *mut c_char, Self> {
988 unsafe {
989 let ptr =
990 ffi::g_malloc(mem::size_of::<*mut c_char>() * (self.len() + 1)) as *mut *mut c_char;
991 ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1);
992 Stash(ptr, PhantomData)
993 }
994 }
995
996 #[inline]
997 fn to_glib_full(&self) -> *mut *mut c_char {
998 self.clone().into_raw()
999 }
1000}
1001
1002impl<'a> ToGlibPtr<'a, *const *mut c_char> for StrV {
1003 type Storage = PhantomData<&'a Self>;
1004
1005 #[inline]
1006 fn to_glib_none(&'a self) -> Stash<'a, *const *mut c_char, Self> {
1007 Stash(self.as_ptr(), PhantomData)
1008 }
1009}
1010
1011impl IntoGlibPtr<*mut *mut c_char> for StrV {
1012 #[inline]
1013 unsafe fn into_glib_ptr(self) -> *mut *mut c_char {
1014 self.into_raw()
1015 }
1016}
1017
1018impl StaticType for StrV {
1019 #[inline]
1020 fn static_type() -> crate::Type {
1021 <Vec<String>>::static_type()
1022 }
1023}
1024
1025impl StaticType for &'_ [GStringPtr] {
1026 #[inline]
1027 fn static_type() -> crate::Type {
1028 <Vec<String>>::static_type()
1029 }
1030}
1031
1032impl crate::value::ValueType for StrV {
1033 type Type = Vec<String>;
1034}
1035
1036unsafe impl<'a> crate::value::FromValue<'a> for StrV {
1037 type Checker = crate::value::GenericValueTypeChecker<Self>;
1038
1039 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1040 let ptr = gobject_ffi::g_value_dup_boxed(value.to_glib_none().0) as *mut *mut c_char;
1041 FromGlibPtrContainer::from_glib_full(ptr)
1042 }
1043}
1044
1045unsafe impl<'a> crate::value::FromValue<'a> for &'a [GStringPtr] {
1046 type Checker = crate::value::GenericValueTypeChecker<Self>;
1047
1048 unsafe fn from_value(value: &'a crate::value::Value) -> Self {
1049 let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char;
1050 StrV::from_glib_borrow(ptr)
1051 }
1052}
1053
1054impl crate::value::ToValue for StrV {
1055 fn to_value(&self) -> crate::value::Value {
1056 unsafe {
1057 let mut value = crate::value::Value::for_value_type::<Self>();
1058 gobject_ffi::g_value_set_boxed(
1059 value.to_glib_none_mut().0,
1060 self.as_ptr() as ffi::gpointer,
1061 );
1062 value
1063 }
1064 }
1065
1066 fn value_type(&self) -> crate::Type {
1067 <StrV as StaticType>::static_type()
1068 }
1069}
1070
1071impl From<StrV> for crate::Value {
1072 #[inline]
1073 fn from(s: StrV) -> Self {
1074 unsafe {
1075 let mut value = crate::value::Value::for_value_type::<StrV>();
1076 gobject_ffi::g_value_take_boxed(
1077 value.to_glib_none_mut().0,
1078 s.into_raw() as ffi::gpointer,
1079 );
1080 value
1081 }
1082 }
1083}
1084
1085pub trait IntoStrV {
1088 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R;
1091}
1092
1093impl IntoStrV for StrV {
1094 #[inline]
1095 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1096 <&Self>::run_with_strv(&self, f)
1097 }
1098}
1099
1100impl IntoStrV for &'_ StrV {
1101 #[inline]
1102 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1103 f(unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) })
1104 }
1105}
1106
1107const MAX_STACK_ALLOCATION: usize = 16;
1112
1113impl IntoStrV for Vec<GString> {
1114 #[inline]
1115 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1116 self.as_slice().run_with_strv(f)
1117 }
1118}
1119
1120impl IntoStrV for Vec<&'_ GString> {
1121 #[inline]
1122 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1123 self.as_slice().run_with_strv(f)
1124 }
1125}
1126
1127impl IntoStrV for Vec<&'_ GStr> {
1128 #[inline]
1129 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1130 self.as_slice().run_with_strv(f)
1131 }
1132}
1133
1134impl IntoStrV for Vec<&'_ str> {
1135 #[inline]
1136 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1137 self.as_slice().run_with_strv(f)
1138 }
1139}
1140
1141impl IntoStrV for Vec<String> {
1142 #[inline]
1143 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1144 self.as_slice().run_with_strv(f)
1145 }
1146}
1147
1148impl IntoStrV for Vec<&'_ String> {
1149 #[inline]
1150 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1151 self.as_slice().run_with_strv(f)
1152 }
1153}
1154
1155impl IntoStrV for &[GString] {
1156 #[inline]
1157 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1158 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>();
1159
1160 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1161 unsafe {
1162 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1163 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1164
1165 for (i, item) in self.iter().enumerate() {
1166 *ptrs.add(i) = item.as_ptr() as *mut _;
1167 }
1168 *ptrs.add(self.len()) = ptr::null_mut();
1169
1170 f(std::slice::from_raw_parts(ptrs, self.len()))
1171 }
1172 } else {
1173 let mut s = StrV::with_capacity(self.len());
1174 s.extend_from_slice(self);
1175 s.run_with_strv(f)
1176 }
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 &[&GStr] {
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 &[&str] {
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 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1235
1236 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1237 unsafe {
1238 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1239 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1240 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1241
1242 for (i, item) in self.iter().enumerate() {
1243 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1244 *strs.add(item.len()) = 0;
1245 *ptrs.add(i) = strs;
1246 strs = strs.add(item.len() + 1);
1247 }
1248 *ptrs.add(self.len()) = ptr::null_mut();
1249
1250 f(std::slice::from_raw_parts(ptrs, self.len()))
1251 }
1252 } else {
1253 let mut s = StrV::with_capacity(self.len());
1254 s.extend_from_slice(self);
1255 s.run_with_strv(f)
1256 }
1257 }
1258}
1259
1260impl IntoStrV for &[String] {
1261 #[inline]
1262 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1263 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1264 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1265
1266 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1267 unsafe {
1268 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1269 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1270 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1271
1272 for (i, item) in self.iter().enumerate() {
1273 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1274 *strs.add(item.len()) = 0;
1275 *ptrs.add(i) = strs;
1276 strs = strs.add(item.len() + 1);
1277 }
1278 *ptrs.add(self.len()) = ptr::null_mut();
1279
1280 f(std::slice::from_raw_parts(ptrs, self.len()))
1281 }
1282 } else {
1283 let mut s = StrV::with_capacity(self.len());
1284 s.extend_from_slice(self);
1285 s.run_with_strv(f)
1286 }
1287 }
1288}
1289
1290impl IntoStrV for &[&String] {
1291 #[inline]
1292 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1293 let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>()
1294 + self.iter().map(|s| s.len() + 1).sum::<usize>();
1295
1296 if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() {
1297 unsafe {
1298 let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit();
1299 let ptrs = s.as_mut_ptr() as *mut *mut c_char;
1300 let mut strs = ptrs.add(self.len() + 1) as *mut c_char;
1301
1302 for (i, item) in self.iter().enumerate() {
1303 ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len());
1304 *strs.add(item.len()) = 0;
1305 *ptrs.add(i) = strs;
1306 strs = strs.add(item.len() + 1);
1307 }
1308 *ptrs.add(self.len()) = ptr::null_mut();
1309
1310 f(std::slice::from_raw_parts(ptrs, self.len()))
1311 }
1312 } else {
1313 let mut s = StrV::with_capacity(self.len());
1314 s.extend_from_slice(self);
1315 s.run_with_strv(f)
1316 }
1317 }
1318}
1319
1320impl<const N: usize> IntoStrV for [GString; N] {
1321 #[inline]
1322 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1323 self.as_slice().run_with_strv(f)
1324 }
1325}
1326
1327impl<const N: usize> IntoStrV for [&'_ GString; N] {
1328 #[inline]
1329 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1330 self.as_slice().run_with_strv(f)
1331 }
1332}
1333
1334impl<const N: usize> IntoStrV for [&'_ GStr; N] {
1335 #[inline]
1336 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1337 self.as_slice().run_with_strv(f)
1338 }
1339}
1340
1341impl<const N: usize> IntoStrV for [&'_ str; N] {
1342 #[inline]
1343 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1344 self.as_slice().run_with_strv(f)
1345 }
1346}
1347
1348impl<const N: usize> IntoStrV for [String; N] {
1349 #[inline]
1350 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1351 self.as_slice().run_with_strv(f)
1352 }
1353}
1354
1355impl<const N: usize> IntoStrV for [&'_ String; N] {
1356 #[inline]
1357 fn run_with_strv<R, F: FnOnce(&[*mut c_char]) -> R>(self, f: F) -> R {
1358 self.as_slice().run_with_strv(f)
1359 }
1360}
1361
1362#[cfg(test)]
1363mod test {
1364 use super::*;
1365
1366 #[test]
1367 fn test_from_glib_full() {
1368 let items = ["str1", "str2", "str3", "str4"];
1369
1370 let slice = unsafe {
1371 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *mut c_char;
1372 *ptr.add(0) = items[0].to_glib_full();
1373 *ptr.add(1) = items[1].to_glib_full();
1374 *ptr.add(2) = items[2].to_glib_full();
1375 *ptr.add(3) = items[3].to_glib_full();
1376
1377 StrV::from_glib_full_num(ptr, 4, false)
1378 };
1379
1380 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1381 assert_eq!(a, b);
1382 }
1383 }
1384
1385 #[test]
1386 fn test_from_glib_container() {
1387 let items = [
1388 crate::gstr!("str1"),
1389 crate::gstr!("str2"),
1390 crate::gstr!("str3"),
1391 crate::gstr!("str4"),
1392 ];
1393
1394 let slice = unsafe {
1395 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char;
1396 *ptr.add(0) = items[0].as_ptr();
1397 *ptr.add(1) = items[1].as_ptr();
1398 *ptr.add(2) = items[2].as_ptr();
1399 *ptr.add(3) = items[3].as_ptr();
1400
1401 StrV::from_glib_container_num(ptr, 4, false)
1402 };
1403
1404 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1405 assert_eq!(a, b);
1406 }
1407 }
1408
1409 #[test]
1410 fn test_from_glib_none() {
1411 let items = [
1412 crate::gstr!("str1"),
1413 crate::gstr!("str2"),
1414 crate::gstr!("str3"),
1415 crate::gstr!("str4"),
1416 ];
1417
1418 let slice = unsafe {
1419 let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char;
1420 *ptr.add(0) = items[0].as_ptr();
1421 *ptr.add(1) = items[1].as_ptr();
1422 *ptr.add(2) = items[2].as_ptr();
1423 *ptr.add(3) = items[3].as_ptr();
1424
1425 let res = StrV::from_glib_none_num(ptr, 4, false);
1426 ffi::g_free(ptr as ffi::gpointer);
1427 res
1428 };
1429
1430 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1431 assert_eq!(a, b);
1432 }
1433 }
1434
1435 #[test]
1436 fn test_from_slice() {
1437 let items = [
1438 crate::gstr!("str1"),
1439 crate::gstr!("str2"),
1440 crate::gstr!("str3"),
1441 ];
1442
1443 let slice1 = StrV::from(&items[..]);
1444 let slice2 = StrV::from(items);
1445 assert_eq!(slice1.len(), 3);
1446 assert_eq!(slice1, slice2);
1447 }
1448
1449 #[test]
1450 fn test_safe_api() {
1451 let items = [
1452 crate::gstr!("str1"),
1453 crate::gstr!("str2"),
1454 crate::gstr!("str3"),
1455 ];
1456
1457 let mut slice = StrV::from(&items[..]);
1458 assert_eq!(slice.len(), 3);
1459 slice.push(GString::from("str4"));
1460 assert_eq!(slice.len(), 4);
1461
1462 for (a, b) in Iterator::zip(items.iter(), slice.iter()) {
1463 assert_eq!(a, b);
1464 }
1465 assert_eq!(slice[3], "str4");
1466
1467 let vec = Vec::from(slice);
1468 assert_eq!(vec.len(), 4);
1469 for (a, b) in Iterator::zip(items.iter(), vec.iter()) {
1470 assert_eq!(a, b);
1471 }
1472 assert_eq!(vec[3], "str4");
1473
1474 let mut slice = StrV::from(vec);
1475 assert_eq!(slice.len(), 4);
1476 let e = slice.pop().unwrap();
1477 assert_eq!(e, "str4");
1478 assert_eq!(slice.len(), 3);
1479 slice.insert(2, e);
1480 assert_eq!(slice.len(), 4);
1481 assert_eq!(slice[0], "str1");
1482 assert_eq!(slice[1], "str2");
1483 assert_eq!(slice[2], "str4");
1484 assert_eq!(slice[3], "str3");
1485 let e = slice.remove(2);
1486 assert_eq!(e, "str4");
1487 assert_eq!(slice.len(), 3);
1488 slice.push(e);
1489 assert_eq!(slice.len(), 4);
1490
1491 for (a, b) in Iterator::zip(items.iter(), slice.into_iter()) {
1492 assert_eq!(*a, b);
1493 }
1494 }
1495
1496 #[test]
1497 fn test_into_strv() {
1498 let items = ["str1", "str2", "str3", "str4"];
1499
1500 items[..].run_with_strv(|s| unsafe {
1501 assert!((*s.as_ptr().add(4)).is_null());
1502 assert_eq!(s.len(), items.len());
1503 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1504 assert_eq!(s, items);
1505 });
1506
1507 Vec::from(&items[..]).run_with_strv(|s| unsafe {
1508 assert!((*s.as_ptr().add(4)).is_null());
1509 assert_eq!(s.len(), items.len());
1510 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1511 assert_eq!(s, items);
1512 });
1513
1514 StrV::from(&items[..]).run_with_strv(|s| unsafe {
1515 assert!((*s.as_ptr().add(4)).is_null());
1516 assert_eq!(s.len(), items.len());
1517 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1518 assert_eq!(s, items);
1519 });
1520
1521 let v = items.iter().copied().map(String::from).collect::<Vec<_>>();
1522 items.run_with_strv(|s| unsafe {
1523 assert!((*s.as_ptr().add(4)).is_null());
1524 assert_eq!(s.len(), v.len());
1525 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1526 assert_eq!(s, items);
1527 });
1528
1529 let v = items.iter().copied().map(GString::from).collect::<Vec<_>>();
1530 items.run_with_strv(|s| unsafe {
1531 assert!((*s.as_ptr().add(4)).is_null());
1532 assert_eq!(s.len(), v.len());
1533 let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char);
1534 assert_eq!(s, items);
1535 });
1536 }
1537
1538 #[test]
1539 fn test_join() {
1540 let items = [
1541 crate::gstr!("str1"),
1542 crate::gstr!("str2"),
1543 crate::gstr!("str3"),
1544 ];
1545
1546 let strv = StrV::from(&items[..]);
1547 assert_eq!(strv.join(None::<&str>), "str1str2str3");
1548 assert_eq!(strv.join(Some(",")), "str1,str2,str3");
1549 }
1550
1551 #[test]
1552 fn test_contains() {
1553 let items = [
1554 crate::gstr!("str1"),
1555 crate::gstr!("str2"),
1556 crate::gstr!("str3"),
1557 ];
1558
1559 let strv = StrV::from(&items[..]);
1560 assert!(strv.contains("str2"));
1561 assert!(!strv.contains("str4"));
1562 }
1563}