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// 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        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        // Don't assume ownership of a const pointer.
478        // A transfer: full annotation on a `const GVariantType*` is likely a bug.
479        VariantTy::from_ptr(ptr).to_owned()
480    }
481}
482
483#[doc(hidden)]
484impl FromGlibPtrFull<*mut ffi::GVariantType> for VariantType {
485    #[inline]
486    unsafe fn from_glib_full(ptr: *mut ffi::GVariantType) -> VariantType {
487        debug_assert!(!ptr.is_null());
488        let len: usize = ffi::g_variant_type_get_string_length(ptr) as _;
489        VariantType {
490            ptr: ptr::NonNull::new_unchecked(ptr),
491            len,
492        }
493    }
494}
495
496// rustdoc-stripper-ignore-next
497/// Describes `Variant` types.
498///
499/// This is a borrowed counterpart of [`VariantType`](struct.VariantType.html).
500/// Essentially it's a `str` statically guaranteed to be a valid type string.
501#[repr(transparent)]
502#[derive(Debug, PartialEq, Eq, Hash)]
503pub struct VariantTy {
504    inner: str,
505}
506
507impl VariantTy {
508    // rustdoc-stripper-ignore-next
509    /// `bool`.
510    #[doc(alias = "G_VARIANT_TYPE_BOOLEAN")]
511    pub const BOOLEAN: &'static VariantTy =
512        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BOOLEAN) };
513
514    // rustdoc-stripper-ignore-next
515    /// `u8`.
516    #[doc(alias = "G_VARIANT_TYPE_BYTE")]
517    pub const BYTE: &'static VariantTy =
518        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE) };
519
520    // rustdoc-stripper-ignore-next
521    /// `i16`.
522    #[doc(alias = "G_VARIANT_TYPE_INT16")]
523    pub const INT16: &'static VariantTy =
524        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT16) };
525
526    // rustdoc-stripper-ignore-next
527    /// `u16`.
528    #[doc(alias = "G_VARIANT_TYPE_UINT16")]
529    pub const UINT16: &'static VariantTy =
530        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT16) };
531
532    // rustdoc-stripper-ignore-next
533    /// `i32`.
534    #[doc(alias = "G_VARIANT_TYPE_INT32")]
535    pub const INT32: &'static VariantTy =
536        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT32) };
537
538    // rustdoc-stripper-ignore-next
539    /// `u32`.
540    #[doc(alias = "G_VARIANT_TYPE_UINT32")]
541    pub const UINT32: &'static VariantTy =
542        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT32) };
543
544    // rustdoc-stripper-ignore-next
545    /// `i64`.
546    #[doc(alias = "G_VARIANT_TYPE_INT64")]
547    pub const INT64: &'static VariantTy =
548        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT64) };
549
550    // rustdoc-stripper-ignore-next
551    /// `u64`.
552    #[doc(alias = "G_VARIANT_TYPE_UINT64")]
553    pub const UINT64: &'static VariantTy =
554        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT64) };
555
556    // rustdoc-stripper-ignore-next
557    /// `f64`.
558    #[doc(alias = "G_VARIANT_TYPE_DOUBLE")]
559    pub const DOUBLE: &'static VariantTy =
560        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DOUBLE) };
561
562    // rustdoc-stripper-ignore-next
563    /// `&str`.
564    #[doc(alias = "G_VARIANT_TYPE_STRING")]
565    pub const STRING: &'static VariantTy =
566        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING) };
567
568    // rustdoc-stripper-ignore-next
569    /// DBus object path.
570    #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH")]
571    pub const OBJECT_PATH: &'static VariantTy =
572        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH) };
573
574    // rustdoc-stripper-ignore-next
575    /// Type signature.
576    #[doc(alias = "G_VARIANT_TYPE_SIGNATURE")]
577    pub const SIGNATURE: &'static VariantTy =
578        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_SIGNATURE) };
579
580    // rustdoc-stripper-ignore-next
581    /// Variant.
582    #[doc(alias = "G_VARIANT_TYPE_VARIANT")]
583    pub const VARIANT: &'static VariantTy =
584        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARIANT) };
585
586    // rustdoc-stripper-ignore-next
587    /// Handle.
588    #[doc(alias = "G_VARIANT_TYPE_HANDLE")]
589    pub const HANDLE: &'static VariantTy =
590        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_HANDLE) };
591
592    // rustdoc-stripper-ignore-next
593    /// Unit, i.e. `()`.
594    #[doc(alias = "G_VARIANT_TYPE_UNIT")]
595    pub const UNIT: &'static VariantTy =
596        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UNIT) };
597
598    // rustdoc-stripper-ignore-next
599    /// An indefinite type that is a supertype of every type (including itself).
600    #[doc(alias = "G_VARIANT_TYPE_ANY")]
601    pub const ANY: &'static VariantTy =
602        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ANY) };
603
604    // rustdoc-stripper-ignore-next
605    /// Any basic type.
606    #[doc(alias = "G_VARIANT_TYPE_BASIC")]
607    pub const BASIC: &'static VariantTy =
608        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BASIC) };
609
610    // rustdoc-stripper-ignore-next
611    /// Any maybe type, i.e. `Option<T>`.
612    #[doc(alias = "G_VARIANT_TYPE_MAYBE")]
613    pub const MAYBE: &'static VariantTy =
614        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_MAYBE) };
615
616    // rustdoc-stripper-ignore-next
617    /// Any array type, i.e. `[T]`.
618    #[doc(alias = "G_VARIANT_TYPE_ARRAY")]
619    pub const ARRAY: &'static VariantTy =
620        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ARRAY) };
621
622    // rustdoc-stripper-ignore-next
623    /// Any tuple type, i.e. `(T)`, `(T, T)`, etc.
624    #[doc(alias = "G_VARIANT_TYPE_TUPLE")]
625    pub const TUPLE: &'static VariantTy =
626        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_TUPLE) };
627
628    // rustdoc-stripper-ignore-next
629    /// Any dict entry type, i.e. `DictEntry<K, V>`.
630    #[doc(alias = "G_VARIANT_TYPE_DICT_ENTRY")]
631    pub const DICT_ENTRY: &'static VariantTy =
632        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICT_ENTRY) };
633
634    // rustdoc-stripper-ignore-next
635    /// Any dictionary type, i.e. `HashMap<K, V>`, `BTreeMap<K, V>`.
636    #[doc(alias = "G_VARIANT_TYPE_DICTIONARY")]
637    pub const DICTIONARY: &'static VariantTy =
638        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICTIONARY) };
639
640    // rustdoc-stripper-ignore-next
641    /// String array, i.e. `[&str]`.
642    #[doc(alias = "G_VARIANT_TYPE_STRING_ARRAY")]
643    pub const STRING_ARRAY: &'static VariantTy =
644        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING_ARRAY) };
645
646    // rustdoc-stripper-ignore-next
647    /// Object path array, i.e. `[&str]`.
648    #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH_ARRAY")]
649    pub const OBJECT_PATH_ARRAY: &'static VariantTy =
650        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH_ARRAY) };
651
652    // rustdoc-stripper-ignore-next
653    /// Byte string, i.e. `[u8]`.
654    #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING")]
655    pub const BYTE_STRING: &'static VariantTy =
656        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING) };
657
658    // rustdoc-stripper-ignore-next
659    /// Byte string array, i.e. `[[u8]]`.
660    #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING_ARRAY")]
661    pub const BYTE_STRING_ARRAY: &'static VariantTy =
662        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING_ARRAY) };
663
664    // rustdoc-stripper-ignore-next
665    /// Variant dictionary, i.e. `HashMap<String, Variant>`, `BTreeMap<String, Variant>`, etc.
666    #[doc(alias = "G_VARIANT_TYPE_VARDICT")]
667    pub const VARDICT: &'static VariantTy =
668        unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARDICT) };
669
670    // rustdoc-stripper-ignore-next
671    /// Tries to create a `&VariantTy` from a string slice.
672    ///
673    /// Returns `Ok` if the string is a valid type string, `Err` otherwise.
674    pub fn new(type_string: &str) -> Result<&VariantTy, BoolError> {
675        unsafe {
676            let ptr = type_string.as_ptr();
677            let limit = ptr.add(type_string.len());
678            let mut end = ptr::null();
679
680            let ok = from_glib(ffi::g_variant_type_string_scan(
681                ptr as *const _,
682                limit as *const _,
683                &mut end,
684            ));
685            if ok && end as *const _ == limit {
686                Ok(&*(type_string.as_bytes() as *const [u8] as *const VariantTy))
687            } else {
688                Err(bool_error!("Invalid type string: '{}'", type_string))
689            }
690        }
691    }
692
693    // rustdoc-stripper-ignore-next
694    /// Converts a type string into `&VariantTy` without any checks.
695    ///
696    /// # Safety
697    ///
698    /// The caller is responsible for passing in only a valid variant type string.
699    #[inline]
700    pub const unsafe fn from_str_unchecked(type_string: &str) -> &VariantTy {
701        std::mem::transmute::<&str, &VariantTy>(type_string)
702    }
703
704    // rustdoc-stripper-ignore-next
705    /// Creates `&VariantTy` with a wildcard lifetime from a `GVariantType`
706    /// pointer.
707    #[doc(hidden)]
708    #[allow(clippy::cast_slice_from_raw_parts)]
709    #[inline]
710    pub unsafe fn from_ptr<'a>(ptr: *const ffi::GVariantType) -> &'a VariantTy {
711        debug_assert!(!ptr.is_null());
712        let len: usize = ffi::g_variant_type_get_string_length(ptr) as _;
713        debug_assert!(len > 0);
714        &*(slice::from_raw_parts(ptr as *const u8, len) as *const [u8] as *const VariantTy)
715    }
716
717    // rustdoc-stripper-ignore-next
718    /// Returns a `GVariantType` pointer.
719    #[doc(hidden)]
720    #[inline]
721    pub fn as_ptr(&self) -> *const ffi::GVariantType {
722        self.inner.as_ptr() as *const _
723    }
724
725    // rustdoc-stripper-ignore-next
726    /// Converts to a string slice.
727    #[inline]
728    pub fn as_str(&self) -> &str {
729        &self.inner
730    }
731
732    // rustdoc-stripper-ignore-next
733    /// Check if this variant type is a definite type.
734    #[doc(alias = "g_variant_type_is_definite")]
735    pub fn is_definite(&self) -> bool {
736        unsafe { from_glib(ffi::g_variant_type_is_definite(self.to_glib_none().0)) }
737    }
738
739    // rustdoc-stripper-ignore-next
740    /// Check if this variant type is a container type.
741    #[doc(alias = "g_variant_type_is_container")]
742    pub fn is_container(&self) -> bool {
743        unsafe { from_glib(ffi::g_variant_type_is_container(self.to_glib_none().0)) }
744    }
745
746    // rustdoc-stripper-ignore-next
747    /// Check if this variant type is a basic type.
748    #[doc(alias = "g_variant_type_is_basic")]
749    pub fn is_basic(&self) -> bool {
750        unsafe { from_glib(ffi::g_variant_type_is_basic(self.to_glib_none().0)) }
751    }
752
753    // rustdoc-stripper-ignore-next
754    /// Check if this variant type is a maybe type.
755    #[doc(alias = "g_variant_type_is_maybe")]
756    pub fn is_maybe(&self) -> bool {
757        unsafe { from_glib(ffi::g_variant_type_is_maybe(self.to_glib_none().0)) }
758    }
759
760    // rustdoc-stripper-ignore-next
761    /// Check if this variant type is an array type.
762    #[doc(alias = "g_variant_type_is_array")]
763    pub fn is_array(&self) -> bool {
764        unsafe { from_glib(ffi::g_variant_type_is_array(self.to_glib_none().0)) }
765    }
766
767    // rustdoc-stripper-ignore-next
768    /// Check if this variant type is a tuple type.
769    #[doc(alias = "g_variant_type_is_tuple")]
770    pub fn is_tuple(&self) -> bool {
771        unsafe { from_glib(ffi::g_variant_type_is_tuple(self.to_glib_none().0)) }
772    }
773
774    // rustdoc-stripper-ignore-next
775    /// Check if this variant type is a dict entry type.
776    #[doc(alias = "g_variant_type_is_dict_entry")]
777    pub fn is_dict_entry(&self) -> bool {
778        unsafe { from_glib(ffi::g_variant_type_is_dict_entry(self.to_glib_none().0)) }
779    }
780
781    // rustdoc-stripper-ignore-next
782    /// Check if this variant type is a variant.
783    #[doc(alias = "g_variant_type_is_variant")]
784    pub fn is_variant(&self) -> bool {
785        unsafe { from_glib(ffi::g_variant_type_is_variant(self.to_glib_none().0)) }
786    }
787
788    // rustdoc-stripper-ignore-next
789    /// Check if this variant type is a subtype of another.
790    #[doc(alias = "g_variant_type_is_subtype_of")]
791    pub fn is_subtype_of(&self, supertype: &Self) -> bool {
792        unsafe {
793            from_glib(ffi::g_variant_type_is_subtype_of(
794                self.to_glib_none().0,
795                supertype.to_glib_none().0,
796            ))
797        }
798    }
799
800    // rustdoc-stripper-ignore-next
801    /// Return the element type of this variant type.
802    ///
803    /// # Panics
804    ///
805    /// This function panics if not called with an array or maybe type.
806    #[doc(alias = "g_variant_type_element")]
807    pub fn element(&self) -> &VariantTy {
808        assert!(self.is_array() || self.is_maybe());
809
810        unsafe {
811            let element = ffi::g_variant_type_element(self.to_glib_none().0);
812            Self::from_ptr(element)
813        }
814    }
815
816    // rustdoc-stripper-ignore-next
817    /// Iterate over the types of this variant type.
818    ///
819    /// # Panics
820    ///
821    /// This function panics if not called with a tuple or dictionary entry type.
822    pub fn tuple_types(&self) -> VariantTyIterator<'_> {
823        VariantTyIterator::new(self).expect("VariantTy does not represent a tuple")
824    }
825
826    // rustdoc-stripper-ignore-next
827    /// Return the first type of this variant type.
828    ///
829    /// # Panics
830    ///
831    /// This function panics if not called with a tuple or dictionary entry type.
832    #[doc(alias = "g_variant_type_first")]
833    pub fn first(&self) -> Option<&VariantTy> {
834        assert!(self.as_str().starts_with('(') || self.as_str().starts_with('{'));
835
836        unsafe {
837            let first = ffi::g_variant_type_first(self.to_glib_none().0);
838            if first.is_null() {
839                None
840            } else {
841                Some(Self::from_ptr(first))
842            }
843        }
844    }
845
846    // rustdoc-stripper-ignore-next
847    /// Return the next type of this variant type.
848    #[doc(alias = "g_variant_type_next")]
849    pub fn next(&self) -> Option<&VariantTy> {
850        unsafe {
851            let next = ffi::g_variant_type_next(self.to_glib_none().0);
852            if next.is_null() {
853                None
854            } else {
855                Some(Self::from_ptr(next))
856            }
857        }
858    }
859
860    // rustdoc-stripper-ignore-next
861    /// Return the number of items in this variant type.
862    #[doc(alias = "g_variant_type_n_items")]
863    pub fn n_items(&self) -> usize {
864        unsafe { ffi::g_variant_type_n_items(self.to_glib_none().0) }
865    }
866
867    // rustdoc-stripper-ignore-next
868    /// Return the key type of this variant type.
869    ///
870    /// # Panics
871    ///
872    /// This function panics if not called with a dictionary entry type.
873    #[doc(alias = "g_variant_type_key")]
874    pub fn key(&self) -> &VariantTy {
875        assert!(self.as_str().starts_with('{'));
876
877        unsafe {
878            let key = ffi::g_variant_type_key(self.to_glib_none().0);
879            Self::from_ptr(key)
880        }
881    }
882
883    // rustdoc-stripper-ignore-next
884    /// Return the value type of this variant type.
885    ///
886    /// # Panics
887    ///
888    /// This function panics if not called with a dictionary entry type.
889    #[doc(alias = "g_variant_type_value")]
890    pub fn value(&self) -> &VariantTy {
891        assert!(self.as_str().starts_with('{'));
892
893        unsafe {
894            let value = ffi::g_variant_type_value(self.to_glib_none().0);
895            Self::from_ptr(value)
896        }
897    }
898
899    // rustdoc-stripper-ignore-next
900    /// Return this type as an array.
901    pub(crate) fn as_array<'a>(&self) -> Cow<'a, VariantTy> {
902        if self == VariantTy::STRING {
903            Cow::Borrowed(VariantTy::STRING_ARRAY)
904        } else if self == VariantTy::BYTE {
905            Cow::Borrowed(VariantTy::BYTE_STRING)
906        } else if self == VariantTy::BYTE_STRING {
907            Cow::Borrowed(VariantTy::BYTE_STRING_ARRAY)
908        } else if self == VariantTy::OBJECT_PATH {
909            Cow::Borrowed(VariantTy::OBJECT_PATH_ARRAY)
910        } else if self == VariantTy::DICT_ENTRY {
911            Cow::Borrowed(VariantTy::DICTIONARY)
912        } else {
913            Cow::Owned(VariantType::new_array(self))
914        }
915    }
916}
917
918unsafe impl Sync for VariantTy {}
919
920#[doc(hidden)]
921impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantTy {
922    type Storage = PhantomData<&'a Self>;
923
924    #[inline]
925    fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> {
926        Stash(self.as_ptr(), PhantomData)
927    }
928}
929
930impl fmt::Display for VariantTy {
931    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
932        f.write_str(self.as_str())
933    }
934}
935
936impl<'a> From<&'a VariantTy> for Cow<'a, VariantTy> {
937    #[inline]
938    fn from(ty: &'a VariantTy) -> Cow<'a, VariantTy> {
939        Cow::Borrowed(ty)
940    }
941}
942
943impl AsRef<VariantTy> for VariantTy {
944    #[inline]
945    fn as_ref(&self) -> &Self {
946        self
947    }
948}
949
950impl ToOwned for VariantTy {
951    type Owned = VariantType;
952
953    #[inline]
954    fn to_owned(&self) -> VariantType {
955        unsafe {
956            VariantType {
957                ptr: ptr::NonNull::new_unchecked(ffi::g_variant_type_copy(self.as_ptr())),
958                len: self.inner.len(),
959            }
960        }
961    }
962}
963
964impl StaticType for VariantTy {
965    #[inline]
966    fn static_type() -> Type {
967        unsafe { from_glib(ffi::g_variant_type_get_gtype()) }
968    }
969}
970
971#[doc(hidden)]
972unsafe impl<'a> crate::value::FromValue<'a> for &'a VariantTy {
973    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
974
975    unsafe fn from_value(value: &'a crate::Value) -> Self {
976        let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0);
977        debug_assert!(!ptr.is_null());
978        VariantTy::from_ptr(ptr as *const ffi::GVariantType)
979    }
980}
981
982#[doc(hidden)]
983impl crate::value::ToValue for VariantTy {
984    fn to_value(&self) -> crate::Value {
985        unsafe {
986            let mut value = crate::Value::from_type_unchecked(VariantTy::static_type());
987            gobject_ffi::g_value_set_boxed(
988                value.to_glib_none_mut().0,
989                self.to_glib_none().0 as *mut _,
990            );
991            value
992        }
993    }
994
995    fn value_type(&self) -> crate::Type {
996        VariantTy::static_type()
997    }
998}
999
1000#[doc(hidden)]
1001impl crate::value::ToValue for &VariantTy {
1002    fn to_value(&self) -> crate::Value {
1003        (*self).to_value()
1004    }
1005
1006    #[inline]
1007    fn value_type(&self) -> crate::Type {
1008        VariantTy::static_type()
1009    }
1010}
1011
1012#[doc(hidden)]
1013impl crate::value::ToValueOptional for &VariantTy {
1014    fn to_value_optional(s: Option<&Self>) -> crate::Value {
1015        let mut value = crate::Value::for_value_type::<VariantType>();
1016        unsafe {
1017            gobject_ffi::g_value_set_boxed(
1018                value.to_glib_none_mut().0,
1019                s.to_glib_none().0 as *mut _,
1020            );
1021        }
1022
1023        value
1024    }
1025}
1026
1027impl StaticType for VariantType {
1028    #[inline]
1029    fn static_type() -> Type {
1030        unsafe { from_glib(ffi::g_variant_type_get_gtype()) }
1031    }
1032}
1033
1034#[doc(hidden)]
1035impl crate::value::ValueType for VariantType {
1036    type Type = VariantType;
1037}
1038
1039#[doc(hidden)]
1040impl crate::value::ValueTypeOptional for VariantType {}
1041
1042#[doc(hidden)]
1043unsafe impl<'a> crate::value::FromValue<'a> for VariantType {
1044    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
1045
1046    unsafe fn from_value(value: &'a crate::Value) -> Self {
1047        let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0);
1048        debug_assert!(!ptr.is_null());
1049        from_glib_none(ptr as *const ffi::GVariantType)
1050    }
1051}
1052
1053#[doc(hidden)]
1054impl crate::value::ToValue for VariantType {
1055    fn to_value(&self) -> crate::Value {
1056        unsafe {
1057            let mut value = crate::Value::from_type_unchecked(VariantType::static_type());
1058            gobject_ffi::g_value_set_boxed(
1059                value.to_glib_none_mut().0,
1060                ToGlibPtr::<*mut _>::to_glib_none(&self).0 as *mut _,
1061            );
1062            value
1063        }
1064    }
1065
1066    fn value_type(&self) -> crate::Type {
1067        VariantType::static_type()
1068    }
1069}
1070
1071#[doc(hidden)]
1072impl From<VariantType> for crate::Value {
1073    fn from(t: VariantType) -> Self {
1074        unsafe {
1075            let mut value = crate::Value::from_type_unchecked(VariantType::static_type());
1076            gobject_ffi::g_value_take_boxed(
1077                value.to_glib_none_mut().0,
1078                IntoGlibPtr::<*mut _>::into_glib_ptr(t) as *mut _,
1079            );
1080            value
1081        }
1082    }
1083}
1084
1085#[doc(hidden)]
1086impl crate::value::ToValueOptional for VariantType {
1087    fn to_value_optional(s: Option<&Self>) -> crate::Value {
1088        let mut value = crate::Value::for_value_type::<Self>();
1089        unsafe {
1090            gobject_ffi::g_value_set_boxed(
1091                value.to_glib_none_mut().0,
1092                ToGlibPtr::<*mut _>::to_glib_none(&s).0 as *mut _,
1093            );
1094        }
1095
1096        value
1097    }
1098}
1099
1100impl PartialEq for VariantType {
1101    #[inline]
1102    fn eq(&self, other: &Self) -> bool {
1103        <VariantTy as PartialEq>::eq(self, other)
1104    }
1105}
1106
1107macro_rules! impl_eq {
1108    ($lhs:ty, $rhs: ty) => {
1109        #[allow(clippy::extra_unused_lifetimes)]
1110        impl<'a, 'b> PartialEq<$rhs> for $lhs {
1111            #[inline]
1112            fn eq(&self, other: &$rhs) -> bool {
1113                <VariantTy as PartialEq>::eq(self, other)
1114            }
1115        }
1116
1117        #[allow(clippy::extra_unused_lifetimes)]
1118        impl<'a, 'b> PartialEq<$lhs> for $rhs {
1119            #[inline]
1120            fn eq(&self, other: &$lhs) -> bool {
1121                <VariantTy as PartialEq>::eq(self, other)
1122            }
1123        }
1124    };
1125}
1126
1127impl_eq!(VariantType, VariantTy);
1128impl_eq!(VariantType, &'a VariantTy);
1129impl_eq!(VariantType, Cow<'a, VariantTy>);
1130impl_eq!(&'a VariantTy, Cow<'b, VariantTy>);
1131
1132macro_rules! impl_str_eq {
1133    ($lhs:ty, $rhs: ty) => {
1134        #[allow(clippy::redundant_slicing)]
1135        #[allow(clippy::extra_unused_lifetimes)]
1136        impl<'a, 'b> PartialEq<$rhs> for $lhs {
1137            #[inline]
1138            fn eq(&self, other: &$rhs) -> bool {
1139                self.as_str().eq(&other[..])
1140            }
1141        }
1142
1143        #[allow(clippy::extra_unused_lifetimes)]
1144        impl<'a, 'b> PartialEq<$lhs> for $rhs {
1145            #[inline]
1146            fn eq(&self, other: &$lhs) -> bool {
1147                self[..].eq(other.as_str())
1148            }
1149        }
1150    };
1151}
1152
1153impl_str_eq!(VariantTy, str);
1154impl_str_eq!(VariantTy, &'a str);
1155impl_str_eq!(&'a VariantTy, str);
1156impl_str_eq!(VariantTy, String);
1157impl_str_eq!(&'a VariantTy, String);
1158impl_str_eq!(VariantType, str);
1159impl_str_eq!(VariantType, &'a str);
1160impl_str_eq!(VariantType, String);
1161
1162impl Eq for VariantType {}
1163
1164// rustdoc-stripper-ignore-next
1165/// An iterator over the individual components of a tuple [VariantTy].
1166///
1167/// This can be conveniently constructed using [VariantTy::tuple_types].
1168#[derive(Debug, Copy, Clone)]
1169pub struct VariantTyIterator<'a> {
1170    elem: Option<&'a VariantTy>,
1171}
1172
1173impl<'a> VariantTyIterator<'a> {
1174    // rustdoc-stripper-ignore-next
1175    /// Creates a new iterator over the types of the specified [VariantTy].
1176    ///
1177    /// Returns `Ok` if the type is a definite tuple or dictionary entry type,
1178    /// `Err` otherwise.
1179    pub fn new(ty: &'a VariantTy) -> Result<Self, BoolError> {
1180        if (ty.is_tuple() && ty != VariantTy::TUPLE) || ty.is_dict_entry() {
1181            Ok(Self { elem: ty.first() })
1182        } else {
1183            Err(bool_error!(
1184                "Expected a definite tuple or dictionary entry type"
1185            ))
1186        }
1187    }
1188}
1189
1190impl<'a> Iterator for VariantTyIterator<'a> {
1191    type Item = &'a VariantTy;
1192
1193    #[doc(alias = "g_variant_type_next")]
1194    fn next(&mut self) -> Option<Self::Item> {
1195        let elem = self.elem?;
1196        self.elem = elem.next();
1197        Some(elem)
1198    }
1199}
1200
1201impl iter::FusedIterator for VariantTyIterator<'_> {}
1202
1203#[cfg(test)]
1204mod tests {
1205    use super::*;
1206
1207    unsafe fn equal<T, U>(ptr1: *const T, ptr2: *const U) -> bool {
1208        from_glib(ffi::g_variant_type_equal(
1209            ptr1 as *const _,
1210            ptr2 as *const _,
1211        ))
1212    }
1213
1214    #[test]
1215    fn new() {
1216        let ty = VariantTy::new("((iii)s)").unwrap();
1217        unsafe {
1218            assert!(equal(ty.as_ptr(), b"((iii)s)\0" as *const u8));
1219        }
1220    }
1221
1222    #[test]
1223    fn new_empty() {
1224        assert!(VariantTy::new("").is_err());
1225    }
1226
1227    #[test]
1228    fn new_with_nul() {
1229        assert!(VariantTy::new("((iii\0)s)").is_err());
1230    }
1231
1232    #[test]
1233    fn new_too_short() {
1234        assert!(VariantTy::new("((iii").is_err());
1235    }
1236
1237    #[test]
1238    fn new_too_long() {
1239        assert!(VariantTy::new("(iii)s").is_err());
1240    }
1241
1242    #[test]
1243    fn eq() {
1244        let ty1 = VariantTy::new("((iii)s)").unwrap();
1245        let ty2 = VariantTy::new("((iii)s)").unwrap();
1246        assert_eq!(ty1, ty2);
1247        assert_eq!(ty1, "((iii)s)");
1248        unsafe {
1249            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
1250        }
1251    }
1252
1253    #[test]
1254    fn ne() {
1255        let ty1 = VariantTy::new("((iii)s)").unwrap();
1256        let ty2 = VariantTy::new("((iii)o)").unwrap();
1257        assert_ne!(ty1, ty2);
1258        assert_ne!(ty1, "((iii)o)");
1259        unsafe {
1260            assert!(!equal(ty1.as_ptr(), ty2.as_ptr()));
1261        }
1262    }
1263
1264    #[test]
1265    fn from_bytes() {
1266        unsafe {
1267            let ty = VariantTy::from_ptr(b"((iii)s)" as *const u8 as *const _);
1268            assert_eq!(ty, "((iii)s)");
1269            assert!(equal(ty.as_ptr(), "((iii)s)".as_ptr()));
1270        }
1271    }
1272
1273    #[test]
1274    fn to_owned() {
1275        let ty1 = VariantTy::new("((iii)s)").unwrap();
1276        let ty2 = ty1.to_owned();
1277        assert_eq!(ty1, ty2);
1278        assert_eq!(ty2, "((iii)s)");
1279        unsafe {
1280            assert!(equal(ty1.as_ptr(), ty2.as_ptr()));
1281        }
1282    }
1283
1284    #[test]
1285    fn value() {
1286        let ty1 = VariantType::new("*").unwrap();
1287        let tyv = ty1.to_value();
1288        let ty2 = tyv.get::<VariantType>().unwrap();
1289        assert_eq!(ty1, ty2);
1290
1291        let ty3 = VariantTy::new("*").unwrap();
1292        let tyv2 = ty3.to_value();
1293        let ty4 = tyv2.get::<VariantType>().unwrap();
1294        assert_eq!(ty3, ty4);
1295
1296        let ty5 = VariantTy::ANY;
1297        let tyv3 = ty5.to_value();
1298        let ty6 = tyv3.get::<VariantType>().unwrap();
1299        assert_eq!(ty5, ty6);
1300    }
1301
1302    #[test]
1303    fn type_() {
1304        assert_eq!(VariantTy::static_type(), VariantType::static_type())
1305    }
1306
1307    #[test]
1308    fn tuple_iter() {
1309        let ty = VariantTy::new("((iii)s)").unwrap();
1310        let types: Vec<_> = ty.tuple_types().map(|t| t.as_str()).collect();
1311        assert_eq!(&types, &["(iii)", "s"]);
1312    }
1313}