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