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