glib/
variant_type.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4    borrow::{Borrow, Cow},
5    fmt,
6    hash::{Hash, Hasher},
7    iter,
8    marker::PhantomData,
9    ops::Deref,
10    ptr, slice,
11    str::FromStr,
12};
13
14use crate::{BoolError, Type, ffi, gobject_ffi, prelude::*, translate::*};
15
16// rustdoc-stripper-ignore-next
17/// Describes `Variant` types.
18///
19/// The `Variant` type system (based on the D-Bus one) describes types with
20/// "type strings". `VariantType` is an owned immutable type string (you can
21/// think of it as a `Box<str>` statically guaranteed to be a valid type
22/// string), `&VariantTy` is a borrowed one (like `&str`).
23#[doc(alias = "GVariantType")]
24pub struct VariantType {
25    // GVariantType* essentially is a char*, that always is valid UTF-8 but
26    // isn't NUL-terminated.
27    ptr: ptr::NonNull<ffi::GVariantType>,
28    // We query the length on creation assuming it's cheap (because type strings
29    // are short) and likely to happen anyway.
30    len: usize,
31}
32
33impl VariantType {
34    // rustdoc-stripper-ignore-next
35    /// Tries to create a `VariantType` from a string slice.
36    ///
37    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
38    pub fn new(type_string: &str) -> Result<VariantType, BoolError> {
39        VariantTy::new(type_string).map(ToOwned::to_owned)
40    }
41
42    // rustdoc-stripper-ignore-next
43    /// Creates a `VariantType` from a key and value type.
44    #[doc(alias = "g_variant_type_new_dict_entry")]
45    pub fn new_dict_entry(key_type: &VariantTy, value_type: &VariantTy) -> VariantType {
46        unsafe {
47            from_glib_full(ffi::g_variant_type_new_dict_entry(
48                key_type.to_glib_none().0,
49                value_type.to_glib_none().0,
50            ))
51        }
52    }
53
54    // rustdoc-stripper-ignore-next
55    /// Creates a `VariantType` from an array element type.
56    #[doc(alias = "g_variant_type_new_array")]
57    pub fn new_array(elem_type: &VariantTy) -> VariantType {
58        unsafe { from_glib_full(ffi::g_variant_type_new_array(elem_type.to_glib_none().0)) }
59    }
60
61    // rustdoc-stripper-ignore-next
62    /// Creates a `VariantType` from a maybe element type.
63    #[doc(alias = "g_variant_type_new_maybe")]
64    pub fn new_maybe(child_type: &VariantTy) -> VariantType {
65        unsafe { from_glib_full(ffi::g_variant_type_new_maybe(child_type.to_glib_none().0)) }
66    }
67
68    // rustdoc-stripper-ignore-next
69    /// Creates a `VariantType` from a maybe element type.
70    #[doc(alias = "g_variant_type_new_tuple")]
71    pub fn new_tuple(items: impl IntoIterator<Item = impl AsRef<VariantTy>>) -> VariantType {
72        let mut builder = crate::GStringBuilder::new("(");
73
74        for ty in items {
75            builder.append(ty.as_ref().as_str());
76        }
77
78        builder.append_c(')');
79
80        VariantType::from_string(builder.into_string()).unwrap()
81    }
82
83    // rustdoc-stripper-ignore-next
84    /// Tries to create a `VariantType` from an owned string.
85    ///
86    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
87    pub fn from_string(type_string: impl Into<crate::GString>) -> Result<VariantType, BoolError> {
88        let type_string = type_string.into();
89        VariantTy::new(&type_string)?;
90
91        let len = type_string.len();
92        unsafe {
93            let ptr = type_string.into_glib_ptr();
94
95            Ok(VariantType {
96                ptr: ptr::NonNull::new_unchecked(ptr as *mut ffi::GVariantType),
97                len,
98            })
99        }
100    }
101}
102
103unsafe impl Send for VariantType {}
104unsafe impl Sync for VariantType {}
105
106impl Drop for VariantType {
107    #[inline]
108    fn drop(&mut self) {
109        unsafe { ffi::g_variant_type_free(self.ptr.as_ptr()) }
110    }
111}
112
113impl AsRef<VariantTy> for VariantType {
114    #[inline]
115    fn as_ref(&self) -> &VariantTy {
116        self
117    }
118}
119
120impl Borrow<VariantTy> for VariantType {
121    #[inline]
122    fn borrow(&self) -> &VariantTy {
123        self
124    }
125}
126
127impl Clone for VariantType {
128    #[inline]
129    fn clone(&self) -> VariantType {
130        unsafe {
131            VariantType {
132                ptr: ptr::NonNull::new_unchecked(ffi::g_variant_type_copy(self.ptr.as_ptr())),
133                len: self.len,
134            }
135        }
136    }
137}
138
139impl Deref for VariantType {
140    type Target = VariantTy;
141
142    #[allow(clippy::cast_slice_from_raw_parts)]
143    #[inline]
144    fn deref(&self) -> &VariantTy {
145        unsafe {
146            &*(slice::from_raw_parts(self.ptr.as_ptr() as *const u8, self.len) as *const [u8]
147                as *const VariantTy)
148        }
149    }
150}
151
152impl fmt::Debug for VariantType {
153    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154        <VariantTy as fmt::Debug>::fmt(self, f)
155    }
156}
157
158impl fmt::Display for VariantType {
159    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160        f.write_str(self.as_str())
161    }
162}
163
164impl FromStr for VariantType {
165    type Err = BoolError;
166
167    fn from_str(s: &str) -> Result<Self, Self::Err> {
168        Self::new(s)
169    }
170}
171
172impl Hash for VariantType {
173    #[inline]
174    fn hash<H: Hasher>(&self, state: &mut H) {
175        <VariantTy as Hash>::hash(self, state)
176    }
177}
178
179impl<'a> From<VariantType> for Cow<'a, VariantTy> {
180    #[inline]
181    fn from(ty: VariantType) -> Cow<'a, VariantTy> {
182        Cow::Owned(ty)
183    }
184}
185
186#[doc(hidden)]
187impl IntoGlibPtr<*mut ffi::GVariantType> for VariantType {
188    #[inline]
189    fn into_glib_ptr(self) -> *mut ffi::GVariantType {
190        std::mem::ManuallyDrop::new(self).to_glib_none().0
191    }
192}
193
194#[doc(hidden)]
195impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantType {
196    type Storage = PhantomData<&'a Self>;
197
198    #[inline]
199    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> {
200        Stash(self.ptr.as_ptr(), PhantomData)
201    }
202
203    #[inline]
204    fn to_glib_full(&self) -> *const ffi::GVariantType {
205        unsafe { ffi::g_variant_type_copy(self.ptr.as_ptr()) }
206    }
207}
208
209#[doc(hidden)]
210impl<'a> ToGlibPtr<'a, *mut ffi::GVariantType> for VariantType {
211    type Storage = PhantomData<&'a Self>;
212
213    #[inline]
214    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GVariantType, Self> {
215        Stash(self.ptr.as_ptr(), PhantomData)
216    }
217
218    #[inline]
219    fn to_glib_full(&self) -> *mut ffi::GVariantType {
220        unsafe { ffi::g_variant_type_copy(self.ptr.as_ptr()) }
221    }
222}
223
224#[doc(hidden)]
225impl<'a> ToGlibPtrMut<'a, *mut ffi::GVariantType> for VariantType {
226    type Storage = PhantomData<&'a mut Self>;
227
228    #[inline]
229    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GVariantType, Self> {
230        StashMut(self.ptr.as_ptr(), PhantomData)
231    }
232}
233
234#[doc(hidden)]
235impl FromGlibPtrNone<*const ffi::GVariantType> for VariantType {
236    #[inline]
237    unsafe fn from_glib_none(ptr: *const ffi::GVariantType) -> VariantType {
238        unsafe { VariantTy::from_ptr(ptr).to_owned() }
239    }
240}
241
242#[doc(hidden)]
243impl FromGlibPtrFull<*const ffi::GVariantType> for VariantType {
244    #[inline]
245    unsafe fn from_glib_full(ptr: *const ffi::GVariantType) -> VariantType {
246        unsafe {
247            // Don't assume ownership of a const pointer.
248            // A transfer: full annotation on a `const GVariantType*` is likely a bug.
249            VariantTy::from_ptr(ptr).to_owned()
250        }
251    }
252}
253
254#[doc(hidden)]
255impl FromGlibPtrFull<*mut ffi::GVariantType> for VariantType {
256    #[inline]
257    unsafe fn from_glib_full(ptr: *mut ffi::GVariantType) -> VariantType {
258        unsafe {
259            debug_assert!(!ptr.is_null());
260            let len: usize = ffi::g_variant_type_get_string_length(ptr) as _;
261            VariantType {
262                ptr: ptr::NonNull::new_unchecked(ptr),
263                len,
264            }
265        }
266    }
267}
268
269// rustdoc-stripper-ignore-next
270/// Describes `Variant` types.
271///
272/// This is a borrowed counterpart of [`VariantType`](struct.VariantType.html).
273/// Essentially it's a `str` statically guaranteed to be a valid type string.
274#[repr(transparent)]
275#[derive(Debug, PartialEq, Eq, Hash)]
276pub struct VariantTy {
277    inner: str,
278}
279
280impl VariantTy {
281    // rustdoc-stripper-ignore-next
282    /// `bool`.
283    #[doc(alias = "G_VARIANT_TYPE_BOOLEAN")]
284    pub const BOOLEAN: &'static VariantTy =
285        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BOOLEAN) };
286
287    // rustdoc-stripper-ignore-next
288    /// `u8`.
289    #[doc(alias = "G_VARIANT_TYPE_BYTE")]
290    pub const BYTE: &'static VariantTy =
291        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE) };
292
293    // rustdoc-stripper-ignore-next
294    /// `i16`.
295    #[doc(alias = "G_VARIANT_TYPE_INT16")]
296    pub const INT16: &'static VariantTy =
297        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT16) };
298
299    // rustdoc-stripper-ignore-next
300    /// `u16`.
301    #[doc(alias = "G_VARIANT_TYPE_UINT16")]
302    pub const UINT16: &'static VariantTy =
303        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT16) };
304
305    // rustdoc-stripper-ignore-next
306    /// `i32`.
307    #[doc(alias = "G_VARIANT_TYPE_INT32")]
308    pub const INT32: &'static VariantTy =
309        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT32) };
310
311    // rustdoc-stripper-ignore-next
312    /// `u32`.
313    #[doc(alias = "G_VARIANT_TYPE_UINT32")]
314    pub const UINT32: &'static VariantTy =
315        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT32) };
316
317    // rustdoc-stripper-ignore-next
318    /// `i64`.
319    #[doc(alias = "G_VARIANT_TYPE_INT64")]
320    pub const INT64: &'static VariantTy =
321        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT64) };
322
323    // rustdoc-stripper-ignore-next
324    /// `u64`.
325    #[doc(alias = "G_VARIANT_TYPE_UINT64")]
326    pub const UINT64: &'static VariantTy =
327        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT64) };
328
329    // rustdoc-stripper-ignore-next
330    /// `f64`.
331    #[doc(alias = "G_VARIANT_TYPE_DOUBLE")]
332    pub const DOUBLE: &'static VariantTy =
333        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DOUBLE) };
334
335    // rustdoc-stripper-ignore-next
336    /// `&str`.
337    #[doc(alias = "G_VARIANT_TYPE_STRING")]
338    pub const STRING: &'static VariantTy =
339        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING) };
340
341    // rustdoc-stripper-ignore-next
342    /// DBus object path.
343    #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH")]
344    pub const OBJECT_PATH: &'static VariantTy =
345        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH) };
346
347    // rustdoc-stripper-ignore-next
348    /// Type signature.
349    #[doc(alias = "G_VARIANT_TYPE_SIGNATURE")]
350    pub const SIGNATURE: &'static VariantTy =
351        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_SIGNATURE) };
352
353    // rustdoc-stripper-ignore-next
354    /// Variant.
355    #[doc(alias = "G_VARIANT_TYPE_VARIANT")]
356    pub const VARIANT: &'static VariantTy =
357        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARIANT) };
358
359    // rustdoc-stripper-ignore-next
360    /// Handle.
361    #[doc(alias = "G_VARIANT_TYPE_HANDLE")]
362    pub const HANDLE: &'static VariantTy =
363        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_HANDLE) };
364
365    // rustdoc-stripper-ignore-next
366    /// Unit, i.e. `()`.
367    #[doc(alias = "G_VARIANT_TYPE_UNIT")]
368    pub const UNIT: &'static VariantTy =
369        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UNIT) };
370
371    // rustdoc-stripper-ignore-next
372    /// An indefinite type that is a supertype of every type (including itself).
373    #[doc(alias = "G_VARIANT_TYPE_ANY")]
374    pub const ANY: &'static VariantTy =
375        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ANY) };
376
377    // rustdoc-stripper-ignore-next
378    /// Any basic type.
379    #[doc(alias = "G_VARIANT_TYPE_BASIC")]
380    pub const BASIC: &'static VariantTy =
381        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BASIC) };
382
383    // rustdoc-stripper-ignore-next
384    /// Any maybe type, i.e. `Option<T>`.
385    #[doc(alias = "G_VARIANT_TYPE_MAYBE")]
386    pub const MAYBE: &'static VariantTy =
387        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_MAYBE) };
388
389    // rustdoc-stripper-ignore-next
390    /// Any array type, i.e. `[T]`.
391    #[doc(alias = "G_VARIANT_TYPE_ARRAY")]
392    pub const ARRAY: &'static VariantTy =
393        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ARRAY) };
394
395    // rustdoc-stripper-ignore-next
396    /// Any tuple type, i.e. `(T)`, `(T, T)`, etc.
397    #[doc(alias = "G_VARIANT_TYPE_TUPLE")]
398    pub const TUPLE: &'static VariantTy =
399        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_TUPLE) };
400
401    // rustdoc-stripper-ignore-next
402    /// Any dict entry type, i.e. `DictEntry<K, V>`.
403    #[doc(alias = "G_VARIANT_TYPE_DICT_ENTRY")]
404    pub const DICT_ENTRY: &'static VariantTy =
405        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICT_ENTRY) };
406
407    // rustdoc-stripper-ignore-next
408    /// Any dictionary type, i.e. `HashMap<K, V>`, `BTreeMap<K, V>`.
409    #[doc(alias = "G_VARIANT_TYPE_DICTIONARY")]
410    pub const DICTIONARY: &'static VariantTy =
411        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICTIONARY) };
412
413    // rustdoc-stripper-ignore-next
414    /// String array, i.e. `[&str]`.
415    #[doc(alias = "G_VARIANT_TYPE_STRING_ARRAY")]
416    pub const STRING_ARRAY: &'static VariantTy =
417        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING_ARRAY) };
418
419    // rustdoc-stripper-ignore-next
420    /// Object path array, i.e. `[&str]`.
421    #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH_ARRAY")]
422    pub const OBJECT_PATH_ARRAY: &'static VariantTy =
423        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH_ARRAY) };
424
425    // rustdoc-stripper-ignore-next
426    /// Byte string, i.e. `[u8]`.
427    #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING")]
428    pub const BYTE_STRING: &'static VariantTy =
429        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING) };
430
431    // rustdoc-stripper-ignore-next
432    /// Byte string array, i.e. `[[u8]]`.
433    #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING_ARRAY")]
434    pub const BYTE_STRING_ARRAY: &'static VariantTy =
435        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING_ARRAY) };
436
437    // rustdoc-stripper-ignore-next
438    /// Variant dictionary, i.e. `HashMap<String, Variant>`, `BTreeMap<String, Variant>`, etc.
439    #[doc(alias = "G_VARIANT_TYPE_VARDICT")]
440    pub const VARDICT: &'static VariantTy =
441        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARDICT) };
442
443    // rustdoc-stripper-ignore-next
444    /// Tries to create a `&VariantTy` from a string slice.
445    ///
446    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
447    pub fn new(type_string: &str) -> Result<&VariantTy, BoolError> {
448        unsafe {
449            let ptr = type_string.as_ptr();
450            let limit = ptr.add(type_string.len());
451            let mut end = ptr::null();
452
453            let ok = from_glib(ffi::g_variant_type_string_scan(
454                ptr as *const _,
455                limit as *const _,
456                &mut end,
457            ));
458            if ok && end as *const _ == limit {
459                Ok(&*(type_string.as_bytes() as *const [u8] as *const VariantTy))
460            } else {
461                Err(bool_error!("Invalid type string: '{}'", type_string))
462            }
463        }
464    }
465
466    // rustdoc-stripper-ignore-next
467    /// Converts a type string into `&VariantTy` without any checks.
468    ///
469    /// # Safety
470    ///
471    /// The caller is responsible for passing in only a valid variant type string.
472    #[inline]
473    pub const unsafe fn from_str_unchecked(type_string: &str) -> &VariantTy {
474        unsafe { std::mem::transmute::<&str, &VariantTy>(type_string) }
475    }
476
477    // rustdoc-stripper-ignore-next
478    /// Creates `&VariantTy` with a wildcard lifetime from a `GVariantType`
479    /// pointer.
480    #[doc(hidden)]
481    #[allow(clippy::cast_slice_from_raw_parts)]
482    #[inline]
483    pub unsafe fn from_ptr<'a>(ptr: *const ffi::GVariantType) -> &'a VariantTy {
484        unsafe {
485            debug_assert!(!ptr.is_null());
486            let len: usize = ffi::g_variant_type_get_string_length(ptr) as _;
487            debug_assert!(len > 0);
488            &*(slice::from_raw_parts(ptr as *const u8, len) as *const [u8] as *const VariantTy)
489        }
490    }
491
492    // rustdoc-stripper-ignore-next
493    /// Returns a `GVariantType` pointer.
494    #[doc(hidden)]
495    #[inline]
496    pub fn as_ptr(&self) -> *const ffi::GVariantType {
497        self.inner.as_ptr() as *const _
498    }
499
500    // rustdoc-stripper-ignore-next
501    /// Converts to a string slice.
502    #[inline]
503    pub fn as_str(&self) -> &str {
504        &self.inner
505    }
506
507    // rustdoc-stripper-ignore-next
508    /// Check if this variant type is a definite type.
509    #[doc(alias = "g_variant_type_is_definite")]
510    pub fn is_definite(&self) -> bool {
511        unsafe { from_glib(ffi::g_variant_type_is_definite(self.to_glib_none().0)) }
512    }
513
514    // rustdoc-stripper-ignore-next
515    /// Check if this variant type is a container type.
516    #[doc(alias = "g_variant_type_is_container")]
517    pub fn is_container(&self) -> bool {
518        unsafe { from_glib(ffi::g_variant_type_is_container(self.to_glib_none().0)) }
519    }
520
521    // rustdoc-stripper-ignore-next
522    /// Check if this variant type is a basic type.
523    #[doc(alias = "g_variant_type_is_basic")]
524    pub fn is_basic(&self) -> bool {
525        unsafe { from_glib(ffi::g_variant_type_is_basic(self.to_glib_none().0)) }
526    }
527
528    // rustdoc-stripper-ignore-next
529    /// Check if this variant type is a maybe type.
530    #[doc(alias = "g_variant_type_is_maybe")]
531    pub fn is_maybe(&self) -> bool {
532        unsafe { from_glib(ffi::g_variant_type_is_maybe(self.to_glib_none().0)) }
533    }
534
535    // rustdoc-stripper-ignore-next
536    /// Check if this variant type is an array type.
537    #[doc(alias = "g_variant_type_is_array")]
538    pub fn is_array(&self) -> bool {
539        unsafe { from_glib(ffi::g_variant_type_is_array(self.to_glib_none().0)) }
540    }
541
542    // rustdoc-stripper-ignore-next
543    /// Check if this variant type is a tuple type.
544    #[doc(alias = "g_variant_type_is_tuple")]
545    pub fn is_tuple(&self) -> bool {
546        unsafe { from_glib(ffi::g_variant_type_is_tuple(self.to_glib_none().0)) }
547    }
548
549    // rustdoc-stripper-ignore-next
550    /// Check if this variant type is a dict entry type.
551    #[doc(alias = "g_variant_type_is_dict_entry")]
552    pub fn is_dict_entry(&self) -> bool {
553        unsafe { from_glib(ffi::g_variant_type_is_dict_entry(self.to_glib_none().0)) }
554    }
555
556    // rustdoc-stripper-ignore-next
557    /// Check if this variant type is a variant.
558    #[doc(alias = "g_variant_type_is_variant")]
559    pub fn is_variant(&self) -> bool {
560        unsafe { from_glib(ffi::g_variant_type_is_variant(self.to_glib_none().0)) }
561    }
562
563    // rustdoc-stripper-ignore-next
564    /// Check if this variant type is a subtype of another.
565    #[doc(alias = "g_variant_type_is_subtype_of")]
566    pub fn is_subtype_of(&self, supertype: &Self) -> bool {
567        unsafe {
568            from_glib(ffi::g_variant_type_is_subtype_of(
569                self.to_glib_none().0,
570                supertype.to_glib_none().0,
571            ))
572        }
573    }
574
575    // rustdoc-stripper-ignore-next
576    /// Return the element type of this variant type.
577    ///
578    /// # Panics
579    ///
580    /// This function panics if not called with an array or maybe type.
581    #[doc(alias = "g_variant_type_element")]
582    pub fn element(&self) -> &VariantTy {
583        assert!(self.is_array() || self.is_maybe());
584
585        unsafe {
586            let element = ffi::g_variant_type_element(self.to_glib_none().0);
587            Self::from_ptr(element)
588        }
589    }
590
591    // rustdoc-stripper-ignore-next
592    /// Iterate over the types of this variant type.
593    ///
594    /// # Panics
595    ///
596    /// This function panics if not called with a tuple or dictionary entry type.
597    pub fn tuple_types(&self) -> VariantTyIterator<'_> {
598        VariantTyIterator::new(self).expect("VariantTy does not represent a tuple")
599    }
600
601    // rustdoc-stripper-ignore-next
602    /// Return the first type of this variant type.
603    ///
604    /// # Panics
605    ///
606    /// This function panics if not called with a tuple or dictionary entry type.
607    #[doc(alias = "g_variant_type_first")]
608    pub fn first(&self) -> Option<&VariantTy> {
609        assert!(self.as_str().starts_with('(') || self.as_str().starts_with('{'));
610
611        unsafe {
612            let first = ffi::g_variant_type_first(self.to_glib_none().0);
613            if first.is_null() {
614                None
615            } else {
616                Some(Self::from_ptr(first))
617            }
618        }
619    }
620
621    // rustdoc-stripper-ignore-next
622    /// Return the next type of this variant type.
623    #[doc(alias = "g_variant_type_next")]
624    pub fn next(&self) -> Option<&VariantTy> {
625        unsafe {
626            let next = ffi::g_variant_type_next(self.to_glib_none().0);
627            if next.is_null() {
628                None
629            } else {
630                Some(Self::from_ptr(next))
631            }
632        }
633    }
634
635    // rustdoc-stripper-ignore-next
636    /// Return the number of items in this variant type.
637    #[doc(alias = "g_variant_type_n_items")]
638    pub fn n_items(&self) -> usize {
639        unsafe { ffi::g_variant_type_n_items(self.to_glib_none().0) }
640    }
641
642    // rustdoc-stripper-ignore-next
643    /// Return the key type of this variant type.
644    ///
645    /// # Panics
646    ///
647    /// This function panics if not called with a dictionary entry type.
648    #[doc(alias = "g_variant_type_key")]
649    pub fn key(&self) -> &VariantTy {
650        assert!(self.as_str().starts_with('{'));
651
652        unsafe {
653            let key = ffi::g_variant_type_key(self.to_glib_none().0);
654            Self::from_ptr(key)
655        }
656    }
657
658    // rustdoc-stripper-ignore-next
659    /// Return the value type of this variant type.
660    ///
661    /// # Panics
662    ///
663    /// This function panics if not called with a dictionary entry type.
664    #[doc(alias = "g_variant_type_value")]
665    pub fn value(&self) -> &VariantTy {
666        assert!(self.as_str().starts_with('{'));
667
668        unsafe {
669            let value = ffi::g_variant_type_value(self.to_glib_none().0);
670            Self::from_ptr(value)
671        }
672    }
673
674    // rustdoc-stripper-ignore-next
675    /// Return this type as an array.
676    pub(crate) fn as_array<'a>(&self) -> Cow<'a, VariantTy> {
677        if self == VariantTy::STRING {
678            Cow::Borrowed(VariantTy::STRING_ARRAY)
679        } else if self == VariantTy::BYTE {
680            Cow::Borrowed(VariantTy::BYTE_STRING)
681        } else if self == VariantTy::BYTE_STRING {
682            Cow::Borrowed(VariantTy::BYTE_STRING_ARRAY)
683        } else if self == VariantTy::OBJECT_PATH {
684            Cow::Borrowed(VariantTy::OBJECT_PATH_ARRAY)
685        } else if self == VariantTy::DICT_ENTRY {
686            Cow::Borrowed(VariantTy::DICTIONARY)
687        } else {
688            Cow::Owned(VariantType::new_array(self))
689        }
690    }
691}
692
693unsafe impl Sync for VariantTy {}
694
695#[doc(hidden)]
696impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantTy {
697    type Storage = PhantomData<&'a Self>;
698
699    #[inline]
700    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> {
701        Stash(self.as_ptr(), PhantomData)
702    }
703}
704
705impl fmt::Display for VariantTy {
706    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
707        f.write_str(self.as_str())
708    }
709}
710
711impl<'a> From<&'a VariantTy> for Cow<'a, VariantTy> {
712    #[inline]
713    fn from(ty: &'a VariantTy) -> Cow<'a, VariantTy> {
714        Cow::Borrowed(ty)
715    }
716}
717
718impl AsRef<VariantTy> for VariantTy {
719    #[inline]
720    fn as_ref(&self) -> &Self {
721        self
722    }
723}
724
725impl ToOwned for VariantTy {
726    type Owned = VariantType;
727
728    #[inline]
729    fn to_owned(&self) -> VariantType {
730        unsafe {
731            VariantType {
732                ptr: ptr::NonNull::new_unchecked(ffi::g_variant_type_copy(self.as_ptr())),
733                len: self.inner.len(),
734            }
735        }
736    }
737}
738
739impl StaticType for VariantTy {
740    #[inline]
741    fn static_type() -> Type {
742        unsafe { from_glib(ffi::g_variant_type_get_gtype()) }
743    }
744}
745
746#[doc(hidden)]
747unsafe impl<'a> crate::value::FromValue<'a> for &'a VariantTy {
748    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
749
750    unsafe fn from_value(value: &'a crate::Value) -> Self {
751        unsafe {
752            let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0);
753            debug_assert!(!ptr.is_null());
754            VariantTy::from_ptr(ptr as *const ffi::GVariantType)
755        }
756    }
757}
758
759#[doc(hidden)]
760impl crate::value::ToValue for VariantTy {
761    fn to_value(&self) -> crate::Value {
762        unsafe {
763            let mut value = crate::Value::from_type_unchecked(VariantTy::static_type());
764            gobject_ffi::g_value_set_boxed(
765                value.to_glib_none_mut().0,
766                self.to_glib_none().0 as *mut _,
767            );
768            value
769        }
770    }
771
772    fn value_type(&self) -> crate::Type {
773        VariantTy::static_type()
774    }
775}
776
777#[doc(hidden)]
778impl crate::value::ToValue for &VariantTy {
779    fn to_value(&self) -> crate::Value {
780        (*self).to_value()
781    }
782
783    #[inline]
784    fn value_type(&self) -> crate::Type {
785        VariantTy::static_type()
786    }
787}
788
789#[doc(hidden)]
790impl crate::value::ToValueOptional for &VariantTy {
791    fn to_value_optional(s: Option<&Self>) -> crate::Value {
792        let mut value = crate::Value::for_value_type::<VariantType>();
793        unsafe {
794            gobject_ffi::g_value_set_boxed(
795                value.to_glib_none_mut().0,
796                s.to_glib_none().0 as *mut _,
797            );
798        }
799
800        value
801    }
802}
803
804impl StaticType for VariantType {
805    #[inline]
806    fn static_type() -> Type {
807        unsafe { from_glib(ffi::g_variant_type_get_gtype()) }
808    }
809}
810
811#[doc(hidden)]
812impl crate::value::ValueType for VariantType {
813    type Type = VariantType;
814}
815
816#[doc(hidden)]
817impl crate::value::ValueTypeOptional for VariantType {}
818
819#[doc(hidden)]
820unsafe impl<'a> crate::value::FromValue<'a> for VariantType {
821    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
822
823    unsafe fn from_value(value: &'a crate::Value) -> Self {
824        unsafe {
825            let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0);
826            debug_assert!(!ptr.is_null());
827            from_glib_none(ptr as *const ffi::GVariantType)
828        }
829    }
830}
831
832#[doc(hidden)]
833impl crate::value::ToValue for VariantType {
834    fn to_value(&self) -> crate::Value {
835        unsafe {
836            let mut value = crate::Value::from_type_unchecked(VariantType::static_type());
837            gobject_ffi::g_value_set_boxed(
838                value.to_glib_none_mut().0,
839                ToGlibPtr::<*mut _>::to_glib_none(&self).0 as *mut _,
840            );
841            value
842        }
843    }
844
845    fn value_type(&self) -> crate::Type {
846        VariantType::static_type()
847    }
848}
849
850#[doc(hidden)]
851impl From<VariantType> for crate::Value {
852    fn from(t: VariantType) -> Self {
853        unsafe {
854            let mut value = crate::Value::from_type_unchecked(VariantType::static_type());
855            gobject_ffi::g_value_take_boxed(
856                value.to_glib_none_mut().0,
857                IntoGlibPtr::<*mut _>::into_glib_ptr(t) as *mut _,
858            );
859            value
860        }
861    }
862}
863
864#[doc(hidden)]
865impl crate::value::ToValueOptional for VariantType {
866    fn to_value_optional(s: Option<&Self>) -> crate::Value {
867        let mut value = crate::Value::for_value_type::<Self>();
868        unsafe {
869            gobject_ffi::g_value_set_boxed(
870                value.to_glib_none_mut().0,
871                ToGlibPtr::<*mut _>::to_glib_none(&s).0 as *mut _,
872            );
873        }
874
875        value
876    }
877}
878
879impl PartialEq for VariantType {
880    #[inline]
881    fn eq(&self, other: &Self) -> bool {
882        <VariantTy as PartialEq>::eq(self, other)
883    }
884}
885
886macro_rules! impl_eq {
887    ($lhs:ty, $rhs: ty) => {
888        #[allow(clippy::extra_unused_lifetimes)]
889        impl<'a, 'b> PartialEq<$rhs> for $lhs {
890            #[inline]
891            fn eq(&self, other: &$rhs) -> bool {
892                <VariantTy as PartialEq>::eq(self, other)
893            }
894        }
895
896        #[allow(clippy::extra_unused_lifetimes)]
897        impl<'a, 'b> PartialEq<$lhs> for $rhs {
898            #[inline]
899            fn eq(&self, other: &$lhs) -> bool {
900                <VariantTy as PartialEq>::eq(self, other)
901            }
902        }
903    };
904}
905
906impl_eq!(VariantType, VariantTy);
907impl_eq!(VariantType, &'a VariantTy);
908impl_eq!(VariantType, Cow<'a, VariantTy>);
909impl_eq!(&'a VariantTy, Cow<'b, VariantTy>);
910
911macro_rules! impl_str_eq {
912    ($lhs:ty, $rhs: ty) => {
913        #[allow(clippy::redundant_slicing)]
914        #[allow(clippy::extra_unused_lifetimes)]
915        impl<'a, 'b> PartialEq<$rhs> for $lhs {
916            #[inline]
917            fn eq(&self, other: &$rhs) -> bool {
918                self.as_str().eq(&other[..])
919            }
920        }
921
922        #[allow(clippy::extra_unused_lifetimes)]
923        impl<'a, 'b> PartialEq<$lhs> for $rhs {
924            #[inline]
925            fn eq(&self, other: &$lhs) -> bool {
926                self[..].eq(other.as_str())
927            }
928        }
929    };
930}
931
932impl_str_eq!(VariantTy, str);
933impl_str_eq!(VariantTy, &'a str);
934impl_str_eq!(&'a VariantTy, str);
935impl_str_eq!(VariantTy, String);
936impl_str_eq!(&'a VariantTy, String);
937impl_str_eq!(VariantType, str);
938impl_str_eq!(VariantType, &'a str);
939impl_str_eq!(VariantType, String);
940
941impl Eq for VariantType {}
942
943// rustdoc-stripper-ignore-next
944/// An iterator over the individual components of a tuple [VariantTy].
945///
946/// This can be conveniently constructed using [VariantTy::tuple_types].
947#[derive(Debug, Copy, Clone)]
948pub struct VariantTyIterator<'a> {
949    elem: Option<&'a VariantTy>,
950}
951
952impl<'a> VariantTyIterator<'a> {
953    // rustdoc-stripper-ignore-next
954    /// Creates a new iterator over the types of the specified [VariantTy].
955    ///
956    /// Returns `Ok` if the type is a definite tuple or dictionary entry type,
957    /// `Err` otherwise.
958    pub fn new(ty: &'a VariantTy) -> Result<Self, BoolError> {
959        if (ty.is_tuple() && ty != VariantTy::TUPLE) || ty.is_dict_entry() {
960            Ok(Self { elem: ty.first() })
961        } else {
962            Err(bool_error!(
963                "Expected a definite tuple or dictionary entry type"
964            ))
965        }
966    }
967}
968
969impl<'a> Iterator for VariantTyIterator<'a> {
970    type Item = &'a VariantTy;
971
972    #[doc(alias = "g_variant_type_next")]
973    fn next(&mut self) -> Option<Self::Item> {
974        let elem = self.elem?;
975        self.elem = elem.next();
976        Some(elem)
977    }
978}
979
980impl iter::FusedIterator for VariantTyIterator<'_> {}
981
982#[cfg(test)]
983mod tests {
984    use super::*;
985
986    unsafe fn equal<T, U>(ptr1: *const T, ptr2: *const U) -> bool {
987        unsafe {
988            from_glib(ffi::g_variant_type_equal(
989                ptr1 as *const _,
990                ptr2 as *const _,
991            ))
992        }
993    }
994
995    #[test]
996    fn new() {
997        let ty = VariantTy::new("((iii)s)").unwrap();
998        unsafe {
999            assert!(equal(ty.as_ptr(), b"((iii)s)\0" as *const u8));
1000        }
1001    }
1002
1003    #[test]
1004    fn new_empty() {
1005        assert!(VariantTy::new("").is_err());
1006    }
1007
1008    #[test]
1009    fn new_with_nul() {
1010        assert!(VariantTy::new("((iii\0)s)").is_err());
1011    }
1012
1013    #[test]
1014    fn new_too_short() {
1015        assert!(VariantTy::new("((iii").is_err());
1016    }
1017
1018    #[test]
1019    fn new_too_long() {
1020        assert!(VariantTy::new("(iii)s").is_err());
1021    }
1022
1023    #[test]
1024    fn eq() {
1025        let ty1 = VariantTy::new("((iii)s)").unwrap();
1026        let ty2 = VariantTy::new("((iii)s)").unwrap();
1027        assert_eq!(ty1, ty2);
1028        assert_eq!(ty1, "((iii)s)");
1029        unsafe {
1030            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
1031        }
1032    }
1033
1034    #[test]
1035    fn ne() {
1036        let ty1 = VariantTy::new("((iii)s)").unwrap();
1037        let ty2 = VariantTy::new("((iii)o)").unwrap();
1038        assert_ne!(ty1, ty2);
1039        assert_ne!(ty1, "((iii)o)");
1040        unsafe {
1041            assert!(!equal(ty1.as_ptr(), ty2.as_ptr()));
1042        }
1043    }
1044
1045    #[test]
1046    fn from_bytes() {
1047        unsafe {
1048            let ty = VariantTy::from_ptr(b"((iii)s)" as *const u8 as *const _);
1049            assert_eq!(ty, "((iii)s)");
1050            assert!(equal(ty.as_ptr(), "((iii)s)".as_ptr()));
1051        }
1052    }
1053
1054    #[test]
1055    fn to_owned() {
1056        let ty1 = VariantTy::new("((iii)s)").unwrap();
1057        let ty2 = ty1.to_owned();
1058        assert_eq!(ty1, ty2);
1059        assert_eq!(ty2, "((iii)s)");
1060        unsafe {
1061            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
1062        }
1063    }
1064
1065    #[test]
1066    fn value() {
1067        let ty1 = VariantType::new("*").unwrap();
1068        let tyv = ty1.to_value();
1069        let ty2 = tyv.get::<VariantType>().unwrap();
1070        assert_eq!(ty1, ty2);
1071
1072        let ty3 = VariantTy::new("*").unwrap();
1073        let tyv2 = ty3.to_value();
1074        let ty4 = tyv2.get::<VariantType>().unwrap();
1075        assert_eq!(ty3, ty4);
1076
1077        let ty5 = VariantTy::ANY;
1078        let tyv3 = ty5.to_value();
1079        let ty6 = tyv3.get::<VariantType>().unwrap();
1080        assert_eq!(ty5, ty6);
1081    }
1082
1083    #[test]
1084    fn type_() {
1085        assert_eq!(VariantTy::static_type(), VariantType::static_type())
1086    }
1087
1088    #[test]
1089    fn tuple_iter() {
1090        let ty = VariantTy::new("((iii)s)").unwrap();
1091        let types: Vec<_> = ty.tuple_types().map(|t| t.as_str()).collect();
1092        assert_eq!(&types, &["(iii)", "s"]);
1093    }
1094}