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