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