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