Skip to main content

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// rustdoc-stripper-ignore-next-stop
24/// A type in the [type@GLib.Variant] type system.
25///
26/// [type@GLib.Variant] types are represented as strings, but have a strict
27/// syntax described below. All [type@GLib.VariantType]s passed to GLib must be
28/// valid, and they are typically expected to be static (i.e. not provided by
29/// user input) as they determine how binary [type@GLib.Variant] data is
30/// interpreted.
31///
32/// To convert a static string to a [type@GLib.VariantType] in C, use the
33/// `VARIANT_TYPE()` casting macro. When GLib is compiled with checks
34/// enabled, it will validate the type. To check if an arbitrary string is a
35/// valid [type@GLib.VariantType], use [`string_is_valid()`][Self::string_is_valid()].
36///
37/// ## GVariant Type System
38///
39/// This section introduces the [type@GLib.Variant] type system. It is based, in
40/// large part, on the D-Bus type system, with two major changes and
41/// some minor lifting of restrictions. The
42/// [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html),
43/// therefore, provides a significant amount of
44/// information that is useful when working with [type@GLib.Variant].
45///
46/// The first major change with respect to the D-Bus type system is the
47/// introduction of maybe (or ‘nullable’) types.  Any type in [type@GLib.Variant]
48/// can be converted to a maybe type, in which case, `nothing` (or `null`)
49/// becomes a valid value.  Maybe types have been added by introducing the
50/// character `m` to type strings.
51///
52/// The second major change is that the [type@GLib.Variant] type system supports
53/// the concept of ‘indefinite types’ — types that are less specific than
54/// the normal types found in D-Bus.  For example, it is possible to speak
55/// of ‘an array of any type’ in [type@GLib.Variant], where the D-Bus type system
56/// would require you to speak of ‘an array of integers’ or ‘an array of
57/// strings’.  Indefinite types have been added by introducing the
58/// characters `*`, `?` and `r` to type strings.
59///
60/// Finally, all arbitrary restrictions relating to the complexity of
61/// types are lifted along with the restriction that dictionary entries
62/// may only appear nested inside of arrays.
63///
64/// Just as in D-Bus, [type@GLib.Variant] types are described with strings (‘type
65/// strings’).  Subject to the differences mentioned above, these strings
66/// are of the same form as those found in D-Bus.  Note, however: D-Bus
67/// always works in terms of messages and therefore individual type
68/// strings appear nowhere in its interface.  Instead, ‘signatures’
69/// are a concatenation of the strings of the type of each argument in a
70/// message.  [type@GLib.Variant] deals with single values directly so
71/// [type@GLib.Variant] type strings always describe the type of exactly one
72/// value.  This means that a D-Bus signature string is generally not a valid
73/// [type@GLib.Variant] type string — except in the case that it is the signature
74/// of a message containing exactly one argument.
75///
76/// An indefinite type is similar in spirit to what may be called an
77/// abstract type in other type systems.  No value can exist that has an
78/// indefinite type as its type, but values can exist that have types
79/// that are subtypes of indefinite types.  That is to say,
80/// [`Variant::type_()`][crate::Variant::type_()] will never return an indefinite type, but
81/// calling [`Variant::is_of_type()`][crate::Variant::is_of_type()] with an indefinite type may return
82/// true.  For example, you cannot have a value that represents ‘an
83/// array of no particular type’, but you can have an ‘array of integers’
84/// which certainly matches the type of ‘an array of no particular type’,
85/// since ‘array of integers’ is a subtype of ‘array of no particular
86/// type’.
87///
88/// This is similar to how instances of abstract classes may not
89/// directly exist in other type systems, but instances of their
90/// non-abstract subtypes may.  For example, in GTK, no object that has
91/// the type of [`GtkWidget`](https://docs.gtk.org/gtk4/class.Widget.html) can
92/// exist (since `GtkWidget` is an abstract class), but a [`GtkWindow`](https://docs.gtk.org/gtk4/class.Window.html)
93/// can certainly be instantiated, and you would say that a `GtkWindow` is a
94/// `GtkWidget` (since `GtkWindow` is a subclass of `GtkWidget`).
95///
96/// Two types may not be compared by value; use `GLib::VariantType::equal()`
97/// or [`is_subtype_of()`][Self::is_subtype_of()]  May be copied using
98/// `GLib::VariantType::copy()` and freed using `GLib::VariantType::free()`.
99///
100/// ## GVariant Type Strings
101///
102/// A [type@GLib.Variant] type string can be any of the following:
103///
104/// - any basic type string (listed below)
105/// - `v`, `r` or `*`
106/// - one of the characters `a` or `m`, followed by another type string
107/// - the character `(`, followed by a concatenation of zero or more other
108///   type strings, followed by the character `)`
109/// - the character `{`, followed by a basic type string (see below),
110///   followed by another type string, followed by the character `}`
111///
112/// A basic type string describes a basic type (as per
113/// [`is_basic()`][Self::is_basic()]) and is always a single character in
114/// length. The valid basic type strings are `b`, `y`, `n`, `q`, `i`, `u`, `x`,
115/// `t`, `h`, `d`, `s`, `o`, `g` and `?`.
116///
117/// The above definition is recursive to arbitrary depth. `aaaaai` and
118/// `(ui(nq((y)))s)` are both valid type strings, as is
119/// `a(aa(ui)(qna{ya(yd)}))`. In order to not hit memory limits,
120/// [type@GLib.Variant] imposes a limit on recursion depth of 65 nested
121/// containers. This is the limit in the D-Bus specification (64) plus one to
122/// allow a [`GDBusMessage`](../gio/class.DBusMessage.html) to be nested in
123/// a top-level tuple.
124///
125/// The meaning of each of the characters is as follows:
126///
127/// - `b`: the type string of `G_VARIANT_TYPE_BOOLEAN`; a boolean value.
128/// - `y`: the type string of `G_VARIANT_TYPE_BYTE`; a byte.
129/// - `n`: the type string of `G_VARIANT_TYPE_INT16`; a signed 16 bit integer.
130/// - `q`: the type string of `G_VARIANT_TYPE_UINT16`; an unsigned 16 bit integer.
131/// - `i`: the type string of `G_VARIANT_TYPE_INT32`; a signed 32 bit integer.
132/// - `u`: the type string of `G_VARIANT_TYPE_UINT32`; an unsigned 32 bit integer.
133/// - `x`: the type string of `G_VARIANT_TYPE_INT64`; a signed 64 bit integer.
134/// - `t`: the type string of `G_VARIANT_TYPE_UINT64`; an unsigned 64 bit integer.
135/// - `h`: the type string of `G_VARIANT_TYPE_HANDLE`; a signed 32 bit value
136///   that, by convention, is used as an index into an array of file
137///   descriptors that are sent alongside a D-Bus message.
138/// - `d`: the type string of `G_VARIANT_TYPE_DOUBLE`; a double precision
139///   floating point value.
140/// - `s`: the type string of `G_VARIANT_TYPE_STRING`; a string.
141/// - `o`: the type string of `G_VARIANT_TYPE_OBJECT_PATH`; a string in the form
142///   of a D-Bus object path.
143/// - `g`: the type string of `G_VARIANT_TYPE_SIGNATURE`; a string in the form of
144///   a D-Bus type signature.
145/// - `?`: the type string of `G_VARIANT_TYPE_BASIC`; an indefinite type that
146///   is a supertype of any of the basic types.
147/// - `v`: the type string of `G_VARIANT_TYPE_VARIANT`; a container type that
148///   contain any other type of value.
149/// - `a`: used as a prefix on another type string to mean an array of that
150///   type; the type string `ai`, for example, is the type of an array of
151///   signed 32-bit integers.
152/// - `m`: used as a prefix on another type string to mean a ‘maybe’, or
153///   ‘nullable’, version of that type; the type string `ms`, for example,
154///   is the type of a value that maybe contains a string, or maybe contains
155///   nothing.
156/// - `()`: used to enclose zero or more other concatenated type strings to
157///   create a tuple type; the type string `(is)`, for example, is the type of
158///   a pair of an integer and a string.
159/// - `r`: the type string of `G_VARIANT_TYPE_TUPLE`; an indefinite type that is
160///   a supertype of any tuple type, regardless of the number of items.
161/// - `{}`: used to enclose a basic type string concatenated with another type
162///   string to create a dictionary entry type, which usually appears inside of
163///   an array to form a dictionary; the type string `a{sd}`, for example, is
164///   the type of a dictionary that maps strings to double precision floating
165///   point values.
166///
167///   The first type (the basic type) is the key type and the second type is
168///   the value type. The reason that the first type is restricted to being a
169///   basic type is so that it can easily be hashed.
170/// - `*`: the type string of `G_VARIANT_TYPE_ANY`; the indefinite type that is
171///   a supertype of all types.  Note that, as with all type strings, this
172///   character represents exactly one type. It cannot be used inside of tuples
173///   to mean ‘any number of items’.
174///
175/// Any type string of a container that contains an indefinite type is,
176/// itself, an indefinite type. For example, the type string `a*`
177/// (corresponding to `G_VARIANT_TYPE_ARRAY`) is an indefinite type
178/// that is a supertype of every array type. `(*s)` is a supertype
179/// of all tuples that contain exactly two items where the second
180/// item is a string.
181///
182/// `a{?*}` is an indefinite type that is a supertype of all arrays
183/// containing dictionary entries where the key is any basic type and
184/// the value is any type at all.  This is, by definition, a dictionary,
185/// so this type string corresponds to `G_VARIANT_TYPE_DICTIONARY`. Note
186/// that, due to the restriction that the key of a dictionary entry must
187/// be a basic type, `{**}` is not a valid type string.
188#[doc(alias = "GVariantType")]
189pub struct VariantType {
190    // GVariantType* essentially is a char*, that always is valid UTF-8 but
191    // isn't NUL-terminated.
192    ptr: ptr::NonNull<ffi::GVariantType>,
193    // We query the length on creation assuming it's cheap (because type strings
194    // are short) and likely to happen anyway.
195    len: usize,
196}
197
198impl VariantType {
199    // rustdoc-stripper-ignore-next
200    /// Tries to create a `VariantType` from a string slice.
201    ///
202    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
203    // rustdoc-stripper-ignore-next-stop
204    /// Creates a new [type@GLib.VariantType] corresponding to the type string given
205    /// by @type_string.
206    ///
207    /// It is appropriate to call `GLib::VariantType::free()` on the return value.
208    ///
209    /// It is a programmer error to call this function with an invalid type
210    /// string.  Use [`string_is_valid()`][Self::string_is_valid()] if you are unsure.
211    /// ## `type_string`
212    /// a valid [GVariant type string](./struct.VariantType.html#gvariant-type-strings)
213    ///
214    /// # Returns
215    ///
216    /// a new [type@GLib.VariantType]
217    pub fn new(type_string: &str) -> Result<VariantType, BoolError> {
218        VariantTy::new(type_string).map(ToOwned::to_owned)
219    }
220
221    // rustdoc-stripper-ignore-next
222    /// Creates a `VariantType` from a key and value type.
223    // rustdoc-stripper-ignore-next-stop
224    /// Constructs the type corresponding to a dictionary entry with a key
225    /// of type @key and a value of type @value.
226    ///
227    /// It is appropriate to call `GLib::VariantType::free()` on the return value.
228    /// ## `key`
229    /// a basic type to use for the key
230    /// ## `value`
231    /// a type to use for the value
232    ///
233    /// # Returns
234    ///
235    /// a new dictionary entry type
236    /// Since 2.24
237    #[doc(alias = "g_variant_type_new_dict_entry")]
238    pub fn new_dict_entry(key_type: &VariantTy, value_type: &VariantTy) -> VariantType {
239        unsafe {
240            from_glib_full(ffi::g_variant_type_new_dict_entry(
241                key_type.to_glib_none().0,
242                value_type.to_glib_none().0,
243            ))
244        }
245    }
246
247    // rustdoc-stripper-ignore-next
248    /// Creates a `VariantType` from an array element type.
249    // rustdoc-stripper-ignore-next-stop
250    /// Constructs the type corresponding to an array of elements of the
251    /// type @type_.
252    ///
253    /// It is appropriate to call [`first()`][Self::first()] on the return value.
254    /// ## `element`
255    /// an element type
256    ///
257    /// # Returns
258    ///
259    /// a new array type
260    /// Since 2.24
261    #[doc(alias = "g_variant_type_new_array")]
262    pub fn new_array(elem_type: &VariantTy) -> VariantType {
263        unsafe { from_glib_full(ffi::g_variant_type_new_array(elem_type.to_glib_none().0)) }
264    }
265
266    // rustdoc-stripper-ignore-next
267    /// Creates a `VariantType` from a maybe element type.
268    // rustdoc-stripper-ignore-next-stop
269    /// Constructs the type corresponding to a ‘maybe’ instance containing
270    /// type @type_ or `Nothing`.
271    ///
272    /// It is appropriate to call `GLib::VariantType::free()` on the return value.
273    /// ## `element`
274    /// an element type
275    ///
276    /// # Returns
277    ///
278    /// a new ‘maybe’ type
279    /// Since 2.24
280    #[doc(alias = "g_variant_type_new_maybe")]
281    pub fn new_maybe(child_type: &VariantTy) -> VariantType {
282        unsafe { from_glib_full(ffi::g_variant_type_new_maybe(child_type.to_glib_none().0)) }
283    }
284
285    // rustdoc-stripper-ignore-next
286    /// Creates a `VariantType` from a maybe element type.
287    // rustdoc-stripper-ignore-next-stop
288    /// Constructs a new tuple type, from @items.
289    ///
290    /// @length is the number of items in @items, or `-1` to indicate that
291    /// @items is `NULL`-terminated.
292    ///
293    /// It is appropriate to call `GLib::VariantType::free()` on the return value.
294    /// ## `items`
295    /// an array of types, one for each item
296    ///
297    /// # Returns
298    ///
299    /// a new tuple type
300    /// Since 2.24
301    #[doc(alias = "g_variant_type_new_tuple")]
302    pub fn new_tuple(items: impl IntoIterator<Item = impl AsRef<VariantTy>>) -> VariantType {
303        let mut builder = crate::GStringBuilder::new("(");
304
305        for ty in items {
306            builder.append(ty.as_ref().as_str());
307        }
308
309        builder.append_c(')');
310
311        VariantType::from_string(builder.into_string()).unwrap()
312    }
313
314    // rustdoc-stripper-ignore-next
315    /// Tries to create a `VariantType` from an owned string.
316    ///
317    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
318    pub fn from_string(type_string: impl Into<crate::GString>) -> Result<VariantType, BoolError> {
319        let type_string = type_string.into();
320        VariantTy::new(&type_string)?;
321
322        let len = type_string.len();
323        unsafe {
324            let ptr = type_string.into_glib_ptr();
325
326            Ok(VariantType {
327                ptr: ptr::NonNull::new_unchecked(ptr as *mut ffi::GVariantType),
328                len,
329            })
330        }
331    }
332}
333
334unsafe impl Send for VariantType {}
335unsafe impl Sync for VariantType {}
336
337impl Drop for VariantType {
338    #[inline]
339    fn drop(&mut self) {
340        unsafe { ffi::g_variant_type_free(self.ptr.as_ptr()) }
341    }
342}
343
344impl AsRef<VariantTy> for VariantType {
345    #[inline]
346    fn as_ref(&self) -> &VariantTy {
347        self
348    }
349}
350
351impl Borrow<VariantTy> for VariantType {
352    #[inline]
353    fn borrow(&self) -> &VariantTy {
354        self
355    }
356}
357
358impl Clone for VariantType {
359    #[inline]
360    fn clone(&self) -> VariantType {
361        unsafe {
362            VariantType {
363                ptr: ptr::NonNull::new_unchecked(ffi::g_variant_type_copy(self.ptr.as_ptr())),
364                len: self.len,
365            }
366        }
367    }
368}
369
370impl Deref for VariantType {
371    type Target = VariantTy;
372
373    #[allow(clippy::cast_slice_from_raw_parts)]
374    #[inline]
375    fn deref(&self) -> &VariantTy {
376        unsafe {
377            &*(slice::from_raw_parts(self.ptr.as_ptr() as *const u8, self.len) as *const [u8]
378                as *const VariantTy)
379        }
380    }
381}
382
383impl fmt::Debug for VariantType {
384    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
385        <VariantTy as fmt::Debug>::fmt(self, f)
386    }
387}
388
389impl fmt::Display for VariantType {
390    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
391        f.write_str(self.as_str())
392    }
393}
394
395impl FromStr for VariantType {
396    type Err = BoolError;
397
398    fn from_str(s: &str) -> Result<Self, Self::Err> {
399        Self::new(s)
400    }
401}
402
403impl Hash for VariantType {
404    #[inline]
405    fn hash<H: Hasher>(&self, state: &mut H) {
406        <VariantTy as Hash>::hash(self, state)
407    }
408}
409
410impl<'a> From<VariantType> for Cow<'a, VariantTy> {
411    #[inline]
412    fn from(ty: VariantType) -> Cow<'a, VariantTy> {
413        Cow::Owned(ty)
414    }
415}
416
417#[doc(hidden)]
418impl IntoGlibPtr<*mut ffi::GVariantType> for VariantType {
419    #[inline]
420    fn into_glib_ptr(self) -> *mut ffi::GVariantType {
421        std::mem::ManuallyDrop::new(self).to_glib_none().0
422    }
423}
424
425#[doc(hidden)]
426impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantType {
427    type Storage = PhantomData<&'a Self>;
428
429    #[inline]
430    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> {
431        Stash(self.ptr.as_ptr(), PhantomData)
432    }
433
434    #[inline]
435    fn to_glib_full(&self) -> *const ffi::GVariantType {
436        unsafe { ffi::g_variant_type_copy(self.ptr.as_ptr()) }
437    }
438}
439
440#[doc(hidden)]
441impl<'a> ToGlibPtr<'a, *mut ffi::GVariantType> for VariantType {
442    type Storage = PhantomData<&'a Self>;
443
444    #[inline]
445    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GVariantType, Self> {
446        Stash(self.ptr.as_ptr(), PhantomData)
447    }
448
449    #[inline]
450    fn to_glib_full(&self) -> *mut ffi::GVariantType {
451        unsafe { ffi::g_variant_type_copy(self.ptr.as_ptr()) }
452    }
453}
454
455#[doc(hidden)]
456impl<'a> ToGlibPtrMut<'a, *mut ffi::GVariantType> for VariantType {
457    type Storage = PhantomData<&'a mut Self>;
458
459    #[inline]
460    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GVariantType, Self> {
461        StashMut(self.ptr.as_ptr(), PhantomData)
462    }
463}
464
465#[doc(hidden)]
466impl FromGlibPtrNone<*const ffi::GVariantType> for VariantType {
467    #[inline]
468    unsafe fn from_glib_none(ptr: *const ffi::GVariantType) -> VariantType {
469        unsafe { VariantTy::from_ptr(ptr).to_owned() }
470    }
471}
472
473#[doc(hidden)]
474impl FromGlibPtrFull<*const ffi::GVariantType> for VariantType {
475    #[inline]
476    unsafe fn from_glib_full(ptr: *const ffi::GVariantType) -> VariantType {
477        unsafe {
478            // Don't assume ownership of a const pointer.
479            // A transfer: full annotation on a `const GVariantType*` is likely a bug.
480            VariantTy::from_ptr(ptr).to_owned()
481        }
482    }
483}
484
485#[doc(hidden)]
486impl FromGlibPtrFull<*mut ffi::GVariantType> for VariantType {
487    #[inline]
488    unsafe fn from_glib_full(ptr: *mut ffi::GVariantType) -> VariantType {
489        unsafe {
490            debug_assert!(!ptr.is_null());
491            let len: usize = ffi::g_variant_type_get_string_length(ptr) as _;
492            VariantType {
493                ptr: ptr::NonNull::new_unchecked(ptr),
494                len,
495            }
496        }
497    }
498}
499
500// rustdoc-stripper-ignore-next
501/// Describes `Variant` types.
502///
503/// This is a borrowed counterpart of [`VariantType`](struct.VariantType.html).
504/// Essentially it's a `str` statically guaranteed to be a valid type string.
505#[repr(transparent)]
506#[derive(Debug, PartialEq, Eq, Hash)]
507pub struct VariantTy {
508    inner: str,
509}
510
511impl VariantTy {
512    // rustdoc-stripper-ignore-next
513    /// `bool`.
514    #[doc(alias = "G_VARIANT_TYPE_BOOLEAN")]
515    pub const BOOLEAN: &'static VariantTy =
516        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BOOLEAN) };
517
518    // rustdoc-stripper-ignore-next
519    /// `u8`.
520    #[doc(alias = "G_VARIANT_TYPE_BYTE")]
521    pub const BYTE: &'static VariantTy =
522        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE) };
523
524    // rustdoc-stripper-ignore-next
525    /// `i16`.
526    #[doc(alias = "G_VARIANT_TYPE_INT16")]
527    pub const INT16: &'static VariantTy =
528        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT16) };
529
530    // rustdoc-stripper-ignore-next
531    /// `u16`.
532    #[doc(alias = "G_VARIANT_TYPE_UINT16")]
533    pub const UINT16: &'static VariantTy =
534        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT16) };
535
536    // rustdoc-stripper-ignore-next
537    /// `i32`.
538    #[doc(alias = "G_VARIANT_TYPE_INT32")]
539    pub const INT32: &'static VariantTy =
540        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT32) };
541
542    // rustdoc-stripper-ignore-next
543    /// `u32`.
544    #[doc(alias = "G_VARIANT_TYPE_UINT32")]
545    pub const UINT32: &'static VariantTy =
546        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT32) };
547
548    // rustdoc-stripper-ignore-next
549    /// `i64`.
550    #[doc(alias = "G_VARIANT_TYPE_INT64")]
551    pub const INT64: &'static VariantTy =
552        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT64) };
553
554    // rustdoc-stripper-ignore-next
555    /// `u64`.
556    #[doc(alias = "G_VARIANT_TYPE_UINT64")]
557    pub const UINT64: &'static VariantTy =
558        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT64) };
559
560    // rustdoc-stripper-ignore-next
561    /// `f64`.
562    #[doc(alias = "G_VARIANT_TYPE_DOUBLE")]
563    pub const DOUBLE: &'static VariantTy =
564        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DOUBLE) };
565
566    // rustdoc-stripper-ignore-next
567    /// `&str`.
568    #[doc(alias = "G_VARIANT_TYPE_STRING")]
569    pub const STRING: &'static VariantTy =
570        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING) };
571
572    // rustdoc-stripper-ignore-next
573    /// DBus object path.
574    #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH")]
575    pub const OBJECT_PATH: &'static VariantTy =
576        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH) };
577
578    // rustdoc-stripper-ignore-next
579    /// Type signature.
580    #[doc(alias = "G_VARIANT_TYPE_SIGNATURE")]
581    pub const SIGNATURE: &'static VariantTy =
582        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_SIGNATURE) };
583
584    // rustdoc-stripper-ignore-next
585    /// Variant.
586    #[doc(alias = "G_VARIANT_TYPE_VARIANT")]
587    pub const VARIANT: &'static VariantTy =
588        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARIANT) };
589
590    // rustdoc-stripper-ignore-next
591    /// Handle.
592    #[doc(alias = "G_VARIANT_TYPE_HANDLE")]
593    pub const HANDLE: &'static VariantTy =
594        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_HANDLE) };
595
596    // rustdoc-stripper-ignore-next
597    /// Unit, i.e. `()`.
598    #[doc(alias = "G_VARIANT_TYPE_UNIT")]
599    pub const UNIT: &'static VariantTy =
600        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UNIT) };
601
602    // rustdoc-stripper-ignore-next
603    /// An indefinite type that is a supertype of every type (including itself).
604    #[doc(alias = "G_VARIANT_TYPE_ANY")]
605    pub const ANY: &'static VariantTy =
606        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ANY) };
607
608    // rustdoc-stripper-ignore-next
609    /// Any basic type.
610    #[doc(alias = "G_VARIANT_TYPE_BASIC")]
611    pub const BASIC: &'static VariantTy =
612        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BASIC) };
613
614    // rustdoc-stripper-ignore-next
615    /// Any maybe type, i.e. `Option<T>`.
616    #[doc(alias = "G_VARIANT_TYPE_MAYBE")]
617    pub const MAYBE: &'static VariantTy =
618        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_MAYBE) };
619
620    // rustdoc-stripper-ignore-next
621    /// Any array type, i.e. `[T]`.
622    #[doc(alias = "G_VARIANT_TYPE_ARRAY")]
623    pub const ARRAY: &'static VariantTy =
624        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ARRAY) };
625
626    // rustdoc-stripper-ignore-next
627    /// Any tuple type, i.e. `(T)`, `(T, T)`, etc.
628    #[doc(alias = "G_VARIANT_TYPE_TUPLE")]
629    pub const TUPLE: &'static VariantTy =
630        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_TUPLE) };
631
632    // rustdoc-stripper-ignore-next
633    /// Any dict entry type, i.e. `DictEntry<K, V>`.
634    #[doc(alias = "G_VARIANT_TYPE_DICT_ENTRY")]
635    pub const DICT_ENTRY: &'static VariantTy =
636        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICT_ENTRY) };
637
638    // rustdoc-stripper-ignore-next
639    /// Any dictionary type, i.e. `HashMap<K, V>`, `BTreeMap<K, V>`.
640    #[doc(alias = "G_VARIANT_TYPE_DICTIONARY")]
641    pub const DICTIONARY: &'static VariantTy =
642        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICTIONARY) };
643
644    // rustdoc-stripper-ignore-next
645    /// String array, i.e. `[&str]`.
646    #[doc(alias = "G_VARIANT_TYPE_STRING_ARRAY")]
647    pub const STRING_ARRAY: &'static VariantTy =
648        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING_ARRAY) };
649
650    // rustdoc-stripper-ignore-next
651    /// Object path array, i.e. `[&str]`.
652    #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH_ARRAY")]
653    pub const OBJECT_PATH_ARRAY: &'static VariantTy =
654        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH_ARRAY) };
655
656    // rustdoc-stripper-ignore-next
657    /// Byte string, i.e. `[u8]`.
658    #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING")]
659    pub const BYTE_STRING: &'static VariantTy =
660        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING) };
661
662    // rustdoc-stripper-ignore-next
663    /// Byte string array, i.e. `[[u8]]`.
664    #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING_ARRAY")]
665    pub const BYTE_STRING_ARRAY: &'static VariantTy =
666        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING_ARRAY) };
667
668    // rustdoc-stripper-ignore-next
669    /// Variant dictionary, i.e. `HashMap<String, Variant>`, `BTreeMap<String, Variant>`, etc.
670    #[doc(alias = "G_VARIANT_TYPE_VARDICT")]
671    pub const VARDICT: &'static VariantTy =
672        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARDICT) };
673
674    // rustdoc-stripper-ignore-next
675    /// Tries to create a `&VariantTy` from a string slice.
676    ///
677    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
678    pub fn new(type_string: &str) -> Result<&VariantTy, BoolError> {
679        unsafe {
680            let ptr = type_string.as_ptr();
681            let limit = ptr.add(type_string.len());
682            let mut end = ptr::null();
683
684            let ok = from_glib(ffi::g_variant_type_string_scan(
685                ptr as *const _,
686                limit as *const _,
687                &mut end,
688            ));
689            if ok && end as *const _ == limit {
690                Ok(&*(type_string.as_bytes() as *const [u8] as *const VariantTy))
691            } else {
692                Err(bool_error!("Invalid type string: '{}'", type_string))
693            }
694        }
695    }
696
697    // rustdoc-stripper-ignore-next
698    /// Converts a type string into `&VariantTy` without any checks.
699    ///
700    /// # Safety
701    ///
702    /// The caller is responsible for passing in only a valid variant type string.
703    #[inline]
704    pub const unsafe fn from_str_unchecked(type_string: &str) -> &VariantTy {
705        unsafe { std::mem::transmute::<&str, &VariantTy>(type_string) }
706    }
707
708    // rustdoc-stripper-ignore-next
709    /// Creates `&VariantTy` with a wildcard lifetime from a `GVariantType`
710    /// pointer.
711    #[doc(hidden)]
712    #[allow(clippy::cast_slice_from_raw_parts)]
713    #[inline]
714    pub unsafe fn from_ptr<'a>(ptr: *const ffi::GVariantType) -> &'a VariantTy {
715        unsafe {
716            debug_assert!(!ptr.is_null());
717            let len: usize = ffi::g_variant_type_get_string_length(ptr) as _;
718            debug_assert!(len > 0);
719            &*(slice::from_raw_parts(ptr as *const u8, len) as *const [u8] as *const VariantTy)
720        }
721    }
722
723    // rustdoc-stripper-ignore-next
724    /// Returns a `GVariantType` pointer.
725    #[doc(hidden)]
726    #[inline]
727    pub fn as_ptr(&self) -> *const ffi::GVariantType {
728        self.inner.as_ptr() as *const _
729    }
730
731    // rustdoc-stripper-ignore-next
732    /// Converts to a string slice.
733    #[inline]
734    pub fn as_str(&self) -> &str {
735        &self.inner
736    }
737
738    // rustdoc-stripper-ignore-next
739    /// Check if this variant type is a definite type.
740    #[doc(alias = "g_variant_type_is_definite")]
741    pub fn is_definite(&self) -> bool {
742        unsafe { from_glib(ffi::g_variant_type_is_definite(self.to_glib_none().0)) }
743    }
744
745    // rustdoc-stripper-ignore-next
746    /// Check if this variant type is a container type.
747    #[doc(alias = "g_variant_type_is_container")]
748    pub fn is_container(&self) -> bool {
749        unsafe { from_glib(ffi::g_variant_type_is_container(self.to_glib_none().0)) }
750    }
751
752    // rustdoc-stripper-ignore-next
753    /// Check if this variant type is a basic type.
754    #[doc(alias = "g_variant_type_is_basic")]
755    pub fn is_basic(&self) -> bool {
756        unsafe { from_glib(ffi::g_variant_type_is_basic(self.to_glib_none().0)) }
757    }
758
759    // rustdoc-stripper-ignore-next
760    /// Check if this variant type is a maybe type.
761    #[doc(alias = "g_variant_type_is_maybe")]
762    pub fn is_maybe(&self) -> bool {
763        unsafe { from_glib(ffi::g_variant_type_is_maybe(self.to_glib_none().0)) }
764    }
765
766    // rustdoc-stripper-ignore-next
767    /// Check if this variant type is an array type.
768    #[doc(alias = "g_variant_type_is_array")]
769    pub fn is_array(&self) -> bool {
770        unsafe { from_glib(ffi::g_variant_type_is_array(self.to_glib_none().0)) }
771    }
772
773    // rustdoc-stripper-ignore-next
774    /// Check if this variant type is a tuple type.
775    #[doc(alias = "g_variant_type_is_tuple")]
776    pub fn is_tuple(&self) -> bool {
777        unsafe { from_glib(ffi::g_variant_type_is_tuple(self.to_glib_none().0)) }
778    }
779
780    // rustdoc-stripper-ignore-next
781    /// Check if this variant type is a dict entry type.
782    #[doc(alias = "g_variant_type_is_dict_entry")]
783    pub fn is_dict_entry(&self) -> bool {
784        unsafe { from_glib(ffi::g_variant_type_is_dict_entry(self.to_glib_none().0)) }
785    }
786
787    // rustdoc-stripper-ignore-next
788    /// Check if this variant type is a variant.
789    #[doc(alias = "g_variant_type_is_variant")]
790    pub fn is_variant(&self) -> bool {
791        unsafe { from_glib(ffi::g_variant_type_is_variant(self.to_glib_none().0)) }
792    }
793
794    // rustdoc-stripper-ignore-next
795    /// Check if this variant type is a subtype of another.
796    #[doc(alias = "g_variant_type_is_subtype_of")]
797    pub fn is_subtype_of(&self, supertype: &Self) -> bool {
798        unsafe {
799            from_glib(ffi::g_variant_type_is_subtype_of(
800                self.to_glib_none().0,
801                supertype.to_glib_none().0,
802            ))
803        }
804    }
805
806    // rustdoc-stripper-ignore-next
807    /// Return the element type of this variant type.
808    ///
809    /// # Panics
810    ///
811    /// This function panics if not called with an array or maybe type.
812    #[doc(alias = "g_variant_type_element")]
813    pub fn element(&self) -> &VariantTy {
814        assert!(self.is_array() || self.is_maybe());
815
816        unsafe {
817            let element = ffi::g_variant_type_element(self.to_glib_none().0);
818            Self::from_ptr(element)
819        }
820    }
821
822    // rustdoc-stripper-ignore-next
823    /// Iterate over the types of this variant type.
824    ///
825    /// # Panics
826    ///
827    /// This function panics if not called with a tuple or dictionary entry type.
828    pub fn tuple_types(&self) -> VariantTyIterator<'_> {
829        VariantTyIterator::new(self).expect("VariantTy does not represent a tuple")
830    }
831
832    // rustdoc-stripper-ignore-next
833    /// Return the first type of this variant type.
834    ///
835    /// # Panics
836    ///
837    /// This function panics if not called with a tuple or dictionary entry type.
838    #[doc(alias = "g_variant_type_first")]
839    pub fn first(&self) -> Option<&VariantTy> {
840        assert!(self.as_str().starts_with('(') || self.as_str().starts_with('{'));
841
842        unsafe {
843            let first = ffi::g_variant_type_first(self.to_glib_none().0);
844            if first.is_null() {
845                None
846            } else {
847                Some(Self::from_ptr(first))
848            }
849        }
850    }
851
852    // rustdoc-stripper-ignore-next
853    /// Return the next type of this variant type.
854    #[doc(alias = "g_variant_type_next")]
855    pub fn next(&self) -> Option<&VariantTy> {
856        unsafe {
857            let next = ffi::g_variant_type_next(self.to_glib_none().0);
858            if next.is_null() {
859                None
860            } else {
861                Some(Self::from_ptr(next))
862            }
863        }
864    }
865
866    // rustdoc-stripper-ignore-next
867    /// Return the number of items in this variant type.
868    #[doc(alias = "g_variant_type_n_items")]
869    pub fn n_items(&self) -> usize {
870        unsafe { ffi::g_variant_type_n_items(self.to_glib_none().0) }
871    }
872
873    // rustdoc-stripper-ignore-next
874    /// Return the key type of this variant type.
875    ///
876    /// # Panics
877    ///
878    /// This function panics if not called with a dictionary entry type.
879    #[doc(alias = "g_variant_type_key")]
880    pub fn key(&self) -> &VariantTy {
881        assert!(self.as_str().starts_with('{'));
882
883        unsafe {
884            let key = ffi::g_variant_type_key(self.to_glib_none().0);
885            Self::from_ptr(key)
886        }
887    }
888
889    // rustdoc-stripper-ignore-next
890    /// Return the value type of this variant type.
891    ///
892    /// # Panics
893    ///
894    /// This function panics if not called with a dictionary entry type.
895    #[doc(alias = "g_variant_type_value")]
896    pub fn value(&self) -> &VariantTy {
897        assert!(self.as_str().starts_with('{'));
898
899        unsafe {
900            let value = ffi::g_variant_type_value(self.to_glib_none().0);
901            Self::from_ptr(value)
902        }
903    }
904
905    // rustdoc-stripper-ignore-next
906    /// Return this type as an array.
907    pub(crate) fn as_array<'a>(&self) -> Cow<'a, VariantTy> {
908        if self == VariantTy::STRING {
909            Cow::Borrowed(VariantTy::STRING_ARRAY)
910        } else if self == VariantTy::BYTE {
911            Cow::Borrowed(VariantTy::BYTE_STRING)
912        } else if self == VariantTy::BYTE_STRING {
913            Cow::Borrowed(VariantTy::BYTE_STRING_ARRAY)
914        } else if self == VariantTy::OBJECT_PATH {
915            Cow::Borrowed(VariantTy::OBJECT_PATH_ARRAY)
916        } else if self == VariantTy::DICT_ENTRY {
917            Cow::Borrowed(VariantTy::DICTIONARY)
918        } else {
919            Cow::Owned(VariantType::new_array(self))
920        }
921    }
922}
923
924unsafe impl Sync for VariantTy {}
925
926#[doc(hidden)]
927impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantTy {
928    type Storage = PhantomData<&'a Self>;
929
930    #[inline]
931    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> {
932        Stash(self.as_ptr(), PhantomData)
933    }
934}
935
936impl fmt::Display for VariantTy {
937    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
938        f.write_str(self.as_str())
939    }
940}
941
942impl<'a> From<&'a VariantTy> for Cow<'a, VariantTy> {
943    #[inline]
944    fn from(ty: &'a VariantTy) -> Cow<'a, VariantTy> {
945        Cow::Borrowed(ty)
946    }
947}
948
949impl AsRef<VariantTy> for VariantTy {
950    #[inline]
951    fn as_ref(&self) -> &Self {
952        self
953    }
954}
955
956impl ToOwned for VariantTy {
957    type Owned = VariantType;
958
959    #[inline]
960    fn to_owned(&self) -> VariantType {
961        unsafe {
962            VariantType {
963                ptr: ptr::NonNull::new_unchecked(ffi::g_variant_type_copy(self.as_ptr())),
964                len: self.inner.len(),
965            }
966        }
967    }
968}
969
970impl StaticType for VariantTy {
971    #[inline]
972    fn static_type() -> Type {
973        unsafe { from_glib(ffi::g_variant_type_get_gtype()) }
974    }
975}
976
977#[doc(hidden)]
978unsafe impl<'a> crate::value::FromValue<'a> for &'a VariantTy {
979    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
980
981    unsafe fn from_value(value: &'a crate::Value) -> Self {
982        unsafe {
983            let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0);
984            debug_assert!(!ptr.is_null());
985            VariantTy::from_ptr(ptr as *const ffi::GVariantType)
986        }
987    }
988}
989
990#[doc(hidden)]
991impl crate::value::ToValue for VariantTy {
992    fn to_value(&self) -> crate::Value {
993        unsafe {
994            let mut value = crate::Value::from_type_unchecked(VariantTy::static_type());
995            gobject_ffi::g_value_set_boxed(
996                value.to_glib_none_mut().0,
997                self.to_glib_none().0 as *mut _,
998            );
999            value
1000        }
1001    }
1002
1003    fn value_type(&self) -> crate::Type {
1004        VariantTy::static_type()
1005    }
1006}
1007
1008#[doc(hidden)]
1009impl crate::value::ToValue for &VariantTy {
1010    fn to_value(&self) -> crate::Value {
1011        (*self).to_value()
1012    }
1013
1014    #[inline]
1015    fn value_type(&self) -> crate::Type {
1016        VariantTy::static_type()
1017    }
1018}
1019
1020#[doc(hidden)]
1021impl crate::value::ToValueOptional for &VariantTy {
1022    fn to_value_optional(s: Option<&Self>) -> crate::Value {
1023        let mut value = crate::Value::for_value_type::<VariantType>();
1024        unsafe {
1025            gobject_ffi::g_value_set_boxed(
1026                value.to_glib_none_mut().0,
1027                s.to_glib_none().0 as *mut _,
1028            );
1029        }
1030
1031        value
1032    }
1033}
1034
1035impl StaticType for VariantType {
1036    #[inline]
1037    fn static_type() -> Type {
1038        unsafe { from_glib(ffi::g_variant_type_get_gtype()) }
1039    }
1040}
1041
1042#[doc(hidden)]
1043impl crate::value::ValueType for VariantType {
1044    type Type = VariantType;
1045}
1046
1047#[doc(hidden)]
1048impl crate::value::ValueTypeOptional for VariantType {}
1049
1050#[doc(hidden)]
1051unsafe impl<'a> crate::value::FromValue<'a> for VariantType {
1052    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
1053
1054    unsafe fn from_value(value: &'a crate::Value) -> Self {
1055        unsafe {
1056            let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0);
1057            debug_assert!(!ptr.is_null());
1058            from_glib_none(ptr as *const ffi::GVariantType)
1059        }
1060    }
1061}
1062
1063#[doc(hidden)]
1064impl crate::value::ToValue for VariantType {
1065    fn to_value(&self) -> crate::Value {
1066        unsafe {
1067            let mut value = crate::Value::from_type_unchecked(VariantType::static_type());
1068            gobject_ffi::g_value_set_boxed(
1069                value.to_glib_none_mut().0,
1070                ToGlibPtr::<*mut _>::to_glib_none(&self).0 as *mut _,
1071            );
1072            value
1073        }
1074    }
1075
1076    fn value_type(&self) -> crate::Type {
1077        VariantType::static_type()
1078    }
1079}
1080
1081#[doc(hidden)]
1082impl From<VariantType> for crate::Value {
1083    fn from(t: VariantType) -> Self {
1084        unsafe {
1085            let mut value = crate::Value::from_type_unchecked(VariantType::static_type());
1086            gobject_ffi::g_value_take_boxed(
1087                value.to_glib_none_mut().0,
1088                IntoGlibPtr::<*mut _>::into_glib_ptr(t) as *mut _,
1089            );
1090            value
1091        }
1092    }
1093}
1094
1095#[doc(hidden)]
1096impl crate::value::ToValueOptional for VariantType {
1097    fn to_value_optional(s: Option<&Self>) -> crate::Value {
1098        let mut value = crate::Value::for_value_type::<Self>();
1099        unsafe {
1100            gobject_ffi::g_value_set_boxed(
1101                value.to_glib_none_mut().0,
1102                ToGlibPtr::<*mut _>::to_glib_none(&s).0 as *mut _,
1103            );
1104        }
1105
1106        value
1107    }
1108}
1109
1110impl PartialEq for VariantType {
1111    #[inline]
1112    fn eq(&self, other: &Self) -> bool {
1113        <VariantTy as PartialEq>::eq(self, other)
1114    }
1115}
1116
1117macro_rules! impl_eq {
1118    ($lhs:ty, $rhs: ty) => {
1119        #[allow(clippy::extra_unused_lifetimes)]
1120        impl<'a, 'b> PartialEq<$rhs> for $lhs {
1121            #[inline]
1122            fn eq(&self, other: &$rhs) -> bool {
1123                <VariantTy as PartialEq>::eq(self, other)
1124            }
1125        }
1126
1127        #[allow(clippy::extra_unused_lifetimes)]
1128        impl<'a, 'b> PartialEq<$lhs> for $rhs {
1129            #[inline]
1130            fn eq(&self, other: &$lhs) -> bool {
1131                <VariantTy as PartialEq>::eq(self, other)
1132            }
1133        }
1134    };
1135}
1136
1137impl_eq!(VariantType, VariantTy);
1138impl_eq!(VariantType, &'a VariantTy);
1139impl_eq!(VariantType, Cow<'a, VariantTy>);
1140impl_eq!(&'a VariantTy, Cow<'b, VariantTy>);
1141
1142macro_rules! impl_str_eq {
1143    ($lhs:ty, $rhs: ty) => {
1144        #[allow(clippy::redundant_slicing)]
1145        #[allow(clippy::extra_unused_lifetimes)]
1146        impl<'a, 'b> PartialEq<$rhs> for $lhs {
1147            #[inline]
1148            fn eq(&self, other: &$rhs) -> bool {
1149                self.as_str().eq(&other[..])
1150            }
1151        }
1152
1153        #[allow(clippy::extra_unused_lifetimes)]
1154        impl<'a, 'b> PartialEq<$lhs> for $rhs {
1155            #[inline]
1156            fn eq(&self, other: &$lhs) -> bool {
1157                self[..].eq(other.as_str())
1158            }
1159        }
1160    };
1161}
1162
1163impl_str_eq!(VariantTy, str);
1164impl_str_eq!(VariantTy, &'a str);
1165impl_str_eq!(&'a VariantTy, str);
1166impl_str_eq!(VariantTy, String);
1167impl_str_eq!(&'a VariantTy, String);
1168impl_str_eq!(VariantType, str);
1169impl_str_eq!(VariantType, &'a str);
1170impl_str_eq!(VariantType, String);
1171
1172impl Eq for VariantType {}
1173
1174// rustdoc-stripper-ignore-next
1175/// An iterator over the individual components of a tuple [VariantTy].
1176///
1177/// This can be conveniently constructed using [VariantTy::tuple_types].
1178#[derive(Debug, Copy, Clone)]
1179pub struct VariantTyIterator<'a> {
1180    elem: Option<&'a VariantTy>,
1181}
1182
1183impl<'a> VariantTyIterator<'a> {
1184    // rustdoc-stripper-ignore-next
1185    /// Creates a new iterator over the types of the specified [VariantTy].
1186    ///
1187    /// Returns `Ok` if the type is a definite tuple or dictionary entry type,
1188    /// `Err` otherwise.
1189    pub fn new(ty: &'a VariantTy) -> Result<Self, BoolError> {
1190        if (ty.is_tuple() && ty != VariantTy::TUPLE) || ty.is_dict_entry() {
1191            Ok(Self { elem: ty.first() })
1192        } else {
1193            Err(bool_error!(
1194                "Expected a definite tuple or dictionary entry type"
1195            ))
1196        }
1197    }
1198}
1199
1200impl<'a> Iterator for VariantTyIterator<'a> {
1201    type Item = &'a VariantTy;
1202
1203    #[doc(alias = "g_variant_type_next")]
1204    fn next(&mut self) -> Option<Self::Item> {
1205        let elem = self.elem?;
1206        self.elem = elem.next();
1207        Some(elem)
1208    }
1209}
1210
1211impl iter::FusedIterator for VariantTyIterator<'_> {}
1212
1213#[cfg(test)]
1214mod tests {
1215    use super::*;
1216
1217    unsafe fn equal<T, U>(ptr1: *const T, ptr2: *const U) -> bool {
1218        unsafe {
1219            from_glib(ffi::g_variant_type_equal(
1220                ptr1 as *const _,
1221                ptr2 as *const _,
1222            ))
1223        }
1224    }
1225
1226    #[test]
1227    fn new() {
1228        let ty = VariantTy::new("((iii)s)").unwrap();
1229        unsafe {
1230            assert!(equal(ty.as_ptr(), b"((iii)s)\0" as *const u8));
1231        }
1232    }
1233
1234    #[test]
1235    fn new_empty() {
1236        assert!(VariantTy::new("").is_err());
1237    }
1238
1239    #[test]
1240    fn new_with_nul() {
1241        assert!(VariantTy::new("((iii\0)s)").is_err());
1242    }
1243
1244    #[test]
1245    fn new_too_short() {
1246        assert!(VariantTy::new("((iii").is_err());
1247    }
1248
1249    #[test]
1250    fn new_too_long() {
1251        assert!(VariantTy::new("(iii)s").is_err());
1252    }
1253
1254    #[test]
1255    fn eq() {
1256        let ty1 = VariantTy::new("((iii)s)").unwrap();
1257        let ty2 = VariantTy::new("((iii)s)").unwrap();
1258        assert_eq!(ty1, ty2);
1259        assert_eq!(ty1, "((iii)s)");
1260        unsafe {
1261            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
1262        }
1263    }
1264
1265    #[test]
1266    fn ne() {
1267        let ty1 = VariantTy::new("((iii)s)").unwrap();
1268        let ty2 = VariantTy::new("((iii)o)").unwrap();
1269        assert_ne!(ty1, ty2);
1270        assert_ne!(ty1, "((iii)o)");
1271        unsafe {
1272            assert!(!equal(ty1.as_ptr(), ty2.as_ptr()));
1273        }
1274    }
1275
1276    #[test]
1277    fn from_bytes() {
1278        unsafe {
1279            let ty = VariantTy::from_ptr(b"((iii)s)" as *const u8 as *const _);
1280            assert_eq!(ty, "((iii)s)");
1281            assert!(equal(ty.as_ptr(), "((iii)s)".as_ptr()));
1282        }
1283    }
1284
1285    #[test]
1286    fn to_owned() {
1287        let ty1 = VariantTy::new("((iii)s)").unwrap();
1288        let ty2 = ty1.to_owned();
1289        assert_eq!(ty1, ty2);
1290        assert_eq!(ty2, "((iii)s)");
1291        unsafe {
1292            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
1293        }
1294    }
1295
1296    #[test]
1297    fn value() {
1298        let ty1 = VariantType::new("*").unwrap();
1299        let tyv = ty1.to_value();
1300        let ty2 = tyv.get::<VariantType>().unwrap();
1301        assert_eq!(ty1, ty2);
1302
1303        let ty3 = VariantTy::new("*").unwrap();
1304        let tyv2 = ty3.to_value();
1305        let ty4 = tyv2.get::<VariantType>().unwrap();
1306        assert_eq!(ty3, ty4);
1307
1308        let ty5 = VariantTy::ANY;
1309        let tyv3 = ty5.to_value();
1310        let ty6 = tyv3.get::<VariantType>().unwrap();
1311        assert_eq!(ty5, ty6);
1312    }
1313
1314    #[test]
1315    fn type_() {
1316        assert_eq!(VariantTy::static_type(), VariantType::static_type())
1317    }
1318
1319    #[test]
1320    fn tuple_iter() {
1321        let ty = VariantTy::new("((iii)s)").unwrap();
1322        let types: Vec<_> = ty.tuple_types().map(|t| t.as_str()).collect();
1323        assert_eq!(&types, &["(iii)", "s"]);
1324    }
1325}