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