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