1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 //! `Variant` binding and helper traits.
4 //!
5 //! [`Variant`](struct.Variant.html) is an immutable dynamically-typed generic
6 //! container. Its type and value are defined at construction and never change.
7 //!
8 //! `Variant` types are described by [`VariantType`](../struct.VariantType.html)
9 //! "type strings".
10 //!
11 //! Although `GVariant` supports arbitrarily complex types, this binding is
12 //! currently limited to the basic ones: `bool`, `u8`, `i16`, `u16`, `i32`,
13 //! `u32`, `i64`, `u64`, `f64`, `&str`/`String`, and [`VariantDict`](../struct.VariantDict.html).
14 //!
15 //! # Examples
16 //!
17 //! ```
18 //! use glib::prelude::*; // or `use gtk::prelude::*;`
19 //! use glib::{Variant, FromVariant, ToVariant};
20 //! use std::collections::HashMap;
21 //!
22 //! // Using the `ToVariant` trait.
23 //! let num = 10.to_variant();
24 //!
25 //! // `is` tests the type of the value.
26 //! assert!(num.is::<i32>());
27 //!
28 //! // `get` tries to extract the value.
29 //! assert_eq!(num.get::<i32>(), Some(10));
30 //! assert_eq!(num.get::<u32>(), None);
31 //!
32 //! // `get_str` tries to borrow a string slice.
33 //! let hello = "Hello!".to_variant();
34 //! assert_eq!(hello.str(), Some("Hello!"));
35 //! assert_eq!(num.str(), None);
36 //!
37 //! // `bytes` tries to borrow a byte array (GVariant type `ay`),
38 //! // rather than creating a deep copy which would be expensive for
39 //! // nontrivially sized byte arrays.
40 //! // The test data here is the zstd compression header, which
41 //! // stands in for arbitrary binary data (e.g. not UTF-8).
42 //! let bufdata = b"\xFD\x2F\xB5\x28";
43 //! let bufv = bufdata.to_variant();
44 //! assert_eq!(bufv.bytes().unwrap(), bufdata);
45 //! assert!(num.bytes().is_err());
46 //!
47 //! // Variant carrying a Variant
48 //! let variant = Variant::from_variant(&hello);
49 //! let variant = variant.as_variant().unwrap();
50 //! assert_eq!(variant.str(), Some("Hello!"));
51 //!
52 //! // Variant carrying an array
53 //! let array = ["Hello".to_variant(), "there!".to_variant()];
54 //! let variant = Variant::from_array::<&str>(&array);
55 //! assert_eq!(variant.n_children(), 2);
56 //! assert_eq!(variant.child_value(0).str(), Some("Hello"));
57 //! assert_eq!(variant.child_value(1).str(), Some("there!"));
58 //!
59 //! // You can also convert from and to a Vec
60 //! let array = vec!["Hello", "there!"].to_variant();
61 //! assert_eq!(variant.n_children(), 2);
62 //! let vec = <Vec<String>>::from_variant(&array).unwrap();
63 //! assert_eq!(vec[0], "Hello");
64 //!
65 //! // Conversion to and from HashMap is also possible
66 //! let mut map: HashMap<u16, &str> = HashMap::new();
67 //! map.insert(1, "hi");
68 //! map.insert(2, "there");
69 //! let variant = map.to_variant();
70 //! assert_eq!(variant.n_children(), 2);
71 //! let map: HashMap<u16, String> = HashMap::from_variant(&variant).unwrap();
72 //! assert_eq!(map[&1], "hi");
73 //! assert_eq!(map[&2], "there");
74 //!
75 //! // And conversion to and from tuples.
76 //! let variant = ("hello", 42u16, vec![ "there", "you" ],).to_variant();
77 //! assert_eq!(variant.n_children(), 3);
78 //! assert_eq!(variant.type_().to_str(), "(sqas)");
79 //! let tuple = <(String, u16, Vec<String>)>::from_variant(&variant).unwrap();
80 //! assert_eq!(tuple.0, "hello");
81 //! assert_eq!(tuple.1, 42);
82 //! assert_eq!(tuple.2, &[ "there", "you"]);
83 //!
84 //! // `Option` is supported as well, through maybe types
85 //! let variant = Some("hello").to_variant();
86 //! assert_eq!(variant.n_children(), 1);
87 //! let mut s = <Option<String>>::from_variant(&variant).unwrap();
88 //! assert_eq!(s.unwrap(), "hello");
89 //! s = None;
90 //! let variant = s.to_variant();
91 //! assert_eq!(variant.n_children(), 0);
92 //! let s = <Option<String>>::from_variant(&variant).unwrap();
93 //! assert!(s.is_none());
94 //! ```
95 
96 use crate::bytes::Bytes;
97 use crate::gstring::GString;
98 use crate::translate::*;
99 use crate::StaticType;
100 use crate::Type;
101 use crate::VariantTy;
102 use crate::VariantType;
103 use crate::{VariantIter, VariantStrIter};
104 use std::borrow::Cow;
105 use std::cmp::{Eq, Ordering, PartialEq, PartialOrd};
106 use std::collections::HashMap;
107 use std::fmt;
108 use std::hash::{BuildHasher, Hash, Hasher};
109 use std::slice;
110 use std::str;
111 
112 wrapper! {
113     /// A generic immutable value capable of carrying various types.
114     ///
115     /// See the [module documentation](index.html) for more details.
116     #[doc(alias = "GVariant")]
117     pub struct Variant(Shared<ffi::GVariant>);
118 
119     match fn {
120         ref => |ptr| ffi::g_variant_ref_sink(ptr),
121         unref => |ptr| ffi::g_variant_unref(ptr),
122     }
123 }
124 
125 impl StaticType for Variant {
static_type() -> Type126     fn static_type() -> Type {
127         Type::VARIANT
128     }
129 }
130 
131 #[doc(hidden)]
132 impl crate::value::ValueType for Variant {
133     type Type = Variant;
134 }
135 
136 #[doc(hidden)]
137 unsafe impl<'a> crate::value::FromValue<'a> for Variant {
138     type Checker = crate::value::GenericValueTypeOrNoneChecker<Self>;
139 
from_value(value: &'a crate::Value) -> Self140     unsafe fn from_value(value: &'a crate::Value) -> Self {
141         let ptr = gobject_ffi::g_value_dup_variant(value.to_glib_none().0);
142         assert!(!ptr.is_null());
143         from_glib_full(ptr)
144     }
145 }
146 
147 #[doc(hidden)]
148 impl crate::value::ToValue for Variant {
to_value(&self) -> crate::Value149     fn to_value(&self) -> crate::Value {
150         unsafe {
151             let mut value = crate::Value::from_type(Variant::static_type());
152             gobject_ffi::g_value_take_variant(
153                 value.to_glib_none_mut().0,
154                 self.to_glib_full() as *mut _,
155             );
156             value
157         }
158     }
159 
value_type(&self) -> crate::Type160     fn value_type(&self) -> crate::Type {
161         Variant::static_type()
162     }
163 }
164 
165 #[doc(hidden)]
166 impl crate::value::ToValueOptional for Variant {
to_value_optional(s: Option<&Self>) -> crate::Value167     fn to_value_optional(s: Option<&Self>) -> crate::Value {
168         let mut value = crate::Value::for_value_type::<Self>();
169         unsafe {
170             gobject_ffi::g_value_take_variant(
171                 value.to_glib_none_mut().0,
172                 s.to_glib_full() as *mut _,
173             );
174         }
175 
176         value
177     }
178 }
179 
180 /// An error returned from the [`try_get`](struct.Variant.html#method.try_get) function
181 /// on a [`Variant`](struct.Variant.html) when the expected type does not match the actual type.
182 #[derive(Clone, PartialEq, Eq, Debug)]
183 pub struct VariantTypeMismatchError {
184     pub actual: VariantType,
185     pub expected: VariantType,
186 }
187 
188 impl VariantTypeMismatchError {
new(actual: VariantType, expected: VariantType) -> Self189     pub fn new(actual: VariantType, expected: VariantType) -> Self {
190         Self { actual, expected }
191     }
192 }
193 
194 impl fmt::Display for VariantTypeMismatchError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result195     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196         write!(
197             f,
198             "Type mismatch: Expected '{}' got '{}'",
199             self.expected, self.actual
200         )
201     }
202 }
203 
204 impl std::error::Error for VariantTypeMismatchError {}
205 
206 impl Variant {
207     /// Returns the type of the value.
type_(&self) -> &VariantTy208     pub fn type_(&self) -> &VariantTy {
209         unsafe { VariantTy::from_ptr(ffi::g_variant_get_type(self.to_glib_none().0)) }
210     }
211 
212     /// Returns `true` if the type of the value corresponds to `T`.
213     #[inline]
is<T: StaticVariantType>(&self) -> bool214     pub fn is<T: StaticVariantType>(&self) -> bool {
215         self.type_() == T::static_variant_type()
216     }
217 
218     /// Tries to extract a value of type `T`.
219     ///
220     /// Returns `Some` if `T` matches the variant's type.
221     #[inline]
get<T: FromVariant>(&self) -> Option<T>222     pub fn get<T: FromVariant>(&self) -> Option<T> {
223         T::from_variant(self)
224     }
225 
226     /// Tries to extract a value of type `T`.
try_get<T: FromVariant>(&self) -> Result<T, VariantTypeMismatchError>227     pub fn try_get<T: FromVariant>(&self) -> Result<T, VariantTypeMismatchError> {
228         self.get().ok_or_else(|| {
229             VariantTypeMismatchError::new(
230                 self.type_().to_owned(),
231                 T::static_variant_type().into_owned(),
232             )
233         })
234     }
235 
236     /// Boxes value.
237     #[inline]
from_variant(value: &Variant) -> Self238     pub fn from_variant(value: &Variant) -> Self {
239         unsafe { from_glib_none(ffi::g_variant_new_variant(value.to_glib_none().0)) }
240     }
241 
242     /// Unboxes self.
243     ///
244     /// Returns `Some` if self contains a `Variant`.
245     #[inline]
246     #[doc(alias = "get_variant")]
as_variant(&self) -> Option<Variant>247     pub fn as_variant(&self) -> Option<Variant> {
248         unsafe { from_glib_full(ffi::g_variant_get_variant(self.to_glib_none().0)) }
249     }
250 
251     /// Reads a child item out of a container `Variant` instance.
252     ///
253     /// # Panics
254     ///
255     /// * if `self` is not a container type.
256     /// * if given `index` is larger than number of children.
257     #[doc(alias = "get_child_value")]
258     #[doc(alias = "g_variant_get_child_value")]
child_value(&self, index: usize) -> Variant259     pub fn child_value(&self, index: usize) -> Variant {
260         assert!(self.is_container());
261         assert!(index < self.n_children());
262 
263         unsafe { from_glib_full(ffi::g_variant_get_child_value(self.to_glib_none().0, index)) }
264     }
265 
266     /// Try to read a child item out of a container `Variant` instance.
267     ///
268     /// It returns `None` if `self` is not a container type or if the given
269     /// `index` is larger than number of children.
try_child_value(&self, index: usize) -> Option<Variant>270     pub fn try_child_value(&self, index: usize) -> Option<Variant> {
271         if !(self.is_container() && index < self.n_children()) {
272             return None;
273         }
274 
275         let v =
276             unsafe { from_glib_full(ffi::g_variant_get_child_value(self.to_glib_none().0, index)) };
277         Some(v)
278     }
279 
280     /// Try to read a child item out of a container `Variant` instance.
281     ///
282     /// It returns `Ok(None)` if `self` is not a container type or if the given
283     /// `index` is larger than number of children.  An error is thrown if the
284     /// type does not match.
try_child_get<T: StaticVariantType + FromVariant>( &self, index: usize, ) -> Result<Option<T>, VariantTypeMismatchError>285     pub fn try_child_get<T: StaticVariantType + FromVariant>(
286         &self,
287         index: usize,
288     ) -> Result<Option<T>, VariantTypeMismatchError> {
289         // TODO: In the future optimize this by using g_variant_get_child()
290         // directly to avoid allocating a GVariant.
291         self.try_child_value(index).map(|v| v.try_get()).transpose()
292     }
293 
294     /// Read a child item out of a container `Variant` instance.
295     ///
296     /// # Panics
297     ///
298     /// * if `self` is not a container type.
299     /// * if given `index` is larger than number of children.
300     /// * if the expected variant type does not match
child_get<T: StaticVariantType + FromVariant>(&self, index: usize) -> T301     pub fn child_get<T: StaticVariantType + FromVariant>(&self, index: usize) -> T {
302         // TODO: In the future optimize this by using g_variant_get_child()
303         // directly to avoid allocating a GVariant.
304         self.child_value(index).get().unwrap()
305     }
306 
307     /// Tries to extract a `&str`.
308     ///
309     /// Returns `Some` if the variant has a string type (`s`, `o` or `g` type
310     /// strings).
311     #[doc(alias = "get_str")]
312     #[doc(alias = "g_variant_get_string")]
str(&self) -> Option<&str>313     pub fn str(&self) -> Option<&str> {
314         unsafe {
315             match self.type_().to_str() {
316                 "s" | "o" | "g" => {
317                     let mut len = 0;
318                     let ptr = ffi::g_variant_get_string(self.to_glib_none().0, &mut len);
319                     let ret = str::from_utf8_unchecked(slice::from_raw_parts(
320                         ptr as *const u8,
321                         len as usize,
322                     ));
323                     Some(ret)
324                 }
325                 _ => None,
326             }
327         }
328     }
329 
330     /// Tries to extract a `&[u8]` from a variant of type `ay` (array of bytes).
331     ///
332     /// Returns an error if the type is not `ay`.
bytes(&self) -> Result<&[u8], VariantTypeMismatchError>333     pub fn bytes(&self) -> Result<&[u8], VariantTypeMismatchError> {
334         unsafe {
335             let t = self.type_();
336             let expected_ty = &*Vec::<u8>::static_variant_type();
337             if t == expected_ty {
338                 let selfv = self.to_glib_none();
339                 let len = ffi::g_variant_get_size(selfv.0);
340                 let ptr = ffi::g_variant_get_data(selfv.0);
341                 let ret = slice::from_raw_parts(ptr as *const u8, len as usize);
342                 Ok(ret)
343             } else {
344                 Err(VariantTypeMismatchError {
345                     actual: t.to_owned(),
346                     expected: expected_ty.to_owned(),
347                 })
348             }
349         }
350     }
351 
352     /// Creates a new GVariant array from children.
353     ///
354     /// All children must be of type `T`.
from_array<T: StaticVariantType>(children: &[Variant]) -> Self355     pub fn from_array<T: StaticVariantType>(children: &[Variant]) -> Self {
356         let type_ = T::static_variant_type();
357 
358         for child in children {
359             assert_eq!(type_, child.type_());
360         }
361         unsafe {
362             from_glib_none(ffi::g_variant_new_array(
363                 type_.as_ptr() as *const _,
364                 children.to_glib_none().0,
365                 children.len(),
366             ))
367         }
368     }
369 
370     /// Creates a new GVariant tuple from children.
from_tuple(children: &[Variant]) -> Self371     pub fn from_tuple(children: &[Variant]) -> Self {
372         unsafe {
373             from_glib_none(ffi::g_variant_new_tuple(
374                 children.to_glib_none().0,
375                 children.len(),
376             ))
377         }
378     }
379 
380     /// Creates a new maybe Variant.
from_maybe<T: StaticVariantType>(child: Option<&Variant>) -> Self381     pub fn from_maybe<T: StaticVariantType>(child: Option<&Variant>) -> Self {
382         let type_ = T::static_variant_type();
383         let ptr = match child {
384             Some(child) => {
385                 assert_eq!(type_, child.type_());
386 
387                 child.to_glib_none().0
388             }
389             None => std::ptr::null(),
390         };
391         unsafe {
392             from_glib_none(ffi::g_variant_new_maybe(
393                 type_.as_ptr() as *const _,
394                 ptr as *mut ffi::GVariant,
395             ))
396         }
397     }
398 
399     /// Constructs a new serialised-mode GVariant instance.
400     #[doc(alias = "g_variant_new_from_bytes")]
from_bytes<T: StaticVariantType>(bytes: &Bytes) -> Self401     pub fn from_bytes<T: StaticVariantType>(bytes: &Bytes) -> Self {
402         unsafe {
403             from_glib_none(ffi::g_variant_new_from_bytes(
404                 T::static_variant_type().as_ptr() as *const _,
405                 bytes.to_glib_none().0,
406                 false.into_glib(),
407             ))
408         }
409     }
410 
411     /// Constructs a new serialised-mode GVariant instance.
412     ///
413     /// This is the same as `from_bytes`, except that checks on the passed
414     /// data are skipped.
415     ///
416     /// You should not use this function on data from external sources.
417     ///
418     /// # Safety
419     ///
420     /// Since the data is not validated, this is potentially dangerous if called
421     /// on bytes which are not guaranteed to have come from serialising another
422     /// Variant.  The caller is responsible for ensuring bad data is not passed in.
from_bytes_trusted<T: StaticVariantType>(bytes: &Bytes) -> Self423     pub unsafe fn from_bytes_trusted<T: StaticVariantType>(bytes: &Bytes) -> Self {
424         from_glib_none(ffi::g_variant_new_from_bytes(
425             T::static_variant_type().as_ptr() as *const _,
426             bytes.to_glib_none().0,
427             true.into_glib(),
428         ))
429     }
430 
431     /// Returns the serialised form of a GVariant instance.
432     #[doc(alias = "get_data_as_bytes")]
433     #[doc(alias = "g_variant_get_data_as_bytes")]
data_as_bytes(&self) -> Bytes434     pub fn data_as_bytes(&self) -> Bytes {
435         unsafe { from_glib_full(ffi::g_variant_get_data_as_bytes(self.to_glib_none().0)) }
436     }
437 
438     /// Returns a copy of the variant in normal form.
439     #[doc(alias = "g_variant_get_normal_form")]
normal_form(&self) -> Self440     pub fn normal_form(&self) -> Self {
441         unsafe { from_glib_full(ffi::g_variant_get_normal_form(self.to_glib_none().0)) }
442     }
443 
444     /// Returns a copy of the variant in the opposite endianness.
445     #[doc(alias = "g_variant_byteswap")]
byteswap(&self) -> Self446     pub fn byteswap(&self) -> Self {
447         unsafe { from_glib_full(ffi::g_variant_byteswap(self.to_glib_none().0)) }
448     }
449 
450     /// Determines the number of children in a container GVariant instance.
451     #[doc(alias = "g_variant_n_children")]
n_children(&self) -> usize452     pub fn n_children(&self) -> usize {
453         assert!(self.is_container());
454 
455         unsafe { ffi::g_variant_n_children(self.to_glib_none().0) }
456     }
457 
458     /// Create an iterator over items in the variant.
459     ///
460     /// Note that this heap allocates a variant for each element,
461     /// which can be particularly expensive for large arrays.
iter(&self) -> VariantIter462     pub fn iter(&self) -> VariantIter {
463         assert!(self.is_container());
464 
465         VariantIter::new(self.clone())
466     }
467 
468     /// Create an iterator over borrowed strings from a GVariant of type `as` (array of string).
469     ///
470     /// This will fail if the variant is not an array of with
471     /// the expected child type.
472     ///
473     /// A benefit of this API over [`Self::iter()`] is that it
474     /// minimizes allocation, and provides strongly typed access.
475     ///
476     /// ```
477     /// # use glib::prelude::*;
478     /// let strs = &["foo", "bar"];
479     /// let strs_variant: glib::Variant = strs.to_variant();
480     /// for s in strs_variant.array_iter_str()? {
481     ///     println!("{}", s);
482     /// }
483     /// # Ok::<(), Box<dyn std::error::Error>>(())
484     /// ```
array_iter_str(&self) -> Result<VariantStrIter, VariantTypeMismatchError>485     pub fn array_iter_str(&self) -> Result<VariantStrIter, VariantTypeMismatchError> {
486         let child_ty = String::static_variant_type();
487         let actual_ty = self.type_();
488         let expected_ty = child_ty.with_array();
489         if actual_ty != expected_ty {
490             return Err(VariantTypeMismatchError {
491                 actual: actual_ty.to_owned(),
492                 expected: expected_ty,
493             });
494         }
495 
496         Ok(VariantStrIter::new(self))
497     }
498 
499     /// Variant has a container type.
500     #[doc(alias = "g_variant_is_container")]
is_container(&self) -> bool501     pub fn is_container(&self) -> bool {
502         unsafe { ffi::g_variant_is_container(self.to_glib_none().0) != ffi::GFALSE }
503     }
504 }
505 
506 unsafe impl Send for Variant {}
507 unsafe impl Sync for Variant {}
508 
509 impl fmt::Debug for Variant {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result510     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
511         f.debug_struct("Variant")
512             .field("ptr", &self.to_glib_none().0)
513             .field("type", &self.type_())
514             .field("value", &self.to_string())
515             .finish()
516     }
517 }
518 
519 impl fmt::Display for Variant {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result520     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
521         let serialized: GString = unsafe {
522             from_glib_full(ffi::g_variant_print(
523                 self.to_glib_none().0,
524                 false.into_glib(),
525             ))
526         };
527         f.write_str(&serialized)
528     }
529 }
530 
531 impl PartialEq for Variant {
532     #[doc(alias = "g_variant_equal")]
eq(&self, other: &Self) -> bool533     fn eq(&self, other: &Self) -> bool {
534         unsafe {
535             from_glib(ffi::g_variant_equal(
536                 self.to_glib_none().0 as *const _,
537                 other.to_glib_none().0 as *const _,
538             ))
539         }
540     }
541 }
542 
543 impl Eq for Variant {}
544 
545 impl PartialOrd for Variant {
partial_cmp(&self, other: &Self) -> Option<Ordering>546     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
547         unsafe {
548             if ffi::g_variant_classify(self.to_glib_none().0)
549                 != ffi::g_variant_classify(other.to_glib_none().0)
550             {
551                 return None;
552             }
553 
554             if self.is_container() {
555                 return None;
556             }
557 
558             let res = ffi::g_variant_compare(
559                 self.to_glib_none().0 as *const _,
560                 other.to_glib_none().0 as *const _,
561             );
562 
563             Some(res.cmp(&0))
564         }
565     }
566 }
567 
568 impl Hash for Variant {
569     #[doc(alias = "g_variant_hash")]
hash<H: Hasher>(&self, state: &mut H)570     fn hash<H: Hasher>(&self, state: &mut H) {
571         unsafe { state.write_u32(ffi::g_variant_hash(self.to_glib_none().0 as *const _)) }
572     }
573 }
574 
575 /// Converts to `Variant`.
576 pub trait ToVariant {
577     /// Returns a `Variant` clone of `self`.
to_variant(&self) -> Variant578     fn to_variant(&self) -> Variant;
579 }
580 
581 /// Extracts a value.
582 pub trait FromVariant: Sized + StaticVariantType {
583     /// Tries to extract a value.
584     ///
585     /// Returns `Some` if the variant's type matches `Self`.
from_variant(variant: &Variant) -> Option<Self>586     fn from_variant(variant: &Variant) -> Option<Self>;
587 }
588 
589 /// Returns `VariantType` of `Self`.
590 pub trait StaticVariantType {
591     /// Returns the `VariantType` corresponding to `Self`.
static_variant_type() -> Cow<'static, VariantTy>592     fn static_variant_type() -> Cow<'static, VariantTy>;
593 }
594 
595 impl StaticVariantType for Variant {
static_variant_type() -> Cow<'static, VariantTy>596     fn static_variant_type() -> Cow<'static, VariantTy> {
597         unsafe { VariantTy::from_str_unchecked("v").into() }
598     }
599 }
600 
601 impl<'a, T: ?Sized + ToVariant> ToVariant for &'a T {
to_variant(&self) -> Variant602     fn to_variant(&self) -> Variant {
603         <T as ToVariant>::to_variant(self)
604     }
605 }
606 
607 impl<'a, T: ?Sized + StaticVariantType> StaticVariantType for &'a T {
static_variant_type() -> Cow<'static, VariantTy>608     fn static_variant_type() -> Cow<'static, VariantTy> {
609         <T as StaticVariantType>::static_variant_type()
610     }
611 }
612 
613 macro_rules! impl_numeric {
614     ($name:ty, $type_str:expr, $new_fn:ident, $get_fn:ident) => {
615         impl StaticVariantType for $name {
616             fn static_variant_type() -> Cow<'static, VariantTy> {
617                 unsafe { VariantTy::from_str_unchecked($type_str).into() }
618             }
619         }
620 
621         impl ToVariant for $name {
622             fn to_variant(&self) -> Variant {
623                 unsafe { from_glib_none(ffi::$new_fn(*self)) }
624             }
625         }
626 
627         impl FromVariant for $name {
628             fn from_variant(variant: &Variant) -> Option<Self> {
629                 unsafe {
630                     if variant.is::<Self>() {
631                         Some(ffi::$get_fn(variant.to_glib_none().0))
632                     } else {
633                         None
634                     }
635                 }
636             }
637         }
638     };
639 }
640 
641 impl_numeric!(u8, "y", g_variant_new_byte, g_variant_get_byte);
642 impl_numeric!(i16, "n", g_variant_new_int16, g_variant_get_int16);
643 impl_numeric!(u16, "q", g_variant_new_uint16, g_variant_get_uint16);
644 impl_numeric!(i32, "i", g_variant_new_int32, g_variant_get_int32);
645 impl_numeric!(u32, "u", g_variant_new_uint32, g_variant_get_uint32);
646 impl_numeric!(i64, "x", g_variant_new_int64, g_variant_get_int64);
647 impl_numeric!(u64, "t", g_variant_new_uint64, g_variant_get_uint64);
648 impl_numeric!(f64, "d", g_variant_new_double, g_variant_get_double);
649 
650 impl StaticVariantType for bool {
static_variant_type() -> Cow<'static, VariantTy>651     fn static_variant_type() -> Cow<'static, VariantTy> {
652         unsafe { VariantTy::from_str_unchecked("b").into() }
653     }
654 }
655 
656 impl ToVariant for bool {
to_variant(&self) -> Variant657     fn to_variant(&self) -> Variant {
658         unsafe { from_glib_none(ffi::g_variant_new_boolean(self.into_glib())) }
659     }
660 }
661 
662 impl FromVariant for bool {
from_variant(variant: &Variant) -> Option<Self>663     fn from_variant(variant: &Variant) -> Option<Self> {
664         unsafe {
665             if variant.is::<Self>() {
666                 Some(from_glib(ffi::g_variant_get_boolean(
667                     variant.to_glib_none().0,
668                 )))
669             } else {
670                 None
671             }
672         }
673     }
674 }
675 
676 impl StaticVariantType for String {
static_variant_type() -> Cow<'static, VariantTy>677     fn static_variant_type() -> Cow<'static, VariantTy> {
678         unsafe { VariantTy::from_str_unchecked("s").into() }
679     }
680 }
681 
682 impl ToVariant for String {
to_variant(&self) -> Variant683     fn to_variant(&self) -> Variant {
684         self[..].to_variant()
685     }
686 }
687 
688 impl FromVariant for String {
from_variant(variant: &Variant) -> Option<Self>689     fn from_variant(variant: &Variant) -> Option<Self> {
690         variant.str().map(String::from)
691     }
692 }
693 
694 impl StaticVariantType for str {
static_variant_type() -> Cow<'static, VariantTy>695     fn static_variant_type() -> Cow<'static, VariantTy> {
696         unsafe { VariantTy::from_str_unchecked("s").into() }
697     }
698 }
699 
700 impl ToVariant for str {
to_variant(&self) -> Variant701     fn to_variant(&self) -> Variant {
702         unsafe { from_glib_none(ffi::g_variant_new_take_string(self.to_glib_full())) }
703     }
704 }
705 
706 impl<T: StaticVariantType> StaticVariantType for Option<T> {
static_variant_type() -> Cow<'static, VariantTy>707     fn static_variant_type() -> Cow<'static, VariantTy> {
708         let child_type = T::static_variant_type();
709         let signature = format!("m{}", child_type.to_str());
710 
711         VariantType::new(&signature)
712             .expect("incorrect signature")
713             .into()
714     }
715 }
716 
717 impl<T: StaticVariantType + ToVariant> ToVariant for Option<T> {
to_variant(&self) -> Variant718     fn to_variant(&self) -> Variant {
719         Variant::from_maybe::<T>(self.as_ref().map(|m| m.to_variant()).as_ref())
720     }
721 }
722 
723 impl<T: StaticVariantType + FromVariant> FromVariant for Option<T> {
from_variant(variant: &Variant) -> Option<Self>724     fn from_variant(variant: &Variant) -> Option<Self> {
725         unsafe {
726             if variant.is::<Self>() {
727                 let c_child = ffi::g_variant_get_maybe(variant.to_glib_none().0);
728                 if !c_child.is_null() {
729                     let child: Variant = from_glib_full(c_child);
730 
731                     Some(T::from_variant(&child))
732                 } else {
733                     Some(None)
734                 }
735             } else {
736                 None
737             }
738         }
739     }
740 }
741 
742 impl<T: StaticVariantType> StaticVariantType for [T] {
static_variant_type() -> Cow<'static, VariantTy>743     fn static_variant_type() -> Cow<'static, VariantTy> {
744         T::static_variant_type().with_array().into()
745     }
746 }
747 
748 impl<T: StaticVariantType + ToVariant> ToVariant for [T] {
to_variant(&self) -> Variant749     fn to_variant(&self) -> Variant {
750         let mut vec = Vec::with_capacity(self.len());
751         for child in self {
752             vec.push(child.to_variant());
753         }
754         Variant::from_array::<T>(&vec)
755     }
756 }
757 
758 impl<T: FromVariant> FromVariant for Vec<T> {
from_variant(variant: &Variant) -> Option<Self>759     fn from_variant(variant: &Variant) -> Option<Self> {
760         if !variant.is_container() {
761             return None;
762         }
763 
764         let mut vec = Vec::with_capacity(variant.n_children());
765 
766         for i in 0..variant.n_children() {
767             match variant.child_value(i).get() {
768                 Some(child) => vec.push(child),
769                 None => return None,
770             }
771         }
772 
773         Some(vec)
774     }
775 }
776 
777 impl<T: StaticVariantType + ToVariant> ToVariant for Vec<T> {
to_variant(&self) -> Variant778     fn to_variant(&self) -> Variant {
779         let mut vec = Vec::with_capacity(self.len());
780         for child in self {
781             vec.push(child.to_variant());
782         }
783         Variant::from_array::<T>(&vec)
784     }
785 }
786 
787 impl<T: StaticVariantType> StaticVariantType for Vec<T> {
static_variant_type() -> Cow<'static, VariantTy>788     fn static_variant_type() -> Cow<'static, VariantTy> {
789         <[T]>::static_variant_type()
790     }
791 }
792 
793 #[test]
test_regression_from_variant_panics()794 fn test_regression_from_variant_panics() {
795     let variant = "text".to_variant();
796     let hashmap: Option<HashMap<u64, u64>> = FromVariant::from_variant(&variant);
797     assert!(hashmap.is_none());
798 
799     let variant = HashMap::<u64, u64>::new().to_variant();
800     let hashmap: Option<HashMap<u64, u64>> = FromVariant::from_variant(&variant);
801     assert!(hashmap.is_some());
802 }
803 
804 impl<K, V, H> FromVariant for HashMap<K, V, H>
805 where
806     K: FromVariant + Eq + Hash,
807     V: FromVariant,
808     H: BuildHasher + Default,
809 {
from_variant(variant: &Variant) -> Option<Self>810     fn from_variant(variant: &Variant) -> Option<Self> {
811         if !variant.is_container() {
812             return None;
813         }
814 
815         let mut map = HashMap::default();
816 
817         for i in 0..variant.n_children() {
818             let entry = variant.child_value(i);
819             let key = match entry.child_value(0).get() {
820                 Some(key) => key,
821                 None => return None,
822             };
823             let val = match entry.child_value(1).get() {
824                 Some(val) => val,
825                 None => return None,
826             };
827 
828             map.insert(key, val);
829         }
830 
831         Some(map)
832     }
833 }
834 
835 impl<K, V> ToVariant for HashMap<K, V>
836 where
837     K: StaticVariantType + ToVariant + Eq + Hash,
838     V: StaticVariantType + ToVariant,
839 {
to_variant(&self) -> Variant840     fn to_variant(&self) -> Variant {
841         let mut vec = Vec::with_capacity(self.len());
842         for (key, value) in self {
843             let entry = DictEntry::new(key, value).to_variant();
844             vec.push(entry);
845         }
846         Variant::from_array::<DictEntry<K, V>>(&vec)
847     }
848 }
849 
850 /// A Dictionary entry.
851 ///
852 /// While GVariant format allows a dictionary entry to be an independent type, typically you'll need
853 /// to use this in a dictionary, which is simply an array of dictionary entries. The following code
854 /// creates a dictionary:
855 ///
856 /// ```
857 ///# use glib::prelude::*; // or `use gtk::prelude::*;`
858 /// use glib::{Variant, FromVariant, ToVariant};
859 /// use glib::variant::DictEntry;
860 ///
861 /// let entries = vec![
862 ///     DictEntry::new("uuid", 1000u32).to_variant(),
863 ///     DictEntry::new("guid", 1001u32).to_variant(),
864 /// ];
865 /// let dict = Variant::from_array::<DictEntry<&str, u32>>(&entries);
866 /// assert_eq!(dict.n_children(), 2);
867 /// assert_eq!(dict.type_().to_str(), "a{su}");
868 /// ```
869 pub struct DictEntry<K, V> {
870     key: K,
871     value: V,
872 }
873 
874 impl<K, V> DictEntry<K, V>
875 where
876     K: StaticVariantType + ToVariant + Eq + Hash,
877     V: StaticVariantType + ToVariant,
878 {
new(key: K, value: V) -> Self879     pub fn new(key: K, value: V) -> Self {
880         Self { key, value }
881     }
882 
key(&self) -> &K883     pub fn key(&self) -> &K {
884         &self.key
885     }
886 
value(&self) -> &V887     pub fn value(&self) -> &V {
888         &self.value
889     }
890 }
891 
892 impl<K, V> FromVariant for DictEntry<K, V>
893 where
894     K: FromVariant + Eq + Hash,
895     V: FromVariant,
896 {
from_variant(variant: &Variant) -> Option<Self>897     fn from_variant(variant: &Variant) -> Option<Self> {
898         let key = match variant.child_value(0).get() {
899             Some(key) => key,
900             None => return None,
901         };
902         let value = match variant.child_value(1).get() {
903             Some(value) => value,
904             None => return None,
905         };
906 
907         Some(Self { key, value })
908     }
909 }
910 
911 impl<K, V> ToVariant for DictEntry<K, V>
912 where
913     K: StaticVariantType + ToVariant + Eq + Hash,
914     V: StaticVariantType + ToVariant,
915 {
to_variant(&self) -> Variant916     fn to_variant(&self) -> Variant {
917         unsafe {
918             from_glib_none(ffi::g_variant_new_dict_entry(
919                 self.key.to_variant().to_glib_none().0,
920                 self.value.to_variant().to_glib_none().0,
921             ))
922         }
923     }
924 }
925 
926 impl ToVariant for Variant {
to_variant(&self) -> Variant927     fn to_variant(&self) -> Variant {
928         Variant::from_variant(self)
929     }
930 }
931 
932 impl FromVariant for Variant {
from_variant(variant: &Variant) -> Option<Self>933     fn from_variant(variant: &Variant) -> Option<Self> {
934         variant.as_variant()
935     }
936 }
937 
938 impl<K: StaticVariantType, V: StaticVariantType> StaticVariantType for DictEntry<K, V> {
static_variant_type() -> Cow<'static, VariantTy>939     fn static_variant_type() -> Cow<'static, VariantTy> {
940         let key_type = K::static_variant_type();
941         let value_type = V::static_variant_type();
942         let signature = format!("{{{}{}}}", key_type.to_str(), value_type.to_str());
943 
944         VariantType::new(&signature)
945             .expect("incorrect signature")
946             .into()
947     }
948 }
949 
950 impl<K, V, H> StaticVariantType for HashMap<K, V, H>
951 where
952     K: StaticVariantType,
953     V: StaticVariantType,
954     H: BuildHasher + Default,
955 {
static_variant_type() -> Cow<'static, VariantTy>956     fn static_variant_type() -> Cow<'static, VariantTy> {
957         let key_type = K::static_variant_type();
958         let value_type = V::static_variant_type();
959         let signature = format!("a{{{}{}}}", key_type.to_str(), value_type.to_str());
960 
961         VariantType::new(&signature)
962             .expect("incorrect signature")
963             .into()
964     }
965 }
966 
967 macro_rules! tuple_impls {
968     ($($len:expr => ($($n:tt $name:ident)+))+) => {
969         $(
970             impl<$($name),+> StaticVariantType for ($($name,)+)
971             where
972                 $($name: StaticVariantType,)+
973             {
974                 fn static_variant_type() -> Cow<'static, VariantTy> {
975                     let mut signature = String::with_capacity(255);
976                     signature.push('(');
977                     $(
978                         signature.push_str($name::static_variant_type().to_str());
979                     )+
980                     signature.push(')');
981 
982                     VariantType::new(&signature).expect("incorrect signature").into()
983                 }
984             }
985 
986             impl<$($name),+> FromVariant for ($($name,)+)
987             where
988                 $($name: FromVariant,)+
989             {
990                 fn from_variant(variant: &Variant) -> Option<Self> {
991                     Some((
992                         $(
993                             match $name::from_variant(&variant.child_value($n)) {
994                                 Some(field) => field,
995                                 None => return None,
996                             },
997                         )+
998                     ))
999                 }
1000             }
1001 
1002             impl<$($name),+> ToVariant for ($($name,)+)
1003             where
1004                 $($name: ToVariant,)+
1005             {
1006                 fn to_variant(&self) -> Variant {
1007                     let mut fields = Vec::with_capacity($len);
1008                     $(
1009                         let field = self.$n.to_variant();
1010                         fields.push(field);
1011                     )+
1012                     Variant::from_tuple(&fields)
1013                 }
1014             }
1015         )+
1016     }
1017 }
1018 
1019 tuple_impls! {
1020     1 => (0 T0)
1021     2 => (0 T0 1 T1)
1022     3 => (0 T0 1 T1 2 T2)
1023     4 => (0 T0 1 T1 2 T2 3 T3)
1024     5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
1025     6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
1026     7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
1027     8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
1028     9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
1029     10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
1030     11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
1031     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)
1032     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)
1033     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)
1034     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)
1035     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)
1036 }
1037 
1038 #[cfg(test)]
1039 mod tests {
1040     use super::*;
1041     use std::collections::{HashMap, HashSet};
1042 
1043     macro_rules! unsigned {
1044         ($name:ident, $ty:ident) => {
1045             #[test]
1046             fn $name() {
1047                 let mut n = $ty::max_value();
1048                 while n > 0 {
1049                     let v = n.to_variant();
1050                     assert_eq!(v.get(), Some(n));
1051                     n /= 2;
1052                 }
1053             }
1054         };
1055     }
1056 
1057     macro_rules! signed {
1058         ($name:ident, $ty:ident) => {
1059             #[test]
1060             fn $name() {
1061                 let mut n = $ty::max_value();
1062                 while n > 0 {
1063                     let v = n.to_variant();
1064                     assert_eq!(v.get(), Some(n));
1065                     let v = (-n).to_variant();
1066                     assert_eq!(v.get(), Some(-n));
1067                     n /= 2;
1068                 }
1069             }
1070         };
1071     }
1072 
1073     unsigned!(test_u8, u8);
1074     unsigned!(test_u16, u16);
1075     unsigned!(test_u32, u32);
1076     unsigned!(test_u64, u64);
1077     signed!(test_i16, i16);
1078     signed!(test_i32, i32);
1079     signed!(test_i64, i64);
1080 
1081     #[test]
test_str()1082     fn test_str() {
1083         let s = "this is a test";
1084         let v = s.to_variant();
1085         assert_eq!(v.str(), Some(s));
1086         assert_eq!(42u32.to_variant().str(), None);
1087     }
1088 
1089     #[test]
test_bytes()1090     fn test_bytes() {
1091         let b = b"this is a test";
1092         let v = b.to_variant();
1093         assert_eq!(v.bytes().unwrap(), b);
1094         assert!(42u32.to_variant().bytes().is_err());
1095     }
1096 
1097     #[test]
test_string()1098     fn test_string() {
1099         let s = String::from("this is a test");
1100         let v = s.to_variant();
1101         assert_eq!(v.get(), Some(s));
1102         assert_eq!(v.normal_form(), v);
1103     }
1104 
1105     #[test]
test_eq()1106     fn test_eq() {
1107         let v1 = "this is a test".to_variant();
1108         let v2 = "this is a test".to_variant();
1109         let v3 = "test".to_variant();
1110         assert_eq!(v1, v2);
1111         assert_ne!(v1, v3);
1112     }
1113 
1114     #[test]
test_hash()1115     fn test_hash() {
1116         let v1 = "this is a test".to_variant();
1117         let v2 = "this is a test".to_variant();
1118         let v3 = "test".to_variant();
1119         let mut set = HashSet::new();
1120         set.insert(v1);
1121         assert!(set.contains(&v2));
1122         assert!(!set.contains(&v3));
1123 
1124         assert_eq!(
1125             <HashMap<&str, (&str, u8, u32)>>::static_variant_type().to_str(),
1126             "a{s(syu)}"
1127         );
1128     }
1129 
1130     #[test]
test_array()1131     fn test_array() {
1132         assert_eq!(<Vec<&str>>::static_variant_type().to_str(), "as");
1133         assert_eq!(
1134             <Vec<(&str, u8, u32)>>::static_variant_type().to_str(),
1135             "a(syu)"
1136         );
1137         let a = ["foo", "bar", "baz"].to_variant();
1138         assert_eq!(a.normal_form(), a);
1139         assert_eq!(a.array_iter_str().unwrap().len(), 3);
1140         let o = 0u32.to_variant();
1141         assert!(o.array_iter_str().is_err());
1142     }
1143 
1144     #[test]
test_get() -> Result<(), Box<dyn std::error::Error>>1145     fn test_get() -> Result<(), Box<dyn std::error::Error>> {
1146         let u = 42u32.to_variant();
1147         assert!(u.get::<i32>().is_none());
1148         assert_eq!(u.get::<u32>().unwrap(), 42);
1149         assert!(u.try_get::<i32>().is_err());
1150         // Test ? conversion
1151         assert_eq!(u.try_get::<u32>()?, 42);
1152         Ok(())
1153     }
1154 
1155     #[test]
test_byteswap()1156     fn test_byteswap() {
1157         let u = 42u32.to_variant();
1158         assert_eq!(u.byteswap().get::<u32>().unwrap(), 704643072u32);
1159         assert_eq!(u.byteswap().byteswap().get::<u32>().unwrap(), 42u32);
1160     }
1161 
1162     #[test]
test_try_child()1163     fn test_try_child() {
1164         let a = ["foo"].to_variant();
1165         assert!(a.try_child_value(0).is_some());
1166         assert_eq!(a.try_child_get::<String>(0).unwrap().unwrap(), "foo");
1167         assert_eq!(a.child_get::<String>(0), "foo");
1168         assert!(a.try_child_get::<u32>(0).is_err());
1169         assert!(a.try_child_value(1).is_none());
1170         assert!(a.try_child_get::<String>(1).unwrap().is_none());
1171         let u = 42u32.to_variant();
1172         assert!(u.try_child_value(0).is_none());
1173         assert!(u.try_child_get::<String>(0).unwrap().is_none());
1174     }
1175 }
1176