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    ffi, gobject_ffi, prelude::*, translate::*, Bytes, Type, VariantIter, VariantStrIter,
116    VariantTy, VariantType,
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    #[doc(alias = "GVariant")]
125    pub struct Variant(Shared<ffi::GVariant>);
126
127    match fn {
128        ref => |ptr| ffi::g_variant_ref_sink(ptr),
129        unref => |ptr| ffi::g_variant_unref(ptr),
130    }
131}
132
133impl StaticType for Variant {
134    #[inline]
135    fn static_type() -> Type {
136        Type::VARIANT
137    }
138}
139
140#[doc(hidden)]
141impl crate::value::ValueType for Variant {
142    type Type = Variant;
143}
144
145#[doc(hidden)]
146impl crate::value::ValueTypeOptional for Variant {}
147
148#[doc(hidden)]
149unsafe impl<'a> crate::value::FromValue<'a> for Variant {
150    type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
151
152    unsafe fn from_value(value: &'a crate::Value) -> Self {
153        let ptr = gobject_ffi::g_value_dup_variant(value.to_glib_none().0);
154        debug_assert!(!ptr.is_null());
155        from_glib_full(ptr)
156    }
157}
158
159#[doc(hidden)]
160impl crate::value::ToValue for Variant {
161    fn to_value(&self) -> crate::Value {
162        unsafe {
163            let mut value = crate::Value::from_type_unchecked(Variant::static_type());
164            gobject_ffi::g_value_take_variant(value.to_glib_none_mut().0, self.to_glib_full());
165            value
166        }
167    }
168
169    fn value_type(&self) -> crate::Type {
170        Variant::static_type()
171    }
172}
173
174#[doc(hidden)]
175impl From<Variant> for crate::Value {
176    #[inline]
177    fn from(v: Variant) -> Self {
178        unsafe {
179            let mut value = crate::Value::from_type_unchecked(Variant::static_type());
180            gobject_ffi::g_value_take_variant(value.to_glib_none_mut().0, v.into_glib_ptr());
181            value
182        }
183    }
184}
185
186#[doc(hidden)]
187impl crate::value::ToValueOptional for Variant {
188    fn to_value_optional(s: Option<&Self>) -> crate::Value {
189        let mut value = crate::Value::for_value_type::<Self>();
190        unsafe {
191            gobject_ffi::g_value_take_variant(value.to_glib_none_mut().0, s.to_glib_full());
192        }
193
194        value
195    }
196}
197
198// rustdoc-stripper-ignore-next
199/// An error returned from the [`try_get`](struct.Variant.html#method.try_get) function
200/// on a [`Variant`](struct.Variant.html) when the expected type does not match the actual type.
201#[derive(Clone, PartialEq, Eq, Debug)]
202pub struct VariantTypeMismatchError {
203    pub actual: VariantType,
204    pub expected: VariantType,
205}
206
207impl VariantTypeMismatchError {
208    pub fn new(actual: VariantType, expected: VariantType) -> Self {
209        Self { actual, expected }
210    }
211}
212
213impl fmt::Display for VariantTypeMismatchError {
214    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215        write!(
216            f,
217            "Type mismatch: Expected '{}' got '{}'",
218            self.expected, self.actual
219        )
220    }
221}
222
223impl std::error::Error for VariantTypeMismatchError {}
224
225impl Variant {
226    // rustdoc-stripper-ignore-next
227    /// Returns the type of the value.
228    #[doc(alias = "g_variant_get_type")]
229    pub fn type_(&self) -> &VariantTy {
230        unsafe { VariantTy::from_ptr(ffi::g_variant_get_type(self.to_glib_none().0)) }
231    }
232
233    // rustdoc-stripper-ignore-next
234    /// Returns `true` if the type of the value corresponds to `T`.
235    #[inline]
236    #[doc(alias = "g_variant_is_of_type")]
237    pub fn is<T: StaticVariantType>(&self) -> bool {
238        self.is_type(&T::static_variant_type())
239    }
240
241    // rustdoc-stripper-ignore-next
242    /// Returns `true` if the type of the value corresponds to `type_`.
243    ///
244    /// This is equivalent to [`self.type_().is_subtype_of(type_)`](VariantTy::is_subtype_of).
245    #[inline]
246    #[doc(alias = "g_variant_is_of_type")]
247    pub fn is_type(&self, type_: &VariantTy) -> bool {
248        unsafe {
249            from_glib(ffi::g_variant_is_of_type(
250                self.to_glib_none().0,
251                type_.to_glib_none().0,
252            ))
253        }
254    }
255
256    // rustdoc-stripper-ignore-next
257    /// Returns the classification of the variant.
258    #[doc(alias = "g_variant_classify")]
259    pub fn classify(&self) -> crate::VariantClass {
260        unsafe { from_glib(ffi::g_variant_classify(self.to_glib_none().0)) }
261    }
262
263    // rustdoc-stripper-ignore-next
264    /// Tries to extract a value of type `T`.
265    ///
266    /// Returns `Some` if `T` matches the variant's type.
267    #[inline]
268    pub fn get<T: FromVariant>(&self) -> Option<T> {
269        T::from_variant(self)
270    }
271
272    // rustdoc-stripper-ignore-next
273    /// Tries to extract a value of type `T`.
274    pub fn try_get<T: FromVariant>(&self) -> Result<T, VariantTypeMismatchError> {
275        self.get().ok_or_else(|| {
276            VariantTypeMismatchError::new(
277                self.type_().to_owned(),
278                T::static_variant_type().into_owned(),
279            )
280        })
281    }
282
283    // rustdoc-stripper-ignore-next
284    /// Boxes value.
285    #[inline]
286    pub fn from_variant(value: &Variant) -> Self {
287        unsafe { from_glib_none(ffi::g_variant_new_variant(value.to_glib_none().0)) }
288    }
289
290    // rustdoc-stripper-ignore-next
291    /// Unboxes self.
292    ///
293    /// Returns `Some` if self contains a `Variant`.
294    #[inline]
295    #[doc(alias = "get_variant")]
296    pub fn as_variant(&self) -> Option<Variant> {
297        unsafe { from_glib_full(ffi::g_variant_get_variant(self.to_glib_none().0)) }
298    }
299
300    // rustdoc-stripper-ignore-next
301    /// Reads a child item out of a container `Variant` instance.
302    ///
303    /// # Panics
304    ///
305    /// * if `self` is not a container type.
306    /// * if given `index` is larger than number of children.
307    #[doc(alias = "get_child_value")]
308    #[doc(alias = "g_variant_get_child_value")]
309    #[must_use]
310    pub fn child_value(&self, index: usize) -> Variant {
311        assert!(self.is_container());
312        assert!(index < self.n_children());
313
314        unsafe { from_glib_full(ffi::g_variant_get_child_value(self.to_glib_none().0, index)) }
315    }
316
317    // rustdoc-stripper-ignore-next
318    /// Try to read a child item out of a container `Variant` instance.
319    ///
320    /// It returns `None` if `self` is not a container type or if the given
321    /// `index` is larger than number of children.
322    pub fn try_child_value(&self, index: usize) -> Option<Variant> {
323        if !(self.is_container() && index < self.n_children()) {
324            return None;
325        }
326
327        let v =
328            unsafe { from_glib_full(ffi::g_variant_get_child_value(self.to_glib_none().0, index)) };
329        Some(v)
330    }
331
332    // rustdoc-stripper-ignore-next
333    /// Try to read a child item out of a container `Variant` instance.
334    ///
335    /// It returns `Ok(None)` if `self` is not a container type or if the given
336    /// `index` is larger than number of children.  An error is thrown if the
337    /// type does not match.
338    pub fn try_child_get<T: StaticVariantType + FromVariant>(
339        &self,
340        index: usize,
341    ) -> Result<Option<T>, VariantTypeMismatchError> {
342        // TODO: In the future optimize this by using g_variant_get_child()
343        // directly to avoid allocating a GVariant.
344        self.try_child_value(index).map(|v| v.try_get()).transpose()
345    }
346
347    // rustdoc-stripper-ignore-next
348    /// Read a child item out of a container `Variant` instance.
349    ///
350    /// # Panics
351    ///
352    /// * if `self` is not a container type.
353    /// * if given `index` is larger than number of children.
354    /// * if the expected variant type does not match
355    pub fn child_get<T: StaticVariantType + FromVariant>(&self, index: usize) -> T {
356        // TODO: In the future optimize this by using g_variant_get_child()
357        // directly to avoid allocating a GVariant.
358        self.child_value(index).get().unwrap()
359    }
360
361    // rustdoc-stripper-ignore-next
362    /// Tries to extract a `&str`.
363    ///
364    /// Returns `Some` if the variant has a string type (`s`, `o` or `g` type
365    /// strings).
366    #[doc(alias = "get_str")]
367    #[doc(alias = "g_variant_get_string")]
368    pub fn str(&self) -> Option<&str> {
369        unsafe {
370            match self.type_().as_str() {
371                "s" | "o" | "g" => {
372                    let mut len = 0;
373                    let ptr = ffi::g_variant_get_string(self.to_glib_none().0, &mut len);
374                    if len == 0 {
375                        Some("")
376                    } else {
377                        let ret = str::from_utf8_unchecked(slice::from_raw_parts(
378                            ptr as *const u8,
379                            len as _,
380                        ));
381                        Some(ret)
382                    }
383                }
384                _ => None,
385            }
386        }
387    }
388
389    // rustdoc-stripper-ignore-next
390    /// Tries to extract a `&[T]` from a variant of array type with a suitable element type.
391    ///
392    /// Returns an error if the type is wrong.
393    #[doc(alias = "g_variant_get_fixed_array")]
394    pub fn fixed_array<T: FixedSizeVariantType>(&self) -> Result<&[T], VariantTypeMismatchError> {
395        unsafe {
396            let expected_ty = T::static_variant_type().as_array();
397            if self.type_() != expected_ty {
398                return Err(VariantTypeMismatchError {
399                    actual: self.type_().to_owned(),
400                    expected: expected_ty.into_owned(),
401                });
402            }
403
404            let mut n_elements = mem::MaybeUninit::uninit();
405            let ptr = ffi::g_variant_get_fixed_array(
406                self.to_glib_none().0,
407                n_elements.as_mut_ptr(),
408                mem::size_of::<T>(),
409            );
410
411            let n_elements = n_elements.assume_init();
412            if n_elements == 0 {
413                Ok(&[])
414            } else {
415                debug_assert!(!ptr.is_null());
416                Ok(slice::from_raw_parts(ptr as *const T, n_elements))
417            }
418        }
419    }
420
421    // rustdoc-stripper-ignore-next
422    /// Creates a new Variant array from children.
423    ///
424    /// # Panics
425    ///
426    /// This function panics if not all variants are of type `T`.
427    #[doc(alias = "g_variant_new_array")]
428    pub fn array_from_iter<T: StaticVariantType>(
429        children: impl IntoIterator<Item = Variant>,
430    ) -> Self {
431        Self::array_from_iter_with_type(&T::static_variant_type(), children)
432    }
433
434    // rustdoc-stripper-ignore-next
435    /// Creates a new Variant array from children with the specified type.
436    ///
437    /// # Panics
438    ///
439    /// This function panics if not all variants are of type `type_`.
440    #[doc(alias = "g_variant_new_array")]
441    pub fn array_from_iter_with_type(
442        type_: &VariantTy,
443        children: impl IntoIterator<Item = impl AsRef<Variant>>,
444    ) -> Self {
445        unsafe {
446            let mut builder = mem::MaybeUninit::uninit();
447            ffi::g_variant_builder_init(builder.as_mut_ptr(), type_.as_array().to_glib_none().0);
448            let mut builder = builder.assume_init();
449            for value in children.into_iter() {
450                let value = value.as_ref();
451                if ffi::g_variant_is_of_type(value.to_glib_none().0, type_.to_glib_none().0)
452                    == ffi::GFALSE
453                {
454                    ffi::g_variant_builder_clear(&mut builder);
455                    assert!(value.is_type(type_));
456                }
457
458                ffi::g_variant_builder_add_value(&mut builder, value.to_glib_none().0);
459            }
460            from_glib_none(ffi::g_variant_builder_end(&mut builder))
461        }
462    }
463
464    // rustdoc-stripper-ignore-next
465    /// Creates a new Variant array from a fixed array.
466    #[doc(alias = "g_variant_new_fixed_array")]
467    pub fn array_from_fixed_array<T: FixedSizeVariantType>(array: &[T]) -> Self {
468        let type_ = T::static_variant_type();
469
470        unsafe {
471            from_glib_none(ffi::g_variant_new_fixed_array(
472                type_.as_ptr(),
473                array.as_ptr() as ffi::gconstpointer,
474                array.len(),
475                mem::size_of::<T>(),
476            ))
477        }
478    }
479
480    // rustdoc-stripper-ignore-next
481    /// Creates a new Variant tuple from children.
482    #[doc(alias = "g_variant_new_tuple")]
483    pub fn tuple_from_iter(children: impl IntoIterator<Item = impl AsRef<Variant>>) -> Self {
484        unsafe {
485            let mut builder = mem::MaybeUninit::uninit();
486            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::TUPLE.to_glib_none().0);
487            let mut builder = builder.assume_init();
488            for value in children.into_iter() {
489                ffi::g_variant_builder_add_value(&mut builder, value.as_ref().to_glib_none().0);
490            }
491            from_glib_none(ffi::g_variant_builder_end(&mut builder))
492        }
493    }
494
495    // rustdoc-stripper-ignore-next
496    /// Creates a new dictionary entry Variant.
497    ///
498    /// [DictEntry] should be preferred over this when the types are known statically.
499    #[doc(alias = "g_variant_new_dict_entry")]
500    pub fn from_dict_entry(key: &Variant, value: &Variant) -> Self {
501        unsafe {
502            from_glib_none(ffi::g_variant_new_dict_entry(
503                key.to_glib_none().0,
504                value.to_glib_none().0,
505            ))
506        }
507    }
508
509    // rustdoc-stripper-ignore-next
510    /// Creates a new maybe Variant.
511    #[doc(alias = "g_variant_new_maybe")]
512    pub fn from_maybe<T: StaticVariantType>(child: Option<&Variant>) -> Self {
513        let type_ = T::static_variant_type();
514        match child {
515            Some(child) => {
516                assert_eq!(type_, child.type_());
517
518                Self::from_some(child)
519            }
520            None => Self::from_none(&type_),
521        }
522    }
523
524    // rustdoc-stripper-ignore-next
525    /// Creates a new maybe Variant from a child.
526    #[doc(alias = "g_variant_new_maybe")]
527    pub fn from_some(child: &Variant) -> Self {
528        unsafe {
529            from_glib_none(ffi::g_variant_new_maybe(
530                ptr::null(),
531                child.to_glib_none().0,
532            ))
533        }
534    }
535
536    // rustdoc-stripper-ignore-next
537    /// Creates a new maybe Variant with Nothing.
538    #[doc(alias = "g_variant_new_maybe")]
539    pub fn from_none(type_: &VariantTy) -> Self {
540        unsafe {
541            from_glib_none(ffi::g_variant_new_maybe(
542                type_.to_glib_none().0,
543                ptr::null_mut(),
544            ))
545        }
546    }
547
548    // rustdoc-stripper-ignore-next
549    /// Extract the value of a maybe Variant.
550    ///
551    /// Returns the child value, or `None` if the value is Nothing.
552    ///
553    /// # Panics
554    ///
555    /// Panics if the variant is not maybe-typed.
556    #[inline]
557    pub fn as_maybe(&self) -> Option<Variant> {
558        assert!(self.type_().is_maybe());
559
560        unsafe { from_glib_full(ffi::g_variant_get_maybe(self.to_glib_none().0)) }
561    }
562
563    // rustdoc-stripper-ignore-next
564    /// Pretty-print the contents of this variant in a human-readable form.
565    ///
566    /// A variant can be recreated from this output via [`Variant::parse`].
567    #[doc(alias = "g_variant_print")]
568    pub fn print(&self, type_annotate: bool) -> crate::GString {
569        unsafe {
570            from_glib_full(ffi::g_variant_print(
571                self.to_glib_none().0,
572                type_annotate.into_glib(),
573            ))
574        }
575    }
576
577    // rustdoc-stripper-ignore-next
578    /// Parses a GVariant from the text representation produced by [`print()`](Self::print).
579    #[doc(alias = "g_variant_parse")]
580    pub fn parse(type_: Option<&VariantTy>, text: &str) -> Result<Self, crate::Error> {
581        unsafe {
582            let mut error = ptr::null_mut();
583            let text = text.as_bytes().as_ptr_range();
584            let variant = ffi::g_variant_parse(
585                type_.to_glib_none().0,
586                text.start as *const _,
587                text.end as *const _,
588                ptr::null_mut(),
589                &mut error,
590            );
591            if variant.is_null() {
592                debug_assert!(!error.is_null());
593                Err(from_glib_full(error))
594            } else {
595                debug_assert!(error.is_null());
596                Ok(from_glib_full(variant))
597            }
598        }
599    }
600
601    // rustdoc-stripper-ignore-next
602    /// Constructs a new serialized-mode GVariant instance.
603    #[doc(alias = "g_variant_new_from_bytes")]
604    pub fn from_bytes<T: StaticVariantType>(bytes: &Bytes) -> Self {
605        Variant::from_bytes_with_type(bytes, &T::static_variant_type())
606    }
607
608    // rustdoc-stripper-ignore-next
609    /// Constructs a new serialized-mode GVariant instance.
610    ///
611    /// This is the same as `from_bytes`, except that checks on the passed
612    /// data are skipped.
613    ///
614    /// You should not use this function on data from external sources.
615    ///
616    /// # Safety
617    ///
618    /// Since the data is not validated, this is potentially dangerous if called
619    /// on bytes which are not guaranteed to have come from serialising another
620    /// Variant.  The caller is responsible for ensuring bad data is not passed in.
621    pub unsafe fn from_bytes_trusted<T: StaticVariantType>(bytes: &Bytes) -> Self {
622        Variant::from_bytes_with_type_trusted(bytes, &T::static_variant_type())
623    }
624
625    // rustdoc-stripper-ignore-next
626    /// Constructs a new serialized-mode GVariant instance.
627    #[doc(alias = "g_variant_new_from_data")]
628    pub fn from_data<T: StaticVariantType, A: AsRef<[u8]>>(data: A) -> Self {
629        Variant::from_data_with_type(data, &T::static_variant_type())
630    }
631
632    // rustdoc-stripper-ignore-next
633    /// Constructs a new serialized-mode GVariant instance.
634    ///
635    /// This is the same as `from_data`, except that checks on the passed
636    /// data are skipped.
637    ///
638    /// You should not use this function on data from external sources.
639    ///
640    /// # Safety
641    ///
642    /// Since the data is not validated, this is potentially dangerous if called
643    /// on bytes which are not guaranteed to have come from serialising another
644    /// Variant.  The caller is responsible for ensuring bad data is not passed in.
645    pub unsafe fn from_data_trusted<T: StaticVariantType, A: AsRef<[u8]>>(data: A) -> Self {
646        Variant::from_data_with_type_trusted(data, &T::static_variant_type())
647    }
648
649    // rustdoc-stripper-ignore-next
650    /// Constructs a new serialized-mode GVariant instance with a given type.
651    #[doc(alias = "g_variant_new_from_bytes")]
652    pub fn from_bytes_with_type(bytes: &Bytes, type_: &VariantTy) -> Self {
653        unsafe {
654            from_glib_none(ffi::g_variant_new_from_bytes(
655                type_.as_ptr() as *const _,
656                bytes.to_glib_none().0,
657                false.into_glib(),
658            ))
659        }
660    }
661
662    // rustdoc-stripper-ignore-next
663    /// Constructs a new serialized-mode GVariant instance with a given type.
664    ///
665    /// This is the same as `from_bytes`, except that checks on the passed
666    /// data are skipped.
667    ///
668    /// You should not use this function on data from external sources.
669    ///
670    /// # Safety
671    ///
672    /// Since the data is not validated, this is potentially dangerous if called
673    /// on bytes which are not guaranteed to have come from serialising another
674    /// Variant.  The caller is responsible for ensuring bad data is not passed in.
675    pub unsafe fn from_bytes_with_type_trusted(bytes: &Bytes, type_: &VariantTy) -> Self {
676        from_glib_none(ffi::g_variant_new_from_bytes(
677            type_.as_ptr() as *const _,
678            bytes.to_glib_none().0,
679            true.into_glib(),
680        ))
681    }
682
683    // rustdoc-stripper-ignore-next
684    /// Constructs a new serialized-mode GVariant instance with a given type.
685    #[doc(alias = "g_variant_new_from_data")]
686    pub fn from_data_with_type<A: AsRef<[u8]>>(data: A, type_: &VariantTy) -> Self {
687        unsafe {
688            let data = Box::new(data);
689            let (data_ptr, len) = {
690                let data = (*data).as_ref();
691                (data.as_ptr(), data.len())
692            };
693
694            unsafe extern "C" fn free_data<A: AsRef<[u8]>>(ptr: ffi::gpointer) {
695                let _ = Box::from_raw(ptr as *mut A);
696            }
697
698            from_glib_none(ffi::g_variant_new_from_data(
699                type_.as_ptr() as *const _,
700                data_ptr as ffi::gconstpointer,
701                len,
702                false.into_glib(),
703                Some(free_data::<A>),
704                Box::into_raw(data) as ffi::gpointer,
705            ))
706        }
707    }
708
709    // rustdoc-stripper-ignore-next
710    /// Constructs a new serialized-mode GVariant instance with a given type.
711    ///
712    /// This is the same as `from_data`, except that checks on the passed
713    /// data are skipped.
714    ///
715    /// You should not use this function on data from external sources.
716    ///
717    /// # Safety
718    ///
719    /// Since the data is not validated, this is potentially dangerous if called
720    /// on bytes which are not guaranteed to have come from serialising another
721    /// Variant.  The caller is responsible for ensuring bad data is not passed in.
722    pub unsafe fn from_data_with_type_trusted<A: AsRef<[u8]>>(data: A, type_: &VariantTy) -> Self {
723        let data = Box::new(data);
724        let (data_ptr, len) = {
725            let data = (*data).as_ref();
726            (data.as_ptr(), data.len())
727        };
728
729        unsafe extern "C" fn free_data<A: AsRef<[u8]>>(ptr: ffi::gpointer) {
730            let _ = Box::from_raw(ptr as *mut A);
731        }
732
733        from_glib_none(ffi::g_variant_new_from_data(
734            type_.as_ptr() as *const _,
735            data_ptr as ffi::gconstpointer,
736            len,
737            true.into_glib(),
738            Some(free_data::<A>),
739            Box::into_raw(data) as ffi::gpointer,
740        ))
741    }
742
743    // rustdoc-stripper-ignore-next
744    /// Returns the serialized form of a GVariant instance.
745    #[doc(alias = "get_data_as_bytes")]
746    #[doc(alias = "g_variant_get_data_as_bytes")]
747    pub fn data_as_bytes(&self) -> Bytes {
748        unsafe { from_glib_full(ffi::g_variant_get_data_as_bytes(self.to_glib_none().0)) }
749    }
750
751    // rustdoc-stripper-ignore-next
752    /// Returns the serialized form of a GVariant instance.
753    #[doc(alias = "g_variant_get_data")]
754    pub fn data(&self) -> &[u8] {
755        unsafe {
756            let selfv = self.to_glib_none();
757            let len = ffi::g_variant_get_size(selfv.0);
758            if len == 0 {
759                return &[];
760            }
761            let ptr = ffi::g_variant_get_data(selfv.0);
762            slice::from_raw_parts(ptr as *const _, len as _)
763        }
764    }
765
766    // rustdoc-stripper-ignore-next
767    /// Returns the size of serialized form of a GVariant instance.
768    #[doc(alias = "g_variant_get_size")]
769    pub fn size(&self) -> usize {
770        unsafe { ffi::g_variant_get_size(self.to_glib_none().0) }
771    }
772
773    // rustdoc-stripper-ignore-next
774    /// Stores the serialized form of a GVariant instance into the given slice.
775    ///
776    /// The slice needs to be big enough.
777    #[doc(alias = "g_variant_store")]
778    pub fn store(&self, data: &mut [u8]) -> Result<usize, crate::BoolError> {
779        unsafe {
780            let size = ffi::g_variant_get_size(self.to_glib_none().0);
781            if data.len() < size {
782                return Err(bool_error!("Provided slice is too small"));
783            }
784
785            ffi::g_variant_store(self.to_glib_none().0, data.as_mut_ptr() as ffi::gpointer);
786
787            Ok(size)
788        }
789    }
790
791    // rustdoc-stripper-ignore-next
792    /// Returns a copy of the variant in normal form.
793    #[doc(alias = "g_variant_get_normal_form")]
794    #[must_use]
795    pub fn normal_form(&self) -> Self {
796        unsafe { from_glib_full(ffi::g_variant_get_normal_form(self.to_glib_none().0)) }
797    }
798
799    // rustdoc-stripper-ignore-next
800    /// Returns a copy of the variant in the opposite endianness.
801    #[doc(alias = "g_variant_byteswap")]
802    #[must_use]
803    pub fn byteswap(&self) -> Self {
804        unsafe { from_glib_full(ffi::g_variant_byteswap(self.to_glib_none().0)) }
805    }
806
807    // rustdoc-stripper-ignore-next
808    /// Determines the number of children in a container GVariant instance.
809    #[doc(alias = "g_variant_n_children")]
810    pub fn n_children(&self) -> usize {
811        assert!(self.is_container());
812
813        unsafe { ffi::g_variant_n_children(self.to_glib_none().0) }
814    }
815
816    // rustdoc-stripper-ignore-next
817    /// Create an iterator over items in the variant.
818    ///
819    /// Note that this heap allocates a variant for each element,
820    /// which can be particularly expensive for large arrays.
821    pub fn iter(&self) -> VariantIter {
822        assert!(self.is_container());
823
824        VariantIter::new(self.clone())
825    }
826
827    // rustdoc-stripper-ignore-next
828    /// Create an iterator over borrowed strings from a GVariant of type `as` (array of string).
829    ///
830    /// This will fail if the variant is not an array of with
831    /// the expected child type.
832    ///
833    /// A benefit of this API over [`Self::iter()`] is that it
834    /// minimizes allocation, and provides strongly typed access.
835    ///
836    /// ```
837    /// # use glib::prelude::*;
838    /// let strs = &["foo", "bar"];
839    /// let strs_variant: glib::Variant = strs.to_variant();
840    /// for s in strs_variant.array_iter_str()? {
841    ///     println!("{}", s);
842    /// }
843    /// # Ok::<(), Box<dyn std::error::Error>>(())
844    /// ```
845    pub fn array_iter_str(&self) -> Result<VariantStrIter<'_>, VariantTypeMismatchError> {
846        let child_ty = String::static_variant_type();
847        let actual_ty = self.type_();
848        let expected_ty = child_ty.as_array();
849        if actual_ty != expected_ty {
850            return Err(VariantTypeMismatchError {
851                actual: actual_ty.to_owned(),
852                expected: expected_ty.into_owned(),
853            });
854        }
855
856        Ok(VariantStrIter::new(self))
857    }
858
859    // rustdoc-stripper-ignore-next
860    /// Return whether this Variant is a container type.
861    #[doc(alias = "g_variant_is_container")]
862    pub fn is_container(&self) -> bool {
863        unsafe { from_glib(ffi::g_variant_is_container(self.to_glib_none().0)) }
864    }
865
866    // rustdoc-stripper-ignore-next
867    /// Return whether this Variant is in normal form.
868    #[doc(alias = "g_variant_is_normal_form")]
869    pub fn is_normal_form(&self) -> bool {
870        unsafe { from_glib(ffi::g_variant_is_normal_form(self.to_glib_none().0)) }
871    }
872
873    // rustdoc-stripper-ignore-next
874    /// Return whether input string is a valid `VariantClass::ObjectPath`.
875    #[doc(alias = "g_variant_is_object_path")]
876    pub fn is_object_path(string: &str) -> bool {
877        unsafe { from_glib(ffi::g_variant_is_object_path(string.to_glib_none().0)) }
878    }
879
880    // rustdoc-stripper-ignore-next
881    /// Return whether input string is a valid `VariantClass::Signature`.
882    #[doc(alias = "g_variant_is_signature")]
883    pub fn is_signature(string: &str) -> bool {
884        unsafe { from_glib(ffi::g_variant_is_signature(string.to_glib_none().0)) }
885    }
886}
887
888unsafe impl Send for Variant {}
889unsafe impl Sync for Variant {}
890
891impl fmt::Debug for Variant {
892    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
893        f.debug_struct("Variant")
894            .field("ptr", &ToGlibPtr::<*const _>::to_glib_none(self).0)
895            .field("type", &self.type_())
896            .field("value", &self.to_string())
897            .finish()
898    }
899}
900
901impl fmt::Display for Variant {
902    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
903        f.write_str(&self.print(true))
904    }
905}
906
907impl str::FromStr for Variant {
908    type Err = crate::Error;
909
910    fn from_str(s: &str) -> Result<Self, Self::Err> {
911        Self::parse(None, s)
912    }
913}
914
915impl PartialEq for Variant {
916    #[doc(alias = "g_variant_equal")]
917    fn eq(&self, other: &Self) -> bool {
918        unsafe {
919            from_glib(ffi::g_variant_equal(
920                ToGlibPtr::<*const _>::to_glib_none(self).0 as *const _,
921                ToGlibPtr::<*const _>::to_glib_none(other).0 as *const _,
922            ))
923        }
924    }
925}
926
927impl Eq for Variant {}
928
929impl PartialOrd for Variant {
930    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
931        unsafe {
932            if ffi::g_variant_classify(self.to_glib_none().0)
933                != ffi::g_variant_classify(other.to_glib_none().0)
934            {
935                return None;
936            }
937
938            if self.is_container() {
939                return None;
940            }
941
942            let res = ffi::g_variant_compare(
943                ToGlibPtr::<*const _>::to_glib_none(self).0 as *const _,
944                ToGlibPtr::<*const _>::to_glib_none(other).0 as *const _,
945            );
946
947            Some(res.cmp(&0))
948        }
949    }
950}
951
952impl Hash for Variant {
953    #[doc(alias = "g_variant_hash")]
954    fn hash<H: Hasher>(&self, state: &mut H) {
955        unsafe {
956            state.write_u32(ffi::g_variant_hash(
957                ToGlibPtr::<*const _>::to_glib_none(self).0 as *const _,
958            ))
959        }
960    }
961}
962
963impl AsRef<Variant> for Variant {
964    #[inline]
965    fn as_ref(&self) -> &Self {
966        self
967    }
968}
969
970// rustdoc-stripper-ignore-next
971/// Converts to `Variant`.
972pub trait ToVariant {
973    // rustdoc-stripper-ignore-next
974    /// Returns a `Variant` clone of `self`.
975    fn to_variant(&self) -> Variant;
976}
977
978// rustdoc-stripper-ignore-next
979/// Extracts a value.
980pub trait FromVariant: Sized + StaticVariantType {
981    // rustdoc-stripper-ignore-next
982    /// Tries to extract a value.
983    ///
984    /// Returns `Some` if the variant's type matches `Self`.
985    fn from_variant(variant: &Variant) -> Option<Self>;
986}
987
988// rustdoc-stripper-ignore-next
989/// Returns `VariantType` of `Self`.
990pub trait StaticVariantType {
991    // rustdoc-stripper-ignore-next
992    /// Returns the `VariantType` corresponding to `Self`.
993    fn static_variant_type() -> Cow<'static, VariantTy>;
994}
995
996impl StaticVariantType for Variant {
997    fn static_variant_type() -> Cow<'static, VariantTy> {
998        Cow::Borrowed(VariantTy::VARIANT)
999    }
1000}
1001
1002impl<T: ?Sized + ToVariant> ToVariant for &T {
1003    fn to_variant(&self) -> Variant {
1004        <T as ToVariant>::to_variant(self)
1005    }
1006}
1007
1008impl<'a, T: Into<Variant> + Clone> From<&'a T> for Variant {
1009    #[inline]
1010    fn from(v: &'a T) -> Self {
1011        v.clone().into()
1012    }
1013}
1014
1015impl<T: ?Sized + StaticVariantType> StaticVariantType for &T {
1016    fn static_variant_type() -> Cow<'static, VariantTy> {
1017        <T as StaticVariantType>::static_variant_type()
1018    }
1019}
1020
1021macro_rules! impl_numeric {
1022    ($name:ty, $typ:expr, $new_fn:ident, $get_fn:ident) => {
1023        impl StaticVariantType for $name {
1024            fn static_variant_type() -> Cow<'static, VariantTy> {
1025                Cow::Borrowed($typ)
1026            }
1027        }
1028
1029        impl ToVariant for $name {
1030            fn to_variant(&self) -> Variant {
1031                unsafe { from_glib_none(ffi::$new_fn(*self)) }
1032            }
1033        }
1034
1035        impl From<$name> for Variant {
1036            #[inline]
1037            fn from(v: $name) -> Self {
1038                v.to_variant()
1039            }
1040        }
1041
1042        impl FromVariant for $name {
1043            fn from_variant(variant: &Variant) -> Option<Self> {
1044                unsafe {
1045                    if variant.is::<Self>() {
1046                        Some(ffi::$get_fn(variant.to_glib_none().0))
1047                    } else {
1048                        None
1049                    }
1050                }
1051            }
1052        }
1053    };
1054}
1055
1056impl_numeric!(u8, VariantTy::BYTE, g_variant_new_byte, g_variant_get_byte);
1057impl_numeric!(
1058    i16,
1059    VariantTy::INT16,
1060    g_variant_new_int16,
1061    g_variant_get_int16
1062);
1063impl_numeric!(
1064    u16,
1065    VariantTy::UINT16,
1066    g_variant_new_uint16,
1067    g_variant_get_uint16
1068);
1069impl_numeric!(
1070    i32,
1071    VariantTy::INT32,
1072    g_variant_new_int32,
1073    g_variant_get_int32
1074);
1075impl_numeric!(
1076    u32,
1077    VariantTy::UINT32,
1078    g_variant_new_uint32,
1079    g_variant_get_uint32
1080);
1081impl_numeric!(
1082    i64,
1083    VariantTy::INT64,
1084    g_variant_new_int64,
1085    g_variant_get_int64
1086);
1087impl_numeric!(
1088    u64,
1089    VariantTy::UINT64,
1090    g_variant_new_uint64,
1091    g_variant_get_uint64
1092);
1093impl_numeric!(
1094    f64,
1095    VariantTy::DOUBLE,
1096    g_variant_new_double,
1097    g_variant_get_double
1098);
1099
1100impl StaticVariantType for () {
1101    fn static_variant_type() -> Cow<'static, VariantTy> {
1102        Cow::Borrowed(VariantTy::UNIT)
1103    }
1104}
1105
1106impl ToVariant for () {
1107    fn to_variant(&self) -> Variant {
1108        unsafe { from_glib_none(ffi::g_variant_new_tuple(ptr::null(), 0)) }
1109    }
1110}
1111
1112impl From<()> for Variant {
1113    #[inline]
1114    fn from(_: ()) -> Self {
1115        ().to_variant()
1116    }
1117}
1118
1119impl FromVariant for () {
1120    fn from_variant(variant: &Variant) -> Option<Self> {
1121        if variant.is::<Self>() {
1122            Some(())
1123        } else {
1124            None
1125        }
1126    }
1127}
1128
1129impl StaticVariantType for bool {
1130    fn static_variant_type() -> Cow<'static, VariantTy> {
1131        Cow::Borrowed(VariantTy::BOOLEAN)
1132    }
1133}
1134
1135impl ToVariant for bool {
1136    fn to_variant(&self) -> Variant {
1137        unsafe { from_glib_none(ffi::g_variant_new_boolean(self.into_glib())) }
1138    }
1139}
1140
1141impl From<bool> for Variant {
1142    #[inline]
1143    fn from(v: bool) -> Self {
1144        v.to_variant()
1145    }
1146}
1147
1148impl FromVariant for bool {
1149    fn from_variant(variant: &Variant) -> Option<Self> {
1150        unsafe {
1151            if variant.is::<Self>() {
1152                Some(from_glib(ffi::g_variant_get_boolean(
1153                    variant.to_glib_none().0,
1154                )))
1155            } else {
1156                None
1157            }
1158        }
1159    }
1160}
1161
1162impl StaticVariantType for String {
1163    fn static_variant_type() -> Cow<'static, VariantTy> {
1164        Cow::Borrowed(VariantTy::STRING)
1165    }
1166}
1167
1168impl ToVariant for String {
1169    fn to_variant(&self) -> Variant {
1170        self[..].to_variant()
1171    }
1172}
1173
1174impl From<String> for Variant {
1175    #[inline]
1176    fn from(s: String) -> Self {
1177        s.to_variant()
1178    }
1179}
1180
1181impl FromVariant for String {
1182    fn from_variant(variant: &Variant) -> Option<Self> {
1183        variant.str().map(String::from)
1184    }
1185}
1186
1187impl StaticVariantType for str {
1188    fn static_variant_type() -> Cow<'static, VariantTy> {
1189        String::static_variant_type()
1190    }
1191}
1192
1193impl ToVariant for str {
1194    fn to_variant(&self) -> Variant {
1195        unsafe { from_glib_none(ffi::g_variant_new_take_string(self.to_glib_full())) }
1196    }
1197}
1198
1199impl From<&str> for Variant {
1200    #[inline]
1201    fn from(s: &str) -> Self {
1202        s.to_variant()
1203    }
1204}
1205
1206impl StaticVariantType for std::path::PathBuf {
1207    fn static_variant_type() -> Cow<'static, VariantTy> {
1208        std::path::Path::static_variant_type()
1209    }
1210}
1211
1212impl ToVariant for std::path::PathBuf {
1213    fn to_variant(&self) -> Variant {
1214        self.as_path().to_variant()
1215    }
1216}
1217
1218impl From<std::path::PathBuf> for Variant {
1219    #[inline]
1220    fn from(p: std::path::PathBuf) -> Self {
1221        p.to_variant()
1222    }
1223}
1224
1225impl FromVariant for std::path::PathBuf {
1226    fn from_variant(variant: &Variant) -> Option<Self> {
1227        unsafe {
1228            let ptr = ffi::g_variant_get_bytestring(variant.to_glib_none().0);
1229            Some(crate::translate::c_to_path_buf(ptr as *const _))
1230        }
1231    }
1232}
1233
1234impl StaticVariantType for std::path::Path {
1235    fn static_variant_type() -> Cow<'static, VariantTy> {
1236        <&[u8]>::static_variant_type()
1237    }
1238}
1239
1240impl ToVariant for std::path::Path {
1241    fn to_variant(&self) -> Variant {
1242        let tmp = crate::translate::path_to_c(self);
1243        unsafe { from_glib_none(ffi::g_variant_new_bytestring(tmp.as_ptr() as *const u8)) }
1244    }
1245}
1246
1247impl From<&std::path::Path> for Variant {
1248    #[inline]
1249    fn from(p: &std::path::Path) -> Self {
1250        p.to_variant()
1251    }
1252}
1253
1254impl StaticVariantType for std::ffi::OsString {
1255    fn static_variant_type() -> Cow<'static, VariantTy> {
1256        std::ffi::OsStr::static_variant_type()
1257    }
1258}
1259
1260impl ToVariant for std::ffi::OsString {
1261    fn to_variant(&self) -> Variant {
1262        self.as_os_str().to_variant()
1263    }
1264}
1265
1266impl From<std::ffi::OsString> for Variant {
1267    #[inline]
1268    fn from(s: std::ffi::OsString) -> Self {
1269        s.to_variant()
1270    }
1271}
1272
1273impl FromVariant for std::ffi::OsString {
1274    fn from_variant(variant: &Variant) -> Option<Self> {
1275        unsafe {
1276            let ptr = ffi::g_variant_get_bytestring(variant.to_glib_none().0);
1277            Some(crate::translate::c_to_os_string(ptr as *const _))
1278        }
1279    }
1280}
1281
1282impl StaticVariantType for std::ffi::OsStr {
1283    fn static_variant_type() -> Cow<'static, VariantTy> {
1284        <&[u8]>::static_variant_type()
1285    }
1286}
1287
1288impl ToVariant for std::ffi::OsStr {
1289    fn to_variant(&self) -> Variant {
1290        let tmp = crate::translate::os_str_to_c(self);
1291        unsafe { from_glib_none(ffi::g_variant_new_bytestring(tmp.as_ptr() as *const u8)) }
1292    }
1293}
1294
1295impl From<&std::ffi::OsStr> for Variant {
1296    #[inline]
1297    fn from(s: &std::ffi::OsStr) -> Self {
1298        s.to_variant()
1299    }
1300}
1301
1302impl<T: StaticVariantType> StaticVariantType for Option<T> {
1303    fn static_variant_type() -> Cow<'static, VariantTy> {
1304        Cow::Owned(VariantType::new_maybe(&T::static_variant_type()))
1305    }
1306}
1307
1308impl<T: StaticVariantType + ToVariant> ToVariant for Option<T> {
1309    fn to_variant(&self) -> Variant {
1310        Variant::from_maybe::<T>(self.as_ref().map(|m| m.to_variant()).as_ref())
1311    }
1312}
1313
1314impl<T: StaticVariantType + Into<Variant>> From<Option<T>> for Variant {
1315    #[inline]
1316    fn from(v: Option<T>) -> Self {
1317        Variant::from_maybe::<T>(v.map(|v| v.into()).as_ref())
1318    }
1319}
1320
1321impl<T: StaticVariantType + FromVariant> FromVariant for Option<T> {
1322    fn from_variant(variant: &Variant) -> Option<Self> {
1323        unsafe {
1324            if variant.is::<Self>() {
1325                let c_child = ffi::g_variant_get_maybe(variant.to_glib_none().0);
1326                if !c_child.is_null() {
1327                    let child: Variant = from_glib_full(c_child);
1328
1329                    Some(T::from_variant(&child))
1330                } else {
1331                    Some(None)
1332                }
1333            } else {
1334                None
1335            }
1336        }
1337    }
1338}
1339
1340impl<T: StaticVariantType> StaticVariantType for [T] {
1341    fn static_variant_type() -> Cow<'static, VariantTy> {
1342        T::static_variant_type().as_array()
1343    }
1344}
1345
1346impl<T: StaticVariantType + ToVariant> ToVariant for [T] {
1347    fn to_variant(&self) -> Variant {
1348        unsafe {
1349            if self.is_empty() {
1350                return from_glib_none(ffi::g_variant_new_array(
1351                    T::static_variant_type().to_glib_none().0,
1352                    ptr::null(),
1353                    0,
1354                ));
1355            }
1356
1357            let mut builder = mem::MaybeUninit::uninit();
1358            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1359            let mut builder = builder.assume_init();
1360            for value in self {
1361                let value = value.to_variant();
1362                ffi::g_variant_builder_add_value(&mut builder, value.to_glib_none().0);
1363            }
1364            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1365        }
1366    }
1367}
1368
1369impl<T: StaticVariantType + ToVariant> From<&[T]> for Variant {
1370    #[inline]
1371    fn from(s: &[T]) -> Self {
1372        s.to_variant()
1373    }
1374}
1375
1376impl<T: FromVariant> FromVariant for Vec<T> {
1377    fn from_variant(variant: &Variant) -> Option<Self> {
1378        if !variant.is_container() {
1379            return None;
1380        }
1381
1382        let mut vec = Vec::with_capacity(variant.n_children());
1383
1384        for i in 0..variant.n_children() {
1385            match variant.child_value(i).get() {
1386                Some(child) => vec.push(child),
1387                None => return None,
1388            }
1389        }
1390
1391        Some(vec)
1392    }
1393}
1394
1395impl<T: StaticVariantType + ToVariant> ToVariant for Vec<T> {
1396    fn to_variant(&self) -> Variant {
1397        self.as_slice().to_variant()
1398    }
1399}
1400
1401impl<T: StaticVariantType + Into<Variant>> From<Vec<T>> for Variant {
1402    fn from(v: Vec<T>) -> Self {
1403        unsafe {
1404            if v.is_empty() {
1405                return from_glib_none(ffi::g_variant_new_array(
1406                    T::static_variant_type().to_glib_none().0,
1407                    ptr::null(),
1408                    0,
1409                ));
1410            }
1411
1412            let mut builder = mem::MaybeUninit::uninit();
1413            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1414            let mut builder = builder.assume_init();
1415            for value in v {
1416                let value = value.into();
1417                ffi::g_variant_builder_add_value(&mut builder, value.to_glib_none().0);
1418            }
1419            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1420        }
1421    }
1422}
1423
1424impl<T: StaticVariantType> StaticVariantType for Vec<T> {
1425    fn static_variant_type() -> Cow<'static, VariantTy> {
1426        <[T]>::static_variant_type()
1427    }
1428}
1429
1430impl<K, V, H> FromVariant for HashMap<K, V, H>
1431where
1432    K: FromVariant + Eq + Hash,
1433    V: FromVariant,
1434    H: BuildHasher + Default,
1435{
1436    fn from_variant(variant: &Variant) -> Option<Self> {
1437        if !variant.is_container() {
1438            return None;
1439        }
1440
1441        let mut map = HashMap::default();
1442
1443        for i in 0..variant.n_children() {
1444            let entry = variant.child_value(i);
1445            let key = entry.child_value(0).get()?;
1446            let val = entry.child_value(1).get()?;
1447
1448            map.insert(key, val);
1449        }
1450
1451        Some(map)
1452    }
1453}
1454
1455impl<K, V> FromVariant for BTreeMap<K, V>
1456where
1457    K: FromVariant + Eq + Ord,
1458    V: FromVariant,
1459{
1460    fn from_variant(variant: &Variant) -> Option<Self> {
1461        if !variant.is_container() {
1462            return None;
1463        }
1464
1465        let mut map = BTreeMap::default();
1466
1467        for i in 0..variant.n_children() {
1468            let entry = variant.child_value(i);
1469            let key = entry.child_value(0).get()?;
1470            let val = entry.child_value(1).get()?;
1471
1472            map.insert(key, val);
1473        }
1474
1475        Some(map)
1476    }
1477}
1478
1479impl<K, V> ToVariant for HashMap<K, V>
1480where
1481    K: StaticVariantType + ToVariant + Eq + Hash,
1482    V: StaticVariantType + ToVariant,
1483{
1484    fn to_variant(&self) -> Variant {
1485        unsafe {
1486            if self.is_empty() {
1487                return from_glib_none(ffi::g_variant_new_array(
1488                    DictEntry::<K, V>::static_variant_type().to_glib_none().0,
1489                    ptr::null(),
1490                    0,
1491                ));
1492            }
1493
1494            let mut builder = mem::MaybeUninit::uninit();
1495            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1496            let mut builder = builder.assume_init();
1497            for (key, value) in self {
1498                let entry = DictEntry::new(key, value).to_variant();
1499                ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0);
1500            }
1501            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1502        }
1503    }
1504}
1505
1506impl<K, V> From<HashMap<K, V>> for Variant
1507where
1508    K: StaticVariantType + Into<Variant> + Eq + Hash,
1509    V: StaticVariantType + Into<Variant>,
1510{
1511    fn from(m: HashMap<K, V>) -> Self {
1512        unsafe {
1513            if m.is_empty() {
1514                return from_glib_none(ffi::g_variant_new_array(
1515                    DictEntry::<K, V>::static_variant_type().to_glib_none().0,
1516                    ptr::null(),
1517                    0,
1518                ));
1519            }
1520
1521            let mut builder = mem::MaybeUninit::uninit();
1522            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1523            let mut builder = builder.assume_init();
1524            for (key, value) in m {
1525                let entry = Variant::from(DictEntry::new(key, value));
1526                ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0);
1527            }
1528            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1529        }
1530    }
1531}
1532
1533impl<K, V> ToVariant for BTreeMap<K, V>
1534where
1535    K: StaticVariantType + ToVariant + Eq + Hash,
1536    V: StaticVariantType + ToVariant,
1537{
1538    fn to_variant(&self) -> Variant {
1539        unsafe {
1540            if self.is_empty() {
1541                return from_glib_none(ffi::g_variant_new_array(
1542                    DictEntry::<K, V>::static_variant_type().to_glib_none().0,
1543                    ptr::null(),
1544                    0,
1545                ));
1546            }
1547
1548            let mut builder = mem::MaybeUninit::uninit();
1549            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1550            let mut builder = builder.assume_init();
1551            for (key, value) in self {
1552                let entry = DictEntry::new(key, value).to_variant();
1553                ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0);
1554            }
1555            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1556        }
1557    }
1558}
1559
1560impl<K, V> From<BTreeMap<K, V>> for Variant
1561where
1562    K: StaticVariantType + Into<Variant> + Eq + Hash,
1563    V: StaticVariantType + Into<Variant>,
1564{
1565    fn from(m: BTreeMap<K, V>) -> Self {
1566        unsafe {
1567            if m.is_empty() {
1568                return from_glib_none(ffi::g_variant_new_array(
1569                    DictEntry::<K, V>::static_variant_type().to_glib_none().0,
1570                    ptr::null(),
1571                    0,
1572                ));
1573            }
1574
1575            let mut builder = mem::MaybeUninit::uninit();
1576            ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0);
1577            let mut builder = builder.assume_init();
1578            for (key, value) in m {
1579                let entry = Variant::from(DictEntry::new(key, value));
1580                ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0);
1581            }
1582            from_glib_none(ffi::g_variant_builder_end(&mut builder))
1583        }
1584    }
1585}
1586
1587/// A Dictionary entry.
1588///
1589/// While GVariant format allows a dictionary entry to be an independent type, typically you'll need
1590/// to use this in a dictionary, which is simply an array of dictionary entries. The following code
1591/// creates a dictionary:
1592///
1593/// ```
1594///# use glib::prelude::*; // or `use gtk::prelude::*;`
1595/// use glib::variant::{Variant, FromVariant, DictEntry};
1596///
1597/// let entries = [
1598///     DictEntry::new("uuid", 1000u32),
1599///     DictEntry::new("guid", 1001u32),
1600/// ];
1601/// let dict = entries.into_iter().collect::<Variant>();
1602/// assert_eq!(dict.n_children(), 2);
1603/// assert_eq!(dict.type_().as_str(), "a{su}");
1604/// ```
1605#[derive(Debug, Clone)]
1606pub struct DictEntry<K, V> {
1607    key: K,
1608    value: V,
1609}
1610
1611impl<K, V> DictEntry<K, V>
1612where
1613    K: StaticVariantType,
1614    V: StaticVariantType,
1615{
1616    pub fn new(key: K, value: V) -> Self {
1617        Self { key, value }
1618    }
1619
1620    pub fn key(&self) -> &K {
1621        &self.key
1622    }
1623
1624    pub fn value(&self) -> &V {
1625        &self.value
1626    }
1627}
1628
1629impl<K, V> FromVariant for DictEntry<K, V>
1630where
1631    K: FromVariant,
1632    V: FromVariant,
1633{
1634    fn from_variant(variant: &Variant) -> Option<Self> {
1635        if !variant.type_().is_subtype_of(VariantTy::DICT_ENTRY) {
1636            return None;
1637        }
1638
1639        let key = variant.child_value(0).get()?;
1640        let value = variant.child_value(1).get()?;
1641
1642        Some(Self { key, value })
1643    }
1644}
1645
1646impl<K, V> ToVariant for DictEntry<K, V>
1647where
1648    K: StaticVariantType + ToVariant,
1649    V: StaticVariantType + ToVariant,
1650{
1651    fn to_variant(&self) -> Variant {
1652        Variant::from_dict_entry(&self.key.to_variant(), &self.value.to_variant())
1653    }
1654}
1655
1656impl<K, V> From<DictEntry<K, V>> for Variant
1657where
1658    K: StaticVariantType + Into<Variant>,
1659    V: StaticVariantType + Into<Variant>,
1660{
1661    fn from(e: DictEntry<K, V>) -> Self {
1662        Variant::from_dict_entry(&e.key.into(), &e.value.into())
1663    }
1664}
1665
1666impl ToVariant for Variant {
1667    fn to_variant(&self) -> Variant {
1668        Variant::from_variant(self)
1669    }
1670}
1671
1672impl FromVariant for Variant {
1673    fn from_variant(variant: &Variant) -> Option<Self> {
1674        variant.as_variant()
1675    }
1676}
1677
1678impl<K: StaticVariantType, V: StaticVariantType> StaticVariantType for DictEntry<K, V> {
1679    fn static_variant_type() -> Cow<'static, VariantTy> {
1680        Cow::Owned(VariantType::new_dict_entry(
1681            &K::static_variant_type(),
1682            &V::static_variant_type(),
1683        ))
1684    }
1685}
1686
1687fn static_variant_mapping<K, V>() -> Cow<'static, VariantTy>
1688where
1689    K: StaticVariantType,
1690    V: StaticVariantType,
1691{
1692    use std::fmt::Write;
1693
1694    let key_type = K::static_variant_type();
1695    let value_type = V::static_variant_type();
1696
1697    if key_type == VariantTy::STRING && value_type == VariantTy::VARIANT {
1698        return Cow::Borrowed(VariantTy::VARDICT);
1699    }
1700
1701    let mut builder = crate::GStringBuilder::default();
1702    write!(builder, "a{{{}{}}}", key_type.as_str(), value_type.as_str()).unwrap();
1703
1704    Cow::Owned(VariantType::from_string(builder.into_string()).unwrap())
1705}
1706
1707impl<K, V, H> StaticVariantType for HashMap<K, V, H>
1708where
1709    K: StaticVariantType,
1710    V: StaticVariantType,
1711    H: BuildHasher + Default,
1712{
1713    fn static_variant_type() -> Cow<'static, VariantTy> {
1714        static_variant_mapping::<K, V>()
1715    }
1716}
1717
1718impl<K, V> StaticVariantType for BTreeMap<K, V>
1719where
1720    K: StaticVariantType,
1721    V: StaticVariantType,
1722{
1723    fn static_variant_type() -> Cow<'static, VariantTy> {
1724        static_variant_mapping::<K, V>()
1725    }
1726}
1727
1728macro_rules! tuple_impls {
1729    ($($len:expr => ($($n:tt $name:ident)+))+) => {
1730        $(
1731            impl<$($name),+> StaticVariantType for ($($name,)+)
1732            where
1733                $($name: StaticVariantType,)+
1734            {
1735                fn static_variant_type() -> Cow<'static, VariantTy> {
1736                    Cow::Owned(VariantType::new_tuple(&[
1737                        $(
1738                            $name::static_variant_type(),
1739                        )+
1740                    ]))
1741                }
1742            }
1743
1744            impl<$($name),+> FromVariant for ($($name,)+)
1745            where
1746                $($name: FromVariant,)+
1747            {
1748                fn from_variant(variant: &Variant) -> Option<Self> {
1749                    if !variant.type_().is_subtype_of(VariantTy::TUPLE) {
1750                        return None;
1751                    }
1752
1753                    Some((
1754                        $(
1755                            match variant.try_child_get::<$name>($n) {
1756                                Ok(Some(field)) => field,
1757                                _ => return None,
1758                            },
1759                        )+
1760                    ))
1761                }
1762            }
1763
1764            impl<$($name),+> ToVariant for ($($name,)+)
1765            where
1766                $($name: ToVariant,)+
1767            {
1768                fn to_variant(&self) -> Variant {
1769                    unsafe {
1770                        let mut builder = mem::MaybeUninit::uninit();
1771                        ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::TUPLE.to_glib_none().0);
1772                        let mut builder = builder.assume_init();
1773
1774                        $(
1775                            let field = self.$n.to_variant();
1776                            ffi::g_variant_builder_add_value(&mut builder, field.to_glib_none().0);
1777                        )+
1778
1779                        from_glib_none(ffi::g_variant_builder_end(&mut builder))
1780                    }
1781                }
1782            }
1783
1784            impl<$($name),+> From<($($name,)+)> for Variant
1785            where
1786                $($name: Into<Variant>,)+
1787            {
1788                fn from(t: ($($name,)+)) -> Self {
1789                    unsafe {
1790                        let mut builder = mem::MaybeUninit::uninit();
1791                        ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::TUPLE.to_glib_none().0);
1792                        let mut builder = builder.assume_init();
1793
1794                        $(
1795                            let field = t.$n.into();
1796                            ffi::g_variant_builder_add_value(&mut builder, field.to_glib_none().0);
1797                        )+
1798
1799                        from_glib_none(ffi::g_variant_builder_end(&mut builder))
1800                    }
1801                }
1802            }
1803        )+
1804    }
1805}
1806
1807tuple_impls! {
1808    1 => (0 T0)
1809    2 => (0 T0 1 T1)
1810    3 => (0 T0 1 T1 2 T2)
1811    4 => (0 T0 1 T1 2 T2 3 T3)
1812    5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
1813    6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
1814    7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
1815    8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
1816    9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
1817    10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
1818    11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
1819    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)
1820    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)
1821    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)
1822    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)
1823    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)
1824}
1825
1826impl<T: Into<Variant> + StaticVariantType> FromIterator<T> for Variant {
1827    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1828        Variant::array_from_iter::<T>(iter.into_iter().map(|v| v.into()))
1829    }
1830}
1831
1832/// Trait for fixed size variant types.
1833pub unsafe trait FixedSizeVariantType: StaticVariantType + Sized + Copy {}
1834unsafe impl FixedSizeVariantType for u8 {}
1835unsafe impl FixedSizeVariantType for i16 {}
1836unsafe impl FixedSizeVariantType for u16 {}
1837unsafe impl FixedSizeVariantType for i32 {}
1838unsafe impl FixedSizeVariantType for u32 {}
1839unsafe impl FixedSizeVariantType for i64 {}
1840unsafe impl FixedSizeVariantType for u64 {}
1841unsafe impl FixedSizeVariantType for f64 {}
1842unsafe impl FixedSizeVariantType for bool {}
1843
1844/// Wrapper type for fixed size type arrays.
1845///
1846/// Converting this from/to a `Variant` is generally more efficient than working on the type
1847/// directly. This is especially important when deriving `Variant` trait implementations on custom
1848/// types.
1849///
1850/// This wrapper type can hold for example `Vec<u8>`, `Box<[u8]>` and similar types.
1851#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1852pub struct FixedSizeVariantArray<A, T>(A, std::marker::PhantomData<T>)
1853where
1854    A: AsRef<[T]>,
1855    T: FixedSizeVariantType;
1856
1857impl<A: AsRef<[T]>, T: FixedSizeVariantType> From<A> for FixedSizeVariantArray<A, T> {
1858    fn from(array: A) -> Self {
1859        FixedSizeVariantArray(array, std::marker::PhantomData)
1860    }
1861}
1862
1863impl<A: AsRef<[T]>, T: FixedSizeVariantType> FixedSizeVariantArray<A, T> {
1864    pub fn into_inner(self) -> A {
1865        self.0
1866    }
1867}
1868
1869impl<A: AsRef<[T]>, T: FixedSizeVariantType> std::ops::Deref for FixedSizeVariantArray<A, T> {
1870    type Target = A;
1871
1872    #[inline]
1873    fn deref(&self) -> &Self::Target {
1874        &self.0
1875    }
1876}
1877
1878impl<A: AsRef<[T]>, T: FixedSizeVariantType> std::ops::DerefMut for FixedSizeVariantArray<A, T> {
1879    #[inline]
1880    fn deref_mut(&mut self) -> &mut Self::Target {
1881        &mut self.0
1882    }
1883}
1884
1885impl<A: AsRef<[T]>, T: FixedSizeVariantType> AsRef<A> for FixedSizeVariantArray<A, T> {
1886    #[inline]
1887    fn as_ref(&self) -> &A {
1888        &self.0
1889    }
1890}
1891
1892impl<A: AsRef<[T]>, T: FixedSizeVariantType> AsMut<A> for FixedSizeVariantArray<A, T> {
1893    #[inline]
1894    fn as_mut(&mut self) -> &mut A {
1895        &mut self.0
1896    }
1897}
1898
1899impl<A: AsRef<[T]>, T: FixedSizeVariantType> AsRef<[T]> for FixedSizeVariantArray<A, T> {
1900    #[inline]
1901    fn as_ref(&self) -> &[T] {
1902        self.0.as_ref()
1903    }
1904}
1905
1906impl<A: AsRef<[T]> + AsMut<[T]>, T: FixedSizeVariantType> AsMut<[T]>
1907    for FixedSizeVariantArray<A, T>
1908{
1909    #[inline]
1910    fn as_mut(&mut self) -> &mut [T] {
1911        self.0.as_mut()
1912    }
1913}
1914
1915impl<A: AsRef<[T]>, T: FixedSizeVariantType> StaticVariantType for FixedSizeVariantArray<A, T> {
1916    fn static_variant_type() -> Cow<'static, VariantTy> {
1917        <[T]>::static_variant_type()
1918    }
1919}
1920
1921impl<A: AsRef<[T]> + for<'a> From<&'a [T]>, T: FixedSizeVariantType> FromVariant
1922    for FixedSizeVariantArray<A, T>
1923{
1924    fn from_variant(variant: &Variant) -> Option<Self> {
1925        Some(FixedSizeVariantArray(
1926            A::from(variant.fixed_array::<T>().ok()?),
1927            std::marker::PhantomData,
1928        ))
1929    }
1930}
1931
1932impl<A: AsRef<[T]>, T: FixedSizeVariantType> ToVariant for FixedSizeVariantArray<A, T> {
1933    fn to_variant(&self) -> Variant {
1934        Variant::array_from_fixed_array(self.0.as_ref())
1935    }
1936}
1937
1938impl<A: AsRef<[T]>, T: FixedSizeVariantType> From<FixedSizeVariantArray<A, T>> for Variant {
1939    #[doc(alias = "g_variant_new_from_data")]
1940    fn from(a: FixedSizeVariantArray<A, T>) -> Self {
1941        unsafe {
1942            let data = Box::new(a.0);
1943            let (data_ptr, len) = {
1944                let data = (*data).as_ref();
1945                (data.as_ptr(), mem::size_of_val(data))
1946            };
1947
1948            unsafe extern "C" fn free_data<A: AsRef<[T]>, T: FixedSizeVariantType>(
1949                ptr: ffi::gpointer,
1950            ) {
1951                let _ = Box::from_raw(ptr as *mut A);
1952            }
1953
1954            from_glib_none(ffi::g_variant_new_from_data(
1955                T::static_variant_type().to_glib_none().0,
1956                data_ptr as ffi::gconstpointer,
1957                len,
1958                false.into_glib(),
1959                Some(free_data::<A, T>),
1960                Box::into_raw(data) as ffi::gpointer,
1961            ))
1962        }
1963    }
1964}
1965
1966/// A wrapper type around `Variant` handles.
1967#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1968pub struct Handle(pub i32);
1969
1970impl From<i32> for Handle {
1971    fn from(v: i32) -> Self {
1972        Handle(v)
1973    }
1974}
1975
1976impl From<Handle> for i32 {
1977    fn from(v: Handle) -> Self {
1978        v.0
1979    }
1980}
1981
1982impl StaticVariantType for Handle {
1983    fn static_variant_type() -> Cow<'static, VariantTy> {
1984        Cow::Borrowed(VariantTy::HANDLE)
1985    }
1986}
1987
1988impl ToVariant for Handle {
1989    fn to_variant(&self) -> Variant {
1990        unsafe { from_glib_none(ffi::g_variant_new_handle(self.0)) }
1991    }
1992}
1993
1994impl From<Handle> for Variant {
1995    #[inline]
1996    fn from(h: Handle) -> Self {
1997        h.to_variant()
1998    }
1999}
2000
2001impl FromVariant for Handle {
2002    fn from_variant(variant: &Variant) -> Option<Self> {
2003        unsafe {
2004            if variant.is::<Self>() {
2005                Some(Handle(ffi::g_variant_get_handle(variant.to_glib_none().0)))
2006            } else {
2007                None
2008            }
2009        }
2010    }
2011}
2012
2013/// A wrapper type around `Variant` object paths.
2014///
2015/// Values of these type are guaranteed to be valid object paths.
2016#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2017pub struct ObjectPath(String);
2018
2019impl ObjectPath {
2020    pub fn as_str(&self) -> &str {
2021        &self.0
2022    }
2023}
2024
2025impl Display for ObjectPath {
2026    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2027        self.0.fmt(f)
2028    }
2029}
2030
2031impl std::ops::Deref for ObjectPath {
2032    type Target = str;
2033
2034    #[inline]
2035    fn deref(&self) -> &Self::Target {
2036        &self.0
2037    }
2038}
2039
2040impl TryFrom<String> for ObjectPath {
2041    type Error = crate::BoolError;
2042
2043    fn try_from(v: String) -> Result<Self, Self::Error> {
2044        if !Variant::is_object_path(&v) {
2045            return Err(bool_error!("Invalid object path"));
2046        }
2047
2048        Ok(ObjectPath(v))
2049    }
2050}
2051
2052impl<'a> TryFrom<&'a str> for ObjectPath {
2053    type Error = crate::BoolError;
2054
2055    fn try_from(v: &'a str) -> Result<Self, Self::Error> {
2056        ObjectPath::try_from(String::from(v))
2057    }
2058}
2059
2060impl From<ObjectPath> for String {
2061    fn from(v: ObjectPath) -> Self {
2062        v.0
2063    }
2064}
2065
2066impl StaticVariantType for ObjectPath {
2067    fn static_variant_type() -> Cow<'static, VariantTy> {
2068        Cow::Borrowed(VariantTy::OBJECT_PATH)
2069    }
2070}
2071
2072impl ToVariant for ObjectPath {
2073    fn to_variant(&self) -> Variant {
2074        unsafe { from_glib_none(ffi::g_variant_new_object_path(self.0.to_glib_none().0)) }
2075    }
2076}
2077
2078impl From<ObjectPath> for Variant {
2079    #[inline]
2080    fn from(p: ObjectPath) -> Self {
2081        let mut s = p.0;
2082        s.push('\0');
2083        unsafe { Self::from_data_trusted::<ObjectPath, _>(s) }
2084    }
2085}
2086
2087impl FromVariant for ObjectPath {
2088    #[allow(unused_unsafe)]
2089    fn from_variant(variant: &Variant) -> Option<Self> {
2090        unsafe {
2091            if variant.is::<Self>() {
2092                Some(ObjectPath(String::from(variant.str().unwrap())))
2093            } else {
2094                None
2095            }
2096        }
2097    }
2098}
2099
2100/// A wrapper type around `Variant` signatures.
2101///
2102/// Values of these type are guaranteed to be valid signatures.
2103#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2104pub struct Signature(String);
2105
2106impl Signature {
2107    pub fn as_str(&self) -> &str {
2108        &self.0
2109    }
2110}
2111
2112impl std::ops::Deref for Signature {
2113    type Target = str;
2114
2115    #[inline]
2116    fn deref(&self) -> &Self::Target {
2117        &self.0
2118    }
2119}
2120
2121impl TryFrom<String> for Signature {
2122    type Error = crate::BoolError;
2123
2124    fn try_from(v: String) -> Result<Self, Self::Error> {
2125        if !Variant::is_signature(&v) {
2126            return Err(bool_error!("Invalid signature"));
2127        }
2128
2129        Ok(Signature(v))
2130    }
2131}
2132
2133impl<'a> TryFrom<&'a str> for Signature {
2134    type Error = crate::BoolError;
2135
2136    fn try_from(v: &'a str) -> Result<Self, Self::Error> {
2137        Signature::try_from(String::from(v))
2138    }
2139}
2140
2141impl From<Signature> for String {
2142    fn from(v: Signature) -> Self {
2143        v.0
2144    }
2145}
2146
2147impl StaticVariantType for Signature {
2148    fn static_variant_type() -> Cow<'static, VariantTy> {
2149        Cow::Borrowed(VariantTy::SIGNATURE)
2150    }
2151}
2152
2153impl ToVariant for Signature {
2154    fn to_variant(&self) -> Variant {
2155        unsafe { from_glib_none(ffi::g_variant_new_signature(self.0.to_glib_none().0)) }
2156    }
2157}
2158
2159impl From<Signature> for Variant {
2160    #[inline]
2161    fn from(s: Signature) -> Self {
2162        let mut s = s.0;
2163        s.push('\0');
2164        unsafe { Self::from_data_trusted::<Signature, _>(s) }
2165    }
2166}
2167
2168impl FromVariant for Signature {
2169    #[allow(unused_unsafe)]
2170    fn from_variant(variant: &Variant) -> Option<Self> {
2171        unsafe {
2172            if variant.is::<Self>() {
2173                Some(Signature(String::from(variant.str().unwrap())))
2174            } else {
2175                None
2176            }
2177        }
2178    }
2179}
2180
2181#[cfg(test)]
2182mod tests {
2183    use std::collections::{HashMap, HashSet};
2184
2185    use super::*;
2186
2187    macro_rules! unsigned {
2188        ($name:ident, $ty:ident) => {
2189            #[test]
2190            fn $name() {
2191                let mut n = $ty::MAX;
2192                while n > 0 {
2193                    let v = n.to_variant();
2194                    assert_eq!(v.get(), Some(n));
2195                    n /= 2;
2196                }
2197            }
2198        };
2199    }
2200
2201    macro_rules! signed {
2202        ($name:ident, $ty:ident) => {
2203            #[test]
2204            fn $name() {
2205                let mut n = $ty::MAX;
2206                while n > 0 {
2207                    let v = n.to_variant();
2208                    assert_eq!(v.get(), Some(n));
2209                    let v = (-n).to_variant();
2210                    assert_eq!(v.get(), Some(-n));
2211                    n /= 2;
2212                }
2213            }
2214        };
2215    }
2216
2217    unsigned!(test_u8, u8);
2218    unsigned!(test_u16, u16);
2219    unsigned!(test_u32, u32);
2220    unsigned!(test_u64, u64);
2221    signed!(test_i16, i16);
2222    signed!(test_i32, i32);
2223    signed!(test_i64, i64);
2224
2225    #[test]
2226    fn test_str() {
2227        let s = "this is a test";
2228        let v = s.to_variant();
2229        assert_eq!(v.str(), Some(s));
2230        assert_eq!(42u32.to_variant().str(), None);
2231    }
2232
2233    #[test]
2234    fn test_fixed_array() {
2235        let b = b"this is a test";
2236        let v = Variant::array_from_fixed_array(&b[..]);
2237        assert_eq!(v.type_().as_str(), "ay");
2238        assert_eq!(v.fixed_array::<u8>().unwrap(), b);
2239        assert!(42u32.to_variant().fixed_array::<u8>().is_err());
2240
2241        let b = [1u32, 10u32, 100u32];
2242        let v = Variant::array_from_fixed_array(&b);
2243        assert_eq!(v.type_().as_str(), "au");
2244        assert_eq!(v.fixed_array::<u32>().unwrap(), b);
2245        assert!(v.fixed_array::<u8>().is_err());
2246
2247        let b = [true, false, true];
2248        let v = Variant::array_from_fixed_array(&b);
2249        assert_eq!(v.type_().as_str(), "ab");
2250        assert_eq!(v.fixed_array::<bool>().unwrap(), b);
2251        assert!(v.fixed_array::<u8>().is_err());
2252
2253        let b = [1.0f64, 2.0f64, 3.0f64];
2254        let v = Variant::array_from_fixed_array(&b);
2255        assert_eq!(v.type_().as_str(), "ad");
2256        #[allow(clippy::float_cmp)]
2257        {
2258            assert_eq!(v.fixed_array::<f64>().unwrap(), b);
2259        }
2260        assert!(v.fixed_array::<u64>().is_err());
2261    }
2262
2263    #[test]
2264    fn test_fixed_variant_array() {
2265        let b = FixedSizeVariantArray::from(&b"this is a test"[..]);
2266        let v = b.to_variant();
2267        assert_eq!(v.type_().as_str(), "ay");
2268        assert_eq!(
2269            &*v.get::<FixedSizeVariantArray<Vec<u8>, u8>>().unwrap(),
2270            &*b
2271        );
2272
2273        let b = FixedSizeVariantArray::from(vec![1i32, 2, 3]);
2274        let v = b.to_variant();
2275        assert_eq!(v.type_().as_str(), "ai");
2276        assert_eq!(v.get::<FixedSizeVariantArray<Vec<i32>, i32>>().unwrap(), b);
2277    }
2278
2279    #[test]
2280    fn test_string() {
2281        let s = String::from("this is a test");
2282        let v = s.to_variant();
2283        assert_eq!(v.get(), Some(s));
2284        assert_eq!(v.normal_form(), v);
2285    }
2286
2287    #[test]
2288    fn test_eq() {
2289        let v1 = "this is a test".to_variant();
2290        let v2 = "this is a test".to_variant();
2291        let v3 = "test".to_variant();
2292        assert_eq!(v1, v2);
2293        assert_ne!(v1, v3);
2294    }
2295
2296    #[test]
2297    fn test_hash() {
2298        let v1 = "this is a test".to_variant();
2299        let v2 = "this is a test".to_variant();
2300        let v3 = "test".to_variant();
2301        let mut set = HashSet::new();
2302        set.insert(v1);
2303        assert!(set.contains(&v2));
2304        assert!(!set.contains(&v3));
2305
2306        assert_eq!(
2307            <HashMap<&str, (&str, u8, u32)>>::static_variant_type().as_str(),
2308            "a{s(syu)}"
2309        );
2310    }
2311
2312    #[test]
2313    fn test_array() {
2314        assert_eq!(<Vec<&str>>::static_variant_type().as_str(), "as");
2315        assert_eq!(
2316            <Vec<(&str, u8, u32)>>::static_variant_type().as_str(),
2317            "a(syu)"
2318        );
2319        let a = ["foo", "bar", "baz"].to_variant();
2320        assert_eq!(a.normal_form(), a);
2321        assert_eq!(a.array_iter_str().unwrap().len(), 3);
2322        let o = 0u32.to_variant();
2323        assert!(o.array_iter_str().is_err());
2324    }
2325
2326    #[test]
2327    fn test_array_from_iter() {
2328        let a = Variant::array_from_iter::<String>(
2329            ["foo", "bar", "baz"].into_iter().map(|s| s.to_variant()),
2330        );
2331        assert_eq!(a.type_().as_str(), "as");
2332        assert_eq!(a.n_children(), 3);
2333
2334        assert_eq!(a.try_child_get::<String>(0), Ok(Some(String::from("foo"))));
2335        assert_eq!(a.try_child_get::<String>(1), Ok(Some(String::from("bar"))));
2336        assert_eq!(a.try_child_get::<String>(2), Ok(Some(String::from("baz"))));
2337    }
2338
2339    #[test]
2340    fn test_array_collect() {
2341        let a = ["foo", "bar", "baz"].into_iter().collect::<Variant>();
2342        assert_eq!(a.type_().as_str(), "as");
2343        assert_eq!(a.n_children(), 3);
2344
2345        assert_eq!(a.try_child_get::<String>(0), Ok(Some(String::from("foo"))));
2346        assert_eq!(a.try_child_get::<String>(1), Ok(Some(String::from("bar"))));
2347        assert_eq!(a.try_child_get::<String>(2), Ok(Some(String::from("baz"))));
2348    }
2349
2350    #[test]
2351    fn test_tuple() {
2352        assert_eq!(<(&str, u32)>::static_variant_type().as_str(), "(su)");
2353        assert_eq!(<(&str, u8, u32)>::static_variant_type().as_str(), "(syu)");
2354        let a = ("test", 1u8, 2u32).to_variant();
2355        assert_eq!(a.normal_form(), a);
2356        assert_eq!(a.try_child_get::<String>(0), Ok(Some(String::from("test"))));
2357        assert_eq!(a.try_child_get::<u8>(1), Ok(Some(1u8)));
2358        assert_eq!(a.try_child_get::<u32>(2), Ok(Some(2u32)));
2359        assert_eq!(
2360            a.try_get::<(String, u8, u32)>(),
2361            Ok((String::from("test"), 1u8, 2u32))
2362        );
2363    }
2364
2365    #[test]
2366    fn test_tuple_from_iter() {
2367        let a = Variant::tuple_from_iter(["foo".to_variant(), 1u8.to_variant(), 2i32.to_variant()]);
2368        assert_eq!(a.type_().as_str(), "(syi)");
2369        assert_eq!(a.n_children(), 3);
2370
2371        assert_eq!(a.try_child_get::<String>(0), Ok(Some(String::from("foo"))));
2372        assert_eq!(a.try_child_get::<u8>(1), Ok(Some(1u8)));
2373        assert_eq!(a.try_child_get::<i32>(2), Ok(Some(2i32)));
2374    }
2375
2376    #[test]
2377    fn test_empty() {
2378        assert_eq!(<()>::static_variant_type().as_str(), "()");
2379        let a = ().to_variant();
2380        assert_eq!(a.type_().as_str(), "()");
2381        assert_eq!(a.get::<()>(), Some(()));
2382    }
2383
2384    #[test]
2385    fn test_maybe() {
2386        assert!(<Option<()>>::static_variant_type().is_maybe());
2387        let m1 = Some(()).to_variant();
2388        assert_eq!(m1.type_().as_str(), "m()");
2389
2390        assert_eq!(m1.get::<Option<()>>(), Some(Some(())));
2391        assert!(m1.as_maybe().is_some());
2392
2393        let m2 = None::<()>.to_variant();
2394        assert!(m2.as_maybe().is_none());
2395    }
2396
2397    #[test]
2398    fn test_btreemap() {
2399        assert_eq!(
2400            <BTreeMap<String, u32>>::static_variant_type().as_str(),
2401            "a{su}"
2402        );
2403        // Validate that BTreeMap adds entries to dict in sorted order
2404        let mut m = BTreeMap::new();
2405        let total = 20;
2406        for n in 0..total {
2407            let k = format!("v{n:04}");
2408            m.insert(k, n as u32);
2409        }
2410        let v = m.to_variant();
2411        let n = v.n_children();
2412        assert_eq!(total, n);
2413        for n in 0..total {
2414            let child = v
2415                .try_child_get::<DictEntry<String, u32>>(n)
2416                .unwrap()
2417                .unwrap();
2418            assert_eq!(*child.value(), n as u32);
2419        }
2420
2421        assert_eq!(BTreeMap::from_variant(&v).unwrap(), m);
2422    }
2423
2424    #[test]
2425    fn test_get() -> Result<(), Box<dyn std::error::Error>> {
2426        let u = 42u32.to_variant();
2427        assert!(u.get::<i32>().is_none());
2428        assert_eq!(u.get::<u32>().unwrap(), 42);
2429        assert!(u.try_get::<i32>().is_err());
2430        // Test ? conversion
2431        assert_eq!(u.try_get::<u32>()?, 42);
2432        Ok(())
2433    }
2434
2435    #[test]
2436    fn test_byteswap() {
2437        let u = 42u32.to_variant();
2438        assert_eq!(u.byteswap().get::<u32>().unwrap(), 704643072u32);
2439        assert_eq!(u.byteswap().byteswap().get::<u32>().unwrap(), 42u32);
2440    }
2441
2442    #[test]
2443    fn test_try_child() {
2444        let a = ["foo"].to_variant();
2445        assert!(a.try_child_value(0).is_some());
2446        assert_eq!(a.try_child_get::<String>(0).unwrap().unwrap(), "foo");
2447        assert_eq!(a.child_get::<String>(0), "foo");
2448        assert!(a.try_child_get::<u32>(0).is_err());
2449        assert!(a.try_child_value(1).is_none());
2450        assert!(a.try_child_get::<String>(1).unwrap().is_none());
2451        let u = 42u32.to_variant();
2452        assert!(u.try_child_value(0).is_none());
2453        assert!(u.try_child_get::<String>(0).unwrap().is_none());
2454    }
2455
2456    #[test]
2457    fn test_serialize() {
2458        let a = ("test", 1u8, 2u32).to_variant();
2459
2460        let bytes = a.data_as_bytes();
2461        let data = a.data();
2462        let len = a.size();
2463        assert_eq!(bytes.len(), len);
2464        assert_eq!(data.len(), len);
2465
2466        let mut store_data = vec![0u8; len];
2467        assert_eq!(a.store(&mut store_data).unwrap(), len);
2468
2469        assert_eq!(&bytes, data);
2470        assert_eq!(&store_data, data);
2471
2472        let b = Variant::from_data::<(String, u8, u32), _>(store_data);
2473        assert_eq!(a, b);
2474
2475        let c = Variant::from_bytes::<(String, u8, u32)>(&bytes);
2476        assert_eq!(a, c);
2477    }
2478
2479    #[test]
2480    fn test_print_parse() {
2481        let a = ("test", 1u8, 2u32).to_variant();
2482
2483        let a2 = Variant::parse(Some(a.type_()), &a.print(false)).unwrap();
2484        assert_eq!(a, a2);
2485
2486        let a3: Variant = a.to_string().parse().unwrap();
2487        assert_eq!(a, a3);
2488    }
2489
2490    #[cfg(any(unix, windows))]
2491    #[test]
2492    fn test_paths() {
2493        use std::path::PathBuf;
2494
2495        let path = PathBuf::from("foo");
2496        let v = path.to_variant();
2497        assert_eq!(PathBuf::from_variant(&v), Some(path));
2498    }
2499
2500    #[test]
2501    fn test_regression_from_variant_panics() {
2502        let variant = "text".to_variant();
2503        let hashmap: Option<HashMap<u64, u64>> = FromVariant::from_variant(&variant);
2504        assert!(hashmap.is_none());
2505
2506        let variant = HashMap::<u64, u64>::new().to_variant();
2507        let hashmap: Option<HashMap<u64, u64>> = FromVariant::from_variant(&variant);
2508        assert!(hashmap.is_some());
2509    }
2510}