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