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