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::{ffi, gobject_ffi, prelude::*, translate::*, BoolError, Type};
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    unsafe 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        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        // Don't assume ownership of a const pointer.
247        // A transfer: full annotation on a `const GVariantType*` is likely a bug.
248        VariantTy::from_ptr(ptr).to_owned()
249    }
250}
251
252#[doc(hidden)]
253impl FromGlibPtrFull<*mut ffi::GVariantType> for VariantType {
254    #[inline]
255    unsafe fn from_glib_full(ptr: *mut ffi::GVariantType) -> VariantType {
256        debug_assert!(!ptr.is_null());
257        let len: usize = ffi::g_variant_type_get_string_length(ptr) as _;
258        VariantType {
259            ptr: ptr::NonNull::new_unchecked(ptr),
260            len,
261        }
262    }
263}
264
265// rustdoc-stripper-ignore-next
266/// Describes `Variant` types.
267///
268/// This is a borrowed counterpart of [`VariantType`](struct.VariantType.html).
269/// Essentially it's a `str` statically guaranteed to be a valid type string.
270#[repr(transparent)]
271#[derive(Debug, PartialEq, Eq, Hash)]
272pub struct VariantTy {
273    inner: str,
274}
275
276impl VariantTy {
277    // rustdoc-stripper-ignore-next
278    /// `bool`.
279    #[doc(alias = "G_VARIANT_TYPE_BOOLEAN")]
280    pub const BOOLEAN: &'static VariantTy =
281        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BOOLEAN) };
282
283    // rustdoc-stripper-ignore-next
284    /// `u8`.
285    #[doc(alias = "G_VARIANT_TYPE_BYTE")]
286    pub const BYTE: &'static VariantTy =
287        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE) };
288
289    // rustdoc-stripper-ignore-next
290    /// `i16`.
291    #[doc(alias = "G_VARIANT_TYPE_INT16")]
292    pub const INT16: &'static VariantTy =
293        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT16) };
294
295    // rustdoc-stripper-ignore-next
296    /// `u16`.
297    #[doc(alias = "G_VARIANT_TYPE_UINT16")]
298    pub const UINT16: &'static VariantTy =
299        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT16) };
300
301    // rustdoc-stripper-ignore-next
302    /// `i32`.
303    #[doc(alias = "G_VARIANT_TYPE_INT32")]
304    pub const INT32: &'static VariantTy =
305        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT32) };
306
307    // rustdoc-stripper-ignore-next
308    /// `u32`.
309    #[doc(alias = "G_VARIANT_TYPE_UINT32")]
310    pub const UINT32: &'static VariantTy =
311        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT32) };
312
313    // rustdoc-stripper-ignore-next
314    /// `i64`.
315    #[doc(alias = "G_VARIANT_TYPE_INT64")]
316    pub const INT64: &'static VariantTy =
317        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT64) };
318
319    // rustdoc-stripper-ignore-next
320    /// `u64`.
321    #[doc(alias = "G_VARIANT_TYPE_UINT64")]
322    pub const UINT64: &'static VariantTy =
323        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT64) };
324
325    // rustdoc-stripper-ignore-next
326    /// `f64`.
327    #[doc(alias = "G_VARIANT_TYPE_DOUBLE")]
328    pub const DOUBLE: &'static VariantTy =
329        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DOUBLE) };
330
331    // rustdoc-stripper-ignore-next
332    /// `&str`.
333    #[doc(alias = "G_VARIANT_TYPE_STRING")]
334    pub const STRING: &'static VariantTy =
335        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING) };
336
337    // rustdoc-stripper-ignore-next
338    /// DBus object path.
339    #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH")]
340    pub const OBJECT_PATH: &'static VariantTy =
341        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH) };
342
343    // rustdoc-stripper-ignore-next
344    /// Type signature.
345    #[doc(alias = "G_VARIANT_TYPE_SIGNATURE")]
346    pub const SIGNATURE: &'static VariantTy =
347        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_SIGNATURE) };
348
349    // rustdoc-stripper-ignore-next
350    /// Variant.
351    #[doc(alias = "G_VARIANT_TYPE_VARIANT")]
352    pub const VARIANT: &'static VariantTy =
353        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARIANT) };
354
355    // rustdoc-stripper-ignore-next
356    /// Handle.
357    #[doc(alias = "G_VARIANT_TYPE_HANDLE")]
358    pub const HANDLE: &'static VariantTy =
359        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_HANDLE) };
360
361    // rustdoc-stripper-ignore-next
362    /// Unit, i.e. `()`.
363    #[doc(alias = "G_VARIANT_TYPE_UNIT")]
364    pub const UNIT: &'static VariantTy =
365        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UNIT) };
366
367    // rustdoc-stripper-ignore-next
368    /// An indefinite type that is a supertype of every type (including itself).
369    #[doc(alias = "G_VARIANT_TYPE_ANY")]
370    pub const ANY: &'static VariantTy =
371        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ANY) };
372
373    // rustdoc-stripper-ignore-next
374    /// Any basic type.
375    #[doc(alias = "G_VARIANT_TYPE_BASIC")]
376    pub const BASIC: &'static VariantTy =
377        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BASIC) };
378
379    // rustdoc-stripper-ignore-next
380    /// Any maybe type, i.e. `Option<T>`.
381    #[doc(alias = "G_VARIANT_TYPE_MAYBE")]
382    pub const MAYBE: &'static VariantTy =
383        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_MAYBE) };
384
385    // rustdoc-stripper-ignore-next
386    /// Any array type, i.e. `[T]`.
387    #[doc(alias = "G_VARIANT_TYPE_ARRAY")]
388    pub const ARRAY: &'static VariantTy =
389        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ARRAY) };
390
391    // rustdoc-stripper-ignore-next
392    /// Any tuple type, i.e. `(T)`, `(T, T)`, etc.
393    #[doc(alias = "G_VARIANT_TYPE_TUPLE")]
394    pub const TUPLE: &'static VariantTy =
395        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_TUPLE) };
396
397    // rustdoc-stripper-ignore-next
398    /// Any dict entry type, i.e. `DictEntry<K, V>`.
399    #[doc(alias = "G_VARIANT_TYPE_DICT_ENTRY")]
400    pub const DICT_ENTRY: &'static VariantTy =
401        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICT_ENTRY) };
402
403    // rustdoc-stripper-ignore-next
404    /// Any dictionary type, i.e. `HashMap<K, V>`, `BTreeMap<K, V>`.
405    #[doc(alias = "G_VARIANT_TYPE_DICTIONARY")]
406    pub const DICTIONARY: &'static VariantTy =
407        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICTIONARY) };
408
409    // rustdoc-stripper-ignore-next
410    /// String array, i.e. `[&str]`.
411    #[doc(alias = "G_VARIANT_TYPE_STRING_ARRAY")]
412    pub const STRING_ARRAY: &'static VariantTy =
413        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING_ARRAY) };
414
415    // rustdoc-stripper-ignore-next
416    /// Object path array, i.e. `[&str]`.
417    #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH_ARRAY")]
418    pub const OBJECT_PATH_ARRAY: &'static VariantTy =
419        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH_ARRAY) };
420
421    // rustdoc-stripper-ignore-next
422    /// Byte string, i.e. `[u8]`.
423    #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING")]
424    pub const BYTE_STRING: &'static VariantTy =
425        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING) };
426
427    // rustdoc-stripper-ignore-next
428    /// Byte string array, i.e. `[[u8]]`.
429    #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING_ARRAY")]
430    pub const BYTE_STRING_ARRAY: &'static VariantTy =
431        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING_ARRAY) };
432
433    // rustdoc-stripper-ignore-next
434    /// Variant dictionary, i.e. `HashMap<String, Variant>`, `BTreeMap<String, Variant>`, etc.
435    #[doc(alias = "G_VARIANT_TYPE_VARDICT")]
436    pub const VARDICT: &'static VariantTy =
437        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARDICT) };
438
439    // rustdoc-stripper-ignore-next
440    /// Tries to create a `&VariantTy` from a string slice.
441    ///
442    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
443    pub fn new(type_string: &str) -> Result<&VariantTy, BoolError> {
444        unsafe {
445            let ptr = type_string.as_ptr();
446            let limit = ptr.add(type_string.len());
447            let mut end = ptr::null();
448
449            let ok = from_glib(ffi::g_variant_type_string_scan(
450                ptr as *const _,
451                limit as *const _,
452                &mut end,
453            ));
454            if ok && end as *const _ == limit {
455                Ok(&*(type_string.as_bytes() as *const [u8] as *const VariantTy))
456            } else {
457                Err(bool_error!("Invalid type string: '{}'", type_string))
458            }
459        }
460    }
461
462    // rustdoc-stripper-ignore-next
463    /// Converts a type string into `&VariantTy` without any checks.
464    ///
465    /// # Safety
466    ///
467    /// The caller is responsible for passing in only a valid variant type string.
468    #[inline]
469    pub const unsafe fn from_str_unchecked(type_string: &str) -> &VariantTy {
470        std::mem::transmute::<&str, &VariantTy>(type_string)
471    }
472
473    // rustdoc-stripper-ignore-next
474    /// Creates `&VariantTy` with a wildcard lifetime from a `GVariantType`
475    /// pointer.
476    #[doc(hidden)]
477    #[allow(clippy::cast_slice_from_raw_parts)]
478    #[inline]
479    pub unsafe fn from_ptr<'a>(ptr: *const ffi::GVariantType) -> &'a VariantTy {
480        debug_assert!(!ptr.is_null());
481        let len: usize = ffi::g_variant_type_get_string_length(ptr) as _;
482        debug_assert!(len > 0);
483        &*(slice::from_raw_parts(ptr as *const u8, len) as *const [u8] as *const VariantTy)
484    }
485
486    // rustdoc-stripper-ignore-next
487    /// Returns a `GVariantType` pointer.
488    #[doc(hidden)]
489    #[inline]
490    pub fn as_ptr(&self) -> *const ffi::GVariantType {
491        self.inner.as_ptr() as *const _
492    }
493
494    // rustdoc-stripper-ignore-next
495    /// Converts to a string slice.
496    #[inline]
497    pub fn as_str(&self) -> &str {
498        &self.inner
499    }
500
501    // rustdoc-stripper-ignore-next
502    /// Check if this variant type is a definite type.
503    #[doc(alias = "g_variant_type_is_definite")]
504    pub fn is_definite(&self) -> bool {
505        unsafe { from_glib(ffi::g_variant_type_is_definite(self.to_glib_none().0)) }
506    }
507
508    // rustdoc-stripper-ignore-next
509    /// Check if this variant type is a container type.
510    #[doc(alias = "g_variant_type_is_container")]
511    pub fn is_container(&self) -> bool {
512        unsafe { from_glib(ffi::g_variant_type_is_container(self.to_glib_none().0)) }
513    }
514
515    // rustdoc-stripper-ignore-next
516    /// Check if this variant type is a basic type.
517    #[doc(alias = "g_variant_type_is_basic")]
518    pub fn is_basic(&self) -> bool {
519        unsafe { from_glib(ffi::g_variant_type_is_basic(self.to_glib_none().0)) }
520    }
521
522    // rustdoc-stripper-ignore-next
523    /// Check if this variant type is a maybe type.
524    #[doc(alias = "g_variant_type_is_maybe")]
525    pub fn is_maybe(&self) -> bool {
526        unsafe { from_glib(ffi::g_variant_type_is_maybe(self.to_glib_none().0)) }
527    }
528
529    // rustdoc-stripper-ignore-next
530    /// Check if this variant type is an array type.
531    #[doc(alias = "g_variant_type_is_array")]
532    pub fn is_array(&self) -> bool {
533        unsafe { from_glib(ffi::g_variant_type_is_array(self.to_glib_none().0)) }
534    }
535
536    // rustdoc-stripper-ignore-next
537    /// Check if this variant type is a tuple type.
538    #[doc(alias = "g_variant_type_is_tuple")]
539    pub fn is_tuple(&self) -> bool {
540        unsafe { from_glib(ffi::g_variant_type_is_tuple(self.to_glib_none().0)) }
541    }
542
543    // rustdoc-stripper-ignore-next
544    /// Check if this variant type is a dict entry type.
545    #[doc(alias = "g_variant_type_is_dict_entry")]
546    pub fn is_dict_entry(&self) -> bool {
547        unsafe { from_glib(ffi::g_variant_type_is_dict_entry(self.to_glib_none().0)) }
548    }
549
550    // rustdoc-stripper-ignore-next
551    /// Check if this variant type is a variant.
552    #[doc(alias = "g_variant_type_is_variant")]
553    pub fn is_variant(&self) -> bool {
554        unsafe { from_glib(ffi::g_variant_type_is_variant(self.to_glib_none().0)) }
555    }
556
557    // rustdoc-stripper-ignore-next
558    /// Check if this variant type is a subtype of another.
559    #[doc(alias = "g_variant_type_is_subtype_of")]
560    pub fn is_subtype_of(&self, supertype: &Self) -> bool {
561        unsafe {
562            from_glib(ffi::g_variant_type_is_subtype_of(
563                self.to_glib_none().0,
564                supertype.to_glib_none().0,
565            ))
566        }
567    }
568
569    // rustdoc-stripper-ignore-next
570    /// Return the element type of this variant type.
571    ///
572    /// # Panics
573    ///
574    /// This function panics if not called with an array or maybe type.
575    #[doc(alias = "g_variant_type_element")]
576    pub fn element(&self) -> &VariantTy {
577        assert!(self.is_array() || self.is_maybe());
578
579        unsafe {
580            let element = ffi::g_variant_type_element(self.to_glib_none().0);
581            Self::from_ptr(element)
582        }
583    }
584
585    // rustdoc-stripper-ignore-next
586    /// Iterate over the types of this variant type.
587    ///
588    /// # Panics
589    ///
590    /// This function panics if not called with a tuple or dictionary entry type.
591    pub fn tuple_types(&self) -> VariantTyIterator {
592        VariantTyIterator::new(self).expect("VariantTy does not represent a tuple")
593    }
594
595    // rustdoc-stripper-ignore-next
596    /// Return the first type of this variant type.
597    ///
598    /// # Panics
599    ///
600    /// This function panics if not called with a tuple or dictionary entry type.
601    #[doc(alias = "g_variant_type_first")]
602    pub fn first(&self) -> Option<&VariantTy> {
603        assert!(self.as_str().starts_with('(') || self.as_str().starts_with('{'));
604
605        unsafe {
606            let first = ffi::g_variant_type_first(self.to_glib_none().0);
607            if first.is_null() {
608                None
609            } else {
610                Some(Self::from_ptr(first))
611            }
612        }
613    }
614
615    // rustdoc-stripper-ignore-next
616    /// Return the next type of this variant type.
617    #[doc(alias = "g_variant_type_next")]
618    pub fn next(&self) -> Option<&VariantTy> {
619        unsafe {
620            let next = ffi::g_variant_type_next(self.to_glib_none().0);
621            if next.is_null() {
622                None
623            } else {
624                Some(Self::from_ptr(next))
625            }
626        }
627    }
628
629    // rustdoc-stripper-ignore-next
630    /// Return the number of items in this variant type.
631    #[doc(alias = "g_variant_type_n_items")]
632    pub fn n_items(&self) -> usize {
633        unsafe { ffi::g_variant_type_n_items(self.to_glib_none().0) }
634    }
635
636    // rustdoc-stripper-ignore-next
637    /// Return the key type of this variant type.
638    ///
639    /// # Panics
640    ///
641    /// This function panics if not called with a dictionary entry type.
642    #[doc(alias = "g_variant_type_key")]
643    pub fn key(&self) -> &VariantTy {
644        assert!(self.as_str().starts_with('{'));
645
646        unsafe {
647            let key = ffi::g_variant_type_key(self.to_glib_none().0);
648            Self::from_ptr(key)
649        }
650    }
651
652    // rustdoc-stripper-ignore-next
653    /// Return the value type of this variant type.
654    ///
655    /// # Panics
656    ///
657    /// This function panics if not called with a dictionary entry type.
658    #[doc(alias = "g_variant_type_value")]
659    pub fn value(&self) -> &VariantTy {
660        assert!(self.as_str().starts_with('{'));
661
662        unsafe {
663            let value = ffi::g_variant_type_value(self.to_glib_none().0);
664            Self::from_ptr(value)
665        }
666    }
667
668    // rustdoc-stripper-ignore-next
669    /// Return this type as an array.
670    pub(crate) fn as_array<'a>(&self) -> Cow<'a, VariantTy> {
671        if self == VariantTy::STRING {
672            Cow::Borrowed(VariantTy::STRING_ARRAY)
673        } else if self == VariantTy::BYTE {
674            Cow::Borrowed(VariantTy::BYTE_STRING)
675        } else if self == VariantTy::BYTE_STRING {
676            Cow::Borrowed(VariantTy::BYTE_STRING_ARRAY)
677        } else if self == VariantTy::OBJECT_PATH {
678            Cow::Borrowed(VariantTy::OBJECT_PATH_ARRAY)
679        } else if self == VariantTy::DICT_ENTRY {
680            Cow::Borrowed(VariantTy::DICTIONARY)
681        } else {
682            Cow::Owned(VariantType::new_array(self))
683        }
684    }
685}
686
687unsafe impl Sync for VariantTy {}
688
689#[doc(hidden)]
690impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantTy {
691    type Storage = PhantomData<&'a Self>;
692
693    #[inline]
694    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> {
695        Stash(self.as_ptr(), PhantomData)
696    }
697}
698
699impl fmt::Display for VariantTy {
700    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
701        f.write_str(self.as_str())
702    }
703}
704
705impl<'a> From<&'a VariantTy> for Cow<'a, VariantTy> {
706    #[inline]
707    fn from(ty: &'a VariantTy) -> Cow<'a, VariantTy> {
708        Cow::Borrowed(ty)
709    }
710}
711
712impl AsRef<VariantTy> for VariantTy {
713    #[inline]
714    fn as_ref(&self) -> &Self {
715        self
716    }
717}
718
719impl ToOwned for VariantTy {
720    type Owned = VariantType;
721
722    #[inline]
723    fn to_owned(&self) -> VariantType {
724        unsafe {
725            VariantType {
726                ptr: ptr::NonNull::new_unchecked(ffi::g_variant_type_copy(self.as_ptr())),
727                len: self.inner.len(),
728            }
729        }
730    }
731}
732
733impl StaticType for VariantTy {
734    #[inline]
735    fn static_type() -> Type {
736        unsafe { from_glib(ffi::g_variant_type_get_gtype()) }
737    }
738}
739
740#[doc(hidden)]
741unsafe impl<'a> crate::value::FromValue<'a> for &'a VariantTy {
742    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
743
744    unsafe fn from_value(value: &'a crate::Value) -> Self {
745        let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0);
746        debug_assert!(!ptr.is_null());
747        VariantTy::from_ptr(ptr as *const ffi::GVariantType)
748    }
749}
750
751#[doc(hidden)]
752impl crate::value::ToValue for VariantTy {
753    fn to_value(&self) -> crate::Value {
754        unsafe {
755            let mut value = crate::Value::from_type_unchecked(VariantTy::static_type());
756            gobject_ffi::g_value_set_boxed(
757                value.to_glib_none_mut().0,
758                self.to_glib_none().0 as *mut _,
759            );
760            value
761        }
762    }
763
764    fn value_type(&self) -> crate::Type {
765        VariantTy::static_type()
766    }
767}
768
769#[doc(hidden)]
770impl crate::value::ToValue for &VariantTy {
771    fn to_value(&self) -> crate::Value {
772        (*self).to_value()
773    }
774
775    #[inline]
776    fn value_type(&self) -> crate::Type {
777        VariantTy::static_type()
778    }
779}
780
781#[doc(hidden)]
782impl crate::value::ToValueOptional for &VariantTy {
783    fn to_value_optional(s: Option<&Self>) -> crate::Value {
784        let mut value = crate::Value::for_value_type::<VariantType>();
785        unsafe {
786            gobject_ffi::g_value_set_boxed(
787                value.to_glib_none_mut().0,
788                s.to_glib_none().0 as *mut _,
789            );
790        }
791
792        value
793    }
794}
795
796impl StaticType for VariantType {
797    #[inline]
798    fn static_type() -> Type {
799        unsafe { from_glib(ffi::g_variant_type_get_gtype()) }
800    }
801}
802
803#[doc(hidden)]
804impl crate::value::ValueType for VariantType {
805    type Type = VariantType;
806}
807
808#[doc(hidden)]
809impl crate::value::ValueTypeOptional for VariantType {}
810
811#[doc(hidden)]
812unsafe impl<'a> crate::value::FromValue<'a> for VariantType {
813    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
814
815    unsafe fn from_value(value: &'a crate::Value) -> Self {
816        let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0);
817        debug_assert!(!ptr.is_null());
818        from_glib_none(ptr as *const ffi::GVariantType)
819    }
820}
821
822#[doc(hidden)]
823impl crate::value::ToValue for VariantType {
824    fn to_value(&self) -> crate::Value {
825        unsafe {
826            let mut value = crate::Value::from_type_unchecked(VariantType::static_type());
827            gobject_ffi::g_value_set_boxed(
828                value.to_glib_none_mut().0,
829                ToGlibPtr::<*mut _>::to_glib_none(&self).0 as *mut _,
830            );
831            value
832        }
833    }
834
835    fn value_type(&self) -> crate::Type {
836        VariantType::static_type()
837    }
838}
839
840#[doc(hidden)]
841impl From<VariantType> for crate::Value {
842    fn from(t: VariantType) -> Self {
843        unsafe {
844            let mut value = crate::Value::from_type_unchecked(VariantType::static_type());
845            gobject_ffi::g_value_take_boxed(
846                value.to_glib_none_mut().0,
847                IntoGlibPtr::<*mut _>::into_glib_ptr(t) as *mut _,
848            );
849            value
850        }
851    }
852}
853
854#[doc(hidden)]
855impl crate::value::ToValueOptional for VariantType {
856    fn to_value_optional(s: Option<&Self>) -> crate::Value {
857        let mut value = crate::Value::for_value_type::<Self>();
858        unsafe {
859            gobject_ffi::g_value_set_boxed(
860                value.to_glib_none_mut().0,
861                ToGlibPtr::<*mut _>::to_glib_none(&s).0 as *mut _,
862            );
863        }
864
865        value
866    }
867}
868
869impl PartialEq for VariantType {
870    #[inline]
871    fn eq(&self, other: &Self) -> bool {
872        <VariantTy as PartialEq>::eq(self, other)
873    }
874}
875
876macro_rules! impl_eq {
877    ($lhs:ty, $rhs: ty) => {
878        #[allow(clippy::extra_unused_lifetimes)]
879        impl<'a, 'b> PartialEq<$rhs> for $lhs {
880            #[inline]
881            fn eq(&self, other: &$rhs) -> bool {
882                <VariantTy as PartialEq>::eq(self, other)
883            }
884        }
885
886        #[allow(clippy::extra_unused_lifetimes)]
887        impl<'a, 'b> PartialEq<$lhs> for $rhs {
888            #[inline]
889            fn eq(&self, other: &$lhs) -> bool {
890                <VariantTy as PartialEq>::eq(self, other)
891            }
892        }
893    };
894}
895
896impl_eq!(VariantType, VariantTy);
897impl_eq!(VariantType, &'a VariantTy);
898impl_eq!(VariantType, Cow<'a, VariantTy>);
899impl_eq!(&'a VariantTy, Cow<'b, VariantTy>);
900
901macro_rules! impl_str_eq {
902    ($lhs:ty, $rhs: ty) => {
903        #[allow(clippy::redundant_slicing)]
904        #[allow(clippy::extra_unused_lifetimes)]
905        impl<'a, 'b> PartialEq<$rhs> for $lhs {
906            #[inline]
907            fn eq(&self, other: &$rhs) -> bool {
908                self.as_str().eq(&other[..])
909            }
910        }
911
912        #[allow(clippy::extra_unused_lifetimes)]
913        impl<'a, 'b> PartialEq<$lhs> for $rhs {
914            #[inline]
915            fn eq(&self, other: &$lhs) -> bool {
916                self[..].eq(other.as_str())
917            }
918        }
919    };
920}
921
922impl_str_eq!(VariantTy, str);
923impl_str_eq!(VariantTy, &'a str);
924impl_str_eq!(&'a VariantTy, str);
925impl_str_eq!(VariantTy, String);
926impl_str_eq!(&'a VariantTy, String);
927impl_str_eq!(VariantType, str);
928impl_str_eq!(VariantType, &'a str);
929impl_str_eq!(VariantType, String);
930
931impl Eq for VariantType {}
932
933// rustdoc-stripper-ignore-next
934/// An iterator over the individual components of a tuple [VariantTy].
935///
936/// This can be conveniently constructed using [VariantTy::tuple_types].
937#[derive(Debug, Copy, Clone)]
938pub struct VariantTyIterator<'a> {
939    elem: Option<&'a VariantTy>,
940}
941
942impl<'a> VariantTyIterator<'a> {
943    // rustdoc-stripper-ignore-next
944    /// Creates a new iterator over the types of the specified [VariantTy].
945    ///
946    /// Returns `Ok` if the type is a definite tuple or dictionary entry type,
947    /// `Err` otherwise.
948    pub fn new(ty: &'a VariantTy) -> Result<Self, BoolError> {
949        if (ty.is_tuple() && ty != VariantTy::TUPLE) || ty.is_dict_entry() {
950            Ok(Self { elem: ty.first() })
951        } else {
952            Err(bool_error!(
953                "Expected a definite tuple or dictionary entry type"
954            ))
955        }
956    }
957}
958
959impl<'a> Iterator for VariantTyIterator<'a> {
960    type Item = &'a VariantTy;
961
962    #[doc(alias = "g_variant_type_next")]
963    fn next(&mut self) -> Option<Self::Item> {
964        let elem = self.elem?;
965        self.elem = elem.next();
966        Some(elem)
967    }
968}
969
970impl iter::FusedIterator for VariantTyIterator<'_> {}
971
972#[cfg(test)]
973mod tests {
974    use super::*;
975
976    unsafe fn equal<T, U>(ptr1: *const T, ptr2: *const U) -> bool {
977        from_glib(ffi::g_variant_type_equal(
978            ptr1 as *const _,
979            ptr2 as *const _,
980        ))
981    }
982
983    #[test]
984    fn new() {
985        let ty = VariantTy::new("((iii)s)").unwrap();
986        unsafe {
987            assert!(equal(ty.as_ptr(), b"((iii)s)\0" as *const u8));
988        }
989    }
990
991    #[test]
992    fn new_empty() {
993        assert!(VariantTy::new("").is_err());
994    }
995
996    #[test]
997    fn new_with_nul() {
998        assert!(VariantTy::new("((iii\0)s)").is_err());
999    }
1000
1001    #[test]
1002    fn new_too_short() {
1003        assert!(VariantTy::new("((iii").is_err());
1004    }
1005
1006    #[test]
1007    fn new_too_long() {
1008        assert!(VariantTy::new("(iii)s").is_err());
1009    }
1010
1011    #[test]
1012    fn eq() {
1013        let ty1 = VariantTy::new("((iii)s)").unwrap();
1014        let ty2 = VariantTy::new("((iii)s)").unwrap();
1015        assert_eq!(ty1, ty2);
1016        assert_eq!(ty1, "((iii)s)");
1017        unsafe {
1018            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
1019        }
1020    }
1021
1022    #[test]
1023    fn ne() {
1024        let ty1 = VariantTy::new("((iii)s)").unwrap();
1025        let ty2 = VariantTy::new("((iii)o)").unwrap();
1026        assert_ne!(ty1, ty2);
1027        assert_ne!(ty1, "((iii)o)");
1028        unsafe {
1029            assert!(!equal(ty1.as_ptr(), ty2.as_ptr()));
1030        }
1031    }
1032
1033    #[test]
1034    fn from_bytes() {
1035        unsafe {
1036            let ty = VariantTy::from_ptr(b"((iii)s)" as *const u8 as *const _);
1037            assert_eq!(ty, "((iii)s)");
1038            assert!(equal(ty.as_ptr(), "((iii)s)".as_ptr()));
1039        }
1040    }
1041
1042    #[test]
1043    fn to_owned() {
1044        let ty1 = VariantTy::new("((iii)s)").unwrap();
1045        let ty2 = ty1.to_owned();
1046        assert_eq!(ty1, ty2);
1047        assert_eq!(ty2, "((iii)s)");
1048        unsafe {
1049            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
1050        }
1051    }
1052
1053    #[test]
1054    fn value() {
1055        let ty1 = VariantType::new("*").unwrap();
1056        let tyv = ty1.to_value();
1057        let ty2 = tyv.get::<VariantType>().unwrap();
1058        assert_eq!(ty1, ty2);
1059
1060        let ty3 = VariantTy::new("*").unwrap();
1061        let tyv2 = ty3.to_value();
1062        let ty4 = tyv2.get::<VariantType>().unwrap();
1063        assert_eq!(ty3, ty4);
1064
1065        let ty5 = VariantTy::ANY;
1066        let tyv3 = ty5.to_value();
1067        let ty6 = tyv3.get::<VariantType>().unwrap();
1068        assert_eq!(ty5, ty6);
1069    }
1070
1071    #[test]
1072    fn type_() {
1073        assert_eq!(VariantTy::static_type(), VariantType::static_type())
1074    }
1075
1076    #[test]
1077    fn tuple_iter() {
1078        let ty = VariantTy::new("((iii)s)").unwrap();
1079        let types: Vec<_> = ty.tuple_types().map(|t| t.as_str()).collect();
1080        assert_eq!(&types, &["(iii)", "s"]);
1081    }
1082}