Skip to main content

glib/
variant.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! `Variant` binding and helper traits.
5//!
6//! [`Variant`](struct.Variant.html) is an immutable dynamically-typed generic
7//! container. Its type and value are defined at construction and never change.
8//!
9//! `Variant` types are described by [`VariantType`](../struct.VariantType.html)
10//! "type strings".
11//!
12//! `GVariant` supports arbitrarily complex types built from primitives like integers, floating point
13//! numbers, strings, arrays, tuples and dictionaries. See [`ToVariant#foreign-impls`] for
14//! a full list of supported types. You may also implement [`ToVariant`] and [`FromVariant`]
15//! manually, or derive them using the [`Variant`](derive@crate::Variant) derive macro.
16//!
17//! # Examples
18//!
19//! ```
20//! use glib::prelude::*; // or `use gtk::prelude::*;`
21//! use glib::variant::{Variant, FromVariant};
22//! use std::collections::HashMap;
23//!
24//! // Using the `ToVariant` trait.
25//! let num = 10.to_variant();
26//!
27//! // `is` tests the type of the value.
28//! assert!(num.is::<i32>());
29//!
30//! // `get` tries to extract the value.
31//! assert_eq!(num.get::<i32>(), Some(10));
32//! assert_eq!(num.get::<u32>(), None);
33//!
34//! // `get_str` tries to borrow a string slice.
35//! let hello = "Hello!".to_variant();
36//! assert_eq!(hello.str(), Some("Hello!"));
37//! assert_eq!(num.str(), None);
38//!
39//! // `fixed_array` tries to borrow a fixed size array (u8, bool, i16, etc.),
40//! // rather than creating a deep copy which would be expensive for
41//! // nontrivially sized arrays of fixed size elements.
42//! // The test data here is the zstd compression header, which
43//! // stands in for arbitrary binary data (e.g. not UTF-8).
44//! let bufdata = b"\xFD\x2F\xB5\x28";
45//! let bufv = glib::Variant::array_from_fixed_array(&bufdata[..]);
46//! assert_eq!(bufv.fixed_array::<u8>().unwrap(), bufdata);
47//! assert!(num.fixed_array::<u8>().is_err());
48//!
49//! // Variant carrying a Variant
50//! let variant = Variant::from_variant(&hello);
51//! let variant = variant.as_variant().unwrap();
52//! assert_eq!(variant.str(), Some("Hello!"));
53//!
54//! // Variant carrying an array
55//! let array = ["Hello", "there!"];
56//! let variant = array.into_iter().collect::<Variant>();
57//! assert_eq!(variant.n_children(), 2);
58//! assert_eq!(variant.child_value(0).str(), Some("Hello"));
59//! assert_eq!(variant.child_value(1).str(), Some("there!"));
60//!
61//! // You can also convert from and to a Vec
62//! let variant = vec!["Hello", "there!"].to_variant();
63//! assert_eq!(variant.n_children(), 2);
64//! let vec = <Vec<String>>::from_variant(&variant).unwrap();
65//! assert_eq!(vec[0], "Hello");
66//!
67//! // Conversion to and from HashMap and BTreeMap is also possible
68//! let mut map: HashMap<u16, &str> = HashMap::new();
69//! map.insert(1, "hi");
70//! map.insert(2, "there");
71//! let variant = map.to_variant();
72//! assert_eq!(variant.n_children(), 2);
73//! let map: HashMap<u16, String> = HashMap::from_variant(&variant).unwrap();
74//! assert_eq!(map[&1], "hi");
75//! assert_eq!(map[&2], "there");
76//!
77//! // And conversion to and from tuples.
78//! let variant = ("hello", 42u16, vec![ "there", "you" ],).to_variant();
79//! assert_eq!(variant.n_children(), 3);
80//! assert_eq!(variant.type_().as_str(), "(sqas)");
81//! let tuple = <(String, u16, Vec<String>)>::from_variant(&variant).unwrap();
82//! assert_eq!(tuple.0, "hello");
83//! assert_eq!(tuple.1, 42);
84//! assert_eq!(tuple.2, &[ "there", "you"]);
85//!
86//! // `Option` is supported as well, through maybe types
87//! let variant = Some("hello").to_variant();
88//! assert_eq!(variant.n_children(), 1);
89//! let mut s = <Option<String>>::from_variant(&variant).unwrap();
90//! assert_eq!(s.unwrap(), "hello");
91//! s = None;
92//! let variant = s.to_variant();
93//! assert_eq!(variant.n_children(), 0);
94//! let s = <Option<String>>::from_variant(&variant).unwrap();
95//! assert!(s.is_none());
96//!
97//! // Paths may be converted, too. Please note the portability warning above!
98//! use std::path::{Path, PathBuf};
99//! let path = Path::new("foo/bar");
100//! let path_variant = path.to_variant();
101//! assert_eq!(PathBuf::from_variant(&path_variant).as_deref(), Some(path));
102//! ```
103
104use std::{
105    borrow::Cow,
106    cmp::Ordering,
107    collections::{BTreeMap, HashMap},
108    fmt,
109    fmt::Display,
110    hash::{BuildHasher, Hash, Hasher},
111    mem, ptr, slice, str,
112};
113
114use crate::{
115    Bytes, Type, VariantIter, VariantStrIter, VariantTy, VariantType, ffi, gobject_ffi, prelude::*,
116    translate::*,
117};
118
119wrapper! {
120    // rustdoc-stripper-ignore-next
121    /// A generic immutable value capable of carrying various types.
122    ///
123    /// See the [module documentation](index.html) for more details.
124    // rustdoc-stripper-ignore-next-stop
125    ///  the one referring to the
126    /// dictionary.
127    ///
128    /// If calls are made to start accessing the other values then
129    /// `GVariant` instances will exist for those values only for as long
130    /// as they are in use (ie: until you call `GLib::Variant::unref()`).  The
131    /// type information is shared.  The serialized data and the buffer
132    /// management structure for that serialized data is shared by the
133    /// child.
134    ///
135    /// ## Summary
136    ///
137    /// To put the entire example together, for our dictionary mapping
138    /// strings to variants (with two entries, as given above), we are
139    /// using 91 bytes of memory for type information, 29 bytes of memory
140    /// for the serialized data, 16 bytes for buffer management and 24
141    /// bytes for the `GVariant` instance, or a total of 160 bytes, plus
142    /// allocation overhead.  If we were to use [`child_value()`][Self::child_value()]
143    /// to access the two dictionary entries, we would use an additional 48
144    /// bytes.  If we were to have other dictionaries of the same type, we
145    /// would use more memory for the serialized data and buffer
146    /// management for those dictionaries, but the type information would
147    /// be shared.
148    #[doc(alias = "GVariant")]
149    pub struct Variant(Shared<ffi::GVariant>);
150
151    match fn {
152        ref => |ptr| ffi::g_variant_ref_sink(ptr),
153        unref => |ptr| ffi::g_variant_unref(ptr),
154    }
155}
156
157impl StaticType for Variant {
158    #[inline]
159    fn static_type() -> Type {
160        Type::VARIANT
161    }
162}
163
164#[doc(hidden)]
165impl crate::value::ValueType for Variant {
166    type Type = Variant;
167}
168
169#[doc(hidden)]
170impl crate::value::ValueTypeOptional for Variant {}
171
172#[doc(hidden)]
173unsafe impl<'a> crate::value::FromValue<'a> for Variant {
174    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
175
176    unsafe fn from_value(value: &'a crate::Value) -> Self {
177        unsafe {
178            let ptr = gobject_ffi::g_value_dup_variant(value.to_glib_none().0);
179            debug_assert!(!ptr.is_null());
180            from_glib_full(ptr)
181        }
182    }
183}
184
185#[doc(hidden)]
186impl crate::value::ToValue for Variant {
187    fn to_value(&self) -> crate::Value {
188        unsafe {
189            let mut value = crate::Value::from_type_unchecked(Variant::static_type());
190            gobject_ffi::g_value_take_variant(value.to_glib_none_mut().0, self.to_glib_full());
191            value
192        }
193    }
194
195    fn value_type(&self) -> crate::Type {
196        Variant::static_type()
197    }
198}
199
200#[doc(hidden)]
201impl From<Variant> for crate::Value {
202    #[inline]
203    fn from(v: Variant) -> Self {
204        unsafe {
205            let mut value = crate::Value::from_type_unchecked(Variant::static_type());
206            gobject_ffi::g_value_take_variant(value.to_glib_none_mut().0, v.into_glib_ptr());
207            value
208        }
209    }
210}
211
212#[doc(hidden)]
213impl crate::value::ToValueOptional for Variant {
214    fn to_value_optional(s: Option<&Self>) -> crate::Value {
215        let mut value = crate::Value::for_value_type::<Self>();
216        unsafe {
217            gobject_ffi::g_value_take_variant(value.to_glib_none_mut().0, s.to_glib_full());
218        }
219
220        value
221    }
222}
223
224// rustdoc-stripper-ignore-next
225/// An error returned from the [`try_get`](struct.Variant.html#method.try_get) function
226/// on a [`Variant`](struct.Variant.html) when the expected type does not match the actual type.
227#[derive(Clone, PartialEq, Eq, Debug)]
228pub struct VariantTypeMismatchError {
229    pub actual: VariantType,
230    pub expected: VariantType,
231}
232
233impl VariantTypeMismatchError {
234    pub fn new(actual: VariantType, expected: VariantType) -> Self {
235        Self { actual, expected }
236    }
237}
238
239impl fmt::Display for VariantTypeMismatchError {
240    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        write!(
242            f,
243            "Type mismatch: Expected '{}' got '{}'",
244            self.expected, self.actual
245        )
246    }
247}
248
249impl std::error::Error for VariantTypeMismatchError {}
250
251impl Variant {
252    // rustdoc-stripper-ignore-next
253    /// Returns the type of the value.
254    // rustdoc-stripper-ignore-next-stop
255    /// Determines the type of @self.
256    ///
257    /// The return value is valid for the lifetime of @self and must not
258    /// be freed.
259    ///
260    /// # Returns
261    ///
262    /// a #GVariantType
263    #[doc(alias = "g_variant_get_type")]
264    pub fn type_(&self) -> &VariantTy {
265        unsafe { VariantTy::from_ptr(ffi::g_variant_get_type(self.to_glib_none().0)) }
266    }
267
268    // rustdoc-stripper-ignore-next
269    /// Returns `true` if the type of the value corresponds to `T`.
270    #[inline]
271    #[doc(alias = "g_variant_is_of_type")]
272    pub fn is<T: StaticVariantType>(&self) -> bool {
273        self.is_type(&T::static_variant_type())
274    }
275
276    // rustdoc-stripper-ignore-next
277    /// Returns `true` if the type of the value corresponds to `type_`.
278    ///
279    /// This is equivalent to [`self.type_().is_subtype_of(type_)`](VariantTy::is_subtype_of).
280    #[inline]
281    #[doc(alias = "g_variant_is_of_type")]
282    pub fn is_type(&self, type_: &VariantTy) -> bool {
283        unsafe {
284            from_glib(ffi::g_variant_is_of_type(
285                self.to_glib_none().0,
286                type_.to_glib_none().0,
287            ))
288        }
289    }
290
291    // rustdoc-stripper-ignore-next
292    /// Returns the classification of the variant.
293    // rustdoc-stripper-ignore-next-stop
294    /// Classifies @self according to its top-level type.
295    ///
296    /// # Returns
297    ///
298    /// the #GVariantClass of @self
299    #[doc(alias = "g_variant_classify")]
300    pub fn classify(&self) -> crate::VariantClass {
301        unsafe { from_glib(ffi::g_variant_classify(self.to_glib_none().0)) }
302    }
303
304    // rustdoc-stripper-ignore-next
305    /// Tries to extract a value of type `T`.
306    ///
307    /// Returns `Some` if `T` matches the variant's type.
308    // rustdoc-stripper-ignore-next-stop
309    /// Deconstructs a #GVariant instance.
310    ///
311    /// Think of this function as an analogue to scanf().
312    ///
313    /// The arguments that are expected by this function are entirely
314    /// determined by @format_string.  @format_string also restricts the
315    /// permissible types of @self.  It is an error to give a value with
316    /// an incompatible type.  See the section on
317    /// [GVariant format strings](gvariant-format-strings.html).
318    /// Please note that the syntax of the format string is very likely to be
319    /// extended in the future.
320    ///
321    /// @format_string determines the C types that are used for unpacking
322    /// the values and also determines if the values are copied or borrowed,
323    /// see the section on
324    /// [`GVariant` format strings](gvariant-format-strings.html#pointers).
325    /// ## `format_string`
326    /// a #GVariant format string
327    #[inline]
328    pub fn get<T: FromVariant>(&self) -> Option<T> {
329        T::from_variant(self)
330    }
331
332    // rustdoc-stripper-ignore-next
333    /// Tries to extract a value of type `T`.
334    pub fn try_get<T: FromVariant>(&self) -> Result<T, VariantTypeMismatchError> {
335        self.get().ok_or_else(|| {
336            VariantTypeMismatchError::new(
337                self.type_().to_owned(),
338                T::static_variant_type().into_owned(),
339            )
340        })
341    }
342
343    // rustdoc-stripper-ignore-next
344    /// Boxes value.
345    #[inline]
346    pub fn from_variant(value: &Variant) -> Self {
347        unsafe { from_glib_none(ffi::g_variant_new_variant(value.to_glib_none().0)) }
348    }
349
350    // rustdoc-stripper-ignore-next
351    /// Unboxes self.
352    ///
353    /// Returns `Some` if self contains a `Variant`.
354    #[inline]
355    #[doc(alias = "get_variant")]
356    pub fn as_variant(&self) -> Option<Variant> {
357        unsafe { from_glib_full(ffi::g_variant_get_variant(self.to_glib_none().0)) }
358    }
359
360    // rustdoc-stripper-ignore-next
361    /// Reads a child item out of a container `Variant` instance.
362    ///
363    /// # Panics
364    ///
365    /// * if `self` is not a container type.
366    /// * if given `index` is larger than number of children.
367    // rustdoc-stripper-ignore-next-stop
368    /// Reads a child item out of a container #GVariant instance.  This
369    /// includes variants, maybes, arrays, tuples and dictionary
370    /// entries.  It is an error to call this function on any other type of
371    /// #GVariant.
372    ///
373    /// It is an error if @index_ is greater than the number of child items
374    /// in the container.  See g_variant_n_children().
375    ///
376    /// The returned value is never floating.  You should free it with
377    /// g_variant_unref() when you're done with it.
378    ///
379    /// Note that values borrowed from the returned child are not guaranteed to
380    /// still be valid after the child is freed even if you still hold a reference
381    /// to @self, if @self has not been serialized at the time this function is
382    /// called. To avoid this, you can serialize @self by calling
383    /// g_variant_get_data() and optionally ignoring the return value.
384    ///
385    /// There may be implementation specific restrictions on deeply nested values,
386    /// which would result in the unit tuple being returned as the child value,
387    /// instead of further nested children. #GVariant is guaranteed to handle
388    /// nesting up to at least 64 levels.
389    ///
390    /// This function is O(1).
391    /// ## `index_`
392    /// the index of the child to fetch
393    ///
394    /// # Returns
395    ///
396    /// the child at the specified index
397    #[doc(alias = "get_child_value")]
398    #[doc(alias = "g_variant_get_child_value")]
399    #[must_use]
400    pub fn child_value(&self, index: usize) -> Variant {
401        assert!(self.is_container());
402        assert!(index < self.n_children());
403
404        unsafe { from_glib_full(ffi::g_variant_get_child_value(self.to_glib_none().0, index)) }
405    }
406
407    // rustdoc-stripper-ignore-next
408    /// Try to read a child item out of a container `Variant` instance.
409    ///
410    /// It returns `None` if `self` is not a container type or if the given
411    /// `index` is larger than number of children.
412    pub fn try_child_value(&self, index: usize) -> Option<Variant> {
413        if !(self.is_container() && index < self.n_children()) {
414            return None;
415        }
416
417        let v =
418            unsafe { from_glib_full(ffi::g_variant_get_child_value(self.to_glib_none().0, index)) };
419        Some(v)
420    }
421
422    // rustdoc-stripper-ignore-next
423    /// Try to read a child item out of a container `Variant` instance.
424    ///
425    /// It returns `Ok(None)` if `self` is not a container type or if the given
426    /// `index` is larger than number of children.  An error is thrown if the
427    /// type does not match.
428    pub fn try_child_get<T: StaticVariantType + FromVariant>(
429        &self,
430        index: usize,
431    ) -> Result<Option<T>, VariantTypeMismatchError> {
432        // TODO: In the future optimize this by using g_variant_get_child()
433        // directly to avoid allocating a GVariant.
434        self.try_child_value(index).map(|v| v.try_get()).transpose()
435    }
436
437    // rustdoc-stripper-ignore-next
438    /// Read a child item out of a container `Variant` instance.
439    ///
440    /// # Panics
441    ///
442    /// * if `self` is not a container type.
443    /// * if given `index` is larger than number of children.
444    /// * if the expected variant type does not match
445    pub fn child_get<T: StaticVariantType + FromVariant>(&self, index: usize) -> T {
446        // TODO: In the future optimize this by using g_variant_get_child()
447        // directly to avoid allocating a GVariant.
448        self.child_value(index).get().unwrap()
449    }
450
451    // rustdoc-stripper-ignore-next
452    /// Tries to extract a `&str`.
453    ///
454    /// Returns `Some` if the variant has a string type (`s`, `o` or `g` type
455    /// strings).
456    #[doc(alias = "get_str")]
457    #[doc(alias = "g_variant_get_string")]
458    pub fn str(&self) -> Option<&str> {
459        unsafe {
460            match self.type_().as_str() {
461                "s" | "o" | "g" => {
462                    let mut len = 0;
463                    let ptr = ffi::g_variant_get_string(self.to_glib_none().0, &mut len);
464                    if len == 0 {
465                        Some("")
466                    } else {
467                        let ret = str::from_utf8_unchecked(slice::from_raw_parts(
468                            ptr as *const u8,
469                            len as _,
470                        ));
471                        Some(ret)
472                    }
473                }
474                _ => None,
475            }
476        }
477    }
478
479    // rustdoc-stripper-ignore-next
480    /// Tries to extract a `&[T]` from a variant of array type with a suitable element type.
481    ///
482    /// Returns an error if the type is wrong.
483    // rustdoc-stripper-ignore-next-stop
484    /// Provides access to the serialized data for an array of fixed-sized
485    /// items.
486    ///
487    /// @self must be an array with fixed-sized elements.  Numeric types are
488    /// fixed-size, as are tuples containing only other fixed-sized types.
489    ///
490    /// @element_size must be the size of a single element in the array,
491    /// as given by the section on
492    /// [serialized data memory](struct.Variant.html#serialized-data-memory).
493    ///
494    /// In particular, arrays of these fixed-sized types can be interpreted
495    /// as an array of the given C type, with @element_size set to the size
496    /// the appropriate type:
497    ///
498    /// - `G_VARIANT_TYPE_INT16` (etc.): #gint16 (etc.)
499    /// - `G_VARIANT_TYPE_BOOLEAN`: #guchar (not #gboolean!)
500    /// - `G_VARIANT_TYPE_BYTE`: #guint8
501    /// - `G_VARIANT_TYPE_HANDLE`: #guint32
502    /// - `G_VARIANT_TYPE_DOUBLE`: #gdouble
503    ///
504    /// For example, if calling this function for an array of 32-bit integers,
505    /// you might say `sizeof(gint32)`. This value isn't used except for the purpose
506    /// of a double-check that the form of the serialized data matches the caller's
507    /// expectation.
508    ///
509    /// @n_elements, which must be non-[`None`], is set equal to the number of
510    /// items in the array.
511    /// ## `element_size`
512    /// the size of each element
513    ///
514    /// # Returns
515    ///
516    /// a pointer to
517    ///     the fixed array
518    #[doc(alias = "g_variant_get_fixed_array")]
519    pub fn fixed_array<T: FixedSizeVariantType>(&self) -> Result<&[T], VariantTypeMismatchError> {
520        unsafe {
521            let expected_ty = T::static_variant_type().as_array();
522            if self.type_() != expected_ty {
523                return Err(VariantTypeMismatchError {
524                    actual: self.type_().to_owned(),
525                    expected: expected_ty.into_owned(),
526                });
527            }
528
529            let mut n_elements = mem::MaybeUninit::uninit();
530            let ptr = ffi::g_variant_get_fixed_array(
531                self.to_glib_none().0,
532                n_elements.as_mut_ptr(),
533                mem::size_of::<T>(),
534            );
535
536            let n_elements = n_elements.assume_init();
537            if n_elements == 0 {
538                Ok(&[])
539            } else {
540                debug_assert!(!ptr.is_null());
541                Ok(slice::from_raw_parts(ptr as *const T, n_elements))
542            }
543        }
544    }
545
546    // rustdoc-stripper-ignore-next
547    /// Creates a new Variant array from children.
548    ///
549    /// # Panics
550    ///
551    /// This function panics if not all variants are of type `T`.
552    #[doc(alias = "g_variant_new_array")]
553    pub fn array_from_iter<T: StaticVariantType>(
554        children: impl IntoIterator<Item = Variant>,
555    ) -> Self {
556        Self::array_from_iter_with_type(&T::static_variant_type(), children)
557    }
558
559    // rustdoc-stripper-ignore-next
560    /// Creates a new Variant array from children with the specified type.
561    ///
562    /// # Panics
563    ///
564    /// This function panics if not all variants are of type `type_`.
565    #[doc(alias = "g_variant_new_array")]
566    pub fn array_from_iter_with_type(
567        type_: &VariantTy,
568        children: impl IntoIterator<Item = impl AsRef<Variant>>,
569    ) -> Self {
570        unsafe {
571            let mut builder = mem::MaybeUninit::uninit();
572            ffi::g_variant_builder_init(builder.as_mut_ptr(), type_.as_array().to_glib_none().0);
573            let mut builder = builder.assume_init();
574            for value in children.into_iter() {
575                let value = value.as_ref();
576                if ffi::g_variant_is_of_type(value.to_glib_none().0, type_.to_glib_none().0)
577                    == ffi::GFALSE
578                {
579                    ffi::g_variant_builder_clear(&mut builder);
580                    assert!(value.is_type(type_));
581                }
582
583                ffi::g_variant_builder_add_value(&mut builder, value.to_glib_none().0);
584            }
585            from_glib_none(ffi::g_variant_builder_end(&mut builder))
586        }
587    }
588
589    // rustdoc-stripper-ignore-next
590    /// Creates a new Variant array from a fixed array.
591    #[doc(alias = "g_variant_new_fixed_array")]
592    pub fn array_from_fixed_array<T: FixedSizeVariantType>(array: &[T]) -> Self {
593        let type_ = T::static_variant_type();
594
595        unsafe {
596            from_glib_none(ffi::g_variant_new_fixed_array(
597                type_.as_ptr(),
598                array.as_ptr() as ffi::gconstpointer,
599                array.len(),
600                mem::size_of::<T>(),
601            ))
602        }
603    }
604
605    // rustdoc-stripper-ignore-next
606    /// Creates a new Variant tuple from children.
607    #[doc(alias = "g_variant_new_tuple")]
608    pub fn tuple_from_iter(children: impl IntoIterator<Item = impl AsRef<Variant>>) -> Self {
609        unsafe {
610            let mut builder = mem::MaybeUninit::uninit();
611            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::TUPLE.to_glib_none().0);
612            let mut builder = builder.assume_init();
613            for value in children.into_iter() {
614                ffi::g_variant_builder_add_value(&mut builder, value.as_ref().to_glib_none().0);
615            }
616            from_glib_none(ffi::g_variant_builder_end(&mut builder))
617        }
618    }
619
620    // rustdoc-stripper-ignore-next
621    /// Creates a new dictionary entry Variant.
622    ///
623    /// [DictEntry] should be preferred over this when the types are known statically.
624    #[doc(alias = "g_variant_new_dict_entry")]
625    pub fn from_dict_entry(key: &Variant, value: &Variant) -> Self {
626        unsafe {
627            from_glib_none(ffi::g_variant_new_dict_entry(
628                key.to_glib_none().0,
629                value.to_glib_none().0,
630            ))
631        }
632    }
633
634    // rustdoc-stripper-ignore-next
635    /// Creates a new maybe Variant.
636    #[doc(alias = "g_variant_new_maybe")]
637    pub fn from_maybe<T: StaticVariantType>(child: Option<&Variant>) -> Self {
638        let type_ = T::static_variant_type();
639        match child {
640            Some(child) => {
641                assert_eq!(type_, child.type_());
642
643                Self::from_some(child)
644            }
645            None => Self::from_none(&type_),
646        }
647    }
648
649    // rustdoc-stripper-ignore-next
650    /// Creates a new maybe Variant from a child.
651    #[doc(alias = "g_variant_new_maybe")]
652    pub fn from_some(child: &Variant) -> Self {
653        unsafe {
654            from_glib_none(ffi::g_variant_new_maybe(
655                ptr::null(),
656                child.to_glib_none().0,
657            ))
658        }
659    }
660
661    // rustdoc-stripper-ignore-next
662    /// Creates a new maybe Variant with Nothing.
663    #[doc(alias = "g_variant_new_maybe")]
664    pub fn from_none(type_: &VariantTy) -> Self {
665        unsafe {
666            from_glib_none(ffi::g_variant_new_maybe(
667                type_.to_glib_none().0,
668                ptr::null_mut(),
669            ))
670        }
671    }
672
673    // rustdoc-stripper-ignore-next
674    /// Extract the value of a maybe Variant.
675    ///
676    /// Returns the child value, or `None` if the value is Nothing.
677    ///
678    /// # Panics
679    ///
680    /// Panics if the variant is not maybe-typed.
681    #[inline]
682    pub fn as_maybe(&self) -> Option<Variant> {
683        assert!(self.type_().is_maybe());
684
685        unsafe { from_glib_full(ffi::g_variant_get_maybe(self.to_glib_none().0)) }
686    }
687
688    // rustdoc-stripper-ignore-next
689    /// Pretty-print the contents of this variant in a human-readable form.
690    ///
691    /// A variant can be recreated from this output via [`Variant::parse`].
692    // rustdoc-stripper-ignore-next-stop
693    /// Pretty-prints @self in the format understood by g_variant_parse().
694    ///
695    /// The format is described [here](gvariant-text-format.html).
696    ///
697    /// If @type_annotate is [`true`], then type information is included in
698    /// the output.
699    /// ## `type_annotate`
700    /// [`true`] if type information should be included in
701    ///                 the output
702    ///
703    /// # Returns
704    ///
705    /// a newly-allocated string holding the result.
706    #[doc(alias = "g_variant_print")]
707    pub fn print(&self, type_annotate: bool) -> crate::GString {
708        unsafe {
709            from_glib_full(ffi::g_variant_print(
710                self.to_glib_none().0,
711                type_annotate.into_glib(),
712            ))
713        }
714    }
715
716    // rustdoc-stripper-ignore-next
717    /// Parses a GVariant from the text representation produced by [`print()`](Self::print).
718    #[doc(alias = "g_variant_parse")]
719    pub fn parse(type_: Option<&VariantTy>, text: &str) -> Result<Self, crate::Error> {
720        unsafe {
721            let mut error = ptr::null_mut();
722            let text = text.as_bytes().as_ptr_range();
723            let variant = ffi::g_variant_parse(
724                type_.to_glib_none().0,
725                text.start as *const _,
726                text.end as *const _,
727                ptr::null_mut(),
728                &mut error,
729            );
730            if variant.is_null() {
731                debug_assert!(!error.is_null());
732                Err(from_glib_full(error))
733            } else {
734                debug_assert!(error.is_null());
735                Ok(from_glib_full(variant))
736            }
737        }
738    }
739
740    // rustdoc-stripper-ignore-next
741    /// Constructs a new serialized-mode GVariant instance.
742    // rustdoc-stripper-ignore-next-stop
743    /// Constructs a new serialized-mode #GVariant instance.  This is the
744    /// inner interface for creation of new serialized values that gets
745    /// called from various functions in gvariant.c.
746    ///
747    /// A reference is taken on @bytes.
748    ///
749    /// The data in @bytes must be aligned appropriately for the @type_ being loaded.
750    /// Otherwise this function will internally create a copy of the memory (since
751    /// GLib 2.60) or (in older versions) fail and exit the process.
752    /// ## `type_`
753    /// a #GVariantType
754    /// ## `bytes`
755    /// a #GBytes
756    /// ## `trusted`
757    /// if the contents of @bytes are trusted
758    ///
759    /// # Returns
760    ///
761    /// a new #GVariant with a floating reference
762    #[doc(alias = "g_variant_new_from_bytes")]
763    pub fn from_bytes<T: StaticVariantType>(bytes: &Bytes) -> Self {
764        Variant::from_bytes_with_type(bytes, &T::static_variant_type())
765    }
766
767    // rustdoc-stripper-ignore-next
768    /// Constructs a new serialized-mode GVariant instance.
769    ///
770    /// This is the same as `from_bytes`, except that checks on the passed
771    /// data are skipped.
772    ///
773    /// You should not use this function on data from external sources.
774    ///
775    /// # Safety
776    ///
777    /// Since the data is not validated, this is potentially dangerous if called
778    /// on bytes which are not guaranteed to have come from serialising another
779    /// Variant.  The caller is responsible for ensuring bad data is not passed in.
780    pub unsafe fn from_bytes_trusted<T: StaticVariantType>(bytes: &Bytes) -> Self {
781        unsafe { Variant::from_bytes_with_type_trusted(bytes, &T::static_variant_type()) }
782    }
783
784    // rustdoc-stripper-ignore-next
785    /// Constructs a new serialized-mode GVariant instance.
786    // rustdoc-stripper-ignore-next-stop
787    /// Creates a new #GVariant instance from serialized data.
788    ///
789    /// @type_ is the type of #GVariant instance that will be constructed.
790    /// The interpretation of @data depends on knowing the type.
791    ///
792    /// @data is not modified by this function and must remain valid with an
793    /// unchanging value until such a time as @notify is called with
794    /// @user_data.  If the contents of @data change before that time then
795    /// the result is undefined.
796    ///
797    /// If @data is trusted to be serialized data in normal form then
798    /// @trusted should be [`true`].  This applies to serialized data created
799    /// within this process or read from a trusted location on the disk (such
800    /// as a file installed in /usr/lib alongside your application).  You
801    /// should set trusted to [`false`] if @data is read from the network, a
802    /// file in the user's home directory, etc.
803    ///
804    /// If @data was not stored in this machine's native endianness, any multi-byte
805    /// numeric values in the returned variant will also be in non-native
806    /// endianness. g_variant_byteswap() can be used to recover the original values.
807    ///
808    /// @notify will be called with @user_data when @data is no longer
809    /// needed.  The exact time of this call is unspecified and might even be
810    /// before this function returns.
811    ///
812    /// Note: @data must be backed by memory that is aligned appropriately for the
813    /// @type_ being loaded. Otherwise this function will internally create a copy of
814    /// the memory (since GLib 2.60) or (in older versions) fail and exit the
815    /// process.
816    /// ## `type_`
817    /// a definite #GVariantType
818    /// ## `data`
819    /// the serialized data
820    /// ## `trusted`
821    /// [`true`] if @data is definitely in normal form
822    /// ## `notify`
823    /// function to call when @data is no longer needed
824    ///
825    /// # Returns
826    ///
827    /// a new floating #GVariant of type @type_
828    #[doc(alias = "g_variant_new_from_data")]
829    pub fn from_data<T: StaticVariantType, A: AsRef<[u8]> + 'static>(data: A) -> Self {
830        Variant::from_data_with_type(data, &T::static_variant_type())
831    }
832
833    // rustdoc-stripper-ignore-next
834    /// Constructs a new serialized-mode GVariant instance.
835    ///
836    /// This is the same as `from_data`, except that checks on the passed
837    /// data are skipped.
838    ///
839    /// You should not use this function on data from external sources.
840    ///
841    /// # Safety
842    ///
843    /// Since the data is not validated, this is potentially dangerous if called
844    /// on bytes which are not guaranteed to have come from serialising another
845    /// Variant.  The caller is responsible for ensuring bad data is not passed in.
846    pub unsafe fn from_data_trusted<T: StaticVariantType, A: AsRef<[u8]> + 'static>(
847        data: A,
848    ) -> Self {
849        unsafe { Variant::from_data_with_type_trusted(data, &T::static_variant_type()) }
850    }
851
852    // rustdoc-stripper-ignore-next
853    /// Constructs a new serialized-mode GVariant instance with a given type.
854    #[doc(alias = "g_variant_new_from_bytes")]
855    pub fn from_bytes_with_type(bytes: &Bytes, type_: &VariantTy) -> Self {
856        unsafe {
857            from_glib_none(ffi::g_variant_new_from_bytes(
858                type_.as_ptr() as *const _,
859                bytes.to_glib_none().0,
860                false.into_glib(),
861            ))
862        }
863    }
864
865    // rustdoc-stripper-ignore-next
866    /// Constructs a new serialized-mode GVariant instance with a given type.
867    ///
868    /// This is the same as `from_bytes`, except that checks on the passed
869    /// data are skipped.
870    ///
871    /// You should not use this function on data from external sources.
872    ///
873    /// # Safety
874    ///
875    /// Since the data is not validated, this is potentially dangerous if called
876    /// on bytes which are not guaranteed to have come from serialising another
877    /// Variant.  The caller is responsible for ensuring bad data is not passed in.
878    pub unsafe fn from_bytes_with_type_trusted(bytes: &Bytes, type_: &VariantTy) -> Self {
879        unsafe {
880            from_glib_none(ffi::g_variant_new_from_bytes(
881                type_.as_ptr() as *const _,
882                bytes.to_glib_none().0,
883                true.into_glib(),
884            ))
885        }
886    }
887
888    // rustdoc-stripper-ignore-next
889    /// Constructs a new serialized-mode GVariant instance with a given type.
890    #[doc(alias = "g_variant_new_from_data")]
891    pub fn from_data_with_type<A: AsRef<[u8]> + 'static>(data: A, type_: &VariantTy) -> Self {
892        unsafe {
893            let data = Box::new(data);
894            let (data_ptr, len) = {
895                let data = (*data).as_ref();
896                (data.as_ptr(), data.len())
897            };
898
899            unsafe extern "C" fn free_data<A: AsRef<[u8]>>(ptr: ffi::gpointer) {
900                unsafe {
901                    let _ = Box::from_raw(ptr as *mut A);
902                }
903            }
904
905            from_glib_none(ffi::g_variant_new_from_data(
906                type_.as_ptr() as *const _,
907                data_ptr as ffi::gconstpointer,
908                len,
909                false.into_glib(),
910                Some(free_data::<A>),
911                Box::into_raw(data) as ffi::gpointer,
912            ))
913        }
914    }
915
916    // rustdoc-stripper-ignore-next
917    /// Constructs a new serialized-mode GVariant instance with a given type.
918    ///
919    /// This is the same as `from_data`, except that checks on the passed
920    /// data are skipped.
921    ///
922    /// You should not use this function on data from external sources.
923    ///
924    /// # Safety
925    ///
926    /// Since the data is not validated, this is potentially dangerous if called
927    /// on bytes which are not guaranteed to have come from serialising another
928    /// Variant.  The caller is responsible for ensuring bad data is not passed in.
929    pub unsafe fn from_data_with_type_trusted<A: AsRef<[u8]> + 'static>(
930        data: A,
931        type_: &VariantTy,
932    ) -> Self {
933        unsafe {
934            let data = Box::new(data);
935            let (data_ptr, len) = {
936                let data = (*data).as_ref();
937                (data.as_ptr(), data.len())
938            };
939
940            unsafe extern "C" fn free_data<A: AsRef<[u8]>>(ptr: ffi::gpointer) {
941                unsafe {
942                    let _ = Box::from_raw(ptr as *mut A);
943                }
944            }
945
946            from_glib_none(ffi::g_variant_new_from_data(
947                type_.as_ptr() as *const _,
948                data_ptr as ffi::gconstpointer,
949                len,
950                true.into_glib(),
951                Some(free_data::<A>),
952                Box::into_raw(data) as ffi::gpointer,
953            ))
954        }
955    }
956
957    // rustdoc-stripper-ignore-next
958    /// Returns the serialized form of a GVariant instance.
959    // rustdoc-stripper-ignore-next-stop
960    /// Returns a pointer to the serialized form of a #GVariant instance.
961    /// The semantics of this function are exactly the same as
962    /// g_variant_get_data(), except that the returned #GBytes holds
963    /// a reference to the variant data.
964    ///
965    /// # Returns
966    ///
967    /// A new #GBytes representing the variant data
968    #[doc(alias = "get_data_as_bytes")]
969    #[doc(alias = "g_variant_get_data_as_bytes")]
970    pub fn data_as_bytes(&self) -> Bytes {
971        unsafe { from_glib_full(ffi::g_variant_get_data_as_bytes(self.to_glib_none().0)) }
972    }
973
974    // rustdoc-stripper-ignore-next
975    /// Returns the serialized form of a GVariant instance.
976    // rustdoc-stripper-ignore-next-stop
977    /// Returns a pointer to the serialized form of a #GVariant instance.
978    /// The returned data may not be in fully-normalised form if read from an
979    /// untrusted source.  The returned data must not be freed; it remains
980    /// valid for as long as @self exists.
981    ///
982    /// If @self is a fixed-sized value that was deserialized from a
983    /// corrupted serialized container then [`None`] may be returned.  In this
984    /// case, the proper thing to do is typically to use the appropriate
985    /// number of nul bytes in place of @self.  If @self is not fixed-sized
986    /// then [`None`] is never returned.
987    ///
988    /// In the case that @self is already in serialized form, this function
989    /// is O(1).  If the value is not already in serialized form,
990    /// serialization occurs implicitly and is approximately O(n) in the size
991    /// of the result.
992    ///
993    /// To deserialize the data returned by this function, in addition to the
994    /// serialized data, you must know the type of the #GVariant, and (if the
995    /// machine might be different) the endianness of the machine that stored
996    /// it. As a result, file formats or network messages that incorporate
997    /// serialized #GVariants must include this information either
998    /// implicitly (for instance "the file always contains a
999    /// `G_VARIANT_TYPE_VARIANT` and it is always in little-endian order") or
1000    /// explicitly (by storing the type and/or endianness in addition to the
1001    /// serialized data).
1002    ///
1003    /// # Returns
1004    ///
1005    /// the serialized form of @self, or [`None`]
1006    #[doc(alias = "g_variant_get_data")]
1007    pub fn data(&self) -> &[u8] {
1008        unsafe {
1009            let selfv = self.to_glib_none();
1010            let len = ffi::g_variant_get_size(selfv.0);
1011            if len == 0 {
1012                return &[];
1013            }
1014            let ptr = ffi::g_variant_get_data(selfv.0);
1015            slice::from_raw_parts(ptr as *const _, len as _)
1016        }
1017    }
1018
1019    // rustdoc-stripper-ignore-next
1020    /// Returns the size of serialized form of a GVariant instance.
1021    // rustdoc-stripper-ignore-next-stop
1022    /// Determines the number of bytes that would be required to store @self
1023    /// with g_variant_store().
1024    ///
1025    /// If @self has a fixed-sized type then this function always returned
1026    /// that fixed size.
1027    ///
1028    /// In the case that @self is already in serialized form or the size has
1029    /// already been calculated (ie: this function has been called before)
1030    /// then this function is O(1).  Otherwise, the size is calculated, an
1031    /// operation which is approximately O(n) in the number of values
1032    /// involved.
1033    ///
1034    /// # Returns
1035    ///
1036    /// the serialized size of @self
1037    #[doc(alias = "g_variant_get_size")]
1038    pub fn size(&self) -> usize {
1039        unsafe { ffi::g_variant_get_size(self.to_glib_none().0) }
1040    }
1041
1042    // rustdoc-stripper-ignore-next
1043    /// Stores the serialized form of a GVariant instance into the given slice.
1044    ///
1045    /// The slice needs to be big enough.
1046    // rustdoc-stripper-ignore-next-stop
1047    /// Stores the serialized form of @self at @data.  @data should be
1048    /// large enough.  See g_variant_get_size().
1049    ///
1050    /// The stored data is in machine native byte order but may not be in
1051    /// fully-normalised form if read from an untrusted source.  See
1052    /// g_variant_get_normal_form() for a solution.
1053    ///
1054    /// As with g_variant_get_data(), to be able to deserialize the
1055    /// serialized variant successfully, its type and (if the destination
1056    /// machine might be different) its endianness must also be available.
1057    ///
1058    /// This function is approximately O(n) in the size of @data.
1059    #[doc(alias = "g_variant_store")]
1060    pub fn store(&self, data: &mut [u8]) -> Result<usize, crate::BoolError> {
1061        unsafe {
1062            let size = ffi::g_variant_get_size(self.to_glib_none().0);
1063            if data.len() < size {
1064                return Err(bool_error!("Provided slice is too small"));
1065            }
1066
1067            ffi::g_variant_store(self.to_glib_none().0, data.as_mut_ptr() as ffi::gpointer);
1068
1069            Ok(size)
1070        }
1071    }
1072
1073    // rustdoc-stripper-ignore-next
1074    /// Returns a copy of the variant in normal form.
1075    // rustdoc-stripper-ignore-next-stop
1076    /// Gets a #GVariant instance that has the same value as @self and is
1077    /// trusted to be in normal form.
1078    ///
1079    /// If @self is already trusted to be in normal form then a new
1080    /// reference to @self is returned.
1081    ///
1082    /// If @self is not already trusted, then it is scanned to check if it
1083    /// is in normal form.  If it is found to be in normal form then it is
1084    /// marked as trusted and a new reference to it is returned.
1085    ///
1086    /// If @self is found not to be in normal form then a new trusted
1087    /// #GVariant is created with the same value as @self. The non-normal parts of
1088    /// @self will be replaced with default values which are guaranteed to be in
1089    /// normal form.
1090    ///
1091    /// It makes sense to call this function if you've received #GVariant
1092    /// data from untrusted sources and you want to ensure your serialized
1093    /// output is definitely in normal form.
1094    ///
1095    /// If @self is already in normal form, a new reference will be returned
1096    /// (which will be floating if @self is floating). If it is not in normal form,
1097    /// the newly created #GVariant will be returned with a single non-floating
1098    /// reference. Typically, g_variant_take_ref() should be called on the return
1099    /// value from this function to guarantee ownership of a single non-floating
1100    /// reference to it.
1101    ///
1102    /// # Returns
1103    ///
1104    /// a trusted #GVariant
1105    #[doc(alias = "g_variant_get_normal_form")]
1106    #[must_use]
1107    pub fn normal_form(&self) -> Self {
1108        unsafe { from_glib_full(ffi::g_variant_get_normal_form(self.to_glib_none().0)) }
1109    }
1110
1111    // rustdoc-stripper-ignore-next
1112    /// Returns a copy of the variant in the opposite endianness.
1113    // rustdoc-stripper-ignore-next-stop
1114    /// Performs a byteswapping operation on the contents of @self.  The
1115    /// result is that all multi-byte numeric data contained in @self is
1116    /// byteswapped.  That includes 16, 32, and 64bit signed and unsigned
1117    /// integers as well as file handles and double precision floating point
1118    /// values.
1119    ///
1120    /// This function is an identity mapping on any value that does not
1121    /// contain multi-byte numeric data.  That include strings, booleans,
1122    /// bytes and containers containing only these things (recursively).
1123    ///
1124    /// While this function can safely handle untrusted, non-normal data, it is
1125    /// recommended to check whether the input is in normal form beforehand, using
1126    /// g_variant_is_normal_form(), and to reject non-normal inputs if your
1127    /// application can be strict about what inputs it rejects.
1128    ///
1129    /// The returned value is always in normal form and is marked as trusted.
1130    /// A full, not floating, reference is returned.
1131    ///
1132    /// # Returns
1133    ///
1134    /// the byteswapped form of @self
1135    #[doc(alias = "g_variant_byteswap")]
1136    #[must_use]
1137    pub fn byteswap(&self) -> Self {
1138        unsafe { from_glib_full(ffi::g_variant_byteswap(self.to_glib_none().0)) }
1139    }
1140
1141    // rustdoc-stripper-ignore-next
1142    /// Determines the number of children in a container GVariant instance.
1143    // rustdoc-stripper-ignore-next-stop
1144    /// Determines the number of children in a container #GVariant instance.
1145    /// This includes variants, maybes, arrays, tuples and dictionary
1146    /// entries.  It is an error to call this function on any other type of
1147    /// #GVariant.
1148    ///
1149    /// For variants, the return value is always 1.  For values with maybe
1150    /// types, it is always zero or one.  For arrays, it is the length of the
1151    /// array.  For tuples it is the number of tuple items (which depends
1152    /// only on the type).  For dictionary entries, it is always 2
1153    ///
1154    /// This function is O(1).
1155    ///
1156    /// # Returns
1157    ///
1158    /// the number of children in the container
1159    #[doc(alias = "g_variant_n_children")]
1160    pub fn n_children(&self) -> usize {
1161        assert!(self.is_container());
1162
1163        unsafe { ffi::g_variant_n_children(self.to_glib_none().0) }
1164    }
1165
1166    // rustdoc-stripper-ignore-next
1167    /// Create an iterator over items in the variant.
1168    ///
1169    /// Note that this heap allocates a variant for each element,
1170    /// which can be particularly expensive for large arrays.
1171    pub fn iter(&self) -> VariantIter {
1172        assert!(self.is_container());
1173
1174        VariantIter::new(self.clone())
1175    }
1176
1177    // rustdoc-stripper-ignore-next
1178    /// Create an iterator over borrowed strings from a GVariant of type `as` (array of string).
1179    ///
1180    /// This will fail if the variant is not an array of with
1181    /// the expected child type.
1182    ///
1183    /// A benefit of this API over [`Self::iter()`] is that it
1184    /// minimizes allocation, and provides strongly typed access.
1185    ///
1186    /// ```
1187    /// # use glib::prelude::*;
1188    /// let strs = &["foo", "bar"];
1189    /// let strs_variant: glib::Variant = strs.to_variant();
1190    /// for s in strs_variant.array_iter_str()? {
1191    ///     println!("{}", s);
1192    /// }
1193    /// # Ok::<(), Box<dyn std::error::Error>>(())
1194    /// ```
1195    pub fn array_iter_str(&self) -> Result<VariantStrIter<'_>, VariantTypeMismatchError> {
1196        let child_ty = String::static_variant_type();
1197        let actual_ty = self.type_();
1198        let expected_ty = child_ty.as_array();
1199        if actual_ty != expected_ty {
1200            return Err(VariantTypeMismatchError {
1201                actual: actual_ty.to_owned(),
1202                expected: expected_ty.into_owned(),
1203            });
1204        }
1205
1206        Ok(VariantStrIter::new(self))
1207    }
1208
1209    // rustdoc-stripper-ignore-next
1210    /// Return whether this Variant is a container type.
1211    // rustdoc-stripper-ignore-next-stop
1212    /// Checks if @self is a container.
1213    ///
1214    /// # Returns
1215    ///
1216    /// [`true`] if @self is a container
1217    #[doc(alias = "g_variant_is_container")]
1218    pub fn is_container(&self) -> bool {
1219        unsafe { from_glib(ffi::g_variant_is_container(self.to_glib_none().0)) }
1220    }
1221
1222    // rustdoc-stripper-ignore-next
1223    /// Return whether this Variant is in normal form.
1224    // rustdoc-stripper-ignore-next-stop
1225    /// Checks if @self is in normal form.
1226    ///
1227    /// The main reason to do this is to detect if a given chunk of
1228    /// serialized data is in normal form: load the data into a #GVariant
1229    /// using g_variant_new_from_data() and then use this function to
1230    /// check.
1231    ///
1232    /// If @self is found to be in normal form then it will be marked as
1233    /// being trusted.  If the value was already marked as being trusted then
1234    /// this function will immediately return [`true`].
1235    ///
1236    /// There may be implementation specific restrictions on deeply nested values.
1237    /// GVariant is guaranteed to handle nesting up to at least 64 levels.
1238    ///
1239    /// # Returns
1240    ///
1241    /// [`true`] if @self is in normal form
1242    #[doc(alias = "g_variant_is_normal_form")]
1243    pub fn is_normal_form(&self) -> bool {
1244        unsafe { from_glib(ffi::g_variant_is_normal_form(self.to_glib_none().0)) }
1245    }
1246
1247    // rustdoc-stripper-ignore-next
1248    /// Return whether input string is a valid `VariantClass::ObjectPath`.
1249    // rustdoc-stripper-ignore-next-stop
1250    /// Determines if a given string is a valid D-Bus object path.  You
1251    /// should ensure that a string is a valid D-Bus object path before
1252    /// passing it to g_variant_new_object_path().
1253    ///
1254    /// A valid object path starts with `/` followed by zero or more
1255    /// sequences of characters separated by `/` characters.  Each sequence
1256    /// must contain only the characters `[A-Z][a-z][0-9]_`.  No sequence
1257    /// (including the one following the final `/` character) may be empty.
1258    /// ## `string`
1259    /// a normal C nul-terminated string
1260    ///
1261    /// # Returns
1262    ///
1263    /// [`true`] if @string is a D-Bus object path
1264    #[doc(alias = "g_variant_is_object_path")]
1265    pub fn is_object_path(string: &str) -> bool {
1266        unsafe { from_glib(ffi::g_variant_is_object_path(string.to_glib_none().0)) }
1267    }
1268
1269    // rustdoc-stripper-ignore-next
1270    /// Return whether input string is a valid `VariantClass::Signature`.
1271    // rustdoc-stripper-ignore-next-stop
1272    /// Determines if a given string is a valid D-Bus type signature.  You
1273    /// should ensure that a string is a valid D-Bus type signature before
1274    /// passing it to g_variant_new_signature().
1275    ///
1276    /// D-Bus type signatures consist of zero or more definite #GVariantType
1277    /// strings in sequence.
1278    /// ## `string`
1279    /// a normal C nul-terminated string
1280    ///
1281    /// # Returns
1282    ///
1283    /// [`true`] if @string is a D-Bus type signature
1284    #[doc(alias = "g_variant_is_signature")]
1285    pub fn is_signature(string: &str) -> bool {
1286        unsafe { from_glib(ffi::g_variant_is_signature(string.to_glib_none().0)) }
1287    }
1288}
1289
1290unsafe impl Send for Variant {}
1291unsafe impl Sync for Variant {}
1292
1293impl fmt::Debug for Variant {
1294    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1295        f.debug_struct("Variant")
1296            .field("ptr", &ToGlibPtr::<*const _>::to_glib_none(self).0)
1297            .field("type", &self.type_())
1298            .field("value", &self.to_string())
1299            .finish()
1300    }
1301}
1302
1303impl fmt::Display for Variant {
1304    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1305        f.write_str(&self.print(true))
1306    }
1307}
1308
1309impl str::FromStr for Variant {
1310    type Err = crate::Error;
1311
1312    fn from_str(s: &str) -> Result<Self, Self::Err> {
1313        Self::parse(None, s)
1314    }
1315}
1316
1317impl PartialEq for Variant {
1318    #[doc(alias = "g_variant_equal")]
1319    fn eq(&self, other: &Self) -> bool {
1320        unsafe {
1321            from_glib(ffi::g_variant_equal(
1322                ToGlibPtr::<*const _>::to_glib_none(self).0 as *const _,
1323                ToGlibPtr::<*const _>::to_glib_none(other).0 as *const _,
1324            ))
1325        }
1326    }
1327}
1328
1329impl Eq for Variant {}
1330
1331impl PartialOrd for Variant {
1332    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1333        unsafe {
1334            if ffi::g_variant_classify(self.to_glib_none().0)
1335                != ffi::g_variant_classify(other.to_glib_none().0)
1336            {
1337                return None;
1338            }
1339
1340            if self.is_container() {
1341                return None;
1342            }
1343
1344            let res = ffi::g_variant_compare(
1345                ToGlibPtr::<*const _>::to_glib_none(self).0 as *const _,
1346                ToGlibPtr::<*const _>::to_glib_none(other).0 as *const _,
1347            );
1348
1349            Some(res.cmp(&0))
1350        }
1351    }
1352}
1353
1354impl Hash for Variant {
1355    #[doc(alias = "g_variant_hash")]
1356    fn hash<H: Hasher>(&self, state: &mut H) {
1357        unsafe {
1358            state.write_u32(ffi::g_variant_hash(
1359                ToGlibPtr::<*const _>::to_glib_none(self).0 as *const _,
1360            ))
1361        }
1362    }
1363}
1364
1365impl AsRef<Variant> for Variant {
1366    #[inline]
1367    fn as_ref(&self) -> &Self {
1368        self
1369    }
1370}
1371
1372// rustdoc-stripper-ignore-next
1373/// Converts to `Variant`.
1374pub trait ToVariant {
1375    // rustdoc-stripper-ignore-next
1376    /// Returns a `Variant` clone of `self`.
1377    fn to_variant(&self) -> Variant;
1378}
1379
1380// rustdoc-stripper-ignore-next
1381/// Extracts a value.
1382pub trait FromVariant: Sized + StaticVariantType {
1383    // rustdoc-stripper-ignore-next
1384    /// Tries to extract a value.
1385    ///
1386    /// Returns `Some` if the variant's type matches `Self`.
1387    fn from_variant(variant: &Variant) -> Option<Self>;
1388}
1389
1390// rustdoc-stripper-ignore-next
1391/// Returns `VariantType` of `Self`.
1392pub trait StaticVariantType {
1393    // rustdoc-stripper-ignore-next
1394    /// Returns the `VariantType` corresponding to `Self`.
1395    fn static_variant_type() -> Cow<'static, VariantTy>;
1396}
1397
1398impl StaticVariantType for Variant {
1399    fn static_variant_type() -> Cow<'static, VariantTy> {
1400        Cow::Borrowed(VariantTy::VARIANT)
1401    }
1402}
1403
1404impl<T: ?Sized + ToVariant> ToVariant for &T {
1405    fn to_variant(&self) -> Variant {
1406        <T as ToVariant>::to_variant(self)
1407    }
1408}
1409
1410impl<'a, T: Into<Variant> + Clone> From<&'a T> for Variant {
1411    #[inline]
1412    fn from(v: &'a T) -> Self {
1413        v.clone().into()
1414    }
1415}
1416
1417impl<T: ?Sized + StaticVariantType> StaticVariantType for &T {
1418    fn static_variant_type() -> Cow<'static, VariantTy> {
1419        <T as StaticVariantType>::static_variant_type()
1420    }
1421}
1422
1423macro_rules! impl_numeric {
1424    ($name:ty, $typ:expr, $new_fn:ident, $get_fn:ident) => {
1425        impl StaticVariantType for $name {
1426            fn static_variant_type() -> Cow<'static, VariantTy> {
1427                Cow::Borrowed($typ)
1428            }
1429        }
1430
1431        impl ToVariant for $name {
1432            fn to_variant(&self) -> Variant {
1433                unsafe { from_glib_none(ffi::$new_fn(*self)) }
1434            }
1435        }
1436
1437        impl From<$name> for Variant {
1438            #[inline]
1439            fn from(v: $name) -> Self {
1440                v.to_variant()
1441            }
1442        }
1443
1444        impl FromVariant for $name {
1445            fn from_variant(variant: &Variant) -> Option<Self> {
1446                unsafe {
1447                    if variant.is::<Self>() {
1448                        Some(ffi::$get_fn(variant.to_glib_none().0))
1449                    } else {
1450                        None
1451                    }
1452                }
1453            }
1454        }
1455    };
1456}
1457
1458impl_numeric!(u8, VariantTy::BYTE, g_variant_new_byte, g_variant_get_byte);
1459impl_numeric!(
1460    i16,
1461    VariantTy::INT16,
1462    g_variant_new_int16,
1463    g_variant_get_int16
1464);
1465impl_numeric!(
1466    u16,
1467    VariantTy::UINT16,
1468    g_variant_new_uint16,
1469    g_variant_get_uint16
1470);
1471impl_numeric!(
1472    i32,
1473    VariantTy::INT32,
1474    g_variant_new_int32,
1475    g_variant_get_int32
1476);
1477impl_numeric!(
1478    u32,
1479    VariantTy::UINT32,
1480    g_variant_new_uint32,
1481    g_variant_get_uint32
1482);
1483impl_numeric!(
1484    i64,
1485    VariantTy::INT64,
1486    g_variant_new_int64,
1487    g_variant_get_int64
1488);
1489impl_numeric!(
1490    u64,
1491    VariantTy::UINT64,
1492    g_variant_new_uint64,
1493    g_variant_get_uint64
1494);
1495impl_numeric!(
1496    f64,
1497    VariantTy::DOUBLE,
1498    g_variant_new_double,
1499    g_variant_get_double
1500);
1501
1502impl StaticVariantType for () {
1503    fn static_variant_type() -> Cow<'static, VariantTy> {
1504        Cow::Borrowed(VariantTy::UNIT)
1505    }
1506}
1507
1508impl ToVariant for () {
1509    fn to_variant(&self) -> Variant {
1510        unsafe { from_glib_none(ffi::g_variant_new_tuple(ptr::null(), 0)) }
1511    }
1512}
1513
1514impl From<()> for Variant {
1515    #[inline]
1516    fn from(_: ()) -> Self {
1517        ().to_variant()
1518    }
1519}
1520
1521impl FromVariant for () {
1522    fn from_variant(variant: &Variant) -> Option<Self> {
1523        if variant.is::<Self>() { Some(()) } else { None }
1524    }
1525}
1526
1527impl StaticVariantType for bool {
1528    fn static_variant_type() -> Cow<'static, VariantTy> {
1529        Cow::Borrowed(VariantTy::BOOLEAN)
1530    }
1531}
1532
1533impl ToVariant for bool {
1534    fn to_variant(&self) -> Variant {
1535        unsafe { from_glib_none(ffi::g_variant_new_boolean(self.into_glib())) }
1536    }
1537}
1538
1539impl From<bool> for Variant {
1540    #[inline]
1541    fn from(v: bool) -> Self {
1542        v.to_variant()
1543    }
1544}
1545
1546impl FromVariant for bool {
1547    fn from_variant(variant: &Variant) -> Option<Self> {
1548        unsafe {
1549            if variant.is::<Self>() {
1550                Some(from_glib(ffi::g_variant_get_boolean(
1551                    variant.to_glib_none().0,
1552                )))
1553            } else {
1554                None
1555            }
1556        }
1557    }
1558}
1559
1560impl StaticVariantType for String {
1561    fn static_variant_type() -> Cow<'static, VariantTy> {
1562        Cow::Borrowed(VariantTy::STRING)
1563    }
1564}
1565
1566impl ToVariant for String {
1567    fn to_variant(&self) -> Variant {
1568        self[..].to_variant()
1569    }
1570}
1571
1572impl From<String> for Variant {
1573    #[inline]
1574    fn from(s: String) -> Self {
1575        s.to_variant()
1576    }
1577}
1578
1579impl FromVariant for String {
1580    fn from_variant(variant: &Variant) -> Option<Self> {
1581        variant.str().map(String::from)
1582    }
1583}
1584
1585impl StaticVariantType for str {
1586    fn static_variant_type() -> Cow<'static, VariantTy> {
1587        String::static_variant_type()
1588    }
1589}
1590
1591impl ToVariant for str {
1592    fn to_variant(&self) -> Variant {
1593        unsafe { from_glib_none(ffi::g_variant_new_take_string(self.to_glib_full())) }
1594    }
1595}
1596
1597impl From<&str> for Variant {
1598    #[inline]
1599    fn from(s: &str) -> Self {
1600        s.to_variant()
1601    }
1602}
1603
1604impl StaticVariantType for std::path::PathBuf {
1605    fn static_variant_type() -> Cow<'static, VariantTy> {
1606        std::path::Path::static_variant_type()
1607    }
1608}
1609
1610impl ToVariant for std::path::PathBuf {
1611    fn to_variant(&self) -> Variant {
1612        self.as_path().to_variant()
1613    }
1614}
1615
1616impl From<std::path::PathBuf> for Variant {
1617    #[inline]
1618    fn from(p: std::path::PathBuf) -> Self {
1619        p.to_variant()
1620    }
1621}
1622
1623impl FromVariant for std::path::PathBuf {
1624    fn from_variant(variant: &Variant) -> Option<Self> {
1625        unsafe {
1626            let ptr = ffi::g_variant_get_bytestring(variant.to_glib_none().0);
1627            Some(crate::translate::c_to_path_buf(ptr as *const _))
1628        }
1629    }
1630}
1631
1632impl StaticVariantType for std::path::Path {
1633    fn static_variant_type() -> Cow<'static, VariantTy> {
1634        <&[u8]>::static_variant_type()
1635    }
1636}
1637
1638impl ToVariant for std::path::Path {
1639    fn to_variant(&self) -> Variant {
1640        let tmp = crate::translate::path_to_c(self);
1641        unsafe { from_glib_none(ffi::g_variant_new_bytestring(tmp.as_ptr() as *const u8)) }
1642    }
1643}
1644
1645impl From<&std::path::Path> for Variant {
1646    #[inline]
1647    fn from(p: &std::path::Path) -> Self {
1648        p.to_variant()
1649    }
1650}
1651
1652impl StaticVariantType for std::ffi::OsString {
1653    fn static_variant_type() -> Cow<'static, VariantTy> {
1654        std::ffi::OsStr::static_variant_type()
1655    }
1656}
1657
1658impl ToVariant for std::ffi::OsString {
1659    fn to_variant(&self) -> Variant {
1660        self.as_os_str().to_variant()
1661    }
1662}
1663
1664impl From<std::ffi::OsString> for Variant {
1665    #[inline]
1666    fn from(s: std::ffi::OsString) -> Self {
1667        s.to_variant()
1668    }
1669}
1670
1671impl FromVariant for std::ffi::OsString {
1672    fn from_variant(variant: &Variant) -> Option<Self> {
1673        unsafe {
1674            let ptr = ffi::g_variant_get_bytestring(variant.to_glib_none().0);
1675            Some(crate::translate::c_to_os_string(ptr as *const _))
1676        }
1677    }
1678}
1679
1680impl StaticVariantType for std::ffi::OsStr {
1681    fn static_variant_type() -> Cow<'static, VariantTy> {
1682        <&[u8]>::static_variant_type()
1683    }
1684}
1685
1686impl ToVariant for std::ffi::OsStr {
1687    fn to_variant(&self) -> Variant {
1688        let tmp = crate::translate::os_str_to_c(self);
1689        unsafe { from_glib_none(ffi::g_variant_new_bytestring(tmp.as_ptr() as *const u8)) }
1690    }
1691}
1692
1693impl From<&std::ffi::OsStr> for Variant {
1694    #[inline]
1695    fn from(s: &std::ffi::OsStr) -> Self {
1696        s.to_variant()
1697    }
1698}
1699
1700impl<T: StaticVariantType> StaticVariantType for Option<T> {
1701    fn static_variant_type() -> Cow<'static, VariantTy> {
1702        Cow::Owned(VariantType::new_maybe(&T::static_variant_type()))
1703    }
1704}
1705
1706impl<T: StaticVariantType + ToVariant> ToVariant for Option<T> {
1707    fn to_variant(&self) -> Variant {
1708        Variant::from_maybe::<T>(self.as_ref().map(|m| m.to_variant()).as_ref())
1709    }
1710}
1711
1712impl<T: StaticVariantType + Into<Variant>> From<Option<T>> for Variant {
1713    #[inline]
1714    fn from(v: Option<T>) -> Self {
1715        Variant::from_maybe::<T>(v.map(|v| v.into()).as_ref())
1716    }
1717}
1718
1719impl<T: StaticVariantType + FromVariant> FromVariant for Option<T> {
1720    fn from_variant(variant: &Variant) -> Option<Self> {
1721        unsafe {
1722            if variant.is::<Self>() {
1723                let c_child = ffi::g_variant_get_maybe(variant.to_glib_none().0);
1724                if !c_child.is_null() {
1725                    let child: Variant = from_glib_full(c_child);
1726
1727                    Some(T::from_variant(&child))
1728                } else {
1729                    Some(None)
1730                }
1731            } else {
1732                None
1733            }
1734        }
1735    }
1736}
1737
1738impl<T: StaticVariantType> StaticVariantType for [T] {
1739    fn static_variant_type() -> Cow<'static, VariantTy> {
1740        T::static_variant_type().as_array()
1741    }
1742}
1743
1744impl<T: StaticVariantType + ToVariant> ToVariant for [T] {
1745    fn to_variant(&self) -> Variant {
1746        unsafe {
1747            if self.is_empty() {
1748                return from_glib_none(ffi::g_variant_new_array(
1749                    T::static_variant_type().to_glib_none().0,
1750                    ptr::null(),
1751                    0,
1752                ));
1753            }
1754
1755            let mut builder = mem::MaybeUninit::uninit();
1756            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1757            let mut builder = builder.assume_init();
1758            for value in self {
1759                let value = value.to_variant();
1760                ffi::g_variant_builder_add_value(&mut builder, value.to_glib_none().0);
1761            }
1762            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1763        }
1764    }
1765}
1766
1767impl<T: StaticVariantType + ToVariant> From<&[T]> for Variant {
1768    #[inline]
1769    fn from(s: &[T]) -> Self {
1770        s.to_variant()
1771    }
1772}
1773
1774impl<T: FromVariant> FromVariant for Vec<T> {
1775    fn from_variant(variant: &Variant) -> Option<Self> {
1776        if !variant.is_container() {
1777            return None;
1778        }
1779
1780        let mut vec = Vec::with_capacity(variant.n_children());
1781
1782        for i in 0..variant.n_children() {
1783            match variant.child_value(i).get() {
1784                Some(child) => vec.push(child),
1785                None => return None,
1786            }
1787        }
1788
1789        Some(vec)
1790    }
1791}
1792
1793impl<T: StaticVariantType + ToVariant> ToVariant for Vec<T> {
1794    fn to_variant(&self) -> Variant {
1795        self.as_slice().to_variant()
1796    }
1797}
1798
1799impl<T: StaticVariantType + Into<Variant>> From<Vec<T>> for Variant {
1800    fn from(v: Vec<T>) -> Self {
1801        unsafe {
1802            if v.is_empty() {
1803                return from_glib_none(ffi::g_variant_new_array(
1804                    T::static_variant_type().to_glib_none().0,
1805                    ptr::null(),
1806                    0,
1807                ));
1808            }
1809
1810            let mut builder = mem::MaybeUninit::uninit();
1811            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1812            let mut builder = builder.assume_init();
1813            for value in v {
1814                let value = value.into();
1815                ffi::g_variant_builder_add_value(&mut builder, value.to_glib_none().0);
1816            }
1817            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1818        }
1819    }
1820}
1821
1822impl<T: StaticVariantType> StaticVariantType for Vec<T> {
1823    fn static_variant_type() -> Cow<'static, VariantTy> {
1824        <[T]>::static_variant_type()
1825    }
1826}
1827
1828impl<K, V, H> FromVariant for HashMap<K, V, H>
1829where
1830    K: FromVariant + Eq + Hash,
1831    V: FromVariant,
1832    H: BuildHasher + Default,
1833{
1834    fn from_variant(variant: &Variant) -> Option<Self> {
1835        if !variant.is_container() {
1836            return None;
1837        }
1838
1839        let mut map = HashMap::default();
1840
1841        for i in 0..variant.n_children() {
1842            let entry = variant.child_value(i);
1843            let key = entry.child_value(0).get()?;
1844            let val = entry.child_value(1).get()?;
1845
1846            map.insert(key, val);
1847        }
1848
1849        Some(map)
1850    }
1851}
1852
1853impl<K, V> FromVariant for BTreeMap<K, V>
1854where
1855    K: FromVariant + Eq + Ord,
1856    V: FromVariant,
1857{
1858    fn from_variant(variant: &Variant) -> Option<Self> {
1859        if !variant.is_container() {
1860            return None;
1861        }
1862
1863        let mut map = BTreeMap::default();
1864
1865        for i in 0..variant.n_children() {
1866            let entry = variant.child_value(i);
1867            let key = entry.child_value(0).get()?;
1868            let val = entry.child_value(1).get()?;
1869
1870            map.insert(key, val);
1871        }
1872
1873        Some(map)
1874    }
1875}
1876
1877impl<K, V> ToVariant for HashMap<K, V>
1878where
1879    K: StaticVariantType + ToVariant + Eq + Hash,
1880    V: StaticVariantType + ToVariant,
1881{
1882    fn to_variant(&self) -> Variant {
1883        unsafe {
1884            if self.is_empty() {
1885                return from_glib_none(ffi::g_variant_new_array(
1886                    DictEntry::<K, V>::static_variant_type().to_glib_none().0,
1887                    ptr::null(),
1888                    0,
1889                ));
1890            }
1891
1892            let mut builder = mem::MaybeUninit::uninit();
1893            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1894            let mut builder = builder.assume_init();
1895            for (key, value) in self {
1896                let entry = DictEntry::new(key, value).to_variant();
1897                ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0);
1898            }
1899            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1900        }
1901    }
1902}
1903
1904impl<K, V> From<HashMap<K, V>> for Variant
1905where
1906    K: StaticVariantType + Into<Variant> + Eq + Hash,
1907    V: StaticVariantType + Into<Variant>,
1908{
1909    fn from(m: HashMap<K, V>) -> Self {
1910        unsafe {
1911            if m.is_empty() {
1912                return from_glib_none(ffi::g_variant_new_array(
1913                    DictEntry::<K, V>::static_variant_type().to_glib_none().0,
1914                    ptr::null(),
1915                    0,
1916                ));
1917            }
1918
1919            let mut builder = mem::MaybeUninit::uninit();
1920            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1921            let mut builder = builder.assume_init();
1922            for (key, value) in m {
1923                let entry = Variant::from(DictEntry::new(key, value));
1924                ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0);
1925            }
1926            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1927        }
1928    }
1929}
1930
1931impl<K, V> ToVariant for BTreeMap<K, V>
1932where
1933    K: StaticVariantType + ToVariant + Eq + Hash,
1934    V: StaticVariantType + ToVariant,
1935{
1936    fn to_variant(&self) -> Variant {
1937        unsafe {
1938            if self.is_empty() {
1939                return from_glib_none(ffi::g_variant_new_array(
1940                    DictEntry::<K, V>::static_variant_type().to_glib_none().0,
1941                    ptr::null(),
1942                    0,
1943                ));
1944            }
1945
1946            let mut builder = mem::MaybeUninit::uninit();
1947            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1948            let mut builder = builder.assume_init();
1949            for (key, value) in self {
1950                let entry = DictEntry::new(key, value).to_variant();
1951                ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0);
1952            }
1953            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1954        }
1955    }
1956}
1957
1958impl<K, V> From<BTreeMap<K, V>> for Variant
1959where
1960    K: StaticVariantType + Into<Variant> + Eq + Hash,
1961    V: StaticVariantType + Into<Variant>,
1962{
1963    fn from(m: BTreeMap<K, V>) -> Self {
1964        unsafe {
1965            if m.is_empty() {
1966                return from_glib_none(ffi::g_variant_new_array(
1967                    DictEntry::<K, V>::static_variant_type().to_glib_none().0,
1968                    ptr::null(),
1969                    0,
1970                ));
1971            }
1972
1973            let mut builder = mem::MaybeUninit::uninit();
1974            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1975            let mut builder = builder.assume_init();
1976            for (key, value) in m {
1977                let entry = Variant::from(DictEntry::new(key, value));
1978                ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0);
1979            }
1980            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1981        }
1982    }
1983}
1984
1985/// A Dictionary entry.
1986///
1987/// While GVariant format allows a dictionary entry to be an independent type, typically you'll need
1988/// to use this in a dictionary, which is simply an array of dictionary entries. The following code
1989/// creates a dictionary:
1990///
1991/// ```
1992///# use glib::prelude::*; // or `use gtk::prelude::*;`
1993/// use glib::variant::{Variant, FromVariant, DictEntry};
1994///
1995/// let entries = [
1996///     DictEntry::new("uuid", 1000u32),
1997///     DictEntry::new("guid", 1001u32),
1998/// ];
1999/// let dict = entries.into_iter().collect::<Variant>();
2000/// assert_eq!(dict.n_children(), 2);
2001/// assert_eq!(dict.type_().as_str(), "a{su}");
2002/// ```
2003#[derive(Debug, Clone)]
2004pub struct DictEntry<K, V> {
2005    key: K,
2006    value: V,
2007}
2008
2009impl<K, V> DictEntry<K, V>
2010where
2011    K: StaticVariantType,
2012    V: StaticVariantType,
2013{
2014    pub fn new(key: K, value: V) -> Self {
2015        Self { key, value }
2016    }
2017
2018    pub fn key(&self) -> &K {
2019        &self.key
2020    }
2021
2022    pub fn value(&self) -> &V {
2023        &self.value
2024    }
2025}
2026
2027impl<K, V> FromVariant for DictEntry<K, V>
2028where
2029    K: FromVariant,
2030    V: FromVariant,
2031{
2032    fn from_variant(variant: &Variant) -> Option<Self> {
2033        if !variant.type_().is_subtype_of(VariantTy::DICT_ENTRY) {
2034            return None;
2035        }
2036
2037        let key = variant.child_value(0).get()?;
2038        let value = variant.child_value(1).get()?;
2039
2040        Some(Self { key, value })
2041    }
2042}
2043
2044impl<K, V> ToVariant for DictEntry<K, V>
2045where
2046    K: StaticVariantType + ToVariant,
2047    V: StaticVariantType + ToVariant,
2048{
2049    fn to_variant(&self) -> Variant {
2050        Variant::from_dict_entry(&self.key.to_variant(), &self.value.to_variant())
2051    }
2052}
2053
2054impl<K, V> From<DictEntry<K, V>> for Variant
2055where
2056    K: StaticVariantType + Into<Variant>,
2057    V: StaticVariantType + Into<Variant>,
2058{
2059    fn from(e: DictEntry<K, V>) -> Self {
2060        Variant::from_dict_entry(&e.key.into(), &e.value.into())
2061    }
2062}
2063
2064impl ToVariant for Variant {
2065    fn to_variant(&self) -> Variant {
2066        Variant::from_variant(self)
2067    }
2068}
2069
2070impl FromVariant for Variant {
2071    fn from_variant(variant: &Variant) -> Option<Self> {
2072        variant.as_variant()
2073    }
2074}
2075
2076impl<K: StaticVariantType, V: StaticVariantType> StaticVariantType for DictEntry<K, V> {
2077    fn static_variant_type() -> Cow<'static, VariantTy> {
2078        Cow::Owned(VariantType::new_dict_entry(
2079            &K::static_variant_type(),
2080            &V::static_variant_type(),
2081        ))
2082    }
2083}
2084
2085fn static_variant_mapping<K, V>() -> Cow<'static, VariantTy>
2086where
2087    K: StaticVariantType,
2088    V: StaticVariantType,
2089{
2090    use std::fmt::Write;
2091
2092    let key_type = K::static_variant_type();
2093    let value_type = V::static_variant_type();
2094
2095    if key_type == VariantTy::STRING && value_type == VariantTy::VARIANT {
2096        return Cow::Borrowed(VariantTy::VARDICT);
2097    }
2098
2099    let mut builder = crate::GStringBuilder::default();
2100    write!(builder, "a{{{}{}}}", key_type.as_str(), value_type.as_str()).unwrap();
2101
2102    Cow::Owned(VariantType::from_string(builder.into_string()).unwrap())
2103}
2104
2105impl<K, V, H> StaticVariantType for HashMap<K, V, H>
2106where
2107    K: StaticVariantType,
2108    V: StaticVariantType,
2109    H: BuildHasher + Default,
2110{
2111    fn static_variant_type() -> Cow<'static, VariantTy> {
2112        static_variant_mapping::<K, V>()
2113    }
2114}
2115
2116impl<K, V> StaticVariantType for BTreeMap<K, V>
2117where
2118    K: StaticVariantType,
2119    V: StaticVariantType,
2120{
2121    fn static_variant_type() -> Cow<'static, VariantTy> {
2122        static_variant_mapping::<K, V>()
2123    }
2124}
2125
2126macro_rules! tuple_impls {
2127    ($($len:expr => ($($n:tt $name:ident)+))+) => {
2128        $(
2129            impl<$($name),+> StaticVariantType for ($($name,)+)
2130            where
2131                $($name: StaticVariantType,)+
2132            {
2133                fn static_variant_type() -> Cow<'static, VariantTy> {
2134                    Cow::Owned(VariantType::new_tuple(&[
2135                        $(
2136                            $name::static_variant_type(),
2137                        )+
2138                    ]))
2139                }
2140            }
2141
2142            impl<$($name),+> FromVariant for ($($name,)+)
2143            where
2144                $($name: FromVariant,)+
2145            {
2146                fn from_variant(variant: &Variant) -> Option<Self> {
2147                    if !variant.type_().is_subtype_of(VariantTy::TUPLE) {
2148                        return None;
2149                    }
2150
2151                    Some((
2152                        $(
2153                            match variant.try_child_get::<$name>($n) {
2154                                Ok(Some(field)) => field,
2155                                _ => return None,
2156                            },
2157                        )+
2158                    ))
2159                }
2160            }
2161
2162            impl<$($name),+> ToVariant for ($($name,)+)
2163            where
2164                $($name: ToVariant,)+
2165            {
2166                fn to_variant(&self) -> Variant {
2167                    unsafe {
2168                        let mut builder = mem::MaybeUninit::uninit();
2169                        ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::TUPLE.to_glib_none().0);
2170                        let mut builder = builder.assume_init();
2171
2172                        $(
2173                            let field = self.$n.to_variant();
2174                            ffi::g_variant_builder_add_value(&mut builder, field.to_glib_none().0);
2175                        )+
2176
2177                        from_glib_none(ffi::g_variant_builder_end(&mut builder))
2178                    }
2179                }
2180            }
2181
2182            impl<$($name),+> From<($($name,)+)> for Variant
2183            where
2184                $($name: Into<Variant>,)+
2185            {
2186                fn from(t: ($($name,)+)) -> Self {
2187                    unsafe {
2188                        let mut builder = mem::MaybeUninit::uninit();
2189                        ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::TUPLE.to_glib_none().0);
2190                        let mut builder = builder.assume_init();
2191
2192                        $(
2193                            let field = t.$n.into();
2194                            ffi::g_variant_builder_add_value(&mut builder, field.to_glib_none().0);
2195                        )+
2196
2197                        from_glib_none(ffi::g_variant_builder_end(&mut builder))
2198                    }
2199                }
2200            }
2201        )+
2202    }
2203}
2204
2205tuple_impls! {
2206    1 => (0 T0)
2207    2 => (0 T0 1 T1)
2208    3 => (0 T0 1 T1 2 T2)
2209    4 => (0 T0 1 T1 2 T2 3 T3)
2210    5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
2211    6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
2212    7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
2213    8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
2214    9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
2215    10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
2216    11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
2217    12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
2218    13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
2219    14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
2220    15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
2221    16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
2222}
2223
2224impl<T: Into<Variant> + StaticVariantType> FromIterator<T> for Variant {
2225    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
2226        Variant::array_from_iter::<T>(iter.into_iter().map(|v| v.into()))
2227    }
2228}
2229
2230/// Trait for fixed size variant types.
2231pub unsafe trait FixedSizeVariantType: StaticVariantType + Sized + Copy {}
2232unsafe impl FixedSizeVariantType for u8 {}
2233unsafe impl FixedSizeVariantType for i16 {}
2234unsafe impl FixedSizeVariantType for u16 {}
2235unsafe impl FixedSizeVariantType for i32 {}
2236unsafe impl FixedSizeVariantType for u32 {}
2237unsafe impl FixedSizeVariantType for i64 {}
2238unsafe impl FixedSizeVariantType for u64 {}
2239unsafe impl FixedSizeVariantType for f64 {}
2240unsafe impl FixedSizeVariantType for bool {}
2241
2242/// Wrapper type for fixed size type arrays.
2243///
2244/// Converting this from/to a `Variant` is generally more efficient than working on the type
2245/// directly. This is especially important when deriving `Variant` trait implementations on custom
2246/// types.
2247///
2248/// This wrapper type can hold for example `Vec<u8>`, `Box<[u8]>` and similar types.
2249#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2250pub struct FixedSizeVariantArray<A, T>(A, std::marker::PhantomData<T>)
2251where
2252    A: AsRef<[T]>,
2253    T: FixedSizeVariantType;
2254
2255impl<A: AsRef<[T]>, T: FixedSizeVariantType> From<A> for FixedSizeVariantArray<A, T> {
2256    fn from(array: A) -> Self {
2257        FixedSizeVariantArray(array, std::marker::PhantomData)
2258    }
2259}
2260
2261impl<A: AsRef<[T]>, T: FixedSizeVariantType> FixedSizeVariantArray<A, T> {
2262    pub fn into_inner(self) -> A {
2263        self.0
2264    }
2265}
2266
2267impl<A: AsRef<[T]>, T: FixedSizeVariantType> std::ops::Deref for FixedSizeVariantArray<A, T> {
2268    type Target = A;
2269
2270    #[inline]
2271    fn deref(&self) -> &Self::Target {
2272        &self.0
2273    }
2274}
2275
2276impl<A: AsRef<[T]>, T: FixedSizeVariantType> std::ops::DerefMut for FixedSizeVariantArray<A, T> {
2277    #[inline]
2278    fn deref_mut(&mut self) -> &mut Self::Target {
2279        &mut self.0
2280    }
2281}
2282
2283impl<A: AsRef<[T]>, T: FixedSizeVariantType> AsRef<A> for FixedSizeVariantArray<A, T> {
2284    #[inline]
2285    fn as_ref(&self) -> &A {
2286        &self.0
2287    }
2288}
2289
2290impl<A: AsRef<[T]>, T: FixedSizeVariantType> AsMut<A> for FixedSizeVariantArray<A, T> {
2291    #[inline]
2292    fn as_mut(&mut self) -> &mut A {
2293        &mut self.0
2294    }
2295}
2296
2297impl<A: AsRef<[T]>, T: FixedSizeVariantType> AsRef<[T]> for FixedSizeVariantArray<A, T> {
2298    #[inline]
2299    fn as_ref(&self) -> &[T] {
2300        self.0.as_ref()
2301    }
2302}
2303
2304impl<A: AsRef<[T]> + AsMut<[T]>, T: FixedSizeVariantType> AsMut<[T]>
2305    for FixedSizeVariantArray<A, T>
2306{
2307    #[inline]
2308    fn as_mut(&mut self) -> &mut [T] {
2309        self.0.as_mut()
2310    }
2311}
2312
2313impl<A: AsRef<[T]>, T: FixedSizeVariantType> StaticVariantType for FixedSizeVariantArray<A, T> {
2314    fn static_variant_type() -> Cow<'static, VariantTy> {
2315        <[T]>::static_variant_type()
2316    }
2317}
2318
2319impl<A: AsRef<[T]> + for<'a> From<&'a [T]>, T: FixedSizeVariantType> FromVariant
2320    for FixedSizeVariantArray<A, T>
2321{
2322    fn from_variant(variant: &Variant) -> Option<Self> {
2323        Some(FixedSizeVariantArray(
2324            A::from(variant.fixed_array::<T>().ok()?),
2325            std::marker::PhantomData,
2326        ))
2327    }
2328}
2329
2330impl<A: AsRef<[T]>, T: FixedSizeVariantType> ToVariant for FixedSizeVariantArray<A, T> {
2331    fn to_variant(&self) -> Variant {
2332        Variant::array_from_fixed_array(self.0.as_ref())
2333    }
2334}
2335
2336impl<A: AsRef<[T]> + 'static, T: FixedSizeVariantType> From<FixedSizeVariantArray<A, T>>
2337    for Variant
2338{
2339    #[doc(alias = "g_variant_new_from_data")]
2340    fn from(a: FixedSizeVariantArray<A, T>) -> Self {
2341        unsafe {
2342            let data = Box::new(a.0);
2343            let (data_ptr, len) = {
2344                let data = (*data).as_ref();
2345                (data.as_ptr(), mem::size_of_val(data))
2346            };
2347
2348            unsafe extern "C" fn free_data<A: AsRef<[T]>, T: FixedSizeVariantType>(
2349                ptr: ffi::gpointer,
2350            ) {
2351                unsafe {
2352                    let _ = Box::from_raw(ptr as *mut A);
2353                }
2354            }
2355
2356            from_glib_none(ffi::g_variant_new_from_data(
2357                T::static_variant_type().to_glib_none().0,
2358                data_ptr as ffi::gconstpointer,
2359                len,
2360                false.into_glib(),
2361                Some(free_data::<A, T>),
2362                Box::into_raw(data) as ffi::gpointer,
2363            ))
2364        }
2365    }
2366}
2367
2368/// A wrapper type around `Variant` handles.
2369#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2370pub struct Handle(pub i32);
2371
2372impl From<i32> for Handle {
2373    fn from(v: i32) -> Self {
2374        Handle(v)
2375    }
2376}
2377
2378impl From<Handle> for i32 {
2379    fn from(v: Handle) -> Self {
2380        v.0
2381    }
2382}
2383
2384impl StaticVariantType for Handle {
2385    fn static_variant_type() -> Cow<'static, VariantTy> {
2386        Cow::Borrowed(VariantTy::HANDLE)
2387    }
2388}
2389
2390impl ToVariant for Handle {
2391    fn to_variant(&self) -> Variant {
2392        unsafe { from_glib_none(ffi::g_variant_new_handle(self.0)) }
2393    }
2394}
2395
2396impl From<Handle> for Variant {
2397    #[inline]
2398    fn from(h: Handle) -> Self {
2399        h.to_variant()
2400    }
2401}
2402
2403impl FromVariant for Handle {
2404    fn from_variant(variant: &Variant) -> Option<Self> {
2405        unsafe {
2406            if variant.is::<Self>() {
2407                Some(Handle(ffi::g_variant_get_handle(variant.to_glib_none().0)))
2408            } else {
2409                None
2410            }
2411        }
2412    }
2413}
2414
2415/// A wrapper type around `Variant` object paths.
2416///
2417/// Values of these type are guaranteed to be valid object paths.
2418#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2419pub struct ObjectPath(String);
2420
2421impl ObjectPath {
2422    pub fn as_str(&self) -> &str {
2423        &self.0
2424    }
2425}
2426
2427impl Display for ObjectPath {
2428    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2429        self.0.fmt(f)
2430    }
2431}
2432
2433impl std::ops::Deref for ObjectPath {
2434    type Target = str;
2435
2436    #[inline]
2437    fn deref(&self) -> &Self::Target {
2438        &self.0
2439    }
2440}
2441
2442impl TryFrom<String> for ObjectPath {
2443    type Error = crate::BoolError;
2444
2445    fn try_from(v: String) -> Result<Self, Self::Error> {
2446        if !Variant::is_object_path(&v) {
2447            return Err(bool_error!("Invalid object path"));
2448        }
2449
2450        Ok(ObjectPath(v))
2451    }
2452}
2453
2454impl<'a> TryFrom<&'a str> for ObjectPath {
2455    type Error = crate::BoolError;
2456
2457    fn try_from(v: &'a str) -> Result<Self, Self::Error> {
2458        ObjectPath::try_from(String::from(v))
2459    }
2460}
2461
2462impl From<ObjectPath> for String {
2463    fn from(v: ObjectPath) -> Self {
2464        v.0
2465    }
2466}
2467
2468impl StaticVariantType for ObjectPath {
2469    fn static_variant_type() -> Cow<'static, VariantTy> {
2470        Cow::Borrowed(VariantTy::OBJECT_PATH)
2471    }
2472}
2473
2474impl ToVariant for ObjectPath {
2475    fn to_variant(&self) -> Variant {
2476        unsafe { from_glib_none(ffi::g_variant_new_object_path(self.0.to_glib_none().0)) }
2477    }
2478}
2479
2480impl From<ObjectPath> for Variant {
2481    #[inline]
2482    fn from(p: ObjectPath) -> Self {
2483        let mut s = p.0;
2484        s.push('\0');
2485        unsafe { Self::from_data_trusted::<ObjectPath, _>(s) }
2486    }
2487}
2488
2489impl FromVariant for ObjectPath {
2490    #[allow(unused_unsafe)]
2491    fn from_variant(variant: &Variant) -> Option<Self> {
2492        unsafe {
2493            if variant.is::<Self>() {
2494                Some(ObjectPath(String::from(variant.str().unwrap())))
2495            } else {
2496                None
2497            }
2498        }
2499    }
2500}
2501
2502/// A wrapper type around `Variant` signatures.
2503///
2504/// Values of these type are guaranteed to be valid signatures.
2505#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2506pub struct Signature(String);
2507
2508impl Signature {
2509    pub fn as_str(&self) -> &str {
2510        &self.0
2511    }
2512}
2513
2514impl std::ops::Deref for Signature {
2515    type Target = str;
2516
2517    #[inline]
2518    fn deref(&self) -> &Self::Target {
2519        &self.0
2520    }
2521}
2522
2523impl TryFrom<String> for Signature {
2524    type Error = crate::BoolError;
2525
2526    fn try_from(v: String) -> Result<Self, Self::Error> {
2527        if !Variant::is_signature(&v) {
2528            return Err(bool_error!("Invalid signature"));
2529        }
2530
2531        Ok(Signature(v))
2532    }
2533}
2534
2535impl<'a> TryFrom<&'a str> for Signature {
2536    type Error = crate::BoolError;
2537
2538    fn try_from(v: &'a str) -> Result<Self, Self::Error> {
2539        Signature::try_from(String::from(v))
2540    }
2541}
2542
2543impl From<Signature> for String {
2544    fn from(v: Signature) -> Self {
2545        v.0
2546    }
2547}
2548
2549impl StaticVariantType for Signature {
2550    fn static_variant_type() -> Cow<'static, VariantTy> {
2551        Cow::Borrowed(VariantTy::SIGNATURE)
2552    }
2553}
2554
2555impl ToVariant for Signature {
2556    fn to_variant(&self) -> Variant {
2557        unsafe { from_glib_none(ffi::g_variant_new_signature(self.0.to_glib_none().0)) }
2558    }
2559}
2560
2561impl From<Signature> for Variant {
2562    #[inline]
2563    fn from(s: Signature) -> Self {
2564        let mut s = s.0;
2565        s.push('\0');
2566        unsafe { Self::from_data_trusted::<Signature, _>(s) }
2567    }
2568}
2569
2570impl FromVariant for Signature {
2571    #[allow(unused_unsafe)]
2572    fn from_variant(variant: &Variant) -> Option<Self> {
2573        unsafe {
2574            if variant.is::<Self>() {
2575                Some(Signature(String::from(variant.str().unwrap())))
2576            } else {
2577                None
2578            }
2579        }
2580    }
2581}
2582
2583#[cfg(test)]
2584mod tests {
2585    use std::collections::{HashMap, HashSet};
2586
2587    use super::*;
2588
2589    macro_rules! unsigned {
2590        ($name:ident, $ty:ident) => {
2591            #[test]
2592            fn $name() {
2593                let mut n = $ty::MAX;
2594                while n > 0 {
2595                    let v = n.to_variant();
2596                    assert_eq!(v.get(), Some(n));
2597                    n /= 2;
2598                }
2599            }
2600        };
2601    }
2602
2603    macro_rules! signed {
2604        ($name:ident, $ty:ident) => {
2605            #[test]
2606            fn $name() {
2607                let mut n = $ty::MAX;
2608                while n > 0 {
2609                    let v = n.to_variant();
2610                    assert_eq!(v.get(), Some(n));
2611                    let v = (-n).to_variant();
2612                    assert_eq!(v.get(), Some(-n));
2613                    n /= 2;
2614                }
2615            }
2616        };
2617    }
2618
2619    unsigned!(test_u8, u8);
2620    unsigned!(test_u16, u16);
2621    unsigned!(test_u32, u32);
2622    unsigned!(test_u64, u64);
2623    signed!(test_i16, i16);
2624    signed!(test_i32, i32);
2625    signed!(test_i64, i64);
2626
2627    #[test]
2628    fn test_str() {
2629        let s = "this is a test";
2630        let v = s.to_variant();
2631        assert_eq!(v.str(), Some(s));
2632        assert_eq!(42u32.to_variant().str(), None);
2633    }
2634
2635    #[test]
2636    fn test_fixed_array() {
2637        let b = b"this is a test";
2638        let v = Variant::array_from_fixed_array(&b[..]);
2639        assert_eq!(v.type_().as_str(), "ay");
2640        assert_eq!(v.fixed_array::<u8>().unwrap(), b);
2641        assert!(42u32.to_variant().fixed_array::<u8>().is_err());
2642
2643        let b = [1u32, 10u32, 100u32];
2644        let v = Variant::array_from_fixed_array(&b);
2645        assert_eq!(v.type_().as_str(), "au");
2646        assert_eq!(v.fixed_array::<u32>().unwrap(), b);
2647        assert!(v.fixed_array::<u8>().is_err());
2648
2649        let b = [true, false, true];
2650        let v = Variant::array_from_fixed_array(&b);
2651        assert_eq!(v.type_().as_str(), "ab");
2652        assert_eq!(v.fixed_array::<bool>().unwrap(), b);
2653        assert!(v.fixed_array::<u8>().is_err());
2654
2655        let b = [1.0f64, 2.0f64, 3.0f64];
2656        let v = Variant::array_from_fixed_array(&b);
2657        assert_eq!(v.type_().as_str(), "ad");
2658        #[allow(clippy::float_cmp)]
2659        {
2660            assert_eq!(v.fixed_array::<f64>().unwrap(), b);
2661        }
2662        assert!(v.fixed_array::<u64>().is_err());
2663    }
2664
2665    #[test]
2666    fn test_fixed_variant_array() {
2667        let b = FixedSizeVariantArray::from(&b"this is a test"[..]);
2668        let v = b.to_variant();
2669        assert_eq!(v.type_().as_str(), "ay");
2670        assert_eq!(
2671            &*v.get::<FixedSizeVariantArray<Vec<u8>, u8>>().unwrap(),
2672            &*b
2673        );
2674
2675        let b = FixedSizeVariantArray::from(vec![1i32, 2, 3]);
2676        let v = b.to_variant();
2677        assert_eq!(v.type_().as_str(), "ai");
2678        assert_eq!(v.get::<FixedSizeVariantArray<Vec<i32>, i32>>().unwrap(), b);
2679    }
2680
2681    #[test]
2682    fn test_string() {
2683        let s = String::from("this is a test");
2684        let v = s.to_variant();
2685        assert_eq!(v.get(), Some(s));
2686        assert_eq!(v.normal_form(), v);
2687    }
2688
2689    #[test]
2690    fn test_eq() {
2691        let v1 = "this is a test".to_variant();
2692        let v2 = "this is a test".to_variant();
2693        let v3 = "test".to_variant();
2694        assert_eq!(v1, v2);
2695        assert_ne!(v1, v3);
2696    }
2697
2698    #[test]
2699    fn test_hash() {
2700        let v1 = "this is a test".to_variant();
2701        let v2 = "this is a test".to_variant();
2702        let v3 = "test".to_variant();
2703        let mut set = HashSet::new();
2704        set.insert(v1);
2705        assert!(set.contains(&v2));
2706        assert!(!set.contains(&v3));
2707
2708        assert_eq!(
2709            <HashMap<&str, (&str, u8, u32)>>::static_variant_type().as_str(),
2710            "a{s(syu)}"
2711        );
2712    }
2713
2714    #[test]
2715    fn test_array() {
2716        assert_eq!(<Vec<&str>>::static_variant_type().as_str(), "as");
2717        assert_eq!(
2718            <Vec<(&str, u8, u32)>>::static_variant_type().as_str(),
2719            "a(syu)"
2720        );
2721        let a = ["foo", "bar", "baz"].to_variant();
2722        assert_eq!(a.normal_form(), a);
2723        assert_eq!(a.array_iter_str().unwrap().len(), 3);
2724        let o = 0u32.to_variant();
2725        assert!(o.array_iter_str().is_err());
2726    }
2727
2728    #[test]
2729    fn test_array_from_iter() {
2730        let a = Variant::array_from_iter::<String>(
2731            ["foo", "bar", "baz"].into_iter().map(|s| s.to_variant()),
2732        );
2733        assert_eq!(a.type_().as_str(), "as");
2734        assert_eq!(a.n_children(), 3);
2735
2736        assert_eq!(a.try_child_get::<String>(0), Ok(Some(String::from("foo"))));
2737        assert_eq!(a.try_child_get::<String>(1), Ok(Some(String::from("bar"))));
2738        assert_eq!(a.try_child_get::<String>(2), Ok(Some(String::from("baz"))));
2739    }
2740
2741    #[test]
2742    fn test_array_collect() {
2743        let a = ["foo", "bar", "baz"].into_iter().collect::<Variant>();
2744        assert_eq!(a.type_().as_str(), "as");
2745        assert_eq!(a.n_children(), 3);
2746
2747        assert_eq!(a.try_child_get::<String>(0), Ok(Some(String::from("foo"))));
2748        assert_eq!(a.try_child_get::<String>(1), Ok(Some(String::from("bar"))));
2749        assert_eq!(a.try_child_get::<String>(2), Ok(Some(String::from("baz"))));
2750    }
2751
2752    #[test]
2753    fn test_tuple() {
2754        assert_eq!(<(&str, u32)>::static_variant_type().as_str(), "(su)");
2755        assert_eq!(<(&str, u8, u32)>::static_variant_type().as_str(), "(syu)");
2756        let a = ("test", 1u8, 2u32).to_variant();
2757        assert_eq!(a.normal_form(), a);
2758        assert_eq!(a.try_child_get::<String>(0), Ok(Some(String::from("test"))));
2759        assert_eq!(a.try_child_get::<u8>(1), Ok(Some(1u8)));
2760        assert_eq!(a.try_child_get::<u32>(2), Ok(Some(2u32)));
2761        assert_eq!(
2762            a.try_get::<(String, u8, u32)>(),
2763            Ok((String::from("test"), 1u8, 2u32))
2764        );
2765    }
2766
2767    #[test]
2768    fn test_tuple_from_iter() {
2769        let a = Variant::tuple_from_iter(["foo".to_variant(), 1u8.to_variant(), 2i32.to_variant()]);
2770        assert_eq!(a.type_().as_str(), "(syi)");
2771        assert_eq!(a.n_children(), 3);
2772
2773        assert_eq!(a.try_child_get::<String>(0), Ok(Some(String::from("foo"))));
2774        assert_eq!(a.try_child_get::<u8>(1), Ok(Some(1u8)));
2775        assert_eq!(a.try_child_get::<i32>(2), Ok(Some(2i32)));
2776    }
2777
2778    #[test]
2779    fn test_empty() {
2780        assert_eq!(<()>::static_variant_type().as_str(), "()");
2781        let a = ().to_variant();
2782        assert_eq!(a.type_().as_str(), "()");
2783        assert_eq!(a.get::<()>(), Some(()));
2784    }
2785
2786    #[test]
2787    fn test_maybe() {
2788        assert!(<Option<()>>::static_variant_type().is_maybe());
2789        let m1 = Some(()).to_variant();
2790        assert_eq!(m1.type_().as_str(), "m()");
2791
2792        assert_eq!(m1.get::<Option<()>>(), Some(Some(())));
2793        assert!(m1.as_maybe().is_some());
2794
2795        let m2 = None::<()>.to_variant();
2796        assert!(m2.as_maybe().is_none());
2797    }
2798
2799    #[test]
2800    fn test_btreemap() {
2801        assert_eq!(
2802            <BTreeMap<String, u32>>::static_variant_type().as_str(),
2803            "a{su}"
2804        );
2805        // Validate that BTreeMap adds entries to dict in sorted order
2806        let mut m = BTreeMap::new();
2807        let total = 20;
2808        for n in 0..total {
2809            let k = format!("v{n:04}");
2810            m.insert(k, n as u32);
2811        }
2812        let v = m.to_variant();
2813        let n = v.n_children();
2814        assert_eq!(total, n);
2815        for n in 0..total {
2816            let child = v
2817                .try_child_get::<DictEntry<String, u32>>(n)
2818                .unwrap()
2819                .unwrap();
2820            assert_eq!(*child.value(), n as u32);
2821        }
2822
2823        assert_eq!(BTreeMap::from_variant(&v).unwrap(), m);
2824    }
2825
2826    #[test]
2827    fn test_get() -> Result<(), Box<dyn std::error::Error>> {
2828        let u = 42u32.to_variant();
2829        assert!(u.get::<i32>().is_none());
2830        assert_eq!(u.get::<u32>().unwrap(), 42);
2831        assert!(u.try_get::<i32>().is_err());
2832        // Test ? conversion
2833        assert_eq!(u.try_get::<u32>()?, 42);
2834        Ok(())
2835    }
2836
2837    #[test]
2838    fn test_byteswap() {
2839        let u = 42u32.to_variant();
2840        assert_eq!(u.byteswap().get::<u32>().unwrap(), 704643072u32);
2841        assert_eq!(u.byteswap().byteswap().get::<u32>().unwrap(), 42u32);
2842    }
2843
2844    #[test]
2845    fn test_try_child() {
2846        let a = ["foo"].to_variant();
2847        assert!(a.try_child_value(0).is_some());
2848        assert_eq!(a.try_child_get::<String>(0).unwrap().unwrap(), "foo");
2849        assert_eq!(a.child_get::<String>(0), "foo");
2850        assert!(a.try_child_get::<u32>(0).is_err());
2851        assert!(a.try_child_value(1).is_none());
2852        assert!(a.try_child_get::<String>(1).unwrap().is_none());
2853        let u = 42u32.to_variant();
2854        assert!(u.try_child_value(0).is_none());
2855        assert!(u.try_child_get::<String>(0).unwrap().is_none());
2856    }
2857
2858    #[test]
2859    fn test_serialize() {
2860        let a = ("test", 1u8, 2u32).to_variant();
2861
2862        let bytes = a.data_as_bytes();
2863        let data = a.data();
2864        let len = a.size();
2865        assert_eq!(bytes.len(), len);
2866        assert_eq!(data.len(), len);
2867
2868        let mut store_data = vec![0u8; len];
2869        assert_eq!(a.store(&mut store_data).unwrap(), len);
2870
2871        assert_eq!(&bytes, data);
2872        assert_eq!(&store_data, data);
2873
2874        let b = Variant::from_data::<(String, u8, u32), _>(store_data);
2875        assert_eq!(a, b);
2876
2877        let c = Variant::from_bytes::<(String, u8, u32)>(&bytes);
2878        assert_eq!(a, c);
2879    }
2880
2881    #[test]
2882    fn test_print_parse() {
2883        let a = ("test", 1u8, 2u32).to_variant();
2884
2885        let a2 = Variant::parse(Some(a.type_()), &a.print(false)).unwrap();
2886        assert_eq!(a, a2);
2887
2888        let a3: Variant = a.to_string().parse().unwrap();
2889        assert_eq!(a, a3);
2890    }
2891
2892    #[cfg(any(unix, windows))]
2893    #[test]
2894    fn test_paths() {
2895        use std::path::PathBuf;
2896
2897        let path = PathBuf::from("foo");
2898        let v = path.to_variant();
2899        assert_eq!(PathBuf::from_variant(&v), Some(path));
2900    }
2901
2902    #[test]
2903    fn test_regression_from_variant_panics() {
2904        let variant = "text".to_variant();
2905        let hashmap: Option<HashMap<u64, u64>> = FromVariant::from_variant(&variant);
2906        assert!(hashmap.is_none());
2907
2908        let variant = HashMap::<u64, u64>::new().to_variant();
2909        let hashmap: Option<HashMap<u64, u64>> = FromVariant::from_variant(&variant);
2910        assert!(hashmap.is_some());
2911    }
2912}