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