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}