zvariant-5.2.0/.cargo_vcs_info.json0000644000000001460000000000100126770ustar { "git": { "sha1": "01508a993fba46dddd8402c16dfce8014c64579b" }, "path_in_vcs": "zvariant" }zvariant-5.2.0/Cargo.toml0000644000000052550000000000100107030ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.77" name = "zvariant" version = "5.2.0" authors = ["Zeeshan Ali Khan "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "D-Bus & GVariant encoding & decoding" readme = "README.md" keywords = [ "D-Bus", "DBus", "IPC", "GVariant", ] categories = [ "data-structures", "encoding", "parsing", ] license = "MIT" repository = "https://github.com/dbus2/zbus/" [package.metadata.docs.rs] all-features = true [lib] name = "zvariant" path = "src/lib.rs" bench = false [[bench]] name = "benchmarks" path = "benches/benchmarks.rs" harness = false [dependencies.arrayvec] version = "0.7.4" features = ["serde"] optional = true [dependencies.camino] version = "1.1.9" optional = true [dependencies.chrono] version = "0.4.38" features = ["serde"] optional = true default-features = false [dependencies.endi] version = "1.1.0" [dependencies.enumflags2] version = "0.7.9" features = ["serde"] optional = true [dependencies.heapless] version = "0.8.0" features = ["serde"] optional = true [dependencies.serde] version = "1.0.200" features = ["derive"] [dependencies.serde_bytes] version = "0.11.14" optional = true [dependencies.static_assertions] version = "1.1.0" [dependencies.time] version = "0.3.36" features = ["serde"] optional = true [dependencies.url] version = "2.5.0" features = ["serde"] optional = true [dependencies.uuid] version = "1.8.0" features = ["serde"] optional = true [dependencies.winnow] version = "0.6" [dependencies.zvariant_derive] version = "=5.2.0" [dependencies.zvariant_utils] version = "3.1.0" [dev-dependencies.chrono] version = "0.4.38" features = [ "serde", "alloc", ] default-features = false [dev-dependencies.criterion] version = "0.5.1" [dev-dependencies.rand] version = "0.8.5" [dev-dependencies.serde_json] version = "1.0.116" [dev-dependencies.serde_repr] version = "0.1.19" [features] camino = ["dep:camino"] default = [] gvariant = [ "zvariant_derive/gvariant", "zvariant_utils/gvariant", ] option-as-array = [] ostree-tests = ["gvariant"] [lints.rust.unexpected_cfgs] level = "warn" priority = 0 check-cfg = ["cfg(tokio_unstable)"] zvariant-5.2.0/Cargo.toml.orig000064400000000000000000000036111046102023000143560ustar 00000000000000[package] name = "zvariant" version = "5.2.0" authors = ["Zeeshan Ali Khan "] edition = "2021" rust-version = { workspace = true } description = "D-Bus & GVariant encoding & decoding" repository = "https://github.com/dbus2/zbus/" keywords = ["D-Bus", "DBus", "IPC", "GVariant"] license = "MIT" categories = ["data-structures", "encoding", "parsing"] readme = "README.md" [features] default = [] # FIXME: Also allow disabling D-Bus support gvariant = ["zvariant_derive/gvariant", "zvariant_utils/gvariant"] ostree-tests = ["gvariant"] # Enables ser/de of `Option` as an array of 0 or 1 elements. option-as-array = [] camino = ["dep:camino"] [dependencies] zvariant_derive = { version = "=5.2.0", path = "../zvariant_derive" } zvariant_utils = { version = "3.1.0", path = "../zvariant_utils" } endi = "1.1.0" serde = { version = "1.0.200", features = ["derive"] } static_assertions = "1.1.0" winnow = "0.6" # Optional dependencies arrayvec = { version = "0.7.4", features = ["serde"], optional = true } enumflags2 = { version = "0.7.9", features = ["serde"], optional = true } serde_bytes = { version = "0.11.14", optional = true } uuid = { version = "1.8.0", features = ["serde"], optional = true } url = { version = "2.5.0", features = ["serde"], optional = true } time = { version = "0.3.36", features = ["serde"], optional = true } chrono = { version = "0.4.38", features = [ "serde", ], default-features = false, optional = true } heapless = { version = "0.8.0", features = ["serde"], optional = true } camino = { version = "1.1.9", optional = true } [dev-dependencies] serde_json = "1.0.116" serde_repr = "0.1.19" rand = "0.8.5" criterion = "0.5.1" chrono = { version = "0.4.38", features = [ "serde", "alloc", ], default-features = false } [lib] bench = false [[bench]] name = "benchmarks" harness = false [package.metadata.docs.rs] all-features = true [lints] workspace = true zvariant-5.2.0/LICENSE000064400000000000000000000020701046102023000124720ustar 00000000000000Copyright (c) 2024 Zeeshan Ali Khan & zbus contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. zvariant-5.2.0/README.md000064400000000000000000000176221046102023000127550ustar 00000000000000# zvariant [![](https://docs.rs/zvariant/badge.svg)](https://docs.rs/zvariant/) [![](https://img.shields.io/crates/v/zvariant)](https://crates.io/crates/zvariant) This crate provides API for encoding/decoding of data to/from [D-Bus wire format][dwf]. This binary wire format is simple and very efficient and hence useful outside of D-Bus context as well. A modified form of this format, [GVariant] is very commonly used for efficient storage of arbitrary data and is also supported by this crate (if you enable `gvariant` cargo feature). Since version 2.0, the API is [serde]-based and hence you'll find it very intuitive if you're already familiar with serde. If you're not familiar with serde, you may want to first read its [tutorial] before learning further about this crate. **Status:** Stable. ## Example code Serialization and deserialization is achieved through the [toplevel functions]: ```rust use std::collections::HashMap; use zvariant::{serialized::Context, to_bytes, Type, LE}; use serde::{Deserialize, Serialize}; // All serialization and deserialization API, needs a context. let ctxt = Context::new_dbus(LE, 0); // You can also use the more efficient GVariant format: // let ctxt = Context::new_gvariant(LE, 0); // i16 let encoded = to_bytes(ctxt, &42i16).unwrap(); let decoded: i16 = encoded.deserialize().unwrap().0; assert_eq!(decoded, 42); // strings let encoded = to_bytes(ctxt, &"hello").unwrap(); let decoded: &str = encoded.deserialize().unwrap().0; assert_eq!(decoded, "hello"); // tuples let t = ("hello", 42i32, true); let encoded = to_bytes(ctxt, &t).unwrap(); let decoded: (&str, i32, bool) = encoded.deserialize().unwrap().0; assert_eq!(decoded, t); // Vec let v = vec!["hello", "world!"]; let encoded = to_bytes(ctxt, &v).unwrap(); let decoded: Vec<&str> = encoded.deserialize().unwrap().0; assert_eq!(decoded, v); // Dictionary let mut map: HashMap = HashMap::new(); map.insert(1, "123"); map.insert(2, "456"); let encoded = to_bytes(ctxt, &map).unwrap(); let decoded: HashMap = encoded.deserialize().unwrap().0; assert_eq!(decoded[&1], "123"); assert_eq!(decoded[&2], "456"); // derive macros to handle custom types. #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct Struct<'s> { field1: u16, field2: i64, field3: &'s str, } assert_eq!(Struct::SIGNATURE, "(qxs)"); let s = Struct { field1: 42, field2: i64::max_value(), field3: "hello", }; let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &s).unwrap(); let decoded: Struct = encoded.deserialize().unwrap().0; assert_eq!(decoded, s); // It can handle enums too, just that all variants must have the same number and types of fields. // Names of fields don't matter though. You can make use of `Value` or `OwnedValue` if you want to // encode different data in different fields. #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] enum Enum<'s> { Variant1 { field1: u16, field2: i64, field3: &'s str }, Variant2(u16, i64, &'s str), Variant3 { f1: u16, f2: i64, f3: &'s str }, } // Enum encoding uses a `u32` to denote the variant index. For unit-type enums that's all that's // needed so the signature is just `u` but complex enums are encoded as a structure whose first // field is the variant index and the second one is the field(s). assert_eq!(Enum::SIGNATURE, "(u(qxs))"); let e = Enum::Variant3 { f1: 42, f2: i64::max_value(), f3: "hello", }; let encoded = to_bytes(ctxt, &e).unwrap(); let decoded: Enum = encoded.deserialize().unwrap().0; assert_eq!(decoded, e); // Enum encoding can be adjusted by using the `serde_repr` crate // and by annotating the representation of the enum with `repr`. use serde_repr::{Serialize_repr, Deserialize_repr}; #[derive(Deserialize_repr, Serialize_repr, Type, PartialEq, Debug)] #[repr(u8)] enum UnitEnum { Variant1, Variant2, Variant3, } assert_eq!(UnitEnum::SIGNATURE, "y"); let encoded = to_bytes(ctxt, &UnitEnum::Variant2).unwrap(); let e: UnitEnum = encoded.deserialize().unwrap().0; assert_eq!(e, UnitEnum::Variant2); // Unit enums can also be (de)serialized as strings. #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] #[zvariant(signature = "s")] enum StrEnum { Variant1, Variant2, Variant3, } assert_eq!(StrEnum::SIGNATURE, "s"); ``` Apart from the obvious requirement of [`serialized::Context`] instance by the main serialization and deserialization API, the type being serialized or deserialized must also implement `Type` trait in addition to [`Serialize`] or [`Deserialize`], respectively. Please refer to [`Type` module documentation] for more details. Most of the [basic types] of D-Bus match 1-1 with all the primitive Rust types. The only two exceptions being, [`Signature`] and [`ObjectPath`], which are really just strings. These types are covered by the [`Basic`] trait. Similarly, most of the [container types] also map nicely to the usual Rust types and collections (as can be seen in the example code above). The only note worthy exception being ARRAY type. As arrays in Rust are fixed-sized, serde treats them as tuples and so does this crate. This means they are encoded as STRUCT type of D-Bus. If you need to serialize to, or deserialize from a D-Bus array, you'll need to use a [slice] (array can easily be converted to a slice), a [`Vec`] or an [`arrayvec::ArrayVec`]. D-Bus string types, including [`Signature`] and [`ObjectPath`], require one additional restriction that strings in Rust do not. They must not contain any interior null bytes (`'\0'`). Encoding/Decoding strings that contain this character will return an error. The generic D-Bus type, `VARIANT` is represented by `Value`, an enum that holds exactly one value of any of the other types. Please refer to [`Value` module documentation] for examples. ## no-std While `std` is currently a hard requirement, optional `no-std` support is planned in the future. On the other hand, `noalloc` support is not planned as it will be extremely difficult to accomplish. However, community contribution can change that. 😊 ## Optional features | Feature | Description | | --- | ----------- | | gvariant | Enable [GVariant] format support | | arrayvec | Implement `Type` for [`arrayvec::ArrayVec`] and [`arrayvec::ArrayString`] | | enumflags2 | Implement `Type` for [`enumflags2::BitFlags`]`` | | option-as-array | Enable `Option` (de)serialization using array encoding | `gvariant` features conflicts with `option-as-array` and hence should not be enabled together. [dwf]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling [GVariant]: https://developer.gnome.org/documentation/specifications/gvariant-specification-1.0.html [serde]: https://crates.io/crates/serde [tutorial]: https://serde.rs/ [toplevel functions]: https://docs.rs/zvariant/latest/zvariant/#functions [`serialized::Context`]: https://docs.rs/zvariant/latest/serialized/struct.Context.html [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html [`Type` module documentation]: https://docs.rs/zvariant/latest/zvariant/trait.Type.html [basic types]: https://dbus.freedesktop.org/doc/dbus-specification.html#basic-types [`Signature`]: https://docs.rs/zvariant/latest/zvariant/struct.Signature.html [`ObjectPath`]: https://docs.rs/zvariant/latest/zvariant/struct.ObjectPath.html [`Basic`]: https://docs.rs/zvariant/latest/zvariant/trait.Basic.html [container types]: https://dbus.freedesktop.org/doc/dbus-specification.html#container-types [slice]: https://doc.rust-lang.org/std/primitive.slice.html [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html [`arrayvec::ArrayVec`]: https://docs.rs/arrayvec/0.7.1/arrayvec/struct.ArrayVec.html [`arrayvec::ArrayString`]: https://docs.rs/arrayvec/0.7.1/arrayvec/struct.ArrayString.html [`enumflags2::Bitflags`]: https://docs.rs/enumflags2/latest/enumflags2/struct.BitFlags.html [`Value` module documentation]: https://docs.rs/zvariant/latest/zvariant/enum.Value.html zvariant-5.2.0/benches/benchmarks.rs000064400000000000000000000141731046102023000155660ustar 00000000000000use serde::{Deserialize, Serialize}; #[cfg(feature = "serde_bytes")] use serde_bytes::ByteBuf; use std::{collections::HashMap, vec}; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use zvariant::{serialized::Context, to_bytes, Type, Value, LE}; macro_rules! benchmark { ($c:ident, $data:ident, $data_type:ty, $func_prefix:literal) => { let ser_function_name = format!("{}_ser", $func_prefix); let de_function_name = format!("{}_de", $func_prefix); // Let's try with DBus format first let ctxt = Context::new_dbus(LE, 0); let mut group = $c.benchmark_group("dbus"); group.measurement_time(std::time::Duration::from_secs(30)); group.bench_function(&ser_function_name, |b| { b.iter(|| { let encoded = to_bytes(black_box(ctxt), black_box(&$data)).unwrap(); black_box(encoded); }) }); let encoded = to_bytes(ctxt, &$data).unwrap(); group.bench_function(&de_function_name, |b| { b.iter(|| { let (s, _): ($data_type, _) = encoded.deserialize().unwrap(); black_box(s); }) }); group.finish(); // Now GVariant. #[cfg(feature = "gvariant")] { let ctxt = Context::new_gvariant(LE, 0); let mut group = $c.benchmark_group("gvariant"); group.measurement_time(std::time::Duration::from_secs(30)); group.bench_function(&ser_function_name, |b| { b.iter(|| { let encoded = to_bytes(black_box(ctxt), black_box(&$data)).unwrap(); black_box(encoded); }) }); let encoded = to_bytes(ctxt, &$data).unwrap(); group.bench_function(&de_function_name, |b| { b.iter(|| { let (s, _): ($data_type, _) = encoded.deserialize().unwrap(); black_box(s); }) }); group.finish(); } }; } #[cfg(feature = "serde_bytes")] fn byte_array(c: &mut Criterion) { let ay = ByteBuf::from(vec![77u8; 100_000]); benchmark!(c, ay, ByteBuf, "byte_array"); } fn fixed_size_array(c: &mut Criterion) { let ay = vec![77u8; 100_000]; benchmark!(c, ay, Vec, "fixed_size_array"); } fn big_array(c: &mut Criterion) { let mut asv_dict = HashMap::new(); let mut ass_dict = HashMap::new(); let int_array = vec![0u64; 1024 * 10]; let mut strings = Vec::new(); let mut string_array: Vec<&str> = Vec::new(); for idx in 0..1024 * 10 { strings.push(format!( "{idx}{idx}{idx}{idx}{idx}{idx}{idx}{idx}{idx}{idx}{idx}{idx}" )); } for s in &strings { string_array.push(s.as_str()); ass_dict.insert(s.as_str(), s.as_str()); asv_dict.insert(s.as_str(), Value::from(s.as_str())); } let structure = BigArrayStruct { string1: "Testtest", int1: 0xFFFFFFFFFFFFFFFFu64, field: BigArrayField { string2: "TesttestTestest", int2: 0xFFFFFFFFFFFFFFFFu64, }, int_array, string_array, }; benchmark!(c, structure, BigArrayStruct<'_>, "big_array"); let data = BigArrayDictStruct { array_struct: structure.clone(), dict: ass_dict, }; benchmark!(c, data, BigArrayDictStruct<'_>, "big_array_and_ass_dict"); let data = BigArrayDictVariantStruct { array_struct: structure, dict: asv_dict, }; benchmark!( c, data, BigArrayDictVariantStruct<'_>, "big_array_and_asv_dict" ); } fn signature_parse(c: &mut Criterion) { #[derive(Type, PartialEq, Debug)] struct LongSignatureStruct { f1: BigArrayDictVariantStruct<'static>, f2: BigArrayDictVariantStruct<'static>, f3: BigArrayDictVariantStruct<'static>, f4: BigArrayDictVariantStruct<'static>, f5: BigArrayDictVariantStruct<'static>, f6: BigArrayDictVariantStruct<'static>, f7: BigArrayDictVariantStruct<'static>, f8: BigArrayDictVariantStruct<'static>, f9: BigArrayDictVariantStruct<'static>, f10: BigArrayDictVariantStruct<'static>, f11: BigArrayDictVariantStruct<'static>, f12: BigArrayDictVariantStruct<'static>, f13: BigArrayDictVariantStruct<'static>, f14: (u32, String, u64, i32), } let signature_str = LongSignatureStruct::SIGNATURE.to_string(); // Ensure we have the maximum signature length allowed by the spec. assert_eq!(signature_str.len(), 255); c.bench_function("signature_parse", |b| { b.iter(|| { zvariant::Signature::try_from(black_box(signature_str.as_str())).unwrap(); }) }); } fn object_path_parse(c: &mut Criterion) { const PATH: &str = "/a/very/very_very/veeeeeeeeeeeeeery/long/long_long/long/long/\ _/long_path/to_test_parsing_of/paths/you/see"; c.bench_function("object_path_parse", |b| { b.iter(|| { zvariant::ObjectPath::try_from(black_box(PATH)).unwrap(); }) }); } #[derive(Deserialize, Serialize, Type, PartialEq, Debug, Clone)] struct BigArrayField<'f> { int2: u64, string2: &'f str, } #[derive(Deserialize, Serialize, Type, PartialEq, Debug, Clone)] struct BigArrayStruct<'s> { string1: &'s str, int1: u64, field: BigArrayField<'s>, int_array: Vec, string_array: Vec<&'s str>, } #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct BigArrayDictStruct<'s> { #[serde(borrow)] array_struct: BigArrayStruct<'s>, dict: HashMap<&'s str, &'s str>, } #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct BigArrayDictVariantStruct<'s> { #[serde(borrow)] array_struct: BigArrayStruct<'s>, dict: HashMap<&'s str, Value<'s>>, } #[cfg(feature = "serde_bytes")] criterion_group!( benches, big_array, byte_array, fixed_size_array, signature_parse, object_path_parse ); #[cfg(not(feature = "serde_bytes"))] criterion_group!( benches, big_array, fixed_size_array, signature_parse, object_path_parse ); criterion_main!(benches); zvariant-5.2.0/src/array.rs000064400000000000000000000221751046102023000137500ustar 00000000000000#![allow(unknown_lints)] use serde::{ de::{DeserializeSeed, Deserializer, SeqAccess, Visitor}, ser::{Serialize, SerializeSeq, Serializer}, }; use static_assertions::assert_impl_all; use std::fmt::{Display, Write}; use crate::{ value::{value_display_fmt, SignatureSeed}, DynamicDeserialize, DynamicType, Error, Result, Signature, Type, Value, }; /// A helper type to wrap arrays in a [`Value`]. /// /// API is provided to convert from, and to a [`Vec`]. /// /// [`Value`]: enum.Value.html#variant.Array /// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html #[derive(Debug, Hash, PartialEq, PartialOrd, Eq, Ord)] pub struct Array<'a> { elements: Vec>, signature: Signature, } assert_impl_all!(Array<'_>: Send, Sync, Unpin); impl<'a> Array<'a> { /// Create a new empty `Array`, given the signature of the elements. pub fn new(element_signature: &Signature) -> Array<'a> { let signature = Signature::array(element_signature.clone()); Array { elements: vec![], signature, } } pub(crate) fn new_full_signature(signature: &Signature) -> Array<'a> { assert!(matches!(signature, Signature::Array(_))); Array { elements: vec![], signature: signature.clone(), } } /// Append `element`. /// /// # Errors /// /// if `element`'s signature doesn't match the element signature `self` was created for. pub fn append<'e: 'a>(&mut self, element: Value<'e>) -> Result<()> { match &self.signature { Signature::Array(child) if element.value_signature() != child.signature() => { return Err(Error::SignatureMismatch( element.value_signature().clone(), child.signature().clone().to_string(), )) } Signature::Array(_) => (), _ => unreachable!("Incorrect `Array` signature"), } self.elements.push(element); Ok(()) } /// Get all the elements. pub fn inner(&self) -> &[Value<'a>] { &self.elements } /// Get the value at the given index. pub fn get(&'a self, idx: usize) -> Result> where V: TryFrom<&'a Value<'a>>, >>::Error: Into, { self.elements .get(idx) .map(|v| v.downcast_ref::()) .transpose() .map_err(Into::into) } /// Get the number of elements. pub fn len(&self) -> usize { self.elements.len() } pub fn is_empty(&self) -> bool { self.elements.len() == 0 } /// The signature of the `Array`. pub fn signature(&self) -> &Signature { &self.signature } /// Get the signature of the elements in the `Array`. pub fn element_signature(&self) -> &Signature { match &self.signature { Signature::Array(child) => child.signature(), _ => unreachable!("Incorrect `Array` signature"), } } pub(crate) fn try_to_owned(&self) -> Result> { Ok(Array { elements: self .elements .iter() .map(|v| v.try_to_owned().map(Into::into)) .collect::>()?, signature: self.signature.clone(), }) } /// Tries to clone the `Array`. pub fn try_clone(&self) -> crate::Result { let elements = self .elements .iter() .map(|v| v.try_clone()) .collect::>>()?; Ok(Self { elements, signature: self.signature.clone(), }) } } impl Display for Array<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { array_display_fmt(self, f, true) } } pub(crate) fn array_display_fmt( array: &Array<'_>, f: &mut std::fmt::Formatter<'_>, type_annotate: bool, ) -> std::fmt::Result { // Print as string if it is a bytestring (i.e., first nul character is the last byte) if let [leading @ .., Value::U8(b'\0')] = array.as_ref() { if !leading.contains(&Value::U8(b'\0')) { let bytes = leading .iter() .map(|v| { v.downcast_ref::() .expect("item must have a signature of a byte") }) .collect::>(); let string = String::from_utf8_lossy(&bytes); write!(f, "b{:?}", string.as_ref())?; return Ok(()); } } if array.is_empty() { if type_annotate { write!(f, "@{} ", array.signature())?; } f.write_str("[]")?; } else { f.write_char('[')?; // Annotate only the first item as the rest will be of the same type. let mut type_annotate = type_annotate; for (i, item) in array.iter().enumerate() { value_display_fmt(item, f, type_annotate)?; type_annotate = false; if i + 1 < array.len() { f.write_str(", ")?; } } f.write_char(']')?; } Ok(()) } /// Use this to deserialize an [Array]. pub struct ArraySeed { signature: Signature, phantom: std::marker::PhantomData<()>, } impl ArraySeed { fn new(signature: &Signature) -> ArraySeed { ArraySeed { signature: signature.clone(), phantom: std::marker::PhantomData, } } } assert_impl_all!(ArraySeed: Unpin); impl DynamicType for Array<'_> { fn signature(&self) -> Signature { self.signature.clone() } } impl DynamicType for ArraySeed { fn signature(&self) -> Signature { self.signature.clone() } } impl<'a> DynamicDeserialize<'a> for Array<'a> { type Deserializer = ArraySeed; fn deserializer_for_signature(signature: &Signature) -> zvariant::Result { if !matches!(signature, Signature::Array(_)) { return Err(zvariant::Error::SignatureMismatch( signature.clone(), "an array signature".to_owned(), )); }; Ok(ArraySeed::new(signature)) } } impl<'a> std::ops::Deref for Array<'a> { type Target = [Value<'a>]; fn deref(&self) -> &Self::Target { self.inner() } } impl<'a, T> From> for Array<'a> where T: Type + Into>, { fn from(values: Vec) -> Self { let element_signature = T::SIGNATURE.clone(); let elements = values.into_iter().map(Value::new).collect(); let signature = Signature::array(element_signature); Self { elements, signature, } } } impl<'a, T> From<&[T]> for Array<'a> where T: Type + Into> + Clone, { fn from(values: &[T]) -> Self { let element_signature = T::SIGNATURE.clone(); let elements = values .iter() .map(|value| Value::new(value.clone())) .collect(); let signature = Signature::array(element_signature); Self { elements, signature, } } } impl<'a, T> From<&Vec> for Array<'a> where T: Type + Into> + Clone, { fn from(values: &Vec) -> Self { Self::from(&values[..]) } } impl<'a, T> TryFrom> for Vec where T: TryFrom>, T::Error: Into, { type Error = Error; fn try_from(v: Array<'a>) -> core::result::Result { // there is no try_map yet.. let mut res = vec![]; for e in v.elements.into_iter() { let value = if let Value::Value(v) = e { T::try_from(*v) } else { T::try_from(e) } .map_err(Into::into)?; res.push(value); } Ok(res) } } // TODO: this could be useful // impl<'a, 'b, T> TryFrom<&'a Array<'b>> for Vec impl Serialize for Array<'_> { fn serialize(&self, serializer: S) -> core::result::Result where S: Serializer, { let mut seq = serializer.serialize_seq(Some(self.elements.len()))?; for element in &self.elements { element.serialize_value_as_seq_element(&mut seq)?; } seq.end() } } impl<'de> DeserializeSeed<'de> for ArraySeed { type Value = Array<'de>; fn deserialize(self, deserializer: D) -> std::result::Result where D: Deserializer<'de>, { deserializer.deserialize_seq(ArrayVisitor { signature: self.signature, }) } } #[derive(Debug, Clone, PartialEq, Eq)] struct ArrayVisitor { signature: Signature, } impl<'de> Visitor<'de> for ArrayVisitor { type Value = Array<'de>; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("an Array value") } fn visit_seq(self, visitor: V) -> std::result::Result, V::Error> where V: SeqAccess<'de>, { SignatureSeed { signature: &self.signature, } .visit_array(visitor) } } zvariant-5.2.0/src/basic.rs000064400000000000000000000121241046102023000137040ustar 00000000000000use crate::{serialized::Format, Signature, Type}; /// Trait for basic types. /// /// All basic types are also [`Type`] implementers. /// /// [`Type`]: trait.Type.html /// [`Value`]: enum.Value.html pub trait Basic: Type { /// The type signature, as a character. const SIGNATURE_CHAR: char; /// The type signature, as a string. const SIGNATURE_STR: &'static str; /// The required padding alignment for the given format. /// /// The default implementation covers all possible cases so you should never need to override /// it. fn alignment(format: Format) -> usize { Self::SIGNATURE.alignment(format) } } impl Basic for &B where B: Basic, { const SIGNATURE_CHAR: char = B::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = B::SIGNATURE_STR; } macro_rules! impl_type { ($for:ty) => { impl Type for $for { const SIGNATURE: &'static Signature = { match Self::SIGNATURE_CHAR { 'y' => &Signature::U8, 'b' => &Signature::Bool, 'n' => &Signature::I16, 'q' => &Signature::U16, 'i' => &Signature::I32, 'u' => &Signature::U32, 'x' => &Signature::I64, 't' => &Signature::U64, 'd' => &Signature::F64, 's' => &Signature::Str, 'g' => &Signature::Signature, 'o' => &Signature::ObjectPath, 'v' => &Signature::Variant, #[cfg(unix)] 'h' => &Signature::Fd, _ => unreachable!(), } }; } }; } impl Basic for u8 { const SIGNATURE_CHAR: char = 'y'; const SIGNATURE_STR: &'static str = "y"; } impl_type!(u8); impl Basic for std::num::NonZeroU8 { const SIGNATURE_CHAR: char = u8::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = u8::SIGNATURE_STR; } impl_type!(std::num::NonZeroU8); // No i8 type in D-Bus/GVariant, let's pretend it's i16 impl Basic for i8 { const SIGNATURE_CHAR: char = i16::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = i16::SIGNATURE_STR; } impl_type!(i8); impl Basic for std::num::NonZeroI8 { const SIGNATURE_CHAR: char = i8::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = i8::SIGNATURE_STR; } impl_type!(std::num::NonZeroI8); impl Basic for bool { const SIGNATURE_CHAR: char = 'b'; const SIGNATURE_STR: &'static str = "b"; } impl_type!(bool); impl Basic for i16 { const SIGNATURE_CHAR: char = 'n'; const SIGNATURE_STR: &'static str = "n"; } impl_type!(i16); impl Basic for std::num::NonZeroI16 { const SIGNATURE_CHAR: char = i16::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = i16::SIGNATURE_STR; } impl_type!(std::num::NonZeroI16); impl Basic for u16 { const SIGNATURE_CHAR: char = 'q'; const SIGNATURE_STR: &'static str = "q"; } impl_type!(u16); impl Basic for std::num::NonZeroU16 { const SIGNATURE_CHAR: char = u16::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = u16::SIGNATURE_STR; } impl_type!(std::num::NonZeroU16); impl Basic for i32 { const SIGNATURE_CHAR: char = 'i'; const SIGNATURE_STR: &'static str = "i"; } impl_type!(i32); impl Basic for std::num::NonZeroI32 { const SIGNATURE_CHAR: char = i32::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = i32::SIGNATURE_STR; } impl_type!(std::num::NonZeroI32); impl Basic for u32 { const SIGNATURE_CHAR: char = 'u'; const SIGNATURE_STR: &'static str = "u"; } impl_type!(u32); impl Basic for std::num::NonZeroU32 { const SIGNATURE_CHAR: char = u32::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = u32::SIGNATURE_STR; } impl_type!(std::num::NonZeroU32); impl Basic for i64 { const SIGNATURE_CHAR: char = 'x'; const SIGNATURE_STR: &'static str = "x"; } impl_type!(i64); impl Basic for std::num::NonZeroI64 { const SIGNATURE_CHAR: char = i64::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = i64::SIGNATURE_STR; } impl_type!(std::num::NonZeroI64); impl Basic for u64 { const SIGNATURE_CHAR: char = 't'; const SIGNATURE_STR: &'static str = "t"; } impl_type!(u64); impl Basic for std::num::NonZeroU64 { const SIGNATURE_CHAR: char = u64::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = u64::SIGNATURE_STR; } impl_type!(std::num::NonZeroU64); // No f32 type in D-Bus/GVariant, let's pretend it's f64 impl Basic for f32 { const SIGNATURE_CHAR: char = f64::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = f64::SIGNATURE_STR; } impl_type!(f32); impl Basic for f64 { const SIGNATURE_CHAR: char = 'd'; const SIGNATURE_STR: &'static str = "d"; } impl_type!(f64); impl Basic for str { const SIGNATURE_CHAR: char = 's'; const SIGNATURE_STR: &'static str = "s"; } impl_type!(str); impl Basic for String { const SIGNATURE_CHAR: char = 's'; const SIGNATURE_STR: &'static str = "s"; } impl_type!(String); impl Basic for char { const SIGNATURE_CHAR: char = <&str>::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = <&str>::SIGNATURE_STR; } impl_type!(char); zvariant-5.2.0/src/container_depths.rs000064400000000000000000000043161046102023000161600ustar 00000000000000use crate::{Error, MaxDepthExceeded, Result}; // We take the limits from the D-Bus specification for gvariant as well. // // The GVariant specification removed all the limits, from the D-Bus specification but that turned // out to be a [mistake]. Although glib went for a higher limit (128) but we'll stick to the D-Bus // limits and expand if/when needed. // // [mistake]: https://gitlab.gnome.org/GNOME/glib/-/commit/7c4e6e9fbe473de0401c778c6b0c4aad27d5145a const MAX_STRUCT_DEPTH: u8 = 32; const MAX_ARRAY_DEPTH: u8 = 32; const MAX_TOTAL_DEPTH: u8 = 64; // Represents the current depth of all container being (de)serialized. #[derive(Debug, Default, Clone, Copy)] pub(crate) struct ContainerDepths { structure: u8, array: u8, variant: u8, #[cfg(feature = "gvariant")] maybe: u8, } impl ContainerDepths { pub fn inc_structure(mut self) -> Result { self.structure += 1; self.check() } pub fn dec_structure(mut self) -> Self { self.structure -= 1; self } pub fn inc_array(mut self) -> Result { self.array += 1; self.check() } pub fn dec_array(mut self) -> Self { self.array -= 1; self } pub fn inc_variant(mut self) -> Result { self.variant += 1; self.check() } #[cfg(feature = "gvariant")] pub fn inc_maybe(mut self) -> Result { self.maybe += 1; self.check() } #[cfg(feature = "gvariant")] pub fn dec_maybe(mut self) -> Self { self.maybe -= 1; self } fn check(self) -> Result { if self.structure > MAX_STRUCT_DEPTH { return Err(Error::MaxDepthExceeded(MaxDepthExceeded::Structure)); } if self.array > MAX_ARRAY_DEPTH { return Err(Error::MaxDepthExceeded(MaxDepthExceeded::Array)); } #[cfg(not(feature = "gvariant"))] let total = self.structure + self.array + self.variant; #[cfg(feature = "gvariant")] let total = self.structure + self.array + self.variant + self.maybe; if total > MAX_TOTAL_DEPTH { return Err(Error::MaxDepthExceeded(MaxDepthExceeded::Container)); } Ok(self) } } zvariant-5.2.0/src/dbus/de.rs000064400000000000000000000532541046102023000141610ustar 00000000000000use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Visitor}; use std::{marker::PhantomData, str}; #[cfg(unix)] use std::os::fd::AsFd; use crate::{ de::{DeserializerCommon, ValueParseStage}, serialized::{Context, Format}, utils::*, Basic, Error, ObjectPath, Result, Signature, }; /// Our D-Bus deserialization implementation. #[derive(Debug)] pub(crate) struct Deserializer<'de, 'sig, 'f, F>(pub(crate) DeserializerCommon<'de, 'sig, 'f, F>); #[allow(clippy::needless_lifetimes)] impl<'de, 'sig, 'f, F> Deserializer<'de, 'sig, 'f, F> { /// Create a Deserializer struct instance. /// /// On Windows, there is no `fds` argument. pub fn new<'r: 'de>( bytes: &'r [u8], #[cfg(unix)] fds: Option<&'f [F]>, signature: &'sig Signature, ctxt: Context, ) -> Result { assert_eq!(ctxt.format(), Format::DBus); Ok(Self(DeserializerCommon { ctxt, signature, bytes, #[cfg(unix)] fds, #[cfg(not(unix))] fds: PhantomData, pos: 0, container_depths: Default::default(), })) } } macro_rules! deserialize_basic { ($method:ident $read_method:ident $visitor_method:ident($type:ty)) => { fn $method(self, visitor: V) -> Result where V: Visitor<'de>, { let v = self .0 .ctxt .endian() .$read_method(self.0.next_const_size_slice::<$type>()?); visitor.$visitor_method(v) } }; } macro_rules! deserialize_as { ($method:ident => $as:ident) => { deserialize_as!($method() => $as()); }; ($method:ident($($in_arg:ident: $type:ty),*) => $as:ident($($as_arg:expr),*)) => { #[inline] fn $method(self, $($in_arg: $type,)* visitor: V) -> Result where V: Visitor<'de>, { self.$as($($as_arg,)* visitor) } } } impl<'de, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> de::Deserializer<'de> for &mut Deserializer<'de, '_, '_, F> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { crate::de::deserialize_any::(self, self.0.signature, visitor) } fn deserialize_bool(self, visitor: V) -> Result where V: Visitor<'de>, { let v = self .0 .ctxt .endian() .read_u32(self.0.next_const_size_slice::()?); let b = match v { 1 => true, 0 => false, // As per D-Bus spec, only 0 and 1 values are allowed _ => { return Err(de::Error::invalid_value( de::Unexpected::Unsigned(v as u64), &"0 or 1", )) } }; visitor.visit_bool(b) } fn deserialize_i8(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_i16(visitor) } deserialize_basic!(deserialize_i16 read_i16 visit_i16(i16)); deserialize_basic!(deserialize_i64 read_i64 visit_i64(i64)); deserialize_basic!(deserialize_u16 read_u16 visit_u16(u16)); deserialize_basic!(deserialize_u32 read_u32 visit_u32(u32)); deserialize_basic!(deserialize_u64 read_u64 visit_u64(u64)); deserialize_basic!(deserialize_f64 read_f64 visit_f64(f64)); fn deserialize_byte_buf(self, visitor: V) -> Result where V: Visitor<'de>, { let bytes = deserialize_ay(self)?; visitor.visit_byte_buf(bytes.into()) } fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de>, { let bytes = deserialize_ay(self)?; visitor.visit_borrowed_bytes(bytes) } deserialize_as!(deserialize_char => deserialize_str); deserialize_as!(deserialize_string => deserialize_str); deserialize_as!(deserialize_tuple(_l: usize) => deserialize_struct("", &[])); deserialize_as!(deserialize_tuple_struct(n: &'static str, _l: usize) => deserialize_struct(n, &[])); deserialize_as!(deserialize_struct(_n: &'static str, _f: &'static [&'static str]) => deserialize_seq()); deserialize_as!(deserialize_map => deserialize_seq); deserialize_as!(deserialize_ignored_any => deserialize_any); fn deserialize_i32(self, visitor: V) -> Result where V: Visitor<'de>, { let v = match &self.0.signature { #[cfg(unix)] Signature::Fd => { let alignment = u32::alignment(Format::DBus); self.0.parse_padding(alignment)?; let idx = self.0.ctxt.endian().read_u32(self.0.next_slice(alignment)?); self.0.get_fd(idx)? } _ => self .0 .ctxt .endian() .read_i32(self.0.next_const_size_slice::()?), }; visitor.visit_i32(v) } fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, { // Endianness is irrelevant for single bytes. visitor.visit_u8(self.0.next_const_size_slice::().map(|bytes| bytes[0])?) } fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, { let v = self .0 .ctxt .endian() .read_f64(self.0.next_const_size_slice::()?); if v.is_finite() && v > (f32::MAX as f64) { return Err(de::Error::invalid_value( de::Unexpected::Float(v), &"Too large for f32", )); } visitor.visit_f32(v as f32) } fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de>, { let len = match self.0.signature { Signature::Signature | Signature::Variant => { let len_slice = self.0.next_slice(1)?; len_slice[0] as usize } Signature::Str | Signature::ObjectPath => { let alignment = u32::alignment(Format::DBus); self.0.parse_padding(alignment)?; let len_slice = self.0.next_slice(alignment)?; self.0.ctxt.endian().read_u32(len_slice) as usize } _ => { let expected = format!( "`{}`, `{}`, `{}` or `{}`", <&str>::SIGNATURE_STR, Signature::SIGNATURE_STR, ObjectPath::SIGNATURE_STR, VARIANT_SIGNATURE_CHAR, ); return Err(Error::SignatureMismatch(self.0.signature.clone(), expected)); } }; let slice = self.0.next_slice(len)?; if slice.contains(&0) { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char('\0'), &"D-Bus string type must not contain interior null bytes", )); } self.0.pos += 1; // skip trailing null byte let s = str::from_utf8(slice).map_err(Error::Utf8)?; visitor.visit_borrowed_str(s) } fn deserialize_option(self, #[allow(unused)] visitor: V) -> Result where V: Visitor<'de>, { #[cfg(feature = "option-as-array")] { // This takes care of parsing all the padding and getting the byte length. let ad = ArrayDeserializer::new(self)?; let len = ad.len; let array_signature = ad.array_signature; let v = if len == 0 { visitor.visit_none() } else { visitor.visit_some(&mut *self) }; self.0.container_depths = self.0.container_depths.dec_array(); self.0.signature = array_signature; v } #[cfg(not(feature = "option-as-array"))] Err(de::Error::custom( "Can only decode Option from D-Bus format if `option-as-array` feature is enabled", )) } fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de>, { visitor.visit_unit() } fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { visitor.visit_unit() } fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { visitor.visit_newtype_struct(self) } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de>, { let alignment = self.0.signature.alignment(Format::DBus); self.0.parse_padding(alignment)?; match self.0.signature { Signature::Variant => { let value_de = ValueDeserializer::new(self); visitor.visit_seq(value_de) } Signature::Array(_) => { let array_de = ArrayDeserializer::new(self)?; visitor.visit_seq(ArraySeqDeserializer(array_de)) } Signature::Dict { .. } => visitor.visit_map(ArrayMapDeserializer::new(self)?), Signature::Structure(_) => visitor.visit_seq(StructureDeserializer::new(self)?), Signature::U8 => { // Empty struct: encoded as a `0u8`. let _: u8 = serde::Deserialize::deserialize(&mut *self)?; visitor.visit_seq(StructureDeserializer { de: self, field_idx: 0, num_fields: 0, }) } _ => Err(Error::SignatureMismatch( self.0.signature.clone(), "a variant, array, dict, structure or u8".to_string(), )), } } fn deserialize_enum( self, name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { let alignment = self.0.signature.alignment(self.0.ctxt.format()); self.0.parse_padding(alignment)?; visitor.visit_enum(crate::de::Enum { de: self, name, _phantom: PhantomData, }) } fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de>, { match self.0.signature { Signature::Str => self.deserialize_str(visitor), Signature::U32 => self.deserialize_u32(visitor), Signature::Structure(fields) => { let mut fields = fields.iter(); let index_signature = fields.next().ok_or_else(|| { Error::SignatureMismatch( self.0.signature.clone(), "a structure with 2 fields and u32 as its first field".to_string(), ) })?; self.0.signature = index_signature; let v = self.deserialize_u32(visitor); self.0.signature = fields.next().ok_or_else(|| { Error::SignatureMismatch( self.0.signature.clone(), "a structure with 2 fields and u32 as its first field".to_string(), ) })?; v } _ => Err(Error::SignatureMismatch( self.0.signature.clone(), "a string, object path or signature".to_string(), )), } } fn is_human_readable(&self) -> bool { false } } struct ArrayDeserializer<'d, 'de, 'sig, 'f, F> { de: &'d mut Deserializer<'de, 'sig, 'f, F>, len: usize, start: usize, // alignment of element element_alignment: usize, array_signature: &'sig Signature, } impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> ArrayDeserializer<'d, 'de, 'sig, 'f, F> { fn new(de: &'d mut Deserializer<'de, 'sig, 'f, F>) -> Result { de.0.parse_padding(ARRAY_ALIGNMENT_DBUS)?; de.0.container_depths = de.0.container_depths.inc_array()?; let len = de.0.ctxt.endian().read_u32(de.0.next_slice(4)?) as usize; // D-Bus expects us to add padding for the first element even when there is no first // element (i-e empty array) so we parse padding already. let (element_alignment, child_signature) = match de.0.signature { Signature::Array(child) => (child.alignment(de.0.ctxt.format()), child.signature()), Signature::Dict { key, .. } => (DICT_ENTRY_ALIGNMENT_DBUS, key.signature()), _ => { return Err(Error::SignatureMismatch( de.0.signature.clone(), "an array or dict".to_string(), )); } }; de.0.parse_padding(element_alignment)?; // In case of an array, we'll only be serializing the array's child elements from now on and // in case of a dict, we'll swap key and value signatures during serlization of each entry, // so let's assume the element signature for array and key signature for dict, from now on. // We restore the original signature at the end of deserialization. let array_signature = de.0.signature; de.0.signature = child_signature; let start = de.0.pos; Ok(Self { de, len, start, element_alignment, array_signature, }) } fn next(&mut self, seed: T) -> Result where T: DeserializeSeed<'de>, { let v = seed.deserialize(&mut *self.de); if self.de.0.pos > self.start + self.len { return Err(serde::de::Error::invalid_length( self.len, &format!(">= {}", self.de.0.pos - self.start).as_str(), )); } v } fn next_element(&mut self, seed: T) -> Result> where T: DeserializeSeed<'de>, { if self.done() { self.end(); return Ok(None); } // Redundant for normal arrays but dict requires each entry to be padded by 8 bytes. self.de.0.parse_padding(self.element_alignment)?; self.next(seed).map(Some) } fn done(&self) -> bool { self.de.0.pos == self.start + self.len } fn end(&mut self) { self.de.0.container_depths = self.de.0.container_depths.dec_array(); self.de.0.signature = self.array_signature; } } fn deserialize_ay<'de, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F>( de: &mut Deserializer<'de, '_, '_, F>, ) -> Result<&'de [u8]> { if !matches!(de.0.signature, Signature::Array(child) if child.signature() == &Signature::U8) { return Err(de::Error::invalid_type(de::Unexpected::Seq, &"ay")); } let mut ad = ArrayDeserializer::new(de)?; let len = ad.len; ad.end(); de.0.next_slice(len) } struct ArraySeqDeserializer<'d, 'de, 'sig, 'f, F>(ArrayDeserializer<'d, 'de, 'sig, 'f, F>); impl<'de, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de> for ArraySeqDeserializer<'_, 'de, '_, '_, F> { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> where T: DeserializeSeed<'de>, { self.0.next_element(seed) } } struct ArrayMapDeserializer<'d, 'de, 'sig, 'f, F> { ad: ArrayDeserializer<'d, 'de, 'sig, 'f, F>, key_signature: &'sig Signature, value_signature: &'sig Signature, } impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> ArrayMapDeserializer<'d, 'de, 'sig, 'f, F> { fn new(de: &'d mut Deserializer<'de, 'sig, 'f, F>) -> Result { let (key_signature, value_signature) = match de.0.signature { Signature::Dict { key, value } => (key.signature(), value.signature()), _ => { return Err(Error::SignatureMismatch( de.0.signature.clone(), "a dict".to_string(), )); } }; let ad = ArrayDeserializer::new(de)?; Ok(Self { ad, key_signature, value_signature, }) } } impl<'de, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> MapAccess<'de> for ArrayMapDeserializer<'_, 'de, '_, '_, F> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: DeserializeSeed<'de>, { self.ad.next_element(seed) } fn next_value_seed(&mut self, seed: V) -> Result where V: DeserializeSeed<'de>, { self.ad.de.0.signature = self.value_signature; let v = self.ad.next(seed); self.ad.de.0.signature = self.key_signature; v } } #[derive(Debug)] struct StructureDeserializer<'d, 'de, 'sig, 'f, F> { de: &'d mut Deserializer<'de, 'sig, 'f, F>, /// Index of the next field to serialize. field_idx: usize, /// The number of fields in the structure. num_fields: usize, } impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> StructureDeserializer<'d, 'de, 'sig, 'f, F> { fn new(de: &'d mut Deserializer<'de, 'sig, 'f, F>) -> Result { let num_fields = match de.0.signature { Signature::Structure(fields) => fields.iter().count(), _ => unreachable!("Incorrect signature for struct"), }; de.0.parse_padding(STRUCT_ALIGNMENT_DBUS)?; de.0.container_depths = de.0.container_depths.inc_structure()?; Ok(Self { de, field_idx: 0, num_fields, }) } } impl<'de, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de> for StructureDeserializer<'_, 'de, '_, '_, F> { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> where T: DeserializeSeed<'de>, { if self.field_idx == self.num_fields { return Ok(None); } let signature = self.de.0.signature; let field_signature = match signature { Signature::Structure(fields) => { let signature = fields.iter().nth(self.field_idx).ok_or_else(|| { Error::SignatureMismatch(signature.clone(), "a struct".to_string()) })?; self.field_idx += 1; signature } _ => unreachable!("Incorrect signature for struct"), }; let mut de = Deserializer::(DeserializerCommon { ctxt: self.de.0.ctxt, signature: field_signature, fds: self.de.0.fds, bytes: self.de.0.bytes, pos: self.de.0.pos, container_depths: self.de.0.container_depths, }); let v = seed.deserialize(&mut de)?; self.de.0.pos = de.0.pos; if self.field_idx == self.num_fields { // All fields have been deserialized. self.de.0.container_depths = self.de.0.container_depths.dec_structure(); } Ok(Some(v)) } } #[derive(Debug)] struct ValueDeserializer<'d, 'de, 'sig, 'f, F> { de: &'d mut Deserializer<'de, 'sig, 'f, F>, stage: ValueParseStage, sig_start: usize, } impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> ValueDeserializer<'d, 'de, 'sig, 'f, F> { fn new(de: &'d mut Deserializer<'de, 'sig, 'f, F>) -> Self { let sig_start = de.0.pos; ValueDeserializer:: { de, stage: ValueParseStage::Signature, sig_start, } } } impl<'de, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de> for ValueDeserializer<'_, 'de, '_, '_, F> { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> where T: DeserializeSeed<'de>, { match self.stage { ValueParseStage::Signature => { self.stage = ValueParseStage::Value; seed.deserialize(&mut *self.de).map(Some) } ValueParseStage::Value => { self.stage = ValueParseStage::Done; let sig_len = self.de.0.bytes[self.sig_start] as usize; // skip length byte let sig_start = self.sig_start + 1; let sig_end = sig_start + sig_len; // Skip trailing nul byte let value_start = sig_end + 1; let slice = subslice(self.de.0.bytes, sig_start..sig_end)?; let signature = Signature::from_bytes(slice)?; let ctxt = Context::new( Format::DBus, self.de.0.ctxt.endian(), self.de.0.ctxt.position() + value_start, ); let mut de = Deserializer::(DeserializerCommon { ctxt, signature: &signature, bytes: subslice(self.de.0.bytes, value_start..)?, fds: self.de.0.fds, pos: 0, container_depths: self.de.0.container_depths.inc_variant()?, }); let v = seed.deserialize(&mut de).map(Some); self.de.0.pos += de.0.pos; v } ValueParseStage::Done => Ok(None), } } } impl<'de, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> EnumAccess<'de> for crate::de::Enum<&mut Deserializer<'de, '_, '_, F>, F> { type Error = Error; type Variant = Self; fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> where V: DeserializeSeed<'de>, { seed.deserialize(&mut *self.de).map(|v| (v, self)) } } zvariant-5.2.0/src/dbus/mod.rs000064400000000000000000000000671046102023000143420ustar 00000000000000mod de; pub(crate) use de::*; mod ser; pub use ser::*; zvariant-5.2.0/src/dbus/ser.rs000064400000000000000000000523061046102023000143570ustar 00000000000000use serde::{ ser::{self, SerializeSeq, SerializeTuple}, Serialize, }; use std::{ io::{Seek, Write}, str::{self, FromStr}, }; use crate::{ container_depths::ContainerDepths, serialized::{Context, Format}, utils::*, Basic, Error, ObjectPath, Result, Signature, WriteBytes, }; /// Our D-Bus serialization implementation. pub(crate) struct Serializer<'ser, W>(pub(crate) crate::SerializerCommon<'ser, W>); impl<'ser, W> Serializer<'ser, W> where W: Write + Seek, { /// Create a D-Bus Serializer struct instance. /// /// On Windows, there is no `fds` argument. pub fn new<'w: 'ser, 'f: 'ser>( signature: &'ser Signature, writer: &'w mut W, #[cfg(unix)] fds: &'f mut crate::ser::FdList, ctxt: Context, ) -> Result { assert_eq!(ctxt.format(), Format::DBus); Ok(Self(crate::SerializerCommon { ctxt, signature, writer, #[cfg(unix)] fds, bytes_written: 0, value_sign: None, container_depths: Default::default(), })) } } macro_rules! serialize_basic { ($method:ident($type:ty) $write_method:ident) => { serialize_basic!($method($type) $write_method($type)); }; ($method:ident($type:ty) $write_method:ident($as:ty)) => { fn $method(self, v: $type) -> Result<()> { self.0.prep_serialize_basic::<$type>()?; self.0.$write_method(self.0.ctxt.endian(), v as $as).map_err(|e| Error::InputOutput(e.into())) } }; } impl<'ser, 'b, W> ser::Serializer for &'b mut Serializer<'ser, W> where W: Write + Seek, { type Ok = (); type Error = Error; type SerializeSeq = SeqSerializer<'ser, 'b, W>; type SerializeTuple = StructSeqSerializer<'ser, 'b, W>; type SerializeTupleStruct = StructSeqSerializer<'ser, 'b, W>; type SerializeTupleVariant = StructSeqSerializer<'ser, 'b, W>; type SerializeMap = MapSerializer<'ser, 'b, W>; type SerializeStruct = StructSeqSerializer<'ser, 'b, W>; type SerializeStructVariant = StructSeqSerializer<'ser, 'b, W>; serialize_basic!(serialize_bool(bool) write_u32(u32)); // No i8 type in D-Bus/GVariant, let's pretend it's i16 serialize_basic!(serialize_i8(i8) write_i16(i16)); serialize_basic!(serialize_i16(i16) write_i16); serialize_basic!(serialize_i64(i64) write_i64); fn serialize_i32(self, v: i32) -> Result<()> { match &self.0.signature { #[cfg(unix)] Signature::Fd => { self.0.add_padding(u32::alignment(Format::DBus))?; let idx = self.0.add_fd(v)?; self.0 .write_u32(self.0.ctxt.endian(), idx) .map_err(|e| Error::InputOutput(e.into())) } _ => { self.0.prep_serialize_basic::()?; self.0 .write_i32(self.0.ctxt.endian(), v) .map_err(|e| Error::InputOutput(e.into())) } } } fn serialize_u8(self, v: u8) -> Result<()> { self.0.prep_serialize_basic::()?; // Endianness is irrelevant for single bytes. self.0 .write_u8(self.0.ctxt.endian(), v) .map_err(|e| Error::InputOutput(e.into())) } serialize_basic!(serialize_u16(u16) write_u16); serialize_basic!(serialize_u32(u32) write_u32); serialize_basic!(serialize_u64(u64) write_u64); // No f32 type in D-Bus/GVariant, let's pretend it's f64 serialize_basic!(serialize_f32(f32) write_f64(f64)); serialize_basic!(serialize_f64(f64) write_f64); fn serialize_char(self, v: char) -> Result<()> { // No char type in D-Bus, let's pretend it's a string self.serialize_str(&v.to_string()) } fn serialize_str(self, v: &str) -> Result<()> { self.0 .add_padding(self.0.signature.alignment(Format::DBus))?; let signature = self.0.signature; if matches!(signature, Signature::Variant) { self.0.value_sign = Some(Signature::from_str(v)?); } match signature { Signature::ObjectPath | Signature::Str => { self.0 .write_u32(self.0.ctxt.endian(), usize_to_u32(v.len())) .map_err(|e| Error::InputOutput(e.into()))?; } Signature::Signature | Signature::Variant => { self.0 .write_u8(self.0.ctxt.endian(), usize_to_u8(v.len())) .map_err(|e| Error::InputOutput(e.into()))?; } _ => { let expected = format!( "`{}`, `{}`, `{}` or `{}`", <&str>::SIGNATURE_STR, Signature::SIGNATURE_STR, ObjectPath::SIGNATURE_STR, VARIANT_SIGNATURE_CHAR, ); return Err(Error::SignatureMismatch(signature.clone(), expected)); } } self.0 .write_all(v.as_bytes()) .map_err(|e| Error::InputOutput(e.into()))?; self.0 .write_all(&b"\0"[..]) .map_err(|e| Error::InputOutput(e.into()))?; Ok(()) } fn serialize_bytes(self, v: &[u8]) -> Result<()> { self.0.add_padding(ARRAY_ALIGNMENT_DBUS)?; self.0 .write_u32(self.0.ctxt.endian(), v.len() as u32) .map_err(|e| Error::InputOutput(e.into()))?; self.0 .write(v) .map(|_| ()) .map_err(|e| Error::InputOutput(e.into())) } fn serialize_none(self) -> Result<()> { #[cfg(feature = "option-as-array")] { let seq = self.serialize_seq(Some(0))?; seq.end() } #[cfg(not(feature = "option-as-array"))] unreachable!( "Can only encode Option in D-Bus format if `option-as-array` feature is enabled", ); } fn serialize_some(self, #[allow(unused)] value: &T) -> Result<()> where T: ?Sized + Serialize, { #[cfg(feature = "option-as-array")] { let mut seq = self.serialize_seq(Some(1))?; seq.serialize_element(value)?; seq.end() } #[cfg(not(feature = "option-as-array"))] unreachable!( "Can only encode Option in D-Bus format if `option-as-array` feature is enabled", ); } fn serialize_unit(self) -> Result<()> { Ok(()) } fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { self.serialize_unit() } fn serialize_unit_variant( self, _name: &'static str, variant_index: u32, variant: &'static str, ) -> Result<()> { if matches!(self.0.signature, Signature::Str) { variant.serialize(self) } else { variant_index.serialize(self) } } fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> where T: ?Sized + Serialize, { value.serialize(self)?; Ok(()) } fn serialize_newtype_variant( self, _name: &'static str, variant_index: u32, _variant: &'static str, value: &T, ) -> Result<()> where T: ?Sized + Serialize, { StructSerializer::enum_variant(self, variant_index) .and_then(|mut ser| ser.serialize_element(value)) } fn serialize_seq(self, _len: Option) -> Result { self.0.add_padding(ARRAY_ALIGNMENT_DBUS)?; // Length in bytes (unfortunately not the same as len passed to us here) which we // initially set to 0. self.0 .write_u32(self.0.ctxt.endian(), 0_u32) .map_err(|e| Error::InputOutput(e.into()))?; // D-Bus expects us to add padding for the first element even when there is no first // element (i-e empty array) so we add padding already. let (alignment, child_signature) = match self.0.signature { Signature::Array(child) => (child.alignment(self.0.ctxt.format()), child.signature()), Signature::Dict { key, .. } => (DICT_ENTRY_ALIGNMENT_DBUS, key.signature()), _ => { return Err(Error::SignatureMismatch( self.0.signature.clone(), "an array or dict".to_string(), )); } }; // In case of an array, we'll only be serializing the array's child elements from now on and // in case of a dict, we'll swap key and value signatures during serlization of each entry, // so let's assume the element signature for array and key signature for dict, from now on. // We restore the original signature at the end of serialization. let array_signature = self.0.signature; self.0.signature = child_signature; let first_padding = self.0.add_padding(alignment)?; let start = self.0.bytes_written; self.0.container_depths = self.0.container_depths.inc_array()?; Ok(SeqSerializer { ser: self, start, first_padding, array_signature, }) } fn serialize_tuple(self, len: usize) -> Result { self.serialize_struct("", len) } fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result { self.serialize_struct(name, len) } fn serialize_tuple_variant( self, _name: &'static str, variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { StructSerializer::enum_variant(self, variant_index).map(StructSeqSerializer::Struct) } fn serialize_map(self, len: Option) -> Result { let (key_signature, value_signature) = match self.0.signature { Signature::Dict { key, value } => (key.signature(), value.signature()), _ => { return Err(Error::SignatureMismatch( self.0.signature.clone(), "a dict".to_string(), )); } }; let seq = self.serialize_seq(len)?; Ok(MapSerializer { seq, key_signature, value_signature, }) } fn serialize_struct(self, _name: &'static str, len: usize) -> Result { if len == 0 { return StructSerializer::unit(self).map(StructSeqSerializer::Struct); } self.0 .add_padding(self.0.signature.alignment(self.0.ctxt.format()))?; match &self.0.signature { Signature::Variant => StructSerializer::variant(self).map(StructSeqSerializer::Struct), Signature::Array(_) => self.serialize_seq(Some(len)).map(StructSeqSerializer::Seq), Signature::Structure(_) => { StructSerializer::structure(self).map(StructSeqSerializer::Struct) } _ => Err(Error::SignatureMismatch( self.0.signature.clone(), "a struct, array or variant".to_string(), )), } } fn serialize_struct_variant( self, _name: &'static str, variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { StructSerializer::enum_variant(self, variant_index).map(StructSeqSerializer::Struct) } fn is_human_readable(&self) -> bool { false } } #[doc(hidden)] pub struct SeqSerializer<'ser, 'b, W> { ser: &'b mut Serializer<'ser, W>, start: usize, // First element's padding first_padding: usize, array_signature: &'ser Signature, } impl SeqSerializer<'_, '_, W> where W: Write + Seek, { pub(self) fn end_seq(self) -> Result<()> { // Set size of array in bytes let array_len = self.ser.0.bytes_written - self.start; let len = usize_to_u32(array_len); let total_array_len = (array_len + self.first_padding + 4) as i64; self.ser .0 .writer .seek(std::io::SeekFrom::Current(-total_array_len)) .map_err(|e| Error::InputOutput(e.into()))?; self.ser .0 .writer .write_u32(self.ser.0.ctxt.endian(), len) .map_err(|e| Error::InputOutput(e.into()))?; self.ser .0 .writer .seek(std::io::SeekFrom::Current(total_array_len - 4)) .map_err(|e| Error::InputOutput(e.into()))?; self.ser.0.container_depths = self.ser.0.container_depths.dec_array(); self.ser.0.signature = self.array_signature; Ok(()) } } impl ser::SerializeSeq for SeqSerializer<'_, '_, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { value.serialize(&mut *self.ser) } fn end(self) -> Result<()> { self.end_seq() } } #[doc(hidden)] pub struct StructSerializer<'ser, 'b, W> { ser: &'b mut Serializer<'ser, W>, // The original container depths. We restore to that at the end. container_depths: ContainerDepths, // Index of the next field to serialize. field_idx: usize, } impl<'ser, 'b, W> StructSerializer<'ser, 'b, W> where W: Write + Seek, { fn variant(ser: &'b mut Serializer<'ser, W>) -> Result { let container_depths = ser.0.container_depths; ser.0.container_depths = ser.0.container_depths.inc_variant()?; Ok(Self { ser, container_depths, field_idx: 0, }) } fn structure(ser: &'b mut Serializer<'ser, W>) -> Result { let container_depths = ser.0.container_depths; ser.0.container_depths = ser.0.container_depths.inc_structure()?; Ok(Self { ser, container_depths, field_idx: 0, }) } fn unit(ser: &'b mut Serializer<'ser, W>) -> Result { // serialize as a `0u8` serde::Serializer::serialize_u8(&mut *ser, 0)?; let container_depths = ser.0.container_depths; Ok(Self { ser, container_depths, field_idx: 0, }) } fn enum_variant(ser: &'b mut Serializer<'ser, W>, variant_index: u32) -> Result { // Encode enum variants as a struct with first field as variant index let Signature::Structure(fields) = ser.0.signature else { return Err(Error::SignatureMismatch( ser.0.signature.clone(), "a struct".to_string(), )); }; let struct_field = fields.iter().nth(1).and_then(|f| { if matches!(f, Signature::Structure(_)) { Some(f) } else { None } }); ser.0.add_padding(STRUCT_ALIGNMENT_DBUS)?; let mut struct_ser = Self::structure(ser)?; struct_ser.serialize_struct_element(&variant_index)?; if let Some(field) = struct_field { // Add struct padding for inner struct and pretend we're the inner struct. struct_ser.ser.0.add_padding(STRUCT_ALIGNMENT_DBUS)?; struct_ser.field_idx = 0; struct_ser.ser.0.signature = field; } Ok(struct_ser) } fn serialize_struct_element(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { let signature = self.ser.0.signature; let field_signature = match signature { Signature::Variant => { match &self.ser.0.value_sign { // Serializing the value of a Value, which means signature was serialized // already, and also put aside for us to be picked here. Some(signature) => signature, // Serializing the signature of a Value. None => &Signature::Variant, } } Signature::Structure(fields) => { let signature = fields.iter().nth(self.field_idx).ok_or_else(|| { Error::SignatureMismatch(signature.clone(), "a struct".to_string()) })?; self.field_idx += 1; signature } _ => unreachable!("Incorrect signature for struct"), }; let bytes_written = self.ser.0.bytes_written; let mut ser = Serializer(crate::SerializerCommon:: { ctxt: self.ser.0.ctxt, signature: field_signature, writer: self.ser.0.writer, #[cfg(unix)] fds: self.ser.0.fds, bytes_written, value_sign: None, container_depths: self.ser.0.container_depths, }); value.serialize(&mut ser)?; self.ser.0.bytes_written = ser.0.bytes_written; self.ser.0.value_sign = ser.0.value_sign; Ok(()) } fn end_struct(self) -> Result<()> { // Restore the original container depths. self.ser.0.container_depths = self.container_depths; Ok(()) } } #[doc(hidden)] /// Allows us to serialize a struct as an ARRAY. pub enum StructSeqSerializer<'ser, 'b, W> { Struct(StructSerializer<'ser, 'b, W>), Seq(SeqSerializer<'ser, 'b, W>), } macro_rules! serialize_struct_anon_fields { ($trait:ident $method:ident) => { impl<'ser, 'b, W> ser::$trait for StructSerializer<'ser, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn $method(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { self.serialize_struct_element(value) } fn end(self) -> Result<()> { self.end_struct() } } impl<'ser, 'b, W> ser::$trait for StructSeqSerializer<'ser, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn $method(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { match self { StructSeqSerializer::Struct(ser) => ser.$method(value), StructSeqSerializer::Seq(ser) => ser.serialize_element(value), } } fn end(self) -> Result<()> { match self { StructSeqSerializer::Struct(ser) => ser.end_struct(), StructSeqSerializer::Seq(ser) => ser.end_seq(), } } } }; } serialize_struct_anon_fields!(SerializeTuple serialize_element); serialize_struct_anon_fields!(SerializeTupleStruct serialize_field); serialize_struct_anon_fields!(SerializeTupleVariant serialize_field); pub(crate) struct MapSerializer<'ser, 'b, W> { seq: SeqSerializer<'ser, 'b, W>, key_signature: &'ser Signature, value_signature: &'ser Signature, } impl ser::SerializeMap for MapSerializer<'_, '_, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<()> where T: ?Sized + Serialize, { self.seq.ser.0.add_padding(DICT_ENTRY_ALIGNMENT_DBUS)?; key.serialize(&mut *self.seq.ser) } fn serialize_value(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { self.seq.ser.0.signature = self.value_signature; value.serialize(&mut *self.seq.ser)?; self.seq.ser.0.signature = self.key_signature; Ok(()) } fn end(self) -> Result<()> { self.seq.end_seq() } } macro_rules! serialize_struct_named_fields { ($trait:ident) => { impl<'ser, 'b, W> ser::$trait for StructSerializer<'ser, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> where T: ?Sized + Serialize, { self.serialize_struct_element(value) } fn end(self) -> Result<()> { self.end_struct() } } impl<'ser, 'b, W> ser::$trait for StructSeqSerializer<'ser, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> where T: ?Sized + Serialize, { match self { StructSeqSerializer::Struct(ser) => ser.serialize_field(key, value), StructSeqSerializer::Seq(ser) => ser.serialize_element(value), } } fn end(self) -> Result<()> { match self { StructSeqSerializer::Struct(ser) => ser.end_struct(), StructSeqSerializer::Seq(ser) => ser.end_seq(), } } } }; } serialize_struct_named_fields!(SerializeStruct); serialize_struct_named_fields!(SerializeStructVariant); zvariant-5.2.0/src/de.rs000064400000000000000000000174241046102023000132230ustar 00000000000000use serde::de::{self, DeserializeSeed, VariantAccess, Visitor}; use std::{marker::PhantomData, str}; #[cfg(unix)] use std::os::fd::{AsFd, AsRawFd}; #[cfg(feature = "gvariant")] use crate::gvariant::Deserializer as GVDeserializer; use crate::{ container_depths::ContainerDepths, dbus::Deserializer as DBusDeserializer, serialized::Context, utils::*, Basic, Error, Result, Signature, }; /// Our deserialization implementation. #[derive(Debug)] pub(crate) struct DeserializerCommon<'de, 'sig, 'f, F> { pub(crate) ctxt: Context, pub(crate) bytes: &'de [u8], #[cfg(unix)] pub(crate) fds: Option<&'f [F]>, #[cfg(not(unix))] pub(crate) fds: PhantomData<&'f F>, pub(crate) pos: usize, pub(crate) signature: &'sig Signature, pub(crate) container_depths: ContainerDepths, } /// Our deserialization implementation. /// /// Using this deserializer involves an redirection to the actual deserializer. It's best /// to use the serialization functions, e.g [`crate::to_bytes`] or specific serializers, /// [`crate::dbus::Deserializer`] or [`crate::zvariant::Deserializer`]. pub(crate) enum Deserializer<'ser, 'sig, 'f, F> { DBus(DBusDeserializer<'ser, 'sig, 'f, F>), #[cfg(feature = "gvariant")] GVariant(GVDeserializer<'ser, 'sig, 'f, F>), } #[cfg(unix)] impl DeserializerCommon<'_, '_, '_, F> where F: AsFd, { pub fn get_fd(&self, idx: u32) -> Result { self.fds .and_then(|fds| fds.get(idx as usize).map(|fd| fd.as_fd().as_raw_fd())) .ok_or(Error::UnknownFd) } } impl<'de, F> DeserializerCommon<'de, '_, '_, F> { pub fn parse_padding(&mut self, alignment: usize) -> Result { let padding = padding_for_n_bytes(self.abs_pos(), alignment); if padding > 0 { if self.pos + padding > self.bytes.len() { return Err(serde::de::Error::invalid_length( self.bytes.len(), &format!(">= {}", self.pos + padding).as_str(), )); } for i in 0..padding { let byte = self.bytes[self.pos + i]; if byte != 0 { return Err(Error::PaddingNot0(byte)); } } self.pos += padding; } Ok(padding) } pub fn prep_deserialize_basic(&mut self) -> Result<()> where T: Basic, { self.parse_padding(T::alignment(self.ctxt.format()))?; Ok(()) } pub fn next_slice(&mut self, len: usize) -> Result<&'de [u8]> { if self.pos + len > self.bytes.len() { return Err(serde::de::Error::invalid_length( self.bytes.len(), &format!(">= {}", self.pos + len).as_str(), )); } let slice = &self.bytes[self.pos..self.pos + len]; self.pos += len; Ok(slice) } pub fn next_const_size_slice(&mut self) -> Result<&[u8]> where T: Basic, { self.prep_deserialize_basic::()?; self.next_slice(T::alignment(self.ctxt.format())) } pub fn abs_pos(&self) -> usize { self.ctxt.position() + self.pos } } macro_rules! deserialize_method { ($method:ident($($arg:ident: $type:ty),*)) => { #[inline] fn $method(self, $($arg: $type,)* visitor: V) -> Result where V: Visitor<'de>, { match self { #[cfg(feature = "gvariant")] Deserializer::GVariant(de) => { de.$method($($arg,)* visitor) } Deserializer::DBus(de) => { de.$method($($arg,)* visitor) } } } } } impl<'de, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> de::Deserializer<'de> for &mut Deserializer<'de, '_, '_, F> { type Error = Error; deserialize_method!(deserialize_any()); deserialize_method!(deserialize_bool()); deserialize_method!(deserialize_i8()); deserialize_method!(deserialize_i16()); deserialize_method!(deserialize_i32()); deserialize_method!(deserialize_i64()); deserialize_method!(deserialize_u8()); deserialize_method!(deserialize_u16()); deserialize_method!(deserialize_u32()); deserialize_method!(deserialize_u64()); deserialize_method!(deserialize_f32()); deserialize_method!(deserialize_f64()); deserialize_method!(deserialize_char()); deserialize_method!(deserialize_str()); deserialize_method!(deserialize_string()); deserialize_method!(deserialize_bytes()); deserialize_method!(deserialize_byte_buf()); deserialize_method!(deserialize_option()); deserialize_method!(deserialize_unit()); deserialize_method!(deserialize_unit_struct(n: &'static str)); deserialize_method!(deserialize_newtype_struct(n: &'static str)); deserialize_method!(deserialize_seq()); deserialize_method!(deserialize_map()); deserialize_method!(deserialize_tuple(n: usize)); deserialize_method!(deserialize_tuple_struct(n: &'static str, l: usize)); deserialize_method!(deserialize_struct( n: &'static str, f: &'static [&'static str] )); deserialize_method!(deserialize_enum( n: &'static str, f: &'static [&'static str] )); deserialize_method!(deserialize_identifier()); deserialize_method!(deserialize_ignored_any()); fn is_human_readable(&self) -> bool { false } } #[derive(Debug)] pub(crate) enum ValueParseStage { Signature, Value, Done, } pub(crate) fn deserialize_any<'de, 'f, D, V>( de: D, signature: &Signature, visitor: V, ) -> Result where D: de::Deserializer<'de, Error = Error>, V: Visitor<'de>, { match signature { Signature::Unit => de.deserialize_unit(visitor), Signature::U8 => de.deserialize_u8(visitor), Signature::Bool => de.deserialize_bool(visitor), Signature::I16 => de.deserialize_i16(visitor), Signature::U16 => de.deserialize_u16(visitor), Signature::I32 => de.deserialize_i32(visitor), #[cfg(unix)] Signature::Fd => de.deserialize_i32(visitor), Signature::U32 => de.deserialize_u32(visitor), Signature::I64 => de.deserialize_i64(visitor), Signature::U64 => de.deserialize_u64(visitor), Signature::F64 => de.deserialize_f64(visitor), Signature::Str | Signature::ObjectPath | Signature::Signature => { de.deserialize_str(visitor) } Signature::Variant => de.deserialize_seq(visitor), Signature::Array(_) => de.deserialize_seq(visitor), Signature::Dict { .. } => de.deserialize_map(visitor), Signature::Structure { .. } => de.deserialize_seq(visitor), #[cfg(feature = "gvariant")] Signature::Maybe(_) => de.deserialize_option(visitor), } } // Enum handling is very generic so it can be here and specific deserializers can use this. pub(crate) struct Enum { pub(crate) de: D, pub(crate) name: &'static str, pub(crate) _phantom: PhantomData, } impl<'de, D, F> VariantAccess<'de> for Enum where D: de::Deserializer<'de, Error = Error>, { type Error = Error; fn unit_variant(self) -> std::result::Result<(), Self::Error> { Ok(()) } fn newtype_variant_seed(self, seed: T) -> Result where T: DeserializeSeed<'de>, { seed.deserialize(self.de) } fn tuple_variant(self, _len: usize, visitor: V) -> Result where V: Visitor<'de>, { de::Deserializer::deserialize_struct(self.de, self.name, &[], visitor) } fn struct_variant(self, fields: &'static [&'static str], visitor: V) -> Result where V: Visitor<'de>, { de::Deserializer::deserialize_struct(self.de, self.name, fields, visitor) } } zvariant-5.2.0/src/deserialize_value.rs000064400000000000000000000047131046102023000163240ustar 00000000000000use core::str; use std::marker::PhantomData; use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; use static_assertions::assert_impl_all; use crate::{Signature, Type}; /// A wrapper to deserialize a value to `T: Type + Deserialize`. /// /// When the type of a value is well-known, you may avoid the cost and complexity of wrapping to a /// generic [`Value`] and instead use this wrapper. /// /// ``` /// # use zvariant::{to_bytes, serialized::Context, DeserializeValue, SerializeValue, LE}; /// # /// # let ctxt = Context::new_dbus(LE, 0); /// # let array = [0, 1, 2]; /// # let v = SerializeValue(&array); /// # let encoded = to_bytes(ctxt, &v).unwrap(); /// let decoded: DeserializeValue<[u8; 3]> = encoded.deserialize().unwrap().0; /// # assert_eq!(decoded.0, array); /// ``` /// /// [`Value`]: enum.Value.html pub struct DeserializeValue<'de, T: Type + Deserialize<'de>>( pub T, std::marker::PhantomData<&'de T>, ); assert_impl_all!(DeserializeValue<'_, i32>: Send, Sync, Unpin); impl<'de, T: Type + Deserialize<'de>> Deserialize<'de> for DeserializeValue<'de, T> { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { const FIELDS: &[&str] = &["signature", "value"]; Ok(DeserializeValue( deserializer.deserialize_struct( "Variant", FIELDS, DeserializeValueVisitor(PhantomData), )?, PhantomData, )) } } struct DeserializeValueVisitor(PhantomData); impl<'de, T: Type + Deserialize<'de>> Visitor<'de> for DeserializeValueVisitor { type Value = T; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("Variant") } fn visit_seq(self, mut seq: V) -> Result where V: SeqAccess<'de>, { let sig: Signature = seq .next_element()? .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; if T::SIGNATURE != &sig { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Str(&sig.to_string()), &"the value signature", )); } seq.next_element()? .ok_or_else(|| serde::de::Error::invalid_length(1, &self)) } } impl<'de, T: Type + Deserialize<'de>> Type for DeserializeValue<'de, T> { const SIGNATURE: &'static Signature = &Signature::Variant; } zvariant-5.2.0/src/dict.rs000064400000000000000000000215501046102023000135510ustar 00000000000000use std::{ collections::{BTreeMap, HashMap}, fmt::{Display, Write}, hash::{BuildHasher, Hash}, }; use serde::ser::{Serialize, SerializeMap, Serializer}; use static_assertions::assert_impl_all; use crate::{value_display_fmt, Basic, DynamicType, Error, Signature, Type, Value}; /// A helper type to wrap dictionaries in a [`Value`]. /// /// API is provided to convert from, and to a [`HashMap`]. /// /// [`Value`]: enum.Value.html#variant.Dict /// [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html #[derive(Debug, Hash, PartialEq, PartialOrd, Eq, Ord)] pub struct Dict<'k, 'v> { map: BTreeMap, Value<'v>>, signature: Signature, } assert_impl_all!(Dict<'_, '_>: Send, Sync, Unpin); impl<'k, 'v> Dict<'k, 'v> { /// Create a new empty `Dict`, given the signature of the keys and values. pub fn new(key_signature: &Signature, value_signature: &Signature) -> Self { let signature = Signature::dict(key_signature.clone(), value_signature.clone()); Self { map: BTreeMap::new(), signature, } } /// Append `key` and `value` as a new entry. /// /// # Errors /// /// * if [`key.value_signature()`] doesn't match the key signature `self` was created for. /// * if [`value.value_signature()`] doesn't match the value signature `self` was created for. /// /// [`key.value_signature()`]: enum.Value.html#method.value_signature /// [`value.value_signature()`]: enum.Value.html#method.value_signature pub fn append<'kv: 'k, 'vv: 'v>( &mut self, key: Value<'kv>, value: Value<'vv>, ) -> Result<(), Error> { match &self.signature { Signature::Dict { key: key_sig, .. } if key.value_signature() != key_sig.signature() => { return Err(Error::SignatureMismatch( key.value_signature().clone(), key_sig.signature().clone().to_string(), )) } Signature::Dict { value: value_sig, .. } if value.value_signature() != value_sig.signature() => { return Err(Error::SignatureMismatch( value.value_signature().clone(), value_sig.signature().clone().to_string(), )) } Signature::Dict { .. } => (), _ => unreachable!("Incorrect `Dict` signature"), } self.map.insert(key, value); Ok(()) } /// Add a new entry. pub fn add(&mut self, key: K, value: V) -> Result<(), Error> where K: Basic + Into> + Ord, V: Into> + DynamicType, { self.append(Value::new(key), Value::new(value)) } /// Get the value for the given key. pub fn get<'d, K, V>(&'d self, key: &'k K) -> Result, Error> where 'd: 'k + 'v, &'k K: TryInto>, <&'k K as TryInto>>::Error: Into, V: TryFrom<&'v Value<'v>>, >>::Error: Into, { let key: Value<'_> = key.try_into().map_err(Into::into)?; self.map.get(&key).map(|v| v.downcast_ref()).transpose() } /// Get the signature of this `Dict`. pub fn signature(&self) -> &Signature { &self.signature } pub(crate) fn try_to_owned(&self) -> crate::Result> { Ok(Dict { signature: self.signature.clone(), map: self .map .iter() .map(|(k, v)| { Ok(( k.try_to_owned().map(Into::into)?, v.try_to_owned().map(Into::into)?, )) }) .collect::>()?, }) } /// Try to clone the `Dict`. pub fn try_clone(&self) -> Result { let entries = self .map .iter() .map(|(k, v)| Ok((k.try_clone()?, v.try_clone()?))) .collect::>()?; Ok(Self { map: entries, signature: self.signature.clone(), }) } /// Create a new empty `Dict`, given the complete signature. pub(crate) fn new_full_signature(signature: &Signature) -> Self { assert!(matches!(signature, Signature::Dict { .. })); Self { map: BTreeMap::new(), signature: signature.clone(), } } pub fn iter(&self) -> impl Iterator, &Value<'v>)> { self.map.iter() } pub fn iter_mut(&mut self) -> impl Iterator, &mut Value<'v>)> { self.map.iter_mut() } // TODO: Provide more API like https://docs.rs/toml/0.5.5/toml/map/struct.Map.html } impl Display for Dict<'_, '_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { dict_display_fmt(self, f, true) } } impl<'k, 'v> IntoIterator for Dict<'k, 'v> { type Item = (Value<'k>, Value<'v>); type IntoIter = , Value<'v>> as IntoIterator>::IntoIter; fn into_iter(self) -> Self::IntoIter { self.map.into_iter() } } pub(crate) fn dict_display_fmt( dict: &Dict<'_, '_>, f: &mut std::fmt::Formatter<'_>, type_annotate: bool, ) -> std::fmt::Result { if dict.map.is_empty() { if type_annotate { write!(f, "@{} ", dict.signature())?; } f.write_str("{}")?; } else { f.write_char('{')?; // Annotate only the first entry as the rest will be of the same type. let mut type_annotate = type_annotate; for (i, (key, value)) in dict.map.iter().enumerate() { value_display_fmt(key, f, type_annotate)?; f.write_str(": ")?; value_display_fmt(value, f, type_annotate)?; type_annotate = false; if i + 1 < dict.map.len() { f.write_str(", ")?; } } f.write_char('}')?; } Ok(()) } impl Serialize for Dict<'_, '_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut map = serializer.serialize_map(Some(self.map.len()))?; for (key, value) in self.map.iter() { key.serialize_value_as_dict_key(&mut map)?; value.serialize_value_as_dict_value(&mut map)?; } map.end() } } // Conversion of Dict to Map types macro_rules! from_dict { ($ty:ident ) => { impl<'k, 'v, K, V $(, $typaram)*> TryFrom> for $ty where K: Basic + TryFrom> $(+ $kbound1 $(+ $kbound2)*)*, V: TryFrom>, K::Error: Into, V::Error: Into, $($typaram: BuildHasher + Default,)* { type Error = Error; fn try_from(v: Dict<'k, 'v>) -> Result { v.map.into_iter().map(|(key, value)| { let key = if let Value::Value(v) = key { K::try_from(*v) } else { K::try_from(key) } .map_err(Into::into)?; let value = if let Value::Value(v) = value { V::try_from(*v) } else { V::try_from(value) } .map_err(Into::into)?; Ok((key, value)) }).collect::>() } } }; } from_dict!(HashMap); from_dict!(BTreeMap); // TODO: this could be useful // impl<'d, 'k, 'v, K, V, H> TryFrom<&'d Dict<'k, 'v>> for HashMap<&'k K, &'v V, H> // Conversion of Hashmap to Dict macro_rules! to_dict { ($ty:ident ) => { impl<'k, 'v, K, V $(, $typaram)*> From<$ty> for Dict<'k, 'v> where K: Type + Into>, V: Type + Into>, $($typaram: BuildHasher,)* { fn from(value: $ty) -> Self { let entries = value .into_iter() .map(|(key, value)| (Value::new(key), Value::new(value))) .collect(); let key_signature = K::SIGNATURE.clone(); let value_signature = V::SIGNATURE.clone(); let signature = Signature::dict(key_signature, value_signature); Self { map: entries, signature, } } } }; } to_dict!(HashMap); to_dict!(BTreeMap); zvariant-5.2.0/src/error.rs000064400000000000000000000170641046102023000137640ustar 00000000000000use serde::{de, ser}; use static_assertions::assert_impl_all; use std::{convert::Infallible, error, fmt, io, result, sync::Arc}; use crate::Signature; /// Enum representing the max depth exceeded error. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum MaxDepthExceeded { /// The maximum allowed depth for structures in encoding was exceeded. Structure, /// The maximum allowed depth for arrays in encoding was exceeded. Array, /// The maximum allowed depth for containers in encoding was exceeded. Container, } impl fmt::Display for MaxDepthExceeded { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Structure => write!( f, "Maximum allowed depth for structures in encoding was exceeded" ), Self::Array => write!( f, "Maximum allowed depth for arrays in encoding was exceeded" ), Self::Container => write!( f, "Maximum allowed depth for containers in encoding was exceeded" ), } } } /// Error type used by zvariant API. #[derive(Debug)] #[non_exhaustive] pub enum Error { /// Generic error. All serde errors gets transformed into this variant. Message(String), /// Wrapper for [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) InputOutput(Arc), /// Type conversions errors. IncorrectType, /// Wrapper for [`std::str::Utf8Error`](https://doc.rust-lang.org/std/str/struct.Utf8Error.html) Utf8(std::str::Utf8Error), /// Non-0 padding byte(s) encountered. PaddingNot0(u8), /// The deserialized file descriptor is not in the given FD index. UnknownFd, /// Missing framing offset at the end of a GVariant-encoded container, MissingFramingOffset, /// The type (signature as first argument) being (de)serialized is not supported by the format. IncompatibleFormat(Signature, crate::serialized::Format), /// The provided signature (first argument) was not valid for reading as the requested type. /// Details on the expected signatures are in the second argument. SignatureMismatch(Signature, String), /// Out of bounds range specified. OutOfBounds, /// The maximum allowed depth for containers in encoding was exceeded. MaxDepthExceeded(MaxDepthExceeded), /// Error from parsing a signature. SignatureParse(crate::signature::Error), /// Attempted to create an empty structure (which is not allowed by the D-Bus specification). EmptyStructure, /// Invalid object path. InvalidObjectPath, } assert_impl_all!(Error: Send, Sync, Unpin); impl PartialEq for Error { fn eq(&self, other: &Self) -> bool { match (self, other) { (Error::Message(msg), Error::Message(other)) => msg == other, // Io is false (Error::IncorrectType, Error::IncorrectType) => true, (Error::Utf8(msg), Error::Utf8(other)) => msg == other, (Error::PaddingNot0(p), Error::PaddingNot0(other)) => p == other, (Error::UnknownFd, Error::UnknownFd) => true, (Error::MaxDepthExceeded(max1), Error::MaxDepthExceeded(max2)) => max1 == max2, (Error::MissingFramingOffset, Error::MissingFramingOffset) => true, ( Error::IncompatibleFormat(sig1, format1), Error::IncompatibleFormat(sig2, format2), ) => sig1 == sig2 && format1 == format2, ( Error::SignatureMismatch(provided1, expected1), Error::SignatureMismatch(provided2, expected2), ) => provided1 == provided2 && expected1 == expected2, (Error::OutOfBounds, Error::OutOfBounds) => true, (Error::SignatureParse(e1), Error::SignatureParse(e2)) => e1 == e2, (Error::EmptyStructure, Error::EmptyStructure) => true, (Error::InvalidObjectPath, Error::InvalidObjectPath) => true, (_, _) => false, } } } impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { Error::InputOutput(e) => Some(e), Error::Utf8(e) => Some(e), _ => None, } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::Message(s) => write!(f, "{s}"), Error::InputOutput(e) => e.fmt(f), Error::IncorrectType => write!(f, "incorrect type"), Error::Utf8(e) => write!(f, "{e}"), Error::PaddingNot0(b) => write!(f, "Unexpected non-0 padding byte `{b}`"), Error::UnknownFd => write!(f, "File descriptor not in the given FD index"), Error::MissingFramingOffset => write!( f, "Missing framing offset at the end of GVariant-encoded container" ), Error::IncompatibleFormat(sig, format) => { write!(f, "Type `{sig}` is not compatible with `{format}` format",) } Error::SignatureMismatch(provided, expected) => write!( f, "Signature mismatch: got `{provided}`, expected {expected}", ), Error::OutOfBounds => write!( f, // FIXME: using the `Debug` impl of `Range` because it doesn't impl `Display`. "Out of bounds range specified", ), Error::MaxDepthExceeded(max) => write!(f, "{max}"), Error::SignatureParse(e) => write!(f, "{e}"), Error::EmptyStructure => write!(f, "Attempted to create an empty structure"), Error::InvalidObjectPath => write!(f, "Invalid object path"), } } } impl Clone for Error { fn clone(&self) -> Self { match self { Error::Message(s) => Error::Message(s.clone()), Error::InputOutput(e) => Error::InputOutput(e.clone()), Error::IncorrectType => Error::IncorrectType, Error::Utf8(e) => Error::Utf8(*e), Error::PaddingNot0(b) => Error::PaddingNot0(*b), Error::UnknownFd => Error::UnknownFd, Error::MissingFramingOffset => Error::MissingFramingOffset, Error::IncompatibleFormat(sig, format) => { Error::IncompatibleFormat(sig.clone(), *format) } Error::SignatureMismatch(provided, expected) => { Error::SignatureMismatch(provided.clone(), expected.clone()) } Error::OutOfBounds => Error::OutOfBounds, Error::MaxDepthExceeded(max) => Error::MaxDepthExceeded(*max), Error::SignatureParse(e) => Error::SignatureParse(*e), Error::EmptyStructure => Error::EmptyStructure, Error::InvalidObjectPath => Error::InvalidObjectPath, } } } impl From for Error { fn from(i: Infallible) -> Self { match i {} } } impl de::Error for Error { // TODO: Add more specific error variants to Error enum above so we can implement other methods // here too. fn custom(msg: T) -> Error where T: fmt::Display, { Error::Message(msg.to_string()) } } impl ser::Error for Error { fn custom(msg: T) -> Error where T: fmt::Display, { Error::Message(msg.to_string()) } } impl From for Error { fn from(val: io::Error) -> Self { Error::InputOutput(Arc::new(val)) } } /// Alias for a `Result` with the error type `zvariant::Error`. pub type Result = result::Result; zvariant-5.2.0/src/fd.rs000064400000000000000000000126141046102023000132200ustar 00000000000000use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use static_assertions::assert_impl_all; use std::os::fd::{self, AsFd, AsRawFd, BorrowedFd, RawFd}; use crate::{Basic, Type}; /// A file-descriptor type wrapper. /// /// Since [`std::os::fd::BorrowedFd`] and [`std::os::fd::OwnedFd`] types /// do not implement [`Serialize`] and [`Deserialize`]. So we provide a /// wrapper for both that implements these traits. /// /// [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html /// [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html #[derive(Debug)] pub enum Fd<'f> { Borrowed(BorrowedFd<'f>), Owned(fd::OwnedFd), } impl Fd<'_> { /// Try to create an owned version of `self`. pub fn try_to_owned(&self) -> crate::Result> { self.as_fd() .try_clone_to_owned() .map(Fd::Owned) .map_err(Into::into) } /// Try to clone `self`. pub fn try_clone(&self) -> crate::Result { Ok(match self { Self::Borrowed(fd) => Self::Borrowed(*fd), Self::Owned(fd) => Self::Owned(fd.try_clone()?), }) } } impl<'f> From> for Fd<'f> { fn from(fd: BorrowedFd<'f>) -> Self { Self::Borrowed(fd) } } impl From for Fd<'_> { fn from(fd: fd::OwnedFd) -> Self { Self::Owned(fd) } } impl From for Fd<'_> { fn from(owned: OwnedFd) -> Self { owned.inner } } impl TryFrom> for fd::OwnedFd { type Error = crate::Error; fn try_from(fd: Fd<'_>) -> crate::Result { match fd { Fd::Borrowed(fd) => fd.try_clone_to_owned().map_err(Into::into), Fd::Owned(fd) => Ok(fd), } } } impl AsRawFd for Fd<'_> { fn as_raw_fd(&self) -> RawFd { self.as_fd().as_raw_fd() } } impl AsFd for Fd<'_> { fn as_fd(&self) -> BorrowedFd<'_> { match self { Self::Borrowed(fd) => fd.as_fd(), Self::Owned(fd) => fd.as_fd(), } } } impl<'fd, T> From<&'fd T> for Fd<'fd> where T: AsFd, { fn from(t: &'fd T) -> Self { Self::Borrowed(t.as_fd()) } } impl std::fmt::Display for Fd<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.as_raw_fd().fmt(f) } } macro_rules! fd_impl { ($i:ty) => { assert_impl_all!($i: Send, Sync, Unpin); impl Basic for $i { const SIGNATURE_CHAR: char = 'h'; const SIGNATURE_STR: &'static str = "h"; } impl Type for $i { const SIGNATURE: &'static crate::Signature = &crate::Signature::Fd; } }; } fd_impl!(Fd<'_>); impl Serialize for Fd<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_i32(self.as_raw_fd()) } } impl<'de> Deserialize<'de> for Fd<'de> { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let raw = i32::deserialize(deserializer)?; // SAFETY: The `'de` lifetimes will ensure the borrow won't outlive the raw FD. let fd = unsafe { BorrowedFd::borrow_raw(raw) }; Ok(Fd::Borrowed(fd)) } } impl PartialEq for Fd<'_> { fn eq(&self, other: &Self) -> bool { self.as_raw_fd().eq(&other.as_raw_fd()) } } impl Eq for Fd<'_> {} impl PartialOrd for Fd<'_> { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Fd<'_> { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.as_raw_fd().cmp(&other.as_raw_fd()) } } impl std::hash::Hash for Fd<'_> { fn hash(&self, state: &mut H) { self.as_raw_fd().hash(state) } } /// A file-descriptor type wrapper. /// /// This is the same as [`Fd`] type, except it only keeps an owned file descriptor. #[derive(Debug, PartialEq, Eq, Hash)] pub struct OwnedFd { inner: Fd<'static>, } fd_impl!(OwnedFd); impl Serialize for OwnedFd { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.inner.serialize(serializer) } } impl<'de> Deserialize<'de> for OwnedFd { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let fd = Fd::deserialize(deserializer)?; Ok(OwnedFd { inner: fd .as_fd() .try_clone_to_owned() .map(Fd::Owned) .map_err(D::Error::custom)?, }) } } impl AsFd for OwnedFd { fn as_fd(&self) -> BorrowedFd<'_> { self.inner.as_fd() } } impl AsRawFd for OwnedFd { fn as_raw_fd(&self) -> RawFd { self.inner.as_raw_fd() } } impl From for OwnedFd { fn from(value: fd::OwnedFd) -> Self { Self { inner: Fd::Owned(value), } } } impl From for fd::OwnedFd { fn from(value: OwnedFd) -> fd::OwnedFd { match value.inner { Fd::Owned(fd) => fd, Fd::Borrowed(_) => unreachable!(), } } } impl From> for OwnedFd { fn from(value: Fd<'static>) -> Self { Self { inner: value } } } impl std::fmt::Display for OwnedFd { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.inner.fmt(f) } } zvariant-5.2.0/src/framing_offset_size.rs000064400000000000000000000101251046102023000166450ustar 00000000000000use crate::{Error, Result, WriteBytes, LE}; // Used internally for GVariant encoding and decoding. // // GVariant containers keeps framing offsets at the end and size of these offsets is dependent on // the size of the container (which includes offsets themselves). #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(usize)] pub(crate) enum FramingOffsetSize { U8 = 1, U16 = 2, U32 = 4, #[cfg(not(target_pointer_width = "32"))] U64 = 8, } impl FramingOffsetSize { pub(crate) fn for_bare_container(container_len: usize, num_offsets: usize) -> Self { let mut offset_size = FramingOffsetSize::U8; loop { if container_len + num_offsets * (offset_size as usize) <= offset_size.max() { return offset_size; } offset_size = offset_size .bump_up() .expect("Can't handle container too large for a 64-bit pointer"); } } pub(crate) fn for_encoded_container(container_len: usize) -> Self { Self::for_bare_container(container_len, 0) } pub(crate) fn write_offset(self, writer: &mut W, offset: usize) -> Result<()> where W: std::io::Write, { match self { FramingOffsetSize::U8 => writer.write_u8(LE, offset as u8), FramingOffsetSize::U16 => writer.write_u16(LE, offset as u16), FramingOffsetSize::U32 => writer.write_u32(LE, offset as u32), #[cfg(not(target_pointer_width = "32"))] FramingOffsetSize::U64 => writer.write_u64(LE, offset as u64), } .map_err(|e| Error::InputOutput(e.into())) } pub fn read_last_offset_from_buffer(self, buffer: &[u8]) -> usize { if buffer.is_empty() { return 0; } let end = buffer.len(); match self { FramingOffsetSize::U8 => buffer[end - 1] as usize, FramingOffsetSize::U16 => LE.read_u16(&buffer[end - 2..end]) as usize, FramingOffsetSize::U32 => LE.read_u32(&buffer[end - 4..end]) as usize, #[cfg(not(target_pointer_width = "32"))] FramingOffsetSize::U64 => LE.read_u64(&buffer[end - 8..end]) as usize, } } fn max(self) -> usize { match self { FramingOffsetSize::U8 => std::u8::MAX as usize, FramingOffsetSize::U16 => std::u16::MAX as usize, FramingOffsetSize::U32 => std::u32::MAX as usize, #[cfg(not(target_pointer_width = "32"))] FramingOffsetSize::U64 => std::u64::MAX as usize, } } fn bump_up(self) -> Option { match self { FramingOffsetSize::U8 => Some(FramingOffsetSize::U16), FramingOffsetSize::U16 => Some(FramingOffsetSize::U32), #[cfg(not(target_pointer_width = "32"))] FramingOffsetSize::U32 => Some(FramingOffsetSize::U64), #[cfg(not(target_pointer_width = "32"))] FramingOffsetSize::U64 => None, #[cfg(target_pointer_width = "32")] FramingOffsetSize::U32 => None, } } } #[cfg(test)] mod tests { use crate::framing_offset_size::FramingOffsetSize; #[test] fn framing_offset_size_bump() { assert_eq!( FramingOffsetSize::for_bare_container(std::u8::MAX as usize - 3, 3), FramingOffsetSize::U8 ); assert_eq!( FramingOffsetSize::for_bare_container(std::u8::MAX as usize - 1, 2), FramingOffsetSize::U16 ); assert_eq!( FramingOffsetSize::for_bare_container(std::u16::MAX as usize - 4, 2), FramingOffsetSize::U16 ); assert_eq!( FramingOffsetSize::for_bare_container(std::u16::MAX as usize - 3, 2), FramingOffsetSize::U32 ); assert_eq!( FramingOffsetSize::for_bare_container(std::u32::MAX as usize - 12, 3), FramingOffsetSize::U32 ); #[cfg(not(target_pointer_width = "32"))] assert_eq!( FramingOffsetSize::for_bare_container(std::u32::MAX as usize - 11, 3), FramingOffsetSize::U64 ); } } zvariant-5.2.0/src/framing_offsets.rs000064400000000000000000000054141046102023000160030ustar 00000000000000use crate::{framing_offset_size::FramingOffsetSize, Result}; use std::collections::VecDeque; // Used internally for GVariant encoding and decoding. // // GVariant containers keeps framing offsets at the end and size of these offsets is dependent on // the size of the container (which includes offsets themselves. #[derive(Debug)] pub(crate) struct FramingOffsets(VecDeque); impl FramingOffsets { pub fn new() -> Self { // FIXME: Set some good default capacity Self(VecDeque::new()) } pub fn from_encoded_array(container: &[u8]) -> Result<(Self, usize)> { let offset_size = FramingOffsetSize::for_encoded_container(container.len()); // The last offset tells us the start of offsets. let offsets_start = offset_size.read_last_offset_from_buffer(container); if offsets_start > container.len() { return Err(serde::de::Error::invalid_length( offsets_start, &format!("< {}", container.len()).as_str(), )); } let mut i = offsets_start; let offsets_len = container.len() - i; let slice_len = offset_size as usize; let mut offsets = Self::new(); while i < container.len() { let end = i + slice_len; if end > container.len() { return Err(serde::de::Error::invalid_length( end, &format!("< {}", container.len()).as_str(), )); } let offset = offset_size.read_last_offset_from_buffer(&container[i..end]); if offset > offsets_start { return Err(serde::de::Error::invalid_length( offset, &format!("< {offsets_start}").as_str(), )); } let offset = offset_size.read_last_offset_from_buffer(&container[i..end]); offsets.push(offset); i += slice_len; } Ok((offsets, offsets_len)) } pub fn push(&mut self, offset: usize) { self.0.push_back(offset); } pub fn push_front(&mut self, offset: usize) { self.0.push_front(offset); } pub fn write_all(self, writer: &mut W, container_len: usize) -> Result<()> where W: std::io::Write, { if self.is_empty() { return Ok(()); } let offset_size = FramingOffsetSize::for_bare_container(container_len, self.0.len()); for offset in self.0 { offset_size.write_offset(writer, offset)?; } Ok(()) } pub fn is_empty(&self) -> bool { self.0.len() == 0 } pub fn pop(&mut self) -> Option { self.0.pop_front() } pub fn peek(&self) -> Option { self.0.front().cloned() } } zvariant-5.2.0/src/from_value.rs000064400000000000000000000136031046102023000147650ustar 00000000000000#[cfg(feature = "gvariant")] use crate::Maybe; use crate::{ Array, Dict, Error, NoneValue, ObjectPath, Optional, OwnedObjectPath, Signature, Str, Structure, Value, }; #[cfg(unix)] use crate::Fd; use std::{collections::HashMap, hash::BuildHasher}; macro_rules! value_try_from { ($kind:ident, $to:ty) => { impl<'a> TryFrom> for $to { type Error = Error; fn try_from(value: Value<'a>) -> Result { if let Value::$kind(value) = value { Ok(value.into()) } else { Err(Error::IncorrectType) } } } }; } macro_rules! value_try_from_ref { ($kind:ident, $to:ty) => { impl<'a> TryFrom<&'a Value<'_>> for &'a $to { type Error = Error; fn try_from(value: &'a Value<'_>) -> Result { if let Value::$kind(value) = value { Ok(value) } else { Err(Error::IncorrectType) } } } }; } macro_rules! value_try_from_ref_clone { ($kind:ident, $to:ty) => { impl<'a> TryFrom<&Value<'a>> for $to { type Error = Error; fn try_from(value: &Value<'a>) -> Result { if let Value::$kind(value) = value { Ok(value.clone().into()) } else { Err(Error::IncorrectType) } } } }; } macro_rules! value_try_from_all { ($from:ident, $to:ty) => { value_try_from!($from, $to); value_try_from_ref!($from, $to); value_try_from_ref_clone!($from, $to); }; } value_try_from_all!(U8, u8); value_try_from_all!(Bool, bool); value_try_from_all!(I16, i16); value_try_from_all!(U16, u16); value_try_from_all!(I32, i32); value_try_from_all!(U32, u32); value_try_from_all!(I64, i64); value_try_from_all!(U64, u64); value_try_from_all!(F64, f64); value_try_from_all!(Str, Str<'a>); value_try_from_all!(Signature, Signature); value_try_from_all!(ObjectPath, ObjectPath<'a>); value_try_from!(Str, String); value_try_from_ref!(Str, str); macro_rules! value_try_from_ref_try_clone { ($kind:ident, $to:ty) => { impl<'a> TryFrom<&Value<'a>> for $to { type Error = Error; fn try_from(value: &Value<'a>) -> Result { if let Value::$kind(value) = value { value.try_clone().map_err(Into::into) } else { Err(Error::IncorrectType) } } } }; } value_try_from!(Structure, Structure<'a>); value_try_from_ref!(Structure, Structure<'a>); value_try_from_ref_try_clone!(Structure, Structure<'a>); value_try_from!(Dict, Dict<'a, 'a>); value_try_from_ref!(Dict, Dict<'a, 'a>); value_try_from_ref_try_clone!(Dict, Dict<'a, 'a>); value_try_from!(Array, Array<'a>); value_try_from_ref!(Array, Array<'a>); value_try_from_ref_try_clone!(Array, Array<'a>); #[cfg(feature = "gvariant")] value_try_from!(Maybe, Maybe<'a>); #[cfg(feature = "gvariant")] value_try_from_ref!(Maybe, Maybe<'a>); #[cfg(feature = "gvariant")] value_try_from_ref_try_clone!(Maybe, Maybe<'a>); #[cfg(unix)] value_try_from!(Fd, Fd<'a>); #[cfg(unix)] value_try_from_ref!(Fd, Fd<'a>); #[cfg(unix)] value_try_from_ref_try_clone!(Fd, Fd<'a>); impl TryFrom<&Value<'_>> for String { type Error = Error; fn try_from(value: &Value<'_>) -> Result { Ok(<&str>::try_from(value)?.into()) } } impl<'a, T> TryFrom> for Vec where T: TryFrom>, T::Error: Into, { type Error = Error; fn try_from(value: Value<'a>) -> Result { if let Value::Array(v) = value { Self::try_from(v) } else { Err(Error::IncorrectType) } } } impl TryFrom> for OwnedObjectPath { type Error = Error; fn try_from(value: Value<'_>) -> Result { ObjectPath::try_from(value).map(OwnedObjectPath::from) } } // tuple conversions in `structure` module for avoiding code-duplication. #[cfg(feature = "enumflags2")] impl<'a, F> TryFrom> for enumflags2::BitFlags where F: enumflags2::BitFlag, F::Numeric: TryFrom, Error = Error>, { type Error = Error; fn try_from(value: Value<'a>) -> Result { Self::from_bits(F::Numeric::try_from(value)?) .map_err(|_| Error::Message("Failed to convert to bitflags".into())) } } impl<'a, K, V, H> TryFrom> for HashMap where K: crate::Basic + TryFrom> + std::hash::Hash + std::cmp::Eq, V: TryFrom>, H: BuildHasher + Default, K::Error: Into, V::Error: Into, { type Error = crate::Error; fn try_from(value: Value<'a>) -> Result { if let Value::Dict(v) = value { Self::try_from(v) } else { Err(crate::Error::IncorrectType) } } } impl<'a, T> TryFrom> for Optional where T: TryFrom> + NoneValue + PartialEq<::NoneType>, T::Error: Into, { type Error = crate::Error; fn try_from(value: Value<'a>) -> Result { T::try_from(value).map_err(Into::into).map(|value| { if value == T::null_value() { Optional::from(None) } else { Optional::from(Some(value)) } }) } } // This would be great but somehow it conflicts with some blanket generic implementations from // core: // // impl<'a, T> TryFrom> for Option // // TODO: this could be useful // impl<'a, 'b, T> TryFrom<&'a Value<'b>> for Vec // impl<'a, 'b, K, V, H> TryFrom<&'a Value<'v>> for HashMap // and more.. zvariant-5.2.0/src/gvariant/de.rs000064400000000000000000000704361046102023000150400ustar 00000000000000use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Visitor}; use std::{ffi::CStr, marker::PhantomData, str}; #[cfg(unix)] use std::os::fd::AsFd; use crate::{ de::{DeserializerCommon, ValueParseStage}, framing_offset_size::FramingOffsetSize, framing_offsets::FramingOffsets, serialized::{Context, Format}, utils::*, Basic, Error, ObjectPath, Result, Signature, }; /// Our GVariant deserialization implementation. #[derive(Debug)] pub(crate) struct Deserializer<'de, 'sig, 'f, F>(pub(crate) DeserializerCommon<'de, 'sig, 'f, F>); impl<'de, 'sig, 'f, F> Deserializer<'de, 'sig, 'f, F> { /// Create a Deserializer struct instance. /// /// On Windows, the function doesn't have `fds` argument. pub fn new<'r: 'de>( bytes: &'r [u8], #[cfg(unix)] fds: Option<&'f [F]>, signature: &'sig Signature, ctxt: Context, ) -> Result { assert_eq!(ctxt.format(), Format::GVariant); Ok(Self(DeserializerCommon { ctxt, signature, bytes, #[cfg(unix)] fds, #[cfg(not(unix))] fds: PhantomData, pos: 0, container_depths: Default::default(), })) } } macro_rules! deserialize_basic { ($method:ident) => { fn $method(self, visitor: V) -> Result where V: Visitor<'de>, { let ctxt = Context::new_dbus(self.0.ctxt.endian(), self.0.ctxt.position() + self.0.pos); let mut dbus_de = crate::dbus::Deserializer::(DeserializerCommon:: { ctxt, signature: self.0.signature, bytes: subslice(self.0.bytes, self.0.pos..)?, fds: self.0.fds, pos: 0, container_depths: self.0.container_depths, }); let v = dbus_de.$method(visitor)?; self.0.signature = dbus_de.0.signature; self.0.pos += dbus_de.0.pos; // Basic types don't have anything to do with container depths so not updating it here. Ok(v) } }; } macro_rules! deserialize_as { ($method:ident => $as:ident) => { deserialize_as!($method() => $as()); }; ($method:ident($($in_arg:ident: $type:ty),*) => $as:ident($($as_arg:expr),*)) => { #[inline] fn $method(self, $($in_arg: $type,)* visitor: V) -> Result where V: Visitor<'de>, { self.$as($($as_arg,)* visitor) } } } impl<'de, 'd, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> de::Deserializer<'de> for &'d mut Deserializer<'de, 'sig, 'f, F> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { crate::de::deserialize_any::(self, &self.0.signature, visitor) } deserialize_basic!(deserialize_bool); deserialize_basic!(deserialize_i8); deserialize_basic!(deserialize_i16); deserialize_basic!(deserialize_i32); deserialize_basic!(deserialize_i64); deserialize_basic!(deserialize_u8); deserialize_basic!(deserialize_u16); deserialize_basic!(deserialize_u32); deserialize_basic!(deserialize_u64); deserialize_basic!(deserialize_f32); deserialize_basic!(deserialize_f64); deserialize_basic!(deserialize_identifier); fn deserialize_byte_buf(self, visitor: V) -> Result where V: Visitor<'de>, { let bytes = deserialize_ay(self)?; visitor.visit_byte_buf(bytes.into()) } fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de>, { let bytes = deserialize_ay(self)?; visitor.visit_borrowed_bytes(bytes) } deserialize_as!(deserialize_char => deserialize_str); deserialize_as!(deserialize_string => deserialize_str); deserialize_as!(deserialize_tuple(_l: usize) => deserialize_struct("", &[])); deserialize_as!(deserialize_tuple_struct(n: &'static str, _l: usize) => deserialize_struct(n, &[])); deserialize_as!(deserialize_struct(_n: &'static str, _f: &'static [&'static str]) => deserialize_seq()); deserialize_as!(deserialize_map => deserialize_seq); deserialize_as!(deserialize_ignored_any => deserialize_any); fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de>, { let slice = subslice(self.0.bytes, self.0.pos..)?; let s = match self.0.signature { Signature::Variant => { if slice.contains(&0) { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char('\0'), &"GVariant string type must not contain interior null bytes", )); } // GVariant decided to skip the trailing nul at the end of signature string str::from_utf8(slice).map_err(Error::Utf8)? } Signature::Str | Signature::Signature | Signature::ObjectPath => { let cstr = CStr::from_bytes_with_nul(slice).map_err(|_| -> Error { let unexpected = if self.0.bytes.is_empty() { de::Unexpected::Other("end of byte stream") } else { let c = self.0.bytes[self.0.bytes.len() - 1] as char; de::Unexpected::Char(c) }; de::Error::invalid_value(unexpected, &"nul byte expected at the end of strings") })?; let s = cstr.to_str().map_err(Error::Utf8)?; self.0.pos += s.len() + 1; // string and trailing null byte s } _ => { let expected = format!( "`{}`, `{}`, `{}` or `{}`", <&str>::SIGNATURE_STR, Signature::SIGNATURE_STR, ObjectPath::SIGNATURE_STR, VARIANT_SIGNATURE_CHAR, ); return Err(Error::SignatureMismatch(self.0.signature.clone(), expected)); } }; visitor.visit_borrowed_str(s) } fn deserialize_option(self, visitor: V) -> Result where V: Visitor<'de>, { let alignment = self.0.signature.alignment(self.0.ctxt.format()); self.0.parse_padding(alignment)?; let child_signature = match self.0.signature { Signature::Maybe(child) => child.signature(), _ => { return Err(Error::SignatureMismatch( self.0.signature.clone(), "a maybe".to_string(), )); } }; let fixed_sized_child = child_signature.is_fixed_sized(); if self.0.pos == self.0.bytes.len() { visitor.visit_none() } else { let ctxt = Context::new( self.0.ctxt.format(), self.0.ctxt.endian(), self.0.ctxt.position() + self.0.pos, ); let end = if fixed_sized_child { self.0.bytes.len() } else { self.0.bytes.len() - 1 }; let mut de = Deserializer::(DeserializerCommon { ctxt, signature: child_signature, bytes: subslice(self.0.bytes, self.0.pos..end)?, fds: self.0.fds, pos: 0, container_depths: self.0.container_depths.inc_maybe()?, }); let v = visitor.visit_some(&mut de)?; self.0.pos += de.0.pos; // No need for retaking the container depths as the underlying type can't be incomplete. if !fixed_sized_child { let byte = *subslice(self.0.bytes, self.0.pos)?; if byte != 0 { return Err(de::Error::invalid_value( de::Unexpected::Bytes(&byte.to_le_bytes()), &"0 byte expected at end of Maybe value", )); } self.0.pos += 1; } Ok(v) } } fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de>, { let byte = *subslice(self.0.bytes, self.0.pos)?; if byte != 0 { return Err(de::Error::invalid_value( de::Unexpected::Bytes(&byte.to_le_bytes()), &"0 byte expected for empty tuples (unit type)", )); } self.0.pos += 1; visitor.visit_unit() } fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { visitor.visit_unit() } fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: Visitor<'de>, { visitor.visit_newtype_struct(self) } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de>, { let alignment = self.0.signature.alignment(Format::GVariant); self.0.parse_padding(alignment)?; match self.0.signature { Signature::Variant => { let value_de = ValueDeserializer::new(self)?; visitor.visit_seq(value_de) } Signature::Array(_) => { let array_de = ArrayDeserializer::new(self)?; visitor.visit_seq(array_de) } Signature::Dict { .. } => visitor.visit_map(ArrayDeserializer::new(self)?), Signature::Structure(_) => visitor.visit_seq(StructureDeserializer::new(self)?), Signature::U8 => { // Empty struct: encoded as a `0u8`. let _: u8 = serde::Deserialize::deserialize(&mut *self)?; let start = self.0.pos; let end = self.0.bytes.len(); visitor.visit_seq(StructureDeserializer { de: self, start, end, field_idx: 0, num_fields: 0, offsets_len: 0, offset_size: FramingOffsetSize::U8, }) } _ => Err(Error::SignatureMismatch( self.0.signature.clone(), "a variant, array, dict, structure or u8".to_string(), )), } } fn deserialize_enum( self, name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { let alignment = self.0.signature.alignment(self.0.ctxt.format()); self.0.parse_padding(alignment)?; let v = visitor.visit_enum(crate::de::Enum { de: &mut *self, name, _phantom: PhantomData, })?; Ok(v) } fn is_human_readable(&self) -> bool { false } } fn deserialize_ay<'de, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F>( de: &mut Deserializer<'de, '_, '_, F>, ) -> Result<&'de [u8]> { if !matches!(de.0.signature, Signature::Array(child) if child.signature() == &Signature::U8) { return Err(de::Error::invalid_type(de::Unexpected::Seq, &"ay")); } let ad = ArrayDeserializer::new(de)?; let len = ad.len; de.0.container_depths = de.0.container_depths.dec_array(); de.0.next_slice(len) } struct ArrayDeserializer<'d, 'de, 'sig, 'f, F> { de: &'d mut Deserializer<'de, 'sig, 'f, F>, len: usize, start: usize, // alignment of element element_alignment: usize, // Element signature in case of normal array, key signature in case of dict. child_signature: &'sig Signature, value_signature: Option<&'sig Signature>, // All offsets (GVariant-specific) offsets: Option, // Length of all the offsets after the array offsets_len: usize, // size of the framing offset of last dict-entry key read (GVariant-specific) key_offset_size: Option, } impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> ArrayDeserializer<'d, 'de, 'sig, 'f, F> { fn new(de: &'d mut Deserializer<'de, 'sig, 'f, F>) -> Result { de.0.container_depths = de.0.container_depths.inc_array()?; let alignment = de.0.signature.alignment(Format::GVariant); de.0.parse_padding(alignment)?; let mut len = de.0.bytes.len() - de.0.pos; let (child_signature, value_signature, fixed_sized_key, fixed_sized_child) = match de.0.signature { Signature::Array(child) => (child.signature(), None, false, child.is_fixed_sized()), Signature::Dict { key, value } => ( key.signature(), Some(value.signature()), key.is_fixed_sized(), key.is_fixed_sized() && value.is_fixed_sized(), ), _ => { return Err(Error::SignatureMismatch( de.0.signature.clone(), "an array or dict".to_string(), )); } }; let (offsets, offsets_len, key_offset_size) = if !fixed_sized_child { let (array_offsets, offsets_len) = FramingOffsets::from_encoded_array(subslice(de.0.bytes, de.0.pos..)?)?; len -= offsets_len; let key_offset_size = if !fixed_sized_key { // The actual offset for keys is calculated per key later, this is just to // put Some value to indicate at key is not fixed sized and thus uses // offsets. Some(FramingOffsetSize::U8) } else { None }; (Some(array_offsets), offsets_len, key_offset_size) } else { (None, 0, None) }; let start = de.0.pos; Ok(Self { de, len, start, element_alignment: alignment, child_signature, value_signature, offsets, offsets_len, key_offset_size, }) } fn element_end(&mut self, pop: bool) -> Result { match self.offsets.as_mut() { Some(offsets) => { assert_eq!(self.de.0.ctxt.format(), Format::GVariant); let offset = if pop { offsets.pop() } else { offsets.peek() }; match offset { Some(offset) => Ok(self.start + offset), None => Err(Error::MissingFramingOffset), } } None => Ok(self.start + self.len), } } fn done(&self) -> bool { match self.offsets.as_ref() { // If all offsets have been popped/used, we're already at the end Some(offsets) => offsets.is_empty(), None => self.de.0.pos == self.start + self.len, } } } impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de> for ArrayDeserializer<'d, 'de, 'sig, 'f, F> { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> where T: DeserializeSeed<'de>, { if self.done() { self.de.0.pos += self.offsets_len; self.de.0.container_depths = self.de.0.container_depths.dec_array(); return Ok(None); } let ctxt = Context::new( self.de.0.ctxt.format(), self.de.0.ctxt.endian(), self.de.0.ctxt.position() + self.de.0.pos, ); let end = self.element_end(true)?; let mut de = Deserializer::(DeserializerCommon { ctxt, signature: &self.child_signature, bytes: subslice(self.de.0.bytes, self.de.0.pos..end)?, fds: self.de.0.fds, pos: 0, container_depths: self.de.0.container_depths, }); let v = seed.deserialize(&mut de).map(Some); self.de.0.pos += de.0.pos; // No need for retaking the container depths as the child can't be incomplete. if self.de.0.pos > self.start + self.len { return Err(serde::de::Error::invalid_length( self.len, &format!(">= {}", self.de.0.pos - self.start).as_str(), )); } v } } impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> MapAccess<'de> for ArrayDeserializer<'d, 'de, 'sig, 'f, F> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: DeserializeSeed<'de>, { if self.done() { self.de.0.pos += self.offsets_len; self.de.0.container_depths = self.de.0.container_depths.dec_array(); return Ok(None); } self.de.0.parse_padding(self.element_alignment)?; let ctxt = Context::new( self.de.0.ctxt.format(), self.de.0.ctxt.endian(), self.de.0.ctxt.position() + self.de.0.pos, ); let element_end = self.element_end(false)?; let key_end = match self.key_offset_size { Some(_) => { if self.de.0.pos > element_end { return Err(serde::de::Error::invalid_length( self.de.0.pos, &format!("< {}", element_end).as_str(), )); } let offset_size = FramingOffsetSize::for_encoded_container(element_end - self.de.0.pos); self.key_offset_size.replace(offset_size); self.de.0.pos + offset_size .read_last_offset_from_buffer(&self.de.0.bytes[self.de.0.pos..element_end]) } None => element_end, }; let mut de = Deserializer::(DeserializerCommon { ctxt, signature: &self.child_signature, bytes: subslice(self.de.0.bytes, self.de.0.pos..key_end)?, fds: self.de.0.fds, pos: 0, container_depths: self.de.0.container_depths, }); let v = seed.deserialize(&mut de).map(Some); self.de.0.pos += de.0.pos; // No need for retaking the container depths as the key can't be incomplete. if self.de.0.pos > self.start + self.len { return Err(serde::de::Error::invalid_length( self.len, &format!(">= {}", self.de.0.pos - self.start).as_str(), )); } v } fn next_value_seed(&mut self, seed: V) -> Result where V: DeserializeSeed<'de>, { let ctxt = Context::new( self.de.0.ctxt.format(), self.de.0.ctxt.endian(), self.de.0.ctxt.position() + self.de.0.pos, ); let element_end = self.element_end(true)?; let value_end = match self.key_offset_size { Some(key_offset_size) => { if key_offset_size as usize > element_end { return Err(serde::de::Error::invalid_length( key_offset_size as usize, &format!("< {}", element_end).as_str(), )); } element_end - key_offset_size as usize } None => element_end, }; let mut de = Deserializer::(DeserializerCommon { ctxt, signature: self.value_signature.as_ref().unwrap(), bytes: subslice(self.de.0.bytes, self.de.0.pos..value_end)?, fds: self.de.0.fds, pos: 0, container_depths: self.de.0.container_depths, }); let v = seed.deserialize(&mut de); self.de.0.pos += de.0.pos; // No need for retaking the container depths as the value can't be incomplete. if let Some(key_offset_size) = self.key_offset_size { self.de.0.pos += key_offset_size as usize; } if self.de.0.pos > self.start + self.len { return Err(serde::de::Error::invalid_length( self.len, &format!(">= {}", self.de.0.pos - self.start).as_str(), )); } v } } #[derive(Debug)] struct StructureDeserializer<'d, 'de, 'sig, 'f, F> { de: &'d mut Deserializer<'de, 'sig, 'f, F>, start: usize, end: usize, /// Index of the next field to serialize. field_idx: usize, /// The number of fields in the structure. num_fields: usize, // Length of all the offsets after the array offsets_len: usize, // size of the framing offset offset_size: FramingOffsetSize, } impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> StructureDeserializer<'d, 'de, 'sig, 'f, F> { fn new(de: &'d mut Deserializer<'de, 'sig, 'f, F>) -> Result { let num_fields = match de.0.signature { Signature::Structure(fields) => fields.iter().count(), _ => unreachable!("Incorrect signature for struct"), }; let alignment = de.0.signature.alignment(Format::GVariant); de.0.parse_padding(alignment)?; de.0.container_depths = de.0.container_depths.inc_structure()?; let start = de.0.pos; let end = de.0.bytes.len(); let offset_size = FramingOffsetSize::for_encoded_container(end - start); Ok(Self { de, start, end, field_idx: 0, num_fields, offsets_len: 0, offset_size, }) } } impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de> for StructureDeserializer<'d, 'de, 'sig, 'f, F> { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> where T: DeserializeSeed<'de>, { if self.field_idx == self.num_fields { return Ok(None); } let ctxt = Context::new( self.de.0.ctxt.format(), self.de.0.ctxt.endian(), self.de.0.ctxt.position() + self.de.0.pos, ); let signature = self.de.0.signature; let field_signature = match signature { Signature::Structure(fields) => { let signature = fields.iter().nth(self.field_idx).ok_or_else(|| { Error::SignatureMismatch(signature.clone(), "a struct".to_string()) })?; self.field_idx += 1; signature } _ => unreachable!("Incorrect signature for struct"), }; let element_end = if !field_signature.is_fixed_sized() { if self.field_idx == self.num_fields { // This is the last item then and in GVariant format, we don't have offset for it // even if it's non-fixed-sized. self.end } else { let end = self .offset_size .read_last_offset_from_buffer(subslice(self.de.0.bytes, self.start..self.end)?) + self.start; let offset_size = self.offset_size as usize; if offset_size > self.end { return Err(serde::de::Error::invalid_length( offset_size, &format!("< {}", self.end).as_str(), )); } self.end -= offset_size; self.offsets_len += offset_size; end } } else { self.end }; let mut de = Deserializer::(DeserializerCommon { ctxt, signature: field_signature, bytes: subslice(self.de.0.bytes, self.de.0.pos..element_end)?, fds: self.de.0.fds, pos: 0, container_depths: self.de.0.container_depths, }); let v = seed.deserialize(&mut de).map(Some); self.de.0.pos += de.0.pos; // No need for retaking the container depths as the field can't be incomplete. if self.field_idx == self.num_fields { // All fields have been deserialized. self.de.0.container_depths = self.de.0.container_depths.dec_structure(); // Skip over the framing offsets (if any) self.de.0.pos += self.offsets_len; } v } } #[derive(Debug)] struct ValueDeserializer<'d, 'de, 'sig, 'f, F> { de: &'d mut Deserializer<'de, 'sig, 'f, F>, stage: ValueParseStage, sig_start: usize, sig_end: usize, value_start: usize, value_end: usize, } impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> ValueDeserializer<'d, 'de, 'sig, 'f, F> { fn new(de: &'d mut Deserializer<'de, 'sig, 'f, F>) -> Result { de.0.parse_padding(VARIANT_ALIGNMENT_GVARIANT)?; // GVariant format has signature at the end let mut separator_pos = None; if de.0.bytes.is_empty() { return Err(de::Error::invalid_value( de::Unexpected::Other("end of byte stream"), &"nul byte separator between Variant's value & signature", )); } // Search for the nul byte separator for i in (de.0.pos..de.0.bytes.len() - 1).rev() { if de.0.bytes[i] == b'\0' { separator_pos = Some(i); break; } } let (sig_start, sig_end, value_start, value_end) = match separator_pos { None => { return Err(de::Error::invalid_value( de::Unexpected::Bytes(&de.0.bytes[de.0.pos..]), &"nul byte separator between Variant's value & signature", )); } Some(separator_pos) => (separator_pos + 1, de.0.bytes.len(), de.0.pos, separator_pos), }; Ok(ValueDeserializer:: { de, stage: ValueParseStage::Signature, sig_start, sig_end, value_start, value_end, }) } } impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de> for ValueDeserializer<'d, 'de, 'sig, 'f, F> { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> where T: DeserializeSeed<'de>, { match self.stage { ValueParseStage::Signature => { self.stage = ValueParseStage::Value; let mut de = Deserializer::(DeserializerCommon { // No padding in signatures so just pass the same context ctxt: self.de.0.ctxt, signature: &Signature::Variant, bytes: subslice(self.de.0.bytes, self.sig_start..self.sig_end)?, fds: self.de.0.fds, pos: 0, container_depths: self.de.0.container_depths, }); seed.deserialize(&mut de).map(Some) } ValueParseStage::Value => { self.stage = ValueParseStage::Done; let slice = subslice(self.de.0.bytes, self.sig_start..self.sig_end)?; let signature = Signature::from_bytes(slice)?; let ctxt = Context::new( self.de.0.ctxt.format(), self.de.0.ctxt.endian(), self.de.0.ctxt.position() + self.value_start, ); let mut de = Deserializer::(DeserializerCommon { ctxt, signature: &signature, bytes: subslice(self.de.0.bytes, self.value_start..self.value_end)?, fds: self.de.0.fds, pos: 0, container_depths: self.de.0.container_depths.inc_variant()?, }); let v = seed.deserialize(&mut de).map(Some); self.de.0.pos = self.sig_end; v } ValueParseStage::Done => Ok(None), } } } impl<'de, 'd, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> EnumAccess<'de> for crate::de::Enum<&'d mut Deserializer<'de, 'sig, 'f, F>, F> { type Error = Error; type Variant = Self; fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> where V: DeserializeSeed<'de>, { seed.deserialize(&mut *self.de).map(|v| (v, self)) } } zvariant-5.2.0/src/gvariant/mod.rs000064400000000000000000000000671046102023000152200ustar 00000000000000mod de; pub(crate) use de::*; mod ser; pub use ser::*; zvariant-5.2.0/src/gvariant/ser.rs000064400000000000000000000570411046102023000152360ustar 00000000000000use serde::{ ser::{self, SerializeSeq, SerializeTuple}, Serialize, }; use std::{ io::{Seek, Write}, str::{self, FromStr}, }; use crate::{ container_depths::ContainerDepths, framing_offset_size::FramingOffsetSize, framing_offsets::FramingOffsets, serialized::{Context, Format}, utils::*, Error, Result, Signature, }; /// Our serialization implementation. pub(crate) struct Serializer<'ser, W>(pub(crate) crate::SerializerCommon<'ser, W>); impl<'ser, W> Serializer<'ser, W> where W: Write + Seek, { /// Create a GVariant Serializer struct instance. /// /// On Windows, the method doesn't have `fds` argument. pub fn new<'w: 'ser, 'f: 'ser>( signature: &'ser Signature, writer: &'w mut W, #[cfg(unix)] fds: &'f mut crate::ser::FdList, ctxt: Context, ) -> Result { assert_eq!(ctxt.format(), Format::GVariant); Ok(Self(crate::SerializerCommon { ctxt, signature, writer, #[cfg(unix)] fds, bytes_written: 0, value_sign: None, container_depths: Default::default(), })) } fn serialize_maybe(&mut self, value: Option<&T>) -> Result<()> where T: ?Sized + Serialize, { let alignment = self.0.signature.alignment(self.0.ctxt.format()); self.0.add_padding(alignment)?; let mut child_signature = match self.0.signature { Signature::Maybe(child) => child.signature(), _ => { return Err(Error::SignatureMismatch( self.0.signature.clone(), "a maybe".to_string(), )); } }; let fixed_sized_child = child_signature.is_fixed_sized(); let value = match value { Some(value) => value, None => return Ok(()), }; std::mem::swap(&mut self.0.signature, &mut child_signature); self.0.container_depths = self.0.container_depths.inc_maybe()?; value.serialize(&mut *self)?; self.0.container_depths = self.0.container_depths.dec_maybe(); std::mem::swap(&mut self.0.signature, &mut child_signature); if !fixed_sized_child { self.0 .write_all(&b"\0"[..]) .map_err(|e| Error::InputOutput(e.into()))?; } Ok(()) } } macro_rules! serialize_basic { ($method:ident, $type:ty) => { fn $method(self, v: $type) -> Result<()> { let ctxt = Context::new_dbus(self.0.ctxt.endian(), self.0.ctxt.position()); let bytes_written = self.0.bytes_written; let mut dbus_ser = crate::dbus::Serializer(crate::SerializerCommon:: { ctxt, signature: self.0.signature, writer: &mut self.0.writer, #[cfg(unix)] fds: self.0.fds, bytes_written, value_sign: None, container_depths: self.0.container_depths, }); dbus_ser.$method(v)?; self.0.bytes_written = dbus_ser.0.bytes_written; Ok(()) } }; } impl<'ser, 'b, W> ser::Serializer for &'b mut Serializer<'ser, W> where W: Write + Seek, { type Ok = (); type Error = Error; type SerializeSeq = SeqSerializer<'ser, 'b, W>; type SerializeTuple = StructSeqSerializer<'ser, 'b, W>; type SerializeTupleStruct = StructSeqSerializer<'ser, 'b, W>; type SerializeTupleVariant = StructSeqSerializer<'ser, 'b, W>; type SerializeMap = MapSerializer<'ser, 'b, W>; type SerializeStruct = StructSeqSerializer<'ser, 'b, W>; type SerializeStructVariant = StructSeqSerializer<'ser, 'b, W>; serialize_basic!(serialize_bool, bool); serialize_basic!(serialize_i16, i16); serialize_basic!(serialize_i32, i32); serialize_basic!(serialize_i64, i64); serialize_basic!(serialize_u8, u8); serialize_basic!(serialize_u16, u16); serialize_basic!(serialize_u32, u32); serialize_basic!(serialize_u64, u64); serialize_basic!(serialize_f64, f64); fn serialize_i8(self, v: i8) -> Result<()> { // No i8 type in GVariant, let's pretend it's i16 self.serialize_i16(v as i16) } fn serialize_f32(self, v: f32) -> Result<()> { // No f32 type in GVariant, let's pretend it's f64 self.serialize_f64(v as f64) } fn serialize_char(self, v: char) -> Result<()> { // No char type in GVariant, let's pretend it's a string self.serialize_str(&v.to_string()) } fn serialize_str(self, v: &str) -> Result<()> { // Strings in GVariant format require no alignment. if matches!(self.0.signature, Signature::Variant) { self.0.value_sign = Some(Signature::from_str(v)?); // signature is serialized after the value in GVariant return Ok(()); } self.0 .write_all(v.as_bytes()) .map_err(|e| Error::InputOutput(e.into()))?; self.0 .write_all(&b"\0"[..]) .map_err(|e| Error::InputOutput(e.into()))?; Ok(()) } fn serialize_bytes(self, v: &[u8]) -> Result<()> { let seq = self.serialize_seq(Some(v.len()))?; seq.ser .0 .write(v) .map_err(|e| Error::InputOutput(e.into()))?; seq.end() } fn serialize_none(self) -> Result<()> { self.serialize_maybe::<()>(None) } fn serialize_some(self, value: &T) -> Result<()> where T: ?Sized + Serialize, { self.serialize_maybe(Some(value)) } fn serialize_unit(self) -> Result<()> { self.0 .write_all(&b"\0"[..]) .map_err(|e| Error::InputOutput(e.into())) } fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { self.serialize_unit() } fn serialize_unit_variant( self, _name: &'static str, variant_index: u32, variant: &'static str, ) -> Result<()> { if matches!(self.0.signature, Signature::Str) { variant.serialize(self) } else { variant_index.serialize(self) } } fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> where T: ?Sized + Serialize, { value.serialize(self)?; Ok(()) } fn serialize_newtype_variant( self, _name: &'static str, variant_index: u32, _variant: &'static str, value: &T, ) -> Result<()> where T: ?Sized + Serialize, { StructSerializer::enum_variant(self, variant_index) .and_then(|mut ser| ser.serialize_element(value)) } fn serialize_seq(self, _len: Option) -> Result { let signature = self.0.signature; let alignment = signature.alignment(Format::GVariant); self.0.add_padding(alignment)?; let (child_signature, fixed_sized_element) = match signature { Signature::Array(child) => (child.signature(), child.is_fixed_sized()), Signature::Dict { key, value } => ( key.signature(), key.is_fixed_sized() && value.is_fixed_sized(), ), _ => { return Err(Error::SignatureMismatch( self.0.signature.clone(), "an array or dict".to_string(), )); } }; let offsets = (!fixed_sized_element).then(FramingOffsets::new); // In case of an array, we'll only be serializing the array's child elements from now on and // in case of a dict, we'll swap key and value signatures during serlization of each entry, // so let's assume the element signature for array and key signature for dict, from now on. // We restore the original signature at the end of serialization. let array_signature = self.0.signature; self.0.signature = child_signature; self.0.container_depths = self.0.container_depths.inc_array()?; let start = self.0.bytes_written; Ok(SeqSerializer { ser: self, start, element_alignment: alignment, offsets, array_signature, }) } fn serialize_tuple(self, len: usize) -> Result { self.serialize_struct("", len) } fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result { self.serialize_struct(name, len) } fn serialize_tuple_variant( self, _name: &'static str, variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { StructSerializer::enum_variant(self, variant_index).map(StructSeqSerializer::Struct) } fn serialize_map(self, len: Option) -> Result { let (key_signature, value_signature, key_start) = match self.0.signature { Signature::Dict { key, value } => ( key.signature(), value.signature(), (!key.is_fixed_sized()).then_some(0), ), _ => { return Err(Error::SignatureMismatch( self.0.signature.clone(), "a dict".to_string(), )); } }; let seq = self.serialize_seq(len)?; Ok(MapSerializer { seq, key_signature, value_signature, key_start, }) } fn serialize_struct(self, _name: &'static str, len: usize) -> Result { if len == 0 { return StructSerializer::unit(self).map(StructSeqSerializer::Struct); } self.0 .add_padding(self.0.signature.alignment(self.0.ctxt.format()))?; match &self.0.signature { Signature::Variant => StructSerializer::variant(self).map(StructSeqSerializer::Struct), Signature::Array(_) => self.serialize_seq(Some(len)).map(StructSeqSerializer::Seq), Signature::Structure(_) => { StructSerializer::structure(self).map(StructSeqSerializer::Struct) } _ => { return Err(Error::SignatureMismatch( self.0.signature.clone(), "a struct, array or variant".to_string(), )); } } } fn serialize_struct_variant( self, _name: &'static str, variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { StructSerializer::enum_variant(self, variant_index).map(StructSeqSerializer::Struct) } fn is_human_readable(&self) -> bool { false } } #[doc(hidden)] pub struct SeqSerializer<'ser, 'b, W> { ser: &'b mut Serializer<'ser, W>, start: usize, // alignment of element element_alignment: usize, // All offsets offsets: Option, array_signature: &'ser Signature, } impl<'ser, 'b, W> SeqSerializer<'ser, 'b, W> where W: Write + Seek, { pub(self) fn end_seq(self) -> Result<()> { self.ser.0.container_depths = self.ser.0.container_depths.dec_array(); self.ser.0.signature = self.array_signature; let offsets = match self.offsets { Some(offsets) => offsets, None => return Ok(()), }; let array_len = self.ser.0.bytes_written - self.start; if array_len == 0 { // Empty sequence return Ok(()); } offsets.write_all(&mut self.ser.0, array_len)?; Ok(()) } } impl<'ser, 'b, W> ser::SerializeSeq for SeqSerializer<'ser, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { value.serialize(&mut *self.ser)?; if let Some(ref mut offsets) = self.offsets { let offset = self.ser.0.bytes_written - self.start; offsets.push(offset); } Ok(()) } fn end(self) -> Result<()> { self.end_seq() } } #[doc(hidden)] pub struct StructSerializer<'ser, 'b, W> { ser: &'b mut Serializer<'ser, W>, start: usize, // All offsets offsets: Option, // The original container depths. We restore to that at the end. container_depths: ContainerDepths, // Index of the next field to serialize. field_idx: usize, } impl<'ser, 'b, W> StructSerializer<'ser, 'b, W> where W: Write + Seek, { fn variant(ser: &'b mut Serializer<'ser, W>) -> Result { ser.0.add_padding(VARIANT_ALIGNMENT_GVARIANT)?; let offsets = match ser.0.signature { Signature::Structure(_) => Some(FramingOffsets::new()), _ => None, }; let start = ser.0.bytes_written; let container_depths = ser.0.container_depths; ser.0.container_depths = ser.0.container_depths.inc_variant()?; Ok(Self { ser, offsets, start, container_depths, field_idx: 0, }) } fn structure(ser: &'b mut Serializer<'ser, W>) -> Result { let alignment = ser.0.signature.alignment(Format::GVariant); ser.0.add_padding(alignment)?; let offsets = match ser.0.signature { Signature::Structure(_) => Some(FramingOffsets::new()), _ => None, }; let start = ser.0.bytes_written; let container_depths = ser.0.container_depths; ser.0.container_depths = ser.0.container_depths.inc_structure()?; Ok(Self { ser, offsets, start, container_depths, field_idx: 0, }) } fn unit(ser: &'b mut Serializer<'ser, W>) -> Result { // serialize as a `0u8` serde::Serializer::serialize_u8(&mut *ser, 0)?; let start = ser.0.bytes_written; let container_depths = ser.0.container_depths; Ok(Self { ser, offsets: None, start, container_depths, field_idx: 0, }) } fn enum_variant(ser: &'b mut Serializer<'ser, W>, variant_index: u32) -> Result { // Encode enum variants as a struct with first field as variant index let Signature::Structure(fields) = &ser.0.signature else { return Err(Error::SignatureMismatch( ser.0.signature.clone(), "a struct".to_string(), )); }; let struct_field = fields.iter().nth(1).and_then(|f| { if matches!(f, Signature::Structure(_)) { Some(f) } else { None } }); let alignment = ser.0.signature.alignment(Format::GVariant); ser.0.add_padding(alignment)?; let mut struct_ser = Self::structure(ser)?; struct_ser.serialize_struct_element(&variant_index)?; if let Some(field) = struct_field { // Add struct padding for inner struct and pretend we're the inner struct. let alignment = field.alignment(Format::GVariant); struct_ser.ser.0.add_padding(alignment)?; struct_ser.field_idx = 0; struct_ser.ser.0.signature = field; } Ok(struct_ser) } fn serialize_struct_element(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { let signature = self.ser.0.signature; let (field_signature, is_variant_value) = match signature { Signature::Variant => { match &self.ser.0.value_sign { // Serializing the value of a Value, which means signature was serialized // already, and also put aside for us to be picked here. Some(signature) => (signature, true), // Serializing the signature of a Value. None => (&Signature::Variant, false), } } Signature::Structure(fields) => { let signature = fields.iter().nth(self.field_idx).ok_or_else(|| { Error::SignatureMismatch(signature.clone(), "a struct".to_string()) })?; self.field_idx += 1; (signature, false) } _ => unreachable!("Incorrect signature for struct or variant"), }; let bytes_written = self.ser.0.bytes_written; let mut ser = Serializer(crate::SerializerCommon:: { ctxt: self.ser.0.ctxt, signature: field_signature, writer: self.ser.0.writer, #[cfg(unix)] fds: self.ser.0.fds, bytes_written, value_sign: None, container_depths: self.ser.0.container_depths, }); value.serialize(&mut ser)?; self.ser.0.bytes_written = ser.0.bytes_written; let field_signature = field_signature.clone(); self.ser.0.value_sign = ser.0.value_sign; match signature { Signature::Variant if is_variant_value => { self.ser .0 .write_all(&b"\0"[..]) .map_err(|e| Error::InputOutput(e.into()))?; write!(self.ser.0, "{field_signature}") .map_err(|e| Error::InputOutput(e.into()))?; } Signature::Variant => (), Signature::Structure(_) => { if let Some(ref mut offsets) = self.offsets { if !field_signature.is_fixed_sized() { offsets.push_front(self.ser.0.bytes_written - self.start); } } } _ => unreachable!("Incorrect signature for struct"), }; Ok(()) } fn end_struct(self) -> Result<()> { // Restore the original container depths. self.ser.0.container_depths = self.container_depths; let mut offsets = match self.offsets { Some(offsets) => offsets, None => return Ok(()), }; let struct_len = self.ser.0.bytes_written - self.start; if struct_len == 0 { // Empty sequence return Ok(()); } if offsets.peek() == Some(struct_len) { // For structs, we don't want offset of last element offsets.pop(); } offsets.write_all(&mut self.ser.0, struct_len)?; Ok(()) } } #[doc(hidden)] /// Allows us to serialize a struct as an ARRAY. pub enum StructSeqSerializer<'ser, 'b, W> { Struct(StructSerializer<'ser, 'b, W>), Seq(SeqSerializer<'ser, 'b, W>), } macro_rules! serialize_struct_anon_fields { ($trait:ident $method:ident) => { impl<'ser, 'b, W> ser::$trait for StructSerializer<'ser, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn $method(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { self.serialize_struct_element(value) } fn end(self) -> Result<()> { self.end_struct() } } impl<'ser, 'b, W> ser::$trait for StructSeqSerializer<'ser, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn $method(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { match self { StructSeqSerializer::Struct(ser) => ser.$method(value), StructSeqSerializer::Seq(ser) => ser.serialize_element(value), } } fn end(self) -> Result<()> { match self { StructSeqSerializer::Struct(ser) => ser.end_struct(), StructSeqSerializer::Seq(ser) => ser.end_seq(), } } } }; } serialize_struct_anon_fields!(SerializeTuple serialize_element); serialize_struct_anon_fields!(SerializeTupleStruct serialize_field); serialize_struct_anon_fields!(SerializeTupleVariant serialize_field); pub(crate) struct MapSerializer<'ser, 'b, W> { seq: SeqSerializer<'ser, 'b, W>, key_signature: &'ser Signature, value_signature: &'ser Signature, // start of last dict-entry key written key_start: Option, } impl<'ser, 'b, W> ser::SerializeMap for MapSerializer<'ser, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<()> where T: ?Sized + Serialize, { self.seq.ser.0.add_padding(self.seq.element_alignment)?; if self.key_start.is_some() { self.key_start.replace(self.seq.ser.0.bytes_written); } key.serialize(&mut *self.seq.ser) } fn serialize_value(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { // For non-fixed-sized keys, we must add the key offset after the value let key_offset = self .key_start .map(|start| self.seq.ser.0.bytes_written - start); self.seq.ser.0.signature = self.value_signature; value.serialize(&mut *self.seq.ser)?; self.seq.ser.0.signature = self.key_signature; if let Some(key_offset) = key_offset { let entry_size = self.seq.ser.0.bytes_written - self.key_start.unwrap_or(0); let offset_size = FramingOffsetSize::for_encoded_container(entry_size); offset_size.write_offset(&mut self.seq.ser.0, key_offset)?; } // And now the offset of the array element end (which is encoded later) if let Some(ref mut offsets) = self.seq.offsets { let offset = self.seq.ser.0.bytes_written - self.seq.start; offsets.push(offset); } Ok(()) } fn end(self) -> Result<()> { self.seq.end_seq() } } macro_rules! serialize_struct_named_fields { ($trait:ident) => { impl<'ser, 'b, W> ser::$trait for StructSerializer<'ser, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> where T: ?Sized + Serialize, { self.serialize_struct_element(value) } fn end(self) -> Result<()> { self.end_struct() } } impl<'ser, 'b, W> ser::$trait for StructSeqSerializer<'ser, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> where T: ?Sized + Serialize, { match self { StructSeqSerializer::Struct(ser) => ser.serialize_field(key, value), StructSeqSerializer::Seq(ser) => ser.serialize_element(value), } } fn end(self) -> Result<()> { match self { StructSeqSerializer::Struct(ser) => ser.end_struct(), StructSeqSerializer::Seq(ser) => ser.end_seq(), } } } }; } serialize_struct_named_fields!(SerializeStruct); serialize_struct_named_fields!(SerializeStructVariant); zvariant-5.2.0/src/into_value.rs000064400000000000000000000100661046102023000147730ustar 00000000000000use std::{collections::HashMap, hash::BuildHasher}; #[cfg(feature = "gvariant")] use crate::Maybe; use crate::{Array, Dict, NoneValue, ObjectPath, Optional, Str, Structure, Type, Value}; #[cfg(unix)] use crate::Fd; // // Conversions from encodable types to `Value` macro_rules! into_value { ($from:ty, $kind:ident) => { impl<'a> From<$from> for Value<'a> { fn from(v: $from) -> Self { Value::$kind(v.into()) } } }; } macro_rules! into_value_from_ref { ($from:ty, $kind:ident) => { impl<'a> From<&'a $from> for Value<'a> { fn from(v: &'a $from) -> Self { Value::$kind(v.clone().into()) } } }; } macro_rules! into_value_from_both { ($from:ty, $kind:ident) => { into_value!($from, $kind); into_value_from_ref!($from, $kind); }; } into_value_from_both!(u8, U8); into_value_from_both!(i8, I16); into_value_from_both!(bool, Bool); into_value_from_both!(u16, U16); into_value_from_both!(i16, I16); into_value_from_both!(u32, U32); into_value_from_both!(i32, I32); into_value_from_both!(u64, U64); into_value_from_both!(i64, I64); into_value_from_both!(f32, F64); into_value_from_both!(f64, F64); into_value_from_both!(&'a str, Str); into_value_from_both!(Str<'a>, Str); into_value_from_both!(ObjectPath<'a>, ObjectPath); macro_rules! try_into_value_from_ref { ($from:ty, $kind:ident) => { impl<'a> TryFrom<&'a $from> for Value<'a> { type Error = crate::Error; fn try_from(v: &'a $from) -> crate::Result { v.try_clone().map(Value::$kind) } } }; } into_value!(Array<'a>, Array); try_into_value_from_ref!(Array<'a>, Array); into_value!(Dict<'a, 'a>, Dict); try_into_value_from_ref!(Dict<'a, 'a>, Dict); #[cfg(feature = "gvariant")] into_value!(Maybe<'a>, Maybe); #[cfg(feature = "gvariant")] try_into_value_from_ref!(Maybe<'a>, Maybe); #[cfg(unix)] into_value!(Fd<'a>, Fd); #[cfg(unix)] try_into_value_from_ref!(Fd<'a>, Fd); impl From for Value<'_> { fn from(v: String) -> Self { Value::Str(crate::Str::from(v)) } } impl<'v, 's: 'v, T> From for Value<'v> where T: Into>, { fn from(v: T) -> Value<'v> { Value::Structure(v.into()) } } impl<'v, V> From<&'v [V]> for Value<'v> where &'v [V]: Into>, { fn from(v: &'v [V]) -> Value<'v> { Value::Array(v.into()) } } impl<'v, V> From> for Value<'v> where Vec: Into>, { fn from(v: Vec) -> Value<'v> { Value::Array(v.into()) } } impl<'v, V> From<&'v Vec> for Value<'v> where &'v Vec: Into>, { fn from(v: &'v Vec) -> Value<'v> { Value::Array(v.into()) } } impl<'a, 'k, 'v, K, V, H> From> for Value<'a> where 'k: 'a, 'v: 'a, K: Type + Into> + std::hash::Hash + std::cmp::Eq, V: Type + Into>, H: BuildHasher + Default, { fn from(value: HashMap) -> Self { Self::Dict(value.into()) } } impl<'v> From<&'v String> for Value<'v> { fn from(v: &'v String) -> Value<'v> { Value::Str(v.into()) } } impl<'v, V> From> for Value<'v> where V: Into> + NoneValue, { fn from(v: Optional) -> Value<'v> { Option::::from(v) .unwrap_or_else(|| V::null_value()) .into() } } #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] impl<'v, V> From> for Value<'v> where Option: Into>, { fn from(v: Option) -> Value<'v> { Value::Maybe(v.into()) } } #[cfg(feature = "option-as-array")] impl<'v, V> From> for Value<'v> where V: Into> + Type, { fn from(v: Option) -> Value<'v> { let mut array = Array::new(V::SIGNATURE); if let Some(v) = v { // We got the signature from the `Type` impl, so this should never panic. array.append(v.into()).expect("signature mismatch"); } array.into() } } zvariant-5.2.0/src/lib.rs000064400000000000000000002041721046102023000133770ustar 00000000000000#![allow(clippy::unusual_byte_groupings)] #![deny(rust_2018_idioms)] #![doc( html_logo_url = "https://raw.githubusercontent.com/dbus2/zbus/9f7a90d2b594ddc48b7a5f39fda5e00cd56a7dfb/logo.png" )] #![doc = include_str!("../README.md")] #![doc(test(attr( warn(unused), deny(warnings), allow(dead_code), // W/o this, we seem to get some bogus warning about `extern crate zbus`. allow(unused_extern_crates), )))] #![cfg_attr(test, recursion_limit = "256")] #[macro_use] mod utils; pub use utils::*; mod array; pub use array::*; mod basic; pub use basic::*; mod dict; pub use dict::*; pub mod serialized; #[cfg(unix)] mod fd; #[cfg(unix)] pub use fd::*; mod object_path; pub use crate::object_path::*; mod ser; pub use ser::*; mod de; pub mod dbus; #[cfg(feature = "gvariant")] pub mod gvariant; pub mod signature; pub use signature::Signature; mod str; pub use crate::str::*; mod structure; pub use crate::structure::*; #[cfg(feature = "gvariant")] mod maybe; #[cfg(feature = "gvariant")] pub use crate::maybe::*; mod optional; pub use crate::optional::*; mod value; pub use value::*; mod serialize_value; pub use serialize_value::*; mod deserialize_value; pub use deserialize_value::*; mod error; pub use error::*; #[macro_use] mod r#type; pub use r#type::*; mod tuple; pub use tuple::*; mod from_value; mod into_value; mod owned_value; pub use owned_value::*; #[cfg(feature = "gvariant")] mod framing_offset_size; #[cfg(feature = "gvariant")] mod framing_offsets; mod container_depths; pub use zvariant_derive::{DeserializeDict, OwnedValue, SerializeDict, Type, Value}; // Required for the macros to function within this crate. extern crate self as zvariant; // Macro support module, not part of the public API. #[doc(hidden)] pub mod export { pub use serde; } // Re-export all of the `endi` API for ease of use. pub use endi::*; #[cfg(test)] #[allow(clippy::disallowed_names)] mod tests { use std::collections::{BTreeMap, HashMap}; #[cfg(feature = "arrayvec")] use arrayvec::{ArrayString, ArrayVec}; use serde_json::json; #[cfg(feature = "arrayvec")] use std::str::FromStr; use serde::{Deserialize, Serialize}; use crate::{to_bytes, to_bytes_for_signature, MaxDepthExceeded}; #[cfg(unix)] use crate::Fd; use crate::{ serialized::{Context, Format}, Array, Basic, DeserializeDict, DeserializeValue, Dict, Error, ObjectPath, Result, SerializeDict, SerializeValue, Str, Structure, Type, Value, BE, LE, NATIVE_ENDIAN, }; // Test through both generic and specific API (wrt byte order) macro_rules! basic_type_test { ($endian:expr, $format:ident, $test_value:expr, $expected_len:expr, $expected_ty:ty, $align:literal) => {{ // Lie that we're starting at byte 1 in the overall message to test padding let ctxt = Context::new(Format::$format, $endian, 1); let encoded = to_bytes(ctxt, &$test_value).unwrap(); let padding = crate::padding_for_n_bytes(1, $align); assert_eq!( encoded.len(), $expected_len + padding, "invalid encoding using `to_bytes`" ); let (decoded, parsed): ($expected_ty, _) = encoded.deserialize().unwrap(); assert!(decoded == $test_value, "invalid decoding"); assert!(parsed == encoded.len(), "invalid parsing"); // Now encode w/o padding let ctxt = Context::new(Format::$format, $endian, 0); let encoded = to_bytes(ctxt, &$test_value).unwrap(); assert_eq!( encoded.len(), $expected_len, "invalid encoding using `to_bytes`" ); encoded }}; ($endian:expr, $format:ident, $test_value:expr, $expected_len:expr, $expected_ty:ty, $align:literal, $kind:ident, $expected_value_len:expr) => {{ let encoded = basic_type_test!( $endian, $format, $test_value, $expected_len, $expected_ty, $align ); // As Value let v: Value<'_> = $test_value.into(); assert_eq!(v.value_signature(), <$expected_ty>::SIGNATURE_STR); assert_eq!(v, Value::$kind($test_value)); value_test!(LE, $format, v, $expected_value_len); let v: $expected_ty = v.try_into().unwrap(); assert_eq!(v, $test_value); encoded }}; } macro_rules! value_test { ($endian:expr, $format:ident, $test_value:expr, $expected_len:expr) => {{ let ctxt = Context::new(Format::$format, $endian, 0); let encoded = to_bytes(ctxt, &$test_value).unwrap(); assert_eq!( encoded.len(), $expected_len, "invalid encoding using `to_bytes`" ); let (decoded, parsed): (Value<'_>, _) = encoded.deserialize().unwrap(); assert!(decoded == $test_value, "invalid decoding"); assert!(parsed == encoded.len(), "invalid parsing"); encoded }}; } fn f64_type_test( format: Format, value: f64, expected_len: usize, expected_value_len: usize, ) -> crate::serialized::Data<'static, 'static> { // Lie that we're starting at byte 1 in the overall message to test padding let ctxt = Context::new(format, NATIVE_ENDIAN, 1); let encoded = to_bytes(ctxt, &value).unwrap(); let padding = crate::padding_for_n_bytes(1, 8); assert_eq!( encoded.len(), expected_len + padding, "invalid encoding using `to_bytes`" ); let decoded: f64 = encoded.deserialize().unwrap().0; assert!( (decoded - value).abs() < f64::EPSILON, "invalid decoding using `from_slice`" ); // Now encode w/o padding let ctxt = Context::new(format, NATIVE_ENDIAN, 0); let encoded = to_bytes(ctxt, &value).unwrap(); assert_eq!( encoded.len(), expected_len, "invalid encoding using `to_bytes`" ); f64_type_test_as_value(format, value, expected_value_len); encoded } fn f64_type_test_as_value(format: Format, value: f64, expected_value_len: usize) { let v: Value<'_> = value.into(); assert_eq!(v.value_signature(), f64::SIGNATURE_STR); assert_eq!(v, Value::F64(value)); f64_value_test(format, v.try_clone().unwrap(), expected_value_len); let v: f64 = v.try_into().unwrap(); assert!((v - value).abs() < f64::EPSILON); } fn f64_value_test(format: Format, v: Value<'_>, expected_value_len: usize) { let ctxt = Context::new(format, LE, 0); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!( encoded.len(), expected_value_len, "invalid encoding using `to_bytes`" ); let decoded: Value<'_> = encoded.deserialize().unwrap().0; assert!(decoded == v, "invalid decoding using `from_slice`"); } // All fixed size types have the same encoding in DBus and GVariant formats. // // NB: Value (i-e VARIANT type) isn't a fixed size type. #[test] fn u8_value() { let encoded = basic_type_test!(LE, DBus, 77_u8, 1, u8, 1, U8, 4); assert_eq!(encoded.len(), 1); #[cfg(feature = "gvariant")] basic_type_test!(LE, GVariant, 77_u8, 1, u8, 1, U8, 3); } #[test] fn i8_value() { basic_type_test!(LE, DBus, 77_i8, 2, i8, 2); #[cfg(feature = "gvariant")] basic_type_test!(LE, GVariant, 77_i8, 2, i8, 2); } #[cfg(unix)] macro_rules! fd_value_test { ($endian:expr, $format:ident, $test_value:expr, $expected_len:expr, $align:literal, $expected_value_len:expr) => {{ use std::os::fd::AsFd; // Lie that we're starting at byte 1 in the overall message to test padding let ctxt = Context::new(Format::$format, $endian, 1); let encoded = to_bytes(ctxt, &$test_value).unwrap(); let padding = crate::padding_for_n_bytes(1, $align); assert_eq!( encoded.len(), $expected_len + padding, "invalid encoding using `to_bytes`" ); #[cfg(unix)] let (_, parsed): (Fd<'_>, _) = encoded.deserialize().unwrap(); assert!( parsed == encoded.len(), "invalid parsing using `from_slice`" ); // Now encode w/o padding let ctxt = Context::new(Format::$format, $endian, 0); let encoded = to_bytes(ctxt, &$test_value).unwrap(); assert_eq!( encoded.len(), $expected_len, "invalid encoding using `to_bytes`" ); // As Value let v: Value<'_> = $test_value.into(); assert_eq!(v.value_signature(), Fd::SIGNATURE_STR); assert_eq!(v, Value::Fd($test_value)); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(encoded.fds().len(), 1, "invalid encoding using `to_bytes`"); assert_eq!( encoded.len(), $expected_value_len, "invalid encoding using `to_bytes`" ); let (decoded, parsed): (Value<'_>, _) = encoded.deserialize().unwrap(); assert_eq!( decoded, Fd::from(encoded.fds()[0].as_fd()).into(), "invalid decoding using `from_slice`" ); assert_eq!(parsed, encoded.len(), "invalid parsing using `from_slice`"); let v: Fd<'_> = v.try_into().unwrap(); assert_eq!(v, $test_value); }}; } #[cfg(unix)] #[test] fn fd_value() { use std::os::fd::AsFd; let stdout = std::io::stdout(); let fd = stdout.as_fd(); fd_value_test!(LE, DBus, Fd::from(fd), 4, 4, 8); #[cfg(feature = "gvariant")] fd_value_test!(LE, GVariant, Fd::from(fd), 4, 4, 6); } #[test] fn u16_value() { let encoded = basic_type_test!(BE, DBus, 0xABBA_u16, 2, u16, 2, U16, 6); assert_eq!(encoded.len(), 2); #[cfg(feature = "gvariant")] basic_type_test!(BE, GVariant, 0xABBA_u16, 2, u16, 2, U16, 4); } #[test] fn i16_value() { let encoded = basic_type_test!(BE, DBus, -0xAB0_i16, 2, i16, 2, I16, 6); assert_eq!(LE.read_i16(&encoded), 0x50F5_i16); #[cfg(feature = "gvariant")] basic_type_test!(BE, GVariant, -0xAB0_i16, 2, i16, 2, I16, 4); } #[test] fn u32_value() { let encoded = basic_type_test!(BE, DBus, 0xABBA_ABBA_u32, 4, u32, 4, U32, 8); assert_eq!(encoded.len(), 4); #[cfg(feature = "gvariant")] basic_type_test!(BE, GVariant, 0xABBA_ABBA_u32, 4, u32, 4, U32, 6); } #[test] fn i32_value() { let encoded = basic_type_test!(BE, DBus, -0xABBA_AB0_i32, 4, i32, 4, I32, 8); assert_eq!(LE.read_i32(&encoded), 0x5055_44F5_i32); #[cfg(feature = "gvariant")] basic_type_test!(BE, GVariant, -0xABBA_AB0_i32, 4, i32, 4, I32, 6); } // u64 is covered by `value_value` test below #[test] fn i64_value() { let encoded = basic_type_test!(BE, DBus, -0xABBA_ABBA_ABBA_AB0_i64, 8, i64, 8, I64, 16); assert_eq!(LE.read_i64(&encoded), 0x5055_4455_4455_44F5_i64); #[cfg(feature = "gvariant")] basic_type_test!(BE, GVariant, -0xABBA_ABBA_ABBA_AB0_i64, 8, i64, 8, I64, 10); } #[test] fn f64_value() { let encoded = f64_type_test(Format::DBus, 99999.99999_f64, 8, 16); assert!((NATIVE_ENDIAN.read_f64(&encoded) - 99999.99999_f64).abs() < f64::EPSILON); #[cfg(feature = "gvariant")] f64_type_test(Format::GVariant, 99999.99999_f64, 8, 10); } #[test] fn str_value() { let string = String::from("hello world"); basic_type_test!(LE, DBus, string, 16, String, 4); basic_type_test!(LE, DBus, string, 16, &str, 4); // GVariant format now #[cfg(feature = "gvariant")] basic_type_test!(LE, GVariant, string, 12, String, 1); let string = "hello world"; basic_type_test!(LE, DBus, string, 16, &str, 4); basic_type_test!(LE, DBus, string, 16, String, 4); // As Value let v: Value<'_> = string.into(); assert_eq!(v.value_signature(), "s"); assert_eq!(v, Value::new("hello world")); value_test!(LE, DBus, v, 20); #[cfg(feature = "gvariant")] value_test!(LE, GVariant, v, 14); let v: String = v.try_into().unwrap(); assert_eq!(v, "hello world"); // Characters are treated as strings basic_type_test!(LE, DBus, 'c', 6, char, 4); #[cfg(feature = "gvariant")] basic_type_test!(LE, GVariant, 'c', 2, char, 1); // As Value let v: Value<'_> = "c".into(); assert_eq!(v.value_signature(), "s"); let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(encoded.len(), 10); let (v, _) = encoded.deserialize::>().unwrap(); assert_eq!(v, Value::new("c")); } #[cfg(feature = "arrayvec")] #[test] fn array_string_value() { let s = ArrayString::<32>::from_str("hello world!").unwrap(); let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &s).unwrap(); assert_eq!(encoded.len(), 17); let decoded: ArrayString<32> = encoded.deserialize().unwrap().0; assert_eq!(&decoded, "hello world!"); } #[cfg(feature = "heapless")] #[test] fn heapless_string_value() { use heapless::String; let s = String::<32>::try_from("hello world!").unwrap(); let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &s).unwrap(); assert_eq!(encoded.len(), 17); let decoded: String<32> = encoded.deserialize().unwrap().0; assert_eq!(&decoded, "hello world!"); } #[test] fn signature() { use crate::Signature; use std::str::FromStr; let sig = Signature::from_str("yys").unwrap(); // Structure will always add () around the signature if it's a struct. basic_type_test!(LE, DBus, sig, 7, Signature, 1); #[cfg(feature = "gvariant")] basic_type_test!(LE, GVariant, sig, 6, Signature, 1); // As Value let v: Value<'_> = sig.into(); assert_eq!(v.value_signature(), "g"); let encoded = value_test!(LE, DBus, v, 10); let v = encoded.deserialize::>().unwrap().0; assert_eq!(v, Value::Signature(Signature::try_from("yys").unwrap())); // GVariant format now #[cfg(feature = "gvariant")] { let encoded = value_test!(LE, GVariant, v, 8); let v = encoded.deserialize::>().unwrap().0; assert_eq!(v, Value::Signature(Signature::try_from("yys").unwrap())); } } #[test] fn object_path_value() { let o = ObjectPath::try_from("/hello/world").unwrap(); basic_type_test!(LE, DBus, o, 17, ObjectPath<'_>, 4); #[cfg(feature = "gvariant")] basic_type_test!(LE, GVariant, o, 13, ObjectPath<'_>, 1); // As Value let v: Value<'_> = o.into(); assert_eq!(v.value_signature(), "o"); let encoded = value_test!(LE, DBus, v, 21); let v = encoded.deserialize::>().unwrap().0; assert_eq!( v, Value::ObjectPath(ObjectPath::try_from("/hello/world").unwrap()) ); // GVariant format now #[cfg(feature = "gvariant")] { let encoded = value_test!(LE, GVariant, v, 15); let v = encoded.deserialize::>().unwrap().0; assert_eq!( v, Value::ObjectPath(ObjectPath::try_from("/hello/world").unwrap()) ); } } #[cfg(unix)] #[test] fn unit_fds() { let ctxt = Context::new_dbus(BE, 0); let encoded = to_bytes(ctxt, &()).unwrap(); assert_eq!(encoded.len(), 0, "invalid encoding using `to_bytes`"); let _: () = encoded .deserialize() .expect("invalid decoding using `from_slice`") .0; } #[test] fn unit() { let ctxt = Context::new_dbus(BE, 0); let encoded = to_bytes(ctxt, &()).unwrap(); assert_eq!(encoded.len(), 0, "invalid encoding using `to_bytes`"); let _: () = encoded .deserialize() .expect("invalid decoding using `from_slice`") .0; } #[test] fn array_value() { // Let's use D-Bus/GVariant terms // // Array of u8 // // First a normal Rust array that is actually serialized as a struct (thank you Serde!) assert_eq!(<[u8; 2]>::SIGNATURE, "(yy)"); let ay = [77u8, 88]; let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &ay).unwrap(); assert_eq!(encoded.len(), 2); let decoded: [u8; 2] = encoded.deserialize().unwrap().0; assert_eq!(&decoded, &[77u8, 88]); // Then rest of the tests just use ArrayVec, heapless::Vec or Vec #[cfg(feature = "arrayvec")] let ay = ArrayVec::from([77u8, 88]); #[cfg(all(not(feature = "arrayvec"), feature = "heapless"))] let ay = heapless::Vec::<_, 2>::from_slice(&[77u8, 88]).unwrap(); #[cfg(all(not(feature = "arrayvec"), not(feature = "heapless")))] let ay = vec![77u8, 88]; let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &ay).unwrap(); assert_eq!(encoded.len(), 6); #[cfg(feature = "arrayvec")] let decoded: ArrayVec = encoded.deserialize().unwrap().0; #[cfg(all(not(feature = "arrayvec"), feature = "heapless"))] let decoded: heapless::Vec = encoded.deserialize().unwrap().0; #[cfg(all(not(feature = "arrayvec"), not(feature = "heapless")))] let decoded: Vec = encoded.deserialize().unwrap().0; assert_eq!(&decoded.as_slice(), &[77u8, 88]); // GVariant format now #[cfg(feature = "gvariant")] { let ctxt = Context::new_gvariant(LE, 0); let gv_encoded = to_bytes(ctxt, &ay).unwrap(); assert_eq!(gv_encoded.len(), 2); } let ctxt = Context::new_dbus(LE, 0); // As Value let v: Value<'_> = ay[..].into(); assert_eq!(v.value_signature(), "ay"); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(encoded.len(), 10); let v = encoded.deserialize::>().unwrap().0; if let Value::Array(array) = v { assert_eq!(*array.element_signature(), "y"); assert_eq!(array.len(), 2); assert_eq!(array.get(0).unwrap(), Some(77u8)); assert_eq!(array.get(1).unwrap(), Some(88u8)); } else { panic!(); } // Now try as Vec let vec = ay.to_vec(); let encoded = to_bytes(ctxt, &vec).unwrap(); assert_eq!(encoded.len(), 6); // Vec as Value let v: Value<'_> = Array::from(&vec).into(); assert_eq!(v.value_signature(), "ay"); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(encoded.len(), 10); // Empty array let at: Vec = vec![]; let encoded = to_bytes(ctxt, &at).unwrap(); assert_eq!(encoded.len(), 8); // GVariant format now #[cfg(feature = "gvariant")] { let ctxt = Context::new_gvariant(LE, 0); let gv_encoded = to_bytes(ctxt, &at).unwrap(); assert_eq!(gv_encoded.len(), 0); let at = encoded.deserialize::>().unwrap().0; assert_eq!(at.len(), 0); } let ctxt = Context::new_dbus(LE, 0); // As Value let v: Value<'_> = at[..].into(); assert_eq!(v.value_signature(), "at"); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(encoded.len(), 8); let v = encoded.deserialize::>().unwrap().0; if let Value::Array(array) = v { assert_eq!(*array.element_signature(), "t"); assert_eq!(array.len(), 0); } else { panic!(); } // GVariant format now #[cfg(feature = "gvariant")] { let ctxt = Context::new_gvariant(LE, 0); let v: Value<'_> = at[..].into(); let gv_encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(gv_encoded.len(), 3); let v = gv_encoded.deserialize::>().unwrap().0; if let Value::Array(array) = v { assert_eq!(*array.element_signature(), "t"); assert_eq!(array.len(), 0); } else { panic!(); } } let ctxt = Context::new_dbus(LE, 0); // // Array of strings // // Can't use 'as' as it's a keyword let as_ = vec!["Hello", "World", "Now", "Bye!"]; let encoded = to_bytes(ctxt, &as_).unwrap(); assert_eq!(encoded.len(), 45); let decoded = encoded.deserialize::>().unwrap().0; assert_eq!(decoded.len(), 4); assert_eq!(decoded[0], "Hello"); assert_eq!(decoded[1], "World"); let decoded = encoded.deserialize::>().unwrap().0; assert_eq!(decoded.as_slice(), as_.as_slice()); // Decode just the second string let slice = encoded.slice(14..); let decoded: &str = slice.deserialize().unwrap().0; assert_eq!(decoded, "World"); // As Value let v: Value<'_> = as_[..].into(); assert_eq!(v.value_signature(), "as"); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(encoded.len(), 49); let v = encoded.deserialize().unwrap().0; if let Value::Array(array) = v { assert_eq!(*array.element_signature(), "s"); assert_eq!(array.len(), 4); assert_eq!(array[0], Value::new("Hello")); assert_eq!(array[1], Value::new("World")); } else { panic!(); } let v: Value<'_> = as_[..].into(); let a: Array<'_> = v.try_into().unwrap(); let _ve: Vec = a.try_into().unwrap(); // GVariant format now #[cfg(feature = "gvariant")] { let ctxt = Context::new_gvariant(LE, 0); let v: Value<'_> = as_[..].into(); let gv_encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(gv_encoded.len(), 28); } // Array of Struct, which in turn containin an Array (We gotta go deeper!) // Signature: "a(yu(xbxas)s)"); let ar = vec![( // top-most simple fields u8::MAX, u32::MAX, ( // 2nd level simple fields i64::MAX, true, i64::MAX, // 2nd level array field &["Hello", "World"][..], ), // one more top-most simple field "hello", )]; let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &ar).unwrap(); assert_eq!(encoded.len(), 78); #[allow(clippy::type_complexity)] let decoded: Vec<(u8, u32, (i64, bool, i64, Vec<&str>), &str)> = encoded.deserialize().unwrap().0; assert_eq!(decoded.len(), 1); let r = &decoded[0]; assert_eq!(r.0, u8::MAX); assert_eq!(r.1, u32::MAX); let inner_r = &r.2; assert_eq!(inner_r.0, i64::MAX); assert!(inner_r.1); assert_eq!(inner_r.2, i64::MAX); let as_ = &inner_r.3; assert_eq!(as_.len(), 2); assert_eq!(as_[0], "Hello"); assert_eq!(as_[1], "World"); assert_eq!(r.3, "hello"); // GVariant format now #[cfg(feature = "gvariant")] { let ctxt = Context::new_gvariant(LE, 0); let gv_encoded = to_bytes(ctxt, &ar).unwrap(); assert_eq!(gv_encoded.len(), 54); let decoded: Vec<(u8, u32, (i64, bool, i64, Vec<&str>), &str)> = gv_encoded.deserialize().unwrap().0; assert_eq!(decoded.len(), 1); let r = &decoded[0]; assert_eq!(r.0, u8::MAX); assert_eq!(r.1, u32::MAX); let inner_r = &r.2; assert_eq!(inner_r.0, i64::MAX); assert!(inner_r.1); assert_eq!(inner_r.2, i64::MAX); let as_ = &inner_r.3; assert_eq!(as_.len(), 2); assert_eq!(as_[0], "Hello"); assert_eq!(as_[1], "World"); assert_eq!(r.3, "hello"); } let ctxt = Context::new_dbus(LE, 0); // As Value let v: Value<'_> = ar[..].into(); assert_eq!(v.value_signature(), "a(yu(xbxas)s)"); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(encoded.len(), 94); let v = encoded.deserialize::>().unwrap().0; if let Value::Array(array) = v.try_clone().unwrap() { assert_eq!(*array.element_signature(), "(yu(xbxas)s)"); assert_eq!(array.len(), 1); let r = &array[0]; if let Value::Structure(r) = r { let fields = r.fields(); assert_eq!(fields[0], Value::U8(u8::MAX)); assert_eq!(fields[1], Value::U32(u32::MAX)); if let Value::Structure(r) = &fields[2] { let fields = r.fields(); assert_eq!(fields[0], Value::I64(i64::MAX)); assert_eq!(fields[1], Value::Bool(true)); assert_eq!(fields[2], Value::I64(i64::MAX)); if let Value::Array(as_) = &fields[3] { assert_eq!(as_.len(), 2); assert_eq!(as_[0], Value::new("Hello")); assert_eq!(as_[1], Value::new("World")); } else { panic!(); } } else { panic!(); } assert_eq!(fields[3], Value::new("hello")); } else { panic!(); } } else { panic!(); } // GVariant format now #[cfg(feature = "gvariant")] { use rand::{distributions::Alphanumeric, thread_rng, Rng}; let ctxt = Context::new_gvariant(LE, 0); let gv_encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(gv_encoded.len(), 68); let v: Value<'_> = gv_encoded.deserialize().unwrap().0; if let Value::Array(array) = v { assert_eq!(*array.element_signature(), "(yu(xbxas)s)"); assert_eq!(array.len(), 1); let r = &array.get(0).unwrap().unwrap(); if let Value::Structure(r) = r { let fields = r.fields(); assert_eq!(fields[0], Value::U8(u8::MAX)); assert_eq!(fields[1], Value::U32(u32::MAX)); if let Value::Structure(r) = &fields[2] { let fields = r.fields(); assert_eq!(fields[0], Value::I64(i64::MAX)); assert_eq!(fields[1], Value::Bool(true)); assert_eq!(fields[2], Value::I64(i64::MAX)); if let Value::Array(as_) = &fields[3] { assert_eq!(as_.len(), 2); assert_eq!(as_.get(0).unwrap(), Some("Hello")); assert_eq!(as_.get(1).unwrap(), Some("World")); } else { panic!(); } } else { panic!(); } assert_eq!(fields[3], Value::new("hello")); } else { panic!(); } } else { panic!(); } let mut rng = thread_rng(); // Let's test GVariant ser/de of a 254 byte array with variable-width elements as to // ensure no problems with non-normal BS of GVariant. let as_ = vec![ (&mut rng) .sample_iter(Alphanumeric) .map(char::from) .take(126) .collect::(), (&mut rng) .sample_iter(Alphanumeric) .map(char::from) .take(126) .collect::(), ]; let gv_encoded = to_bytes(ctxt, &as_).unwrap(); // 252 chars + 2 null terminator bytes doesn't leave room for 2 framing offset bytes so // a 2-byte offset is chosen by the serializer. assert_eq!(gv_encoded.len(), 258); // Check if our own deserializer does the right thing let as2: Vec = gv_encoded.deserialize().unwrap().0; assert_eq!(as2, as_); // Test conversion of Array of Value to Vec let v = Value::new(vec![Value::new(43), Value::new("bonjour")]); let av = >::try_from(v).unwrap(); let av = >>::try_from(av).unwrap(); assert_eq!(av[0], Value::new(43)); assert_eq!(av[1], Value::new("bonjour")); let vec = vec![1, 2]; let val = Value::new(&vec); assert_eq!(TryInto::>::try_into(val).unwrap(), vec); } } #[test] fn struct_byte_array() { let ctxt = Context::new_dbus(LE, 0); let value: (Vec, HashMap>) = (Vec::new(), HashMap::new()); let value = zvariant::to_bytes(ctxt, &value).unwrap(); #[cfg(feature = "serde_bytes")] let (bytes, map): (&serde_bytes::Bytes, HashMap<&str, Value<'_>>) = value .deserialize() .expect("Could not deserialize serde_bytes::Bytes in struct.") .0; #[cfg(not(feature = "serde_bytes"))] let (bytes, map): (&[u8], HashMap<&str, Value<'_>>) = value .deserialize() .expect("Could not deserialize u8 slice in struct") .0; assert!(bytes.is_empty()); assert!(map.is_empty()); } #[test] fn struct_value() { // Struct->Value let s: Value<'_> = ("a", "b", (1, 2)).into(); let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &s).unwrap(); assert_eq!(dbg!(encoded.len()), 40); let decoded: Value<'_> = encoded.deserialize().unwrap().0; let s = >::try_from(decoded).unwrap(); let outer = <(Str<'_>, Str<'_>, Structure<'_>)>::try_from(s).unwrap(); assert_eq!(outer.0, "a"); assert_eq!(outer.1, "b"); let inner = <(i32, i32)>::try_from(outer.2).unwrap(); assert_eq!(inner.0, 1); assert_eq!(inner.1, 2); #[derive(Serialize, Deserialize, Type, PartialEq, Debug)] struct Foo { val: u32, } let foo = Foo { val: 99 }; let v = SerializeValue(&foo); let encoded = to_bytes(ctxt, &v).unwrap(); let decoded: DeserializeValue<'_, Foo> = encoded.deserialize().unwrap().0; assert_eq!(decoded.0, foo); // Unit struct should be treated as a 0-sized tuple (the same as unit type) #[derive(Serialize, Deserialize, Type, PartialEq, Debug)] struct Unit; assert_eq!(Unit::SIGNATURE, ""); let encoded = to_bytes(ctxt, &Unit).unwrap(); assert_eq!(encoded.len(), 0); let _decoded: Unit = encoded.deserialize().unwrap().0; // Structs w/o fields should be treated as a unit struct. #[derive(Serialize, Deserialize, Type, PartialEq, Debug)] struct NoFields {} assert_eq!(NoFields::SIGNATURE, "y"); let encoded = to_bytes(ctxt, &NoFields {}).unwrap(); assert_eq!(encoded.len(), 1); let _decoded: NoFields = encoded.deserialize().unwrap().0; #[cfg(feature = "gvariant")] { let ctxt = Context::new_gvariant(LE, 0); let encoded = to_bytes(ctxt, &NoFields {}).unwrap(); assert_eq!(encoded.len(), 1); let _decoded: NoFields = encoded.deserialize().unwrap().0; } } #[test] fn struct_ref() { let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &(&1u32, &2u32)).unwrap(); let decoded: [u32; 2] = encoded.deserialize().unwrap().0; assert_eq!(decoded, [1u32, 2u32]); } #[test] fn dict_value() { let mut map: HashMap = HashMap::new(); map.insert(1, "123"); map.insert(2, "456"); let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &map).unwrap(); assert_eq!(dbg!(encoded.len()), 40); let decoded: HashMap = encoded.deserialize().unwrap().0; assert_eq!(decoded[&1], "123"); assert_eq!(decoded[&2], "456"); // GVariant format now #[cfg(feature = "gvariant")] { let ctxt = Context::new_gvariant(NATIVE_ENDIAN, 0); let gv_encoded = to_bytes(ctxt, &map).unwrap(); assert_eq!(gv_encoded.len(), 30); let map: HashMap = encoded.deserialize().unwrap().0; assert_eq!(map[&1], "123"); assert_eq!(map[&2], "456"); } let ctxt = Context::new_dbus(LE, 0); // As Value let v: Value<'_> = Dict::from(map).into(); assert_eq!(v.value_signature(), "a{xs}"); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(encoded.len(), 48); // Convert it back let dict: Dict<'_, '_> = v.try_into().unwrap(); let map: HashMap = dict.try_clone().unwrap().try_into().unwrap(); assert_eq!(map[&1], "123"); assert_eq!(map[&2], "456"); // Also decode it back let v = encoded.deserialize().unwrap().0; if let Value::Dict(dict) = v { assert_eq!(dict.get::(&1).unwrap().unwrap(), "123"); assert_eq!(dict.get::(&2).unwrap().unwrap(), "456"); } else { panic!(); } // Convert it to a BTreeMap too. let map: BTreeMap = dict.try_into().unwrap(); assert_eq!(map[&1], "123"); assert_eq!(map[&2], "456"); // Use iterator let mut dict = Dict::from(map); let expect = vec![ (Value::from(1i64), Value::from("123")), (Value::from(2i64), Value::from("456")), ]; let expect_iter = expect.iter().map(|(k, v)| (k, v)).collect::>(); let actual = dict.iter().collect::>(); assert_eq!(actual, expect_iter); let actual = dict.iter().collect::>(); assert_eq!(actual, expect_iter); let actual = dict.iter().collect::>(); assert_eq!(actual, expect_iter); for (_, v) in dict.iter_mut() { if let Value::Str(vv) = v { *vv = Str::from(vv.to_string() + "-hello"); } } let actual = dict.into_iter().collect::>(); let expect = vec![ (Value::from(1i64), Value::from("123-hello")), (Value::from(2i64), Value::from("456-hello")), ]; assert_eq!(actual, expect); #[cfg(feature = "gvariant")] { // GVariant-format requires framing offsets for dict entries with variable-length keys // so let's test that. let mut map: HashMap<&str, &str> = HashMap::new(); map.insert("hi", "1234"); map.insert("world", "561"); let ctxt = Context::new_gvariant(NATIVE_ENDIAN, 0); let gv_encoded = to_bytes(ctxt, &map).unwrap(); assert_eq!(gv_encoded.len(), 22); let map: HashMap<&str, &str> = gv_encoded.deserialize().unwrap().0; assert_eq!(map["hi"], "1234"); assert_eq!(map["world"], "561"); // Ensure SerializeValue produces the same result as Value // Tests for https://github.com/dbus2/zbus/issues/868 let mut map = std::collections::HashMap::<&str, &str>::new(); map.insert("k", "v"); let gv_ser_value_encoded = zvariant::to_bytes(ctxt, &zvariant::SerializeValue(&map)).unwrap(); let gv_value_encoded = to_bytes(ctxt, &zvariant::Value::new(map)).unwrap(); assert_eq!(*gv_value_encoded, *gv_ser_value_encoded); // Now the same but empty dict this time let map: HashMap<&str, &str> = HashMap::new(); let gv_encoded = to_bytes(ctxt, &map).unwrap(); assert_eq!(gv_encoded.len(), 0); let map: HashMap<&str, &str> = gv_encoded.deserialize().unwrap().0; assert_eq!(map.len(), 0); } let ctxt = Context::new_dbus(LE, 0); // Now a hand-crafted Dict Value but with a Value as value let mut dict = Dict::new(<&str>::SIGNATURE, Value::SIGNATURE); dict.add("hello", Value::new("there")).unwrap(); dict.add("bye", Value::new("now")).unwrap(); let v: Value<'_> = dict.into(); assert_eq!(v.value_signature(), "a{sv}"); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(dbg!(encoded.len()), 66); let v: Value<'_> = encoded.deserialize().unwrap().0; if let Value::Dict(dict) = v { assert_eq!( dict.get::<&str, Value<'_>>(&"hello").unwrap().unwrap(), Value::new("there") ); assert_eq!( dict.get::<_, Value<'_>>(&"bye").unwrap().unwrap(), Value::new("now") ); // Try converting to a HashMap let map = >>::try_from(dict.try_clone().unwrap()).unwrap(); assert_eq!(map["hello"], Value::new("there")); assert_eq!(map["bye"], Value::new("now")); // Try converting to a BTreeMap let map = >>::try_from(dict).unwrap(); assert_eq!(map["hello"], Value::new("there")); assert_eq!(map["bye"], Value::new("now")); } else { panic!(); } #[derive(SerializeDict, DeserializeDict, Type, PartialEq, Debug)] #[zvariant(signature = "a{sv}")] struct Test { process_id: Option, group_id: Option, user: String, } let test = Test { process_id: Some(42), group_id: None, user: "me".to_string(), }; let encoded = to_bytes(ctxt, &test).unwrap(); assert_eq!(encoded.len(), 51); let decoded: HashMap<&str, Value<'_>> = encoded.deserialize().unwrap().0; assert_eq!(decoded["process_id"], Value::U32(42)); assert_eq!(decoded["user"], Value::new("me")); assert!(!decoded.contains_key("group_id")); let decoded: Test = encoded.deserialize().unwrap().0; assert_eq!(decoded, test); #[derive(SerializeDict, DeserializeDict, Type, PartialEq, Debug)] #[zvariant(signature = "a{sv}")] struct TestMissing { process_id: Option, group_id: Option, user: String, quota: u8, } let decoded: Result<(TestMissing, _)> = encoded.deserialize(); assert_eq!( decoded.unwrap_err(), Error::Message("missing field `quota`".to_string()) ); #[derive(SerializeDict, DeserializeDict, Type, PartialEq, Debug)] #[zvariant(signature = "a{sv}")] struct TestSkipUnknown { process_id: Option, group_id: Option, } let _: TestSkipUnknown = encoded.deserialize().unwrap().0; #[derive(SerializeDict, DeserializeDict, Type, PartialEq, Debug)] #[zvariant(deny_unknown_fields, signature = "a{sv}")] struct TestUnknown { process_id: Option, group_id: Option, } let decoded: Result<(TestUnknown, _)> = encoded.deserialize(); assert_eq!( decoded.unwrap_err(), Error::Message("unknown field `user`, expected `process_id` or `group_id`".to_string()) ); } #[test] fn dict_compare() { // the order in which a dict has been constructed must not play a role // https://github.com/dbus2/zbus/issues/484 let mut dict1 = Dict::new(<&str>::SIGNATURE, Value::SIGNATURE); dict1.add("first", Value::new("value")).unwrap(); dict1.add("second", Value::new("value")).unwrap(); let mut dict2 = Dict::new(<&str>::SIGNATURE, Value::SIGNATURE); dict2.add("second", Value::new("value")).unwrap(); dict2.add("first", Value::new("value")).unwrap(); assert_eq!(dict1, dict2); } #[test] fn value_value() { let ctxt = Context::new_dbus(BE, 0); let encoded = to_bytes(ctxt, &0xABBA_ABBA_ABBA_ABBA_u64).unwrap(); assert_eq!(encoded.len(), 8); assert_eq!(LE.read_u64(&encoded), 0xBAAB_BAAB_BAAB_BAAB_u64); let decoded: u64 = encoded.deserialize().unwrap().0; assert_eq!(decoded, 0xABBA_ABBA_ABBA_ABBA); // Lie about there being bytes before let ctxt = Context::new_dbus(LE, 2); let encoded = to_bytes(ctxt, &0xABBA_ABBA_ABBA_ABBA_u64).unwrap(); assert_eq!(encoded.len(), 14); let decoded: u64 = encoded.deserialize().unwrap().0; assert_eq!(decoded, 0xABBA_ABBA_ABBA_ABBA_u64); let ctxt = Context::new_dbus(LE, 0); // As Value let v: Value<'_> = 0xFEFE_u64.into(); assert_eq!(v.value_signature(), "t"); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(encoded.len(), 16); let v = encoded.deserialize().unwrap().0; assert_eq!(v, Value::U64(0xFEFE)); // And now as Value in a Value let v = Value::Value(Box::new(v)); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(encoded.len(), 16); let v = encoded.deserialize().unwrap().0; if let Value::Value(v) = v { assert_eq!(v.value_signature(), "t"); assert_eq!(*v, Value::U64(0xFEFE)); } else { panic!(); } // Ensure Value works with other Serializer & Deserializer let v: Value<'_> = 0xFEFE_u64.into(); let encoded = serde_json::to_string(&v).unwrap(); let v = serde_json::from_str::>(&encoded).unwrap(); assert_eq!(v, Value::U64(0xFEFE)); // Now a test case for https://github.com/dbus2/zbus/issues/549 #[derive(Deserialize, Serialize, Debug, PartialEq)] struct Data { inner: zvariant::OwnedValue, } let value = zvariant::Value::new("variant-value"); let inner = zvariant::StructureBuilder::new() .add_field("value1".to_string()) .add_field("value2") .append_field(zvariant::Value::new(value)) // let's try to get a variant .build() .unwrap() .try_into() .unwrap(); let data = Data { inner }; let as_json = serde_json::to_value(&data).unwrap(); let expected_json = json!( { "inner": { "signature": "(ssv)", "value": [ "value1", "value2", { "signature": "s", "value": "variant-value" } ] } } ); assert_eq!(expected_json, as_json); let data_again: Data = serde_json::from_str(&as_json.to_string()).unwrap(); assert_eq!(data, data_again); } #[test] fn enums() { use serde::{Deserialize, Serialize}; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] enum Unit { Variant1, Variant2, Variant3, } let ctxts_n_expected_lens = [ // Unit variants are encoded as u32 and that has the same encoding in both formats. [ (Context::new_dbus(BE, 0), 4usize), (Context::new_dbus(BE, 1), 7), (Context::new_dbus(BE, 2), 6), (Context::new_dbus(BE, 3), 5), (Context::new_dbus(BE, 4), 4), ], #[cfg(feature = "gvariant")] [ (Context::new_gvariant(BE, 0), 4usize), (Context::new_gvariant(BE, 1), 7), (Context::new_gvariant(BE, 2), 6), (Context::new_gvariant(BE, 3), 5), (Context::new_gvariant(BE, 4), 4), ], ]; for ctxts_n_expected_len in ctxts_n_expected_lens { for (ctxt, expected_len) in ctxts_n_expected_len { let encoded = to_bytes_for_signature(ctxt, "u", &Unit::Variant2).unwrap(); assert_eq!(encoded.len(), expected_len); let decoded: Unit = encoded.deserialize_for_signature("u").unwrap().0; assert_eq!(decoded, Unit::Variant2); } } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] enum NewType<'s> { Variant1(&'s str), Variant2(&'s str), Variant3(&'s str), } let ctxts_n_expected_lens = [ [ (Context::new_dbus(BE, 0), 14usize), (Context::new_dbus(BE, 1), 21), (Context::new_dbus(BE, 2), 20), (Context::new_dbus(BE, 3), 19), (Context::new_dbus(BE, 4), 18), ], #[cfg(feature = "gvariant")] [ (Context::new_gvariant(BE, 0), 10usize), (Context::new_gvariant(BE, 1), 13), (Context::new_gvariant(BE, 2), 12), (Context::new_gvariant(BE, 3), 11), (Context::new_gvariant(BE, 4), 10), ], ]; for ctxts_n_expected_len in ctxts_n_expected_lens { for (ctxt, expected_len) in ctxts_n_expected_len { let encoded = to_bytes_for_signature(ctxt, "(us)", &NewType::Variant2("hello")).unwrap(); assert_eq!(encoded.len(), expected_len); let decoded: NewType<'_> = encoded.deserialize_for_signature("(us)").unwrap().0; assert_eq!(decoded, NewType::Variant2("hello")); } } #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] enum Structs { Tuple(u8, u32), Struct { y: u8, t: u32 }, } let ctxts_n_expected_lens = [ [ (Context::new_dbus(BE, 0), 16usize), (Context::new_dbus(BE, 1), 23), (Context::new_dbus(BE, 2), 22), (Context::new_dbus(BE, 3), 21), (Context::new_dbus(BE, 4), 20), ], #[cfg(feature = "gvariant")] [ (Context::new_gvariant(BE, 0), 12usize), (Context::new_gvariant(BE, 1), 15), (Context::new_gvariant(BE, 2), 14), (Context::new_gvariant(BE, 3), 13), (Context::new_gvariant(BE, 4), 12), ], ]; // TODO: Provide convenience API to create complex signatures let signature = "(u(yu))"; for ctxts_n_expected_len in ctxts_n_expected_lens { for (ctxt, expected_len) in ctxts_n_expected_len { let encoded = to_bytes_for_signature(ctxt, signature, &Structs::Tuple(42, 42)).unwrap(); assert_eq!(encoded.len(), expected_len); let decoded: Structs = encoded.deserialize_for_signature(signature).unwrap().0; assert_eq!(decoded, Structs::Tuple(42, 42)); let s = Structs::Struct { y: 42, t: 42 }; let encoded = to_bytes_for_signature(ctxt, signature, &s).unwrap(); assert_eq!(encoded.len(), expected_len); let decoded: Structs = encoded.deserialize_for_signature(signature).unwrap().0; assert_eq!(decoded, Structs::Struct { y: 42, t: 42 }); } } } #[test] fn derive() { use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct Struct<'s> { field1: u16, field2: i64, field3: &'s str, } assert_eq!(Struct::SIGNATURE, "(qxs)"); let s = Struct { field1: 0xFF_FF, field2: 0xFF_FF_FF_FF_FF_FF, field3: "hello", }; let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &s).unwrap(); assert_eq!(encoded.len(), 26); let decoded: Struct<'_> = encoded.deserialize().unwrap().0; assert_eq!(decoded, s); #[derive(Deserialize, Serialize, Type)] struct UnitStruct; assert_eq!(UnitStruct::SIGNATURE, <()>::SIGNATURE); let encoded = to_bytes(ctxt, &UnitStruct).unwrap(); assert_eq!(encoded.len(), 0); let _: UnitStruct = encoded.deserialize().unwrap().0; #[repr(u8)] #[derive(Deserialize_repr, Serialize_repr, Type, Debug, PartialEq)] enum Enum { Variant1, Variant2, Variant3, } assert_eq!(Enum::SIGNATURE, u8::SIGNATURE); let encoded = to_bytes(ctxt, &Enum::Variant3).unwrap(); assert_eq!(encoded.len(), 1); let decoded: Enum = encoded.deserialize().unwrap().0; assert_eq!(decoded, Enum::Variant3); #[repr(i64)] #[derive(Deserialize_repr, Serialize_repr, Type, Debug, PartialEq)] enum Enum2 { Variant1, Variant2, Variant3, } assert_eq!(Enum2::SIGNATURE, i64::SIGNATURE); let encoded = to_bytes(ctxt, &Enum2::Variant2).unwrap(); assert_eq!(encoded.len(), 8); let decoded: Enum2 = encoded.deserialize().unwrap().0; assert_eq!(decoded, Enum2::Variant2); #[derive(Deserialize, Serialize, Type, Debug, PartialEq)] enum NoReprEnum { Variant1, Variant2, Variant3, } // issue#265: Panic on deserialization of a structure w/ a unit enum as its last field. let encoded = to_bytes(ctxt, &(NoReprEnum::Variant2,)).unwrap(); let _: (NoReprEnum,) = encoded.deserialize().unwrap().0; assert_eq!(NoReprEnum::SIGNATURE, u32::SIGNATURE); let encoded = to_bytes(ctxt, &NoReprEnum::Variant2).unwrap(); assert_eq!(encoded.len(), 4); let decoded: NoReprEnum = encoded.deserialize().unwrap().0; assert_eq!(decoded, NoReprEnum::Variant2); #[derive(Deserialize, Serialize, Type, Debug, PartialEq)] #[zvariant(signature = "s")] enum StrEnum { Variant1, Variant2, Variant3, } assert_eq!(StrEnum::SIGNATURE, <&str>::SIGNATURE); let encoded = to_bytes(ctxt, &StrEnum::Variant2).unwrap(); assert_eq!(encoded.len(), 13); let decoded: StrEnum = encoded.deserialize().unwrap().0; assert_eq!(decoded, StrEnum::Variant2); #[derive(Deserialize, Serialize, Type)] enum NewType { Variant1(f64), Variant2(f64), } assert_eq!(NewType::SIGNATURE, "(ud)"); #[derive(Deserialize, Serialize, Type)] enum StructFields { Variant1(u16, i64, &'static str), Variant2 { field1: u16, field2: i64, field3: &'static str, }, } assert_eq!(StructFields::SIGNATURE, "(u(qxs))"); #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct AStruct<'s> { field1: u16, field2: &'s [u8], field3: &'s [u8], field4: i64, } assert_eq!(AStruct::SIGNATURE, "(qayayx)"); let s = AStruct { field1: 0xFF_FF, field2: &[77u8; 8], field3: &[77u8; 8], field4: 0xFF_FF_FF_FF_FF_FF, }; let encoded = to_bytes(ctxt, &s).unwrap(); assert_eq!(encoded.len(), 40); let decoded: AStruct<'_> = encoded.deserialize().unwrap().0; assert_eq!(decoded, s); } #[test] fn serialized_size() { let ctxt = Context::new_dbus(LE, 0); let l = crate::serialized_size(ctxt, &()).unwrap(); assert_eq!(*l, 0); #[cfg(unix)] { let stdout = std::io::stdout(); let l = crate::serialized_size(ctxt, &Fd::from(&stdout)).unwrap(); assert_eq!(*l, 4); assert_eq!(l.num_fds(), 1); } let l = crate::serialized_size(ctxt, &('a', "abc", &(1_u32, 2))).unwrap(); assert_eq!(*l, 24); let v = vec![1, 2]; let l = crate::serialized_size(ctxt, &('a', "abc", &v)).unwrap(); assert_eq!(*l, 28); } #[test] #[cfg(feature = "serde_bytes")] fn serde_bytes() { use serde::{Deserialize, Serialize}; use serde_bytes::*; let ctxt = Context::new_dbus(LE, 0); let ay = Bytes::new(&[77u8; 1_000_000]); let encoded = to_bytes(ctxt, &ay).unwrap(); assert_eq!(encoded.len(), 1_000_004); let decoded: ByteBuf = encoded.deserialize().unwrap().0; assert_eq!(decoded.len(), 1_000_000); #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct Struct<'s> { field1: u16, #[serde(with = "serde_bytes")] field2: &'s [u8], field3: i64, } assert_eq!(Struct::SIGNATURE, "(qayx)"); let s = Struct { field1: 0xFF_FF, field2: &[77u8; 512], field3: 0xFF_FF_FF_FF_FF_FF, }; let encoded = to_bytes(ctxt, &s).unwrap(); assert_eq!(encoded.len(), 528); let decoded: Struct<'_> = encoded.deserialize().unwrap().0; assert_eq!(decoded, s); } #[test] #[cfg(all(feature = "serde_bytes", feature = "gvariant"))] fn serde_bytes_gvariant() { use serde::{Deserialize, Serialize}; use serde_bytes::*; let ctxt = Context::new_gvariant(LE, 0); let ay = Bytes::new(&[77u8; 1_000_000]); let encoded = to_bytes(ctxt, &ay).unwrap(); assert_eq!(encoded.len(), 1_000_000); let decoded: ByteBuf = encoded.deserialize().unwrap().0; assert_eq!(decoded.len(), 1_000_000); #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct Struct<'s> { field1: u16, #[serde(with = "serde_bytes")] field2: &'s [u8], field3: i64, } assert_eq!(Struct::SIGNATURE, "(qayx)"); let s = Struct { field1: 0xFF_FF, field2: &[77u8; 512], field3: 0xFF_FF_FF_FF_FF_FF, }; let encoded = to_bytes(ctxt, &s).unwrap(); assert_eq!(encoded.len(), 530); let decoded: Struct<'_> = encoded.deserialize().unwrap().0; assert_eq!(decoded, s); } #[test] #[cfg(any(feature = "gvariant", feature = "option-as-array"))] fn option_value() { #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] let ctxt = Context::new_gvariant(NATIVE_ENDIAN, 0); #[cfg(feature = "option-as-array")] let ctxt = Context::new_dbus(NATIVE_ENDIAN, 0); // First a Some fixed-sized value let mn = Some(16i16); let encoded = to_bytes(ctxt, &mn).unwrap(); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] assert_eq!(encoded.len(), 2); #[cfg(feature = "option-as-array")] assert_eq!(encoded.len(), 6); let decoded: Option = encoded.deserialize().unwrap().0; assert_eq!(decoded, mn); // As Value let v: Value<'_> = mn.into(); let encoded = to_bytes(ctxt, &v).unwrap(); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] assert_eq!(encoded.len(), 5); #[cfg(feature = "option-as-array")] assert_eq!(encoded.len(), 10); let decoded: Value<'_> = encoded.deserialize().unwrap().0; match decoded { #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] Value::Maybe(maybe) => assert_eq!(maybe.get().unwrap(), mn), #[cfg(feature = "option-as-array")] Value::Array(array) => { assert_eq!(i16::try_from(array[0].try_clone().unwrap()).unwrap(), 16i16) } _ => panic!("unexpected value {decoded:?}"), } // Now a None of the same type let mn: Option = None; let encoded = to_bytes(ctxt, &mn).unwrap(); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] assert_eq!(encoded.len(), 0); #[cfg(feature = "option-as-array")] assert_eq!(encoded.len(), 4); let decoded: Option = encoded.deserialize().unwrap().0; assert!(decoded.is_none()); // Next a Some variable-sized value let ms = Some("hello world"); let encoded = to_bytes(ctxt, &ms).unwrap(); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] assert_eq!(encoded.len(), 13); #[cfg(feature = "option-as-array")] assert_eq!(encoded.len(), 20); let decoded: Option<&str> = encoded.deserialize().unwrap().0; assert_eq!(decoded, ms); // As Value let v: Value<'_> = ms.into(); #[cfg(feature = "option-as-array")] match &v { Value::Array(array) => { assert_eq!( String::try_from(array[0].try_clone().unwrap()).unwrap(), ms.unwrap() ) } _ => panic!("unexpected value {v:?}"), } let encoded = to_bytes(ctxt, &v).unwrap(); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] assert_eq!(encoded.len(), 16); #[cfg(feature = "option-as-array")] assert_eq!(encoded.len(), 24); let decoded: Value<'_> = encoded.deserialize().unwrap().0; match decoded { #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] Value::Maybe(maybe) => { assert_eq!(maybe.get::().unwrap().as_deref(), ms); } #[cfg(feature = "option-as-array")] Value::Array(array) => { assert_eq!( String::try_from(array[0].try_clone().unwrap()).unwrap(), ms.unwrap() ) } _ => panic!("unexpected value {decoded:?}"), } // Now a None of the same type let ms: Option<&str> = None; let encoded = to_bytes(ctxt, &ms).unwrap(); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] assert_eq!(encoded.len(), 0); #[cfg(feature = "option-as-array")] assert_eq!(encoded.len(), 4); let decoded: Option<&str> = encoded.deserialize().unwrap().0; assert!(decoded.is_none()); // In a seq type let ams = vec![ Some(String::from("hello world")), Some(String::from("bye world")), ]; let encoded = to_bytes(ctxt, &ams).unwrap(); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] assert_eq!(encoded.len(), 26); #[cfg(feature = "option-as-array")] assert_eq!(encoded.len(), 42); let decoded: Vec> = encoded.deserialize().unwrap().0; assert_eq!(decoded, ams); // As Value let v: Value<'_> = ams.clone().into(); let encoded = to_bytes(ctxt, &v).unwrap(); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] assert_eq!(encoded.len(), 30); #[cfg(feature = "option-as-array")] assert_eq!(encoded.len(), 50); let decoded: Value<'_> = encoded.deserialize().unwrap().0; assert_eq!(v, decoded); // In a struct let structure: (Option, u64, Option) = (Some(String::from("hello world")), 42u64, None); let encoded = to_bytes(ctxt, &structure).unwrap(); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] assert_eq!(encoded.len(), 25); #[cfg(feature = "option-as-array")] assert_eq!(encoded.len(), 36); let decoded: (Option, u64, Option) = encoded.deserialize().unwrap().0; assert_eq!(decoded, structure); // As Value let v: Value<'_> = structure.clone().into(); let encoded = to_bytes(ctxt, &v).unwrap(); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] assert_eq!(encoded.len(), 33); #[cfg(feature = "option-as-array")] assert_eq!(encoded.len(), 52); let decoded: Value<'_> = encoded.deserialize().unwrap().0; assert_eq!(v, decoded); } #[test] fn struct_with_hashmap() { use serde::{Deserialize, Serialize}; let mut hmap = HashMap::new(); hmap.insert("key".into(), "value".into()); #[derive(Type, Deserialize, Serialize, PartialEq, Debug)] struct Foo { hmap: HashMap, } let foo = Foo { hmap }; assert_eq!(Foo::SIGNATURE, "(a{ss})"); let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &(&foo, 1)).unwrap(); let f: Foo = encoded.deserialize().unwrap().0; assert_eq!(f, foo); } #[test] fn issue_59() { // Ensure we don't panic on deserializing tuple of smaller than expected length. let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &("hello",)).unwrap(); let result: Result<((&str, &str), _)> = encoded.deserialize(); assert!(result.is_err()); } #[test] #[cfg(feature = "gvariant")] fn issue_99() { use crate::to_bytes_for_signature; #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct ZVStruct<'s>(#[serde(borrow)] HashMap<&'s str, Value<'s>>); let mut dict = HashMap::new(); dict.insert("hi", Value::from("hello")); dict.insert("bye", Value::from("then")); let element = ZVStruct(dict); let ctxt = Context::new_gvariant(LE, 0); let signature = ZVStruct::SIGNATURE; let encoded = to_bytes_for_signature(ctxt, signature, &element).unwrap(); let _: ZVStruct<'_> = encoded.deserialize_for_signature(signature).unwrap().0; } #[test] fn issue_1145() { // Ensure f32::NAN can be encoded and decoded. let ctxt = Context::new_dbus(LE, 0); { let encoded = to_bytes(ctxt, &f32::NAN).unwrap(); let result: f32 = encoded.deserialize().unwrap().0; assert!(result.is_nan()); } // Ensure f32::INFINITY can be encoded and decoded. { let encoded = to_bytes(ctxt, &f32::INFINITY).unwrap(); let result: f32 = encoded.deserialize().unwrap().0; assert!(result.is_infinite()); } { let encoded = to_bytes(ctxt, &f32::NEG_INFINITY).unwrap(); let result: f32 = encoded.deserialize().unwrap().0; assert!(result.is_infinite()); } } #[cfg(feature = "ostree-tests")] #[test] fn ostree_de() { #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct Summary<'a>(Vec>, #[serde(borrow)] HashMap<&'a str, Value<'a>>); #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct Repo<'a>(&'a str, #[serde(borrow)] Metadata<'a>); #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct Metadata<'a>(u64, Vec, #[serde(borrow)] HashMap<&'a str, Value<'a>>); let encoded = std::fs::read("../test-data/flatpak-summary.dump").unwrap(); let ctxt = Context::new_gvariant(LE, 0); let encoded = crate::serialized::Data::new(encoded, ctxt); let _: Summary<'_> = encoded.deserialize().unwrap().0; // If we're able to deserialize all the data successfully, don't bother checking the summary // data. } #[test] fn recursion_limits() { let ctxt = Context::new_dbus(LE, 0); // Total container depth exceeds limit (64) let mut value = Value::from(0u8); for _ in 0..64 { value = Value::Value(Box::new(value)); } assert!(matches!( to_bytes(ctxt, &value), Err(Error::MaxDepthExceeded(MaxDepthExceeded::Container)) )); // Array depth exceeds limit (32) let vec = vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![ vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![ vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![ 0u8, ]]]]]]]]]]], ]]]]]]]]]]], ]]]]]]]]]]]; assert!(matches!( to_bytes(ctxt, &vec), Err(Error::MaxDepthExceeded(MaxDepthExceeded::Array)) )); // Struct depth exceeds limit (32) let tuple = (((((((((((((((((((((( (((((((((((0u8,),),),),),),),),),),), ),),),),),),),),),),),),),),),),),),),),),); assert!(matches!( to_bytes(ctxt, &tuple), Err(Error::MaxDepthExceeded(MaxDepthExceeded::Structure)) )); // total depth exceeds limit (64) with struct, array and variant. let mut value = Value::from(0u8); for _ in 0..32 { value = Value::Value(Box::new(value)); } let tuple_array = ( ((((((((((((((((vec![vec![vec![vec![vec![vec![vec![vec![ vec![vec![vec![vec![vec![vec![vec![vec![value]]]]]]]], ]]]]]]]],),),),),),),),),),),),),),),),), ); assert!(matches!( to_bytes(ctxt, &tuple_array), Err(Error::MaxDepthExceeded(MaxDepthExceeded::Container)) )); // TODO: // // * Test deserializers. // * Test gvariant format. } } zvariant-5.2.0/src/maybe.rs000064400000000000000000000117731046102023000137310ustar 00000000000000use serde::ser::{Serialize, Serializer}; use static_assertions::assert_impl_all; use std::fmt::Display; use crate::{value_display_fmt, Error, Signature, Type, Value}; /// A helper type to wrap `Option` (GVariant's Maybe type) in [`Value`]. /// /// API is provided to convert from, and to `Option`. /// /// [`Value`]: enum.Value.html #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Maybe<'a> { value: Box>>, signature: Signature, } assert_impl_all!(Maybe<'_>: Send, Sync, Unpin); impl<'a> Maybe<'a> { /// Get a reference to underlying value. pub fn inner(&self) -> &Option> { &self.value } /// Create a new Just (Some) `Maybe`. pub fn just(value: Value<'a>) -> Self { let value_signature = value.value_signature().clone(); let signature = Signature::maybe(value_signature); Self { signature, value: Box::new(Some(value)), } } pub(crate) fn just_full_signature(value: Value<'a>, signature: &Signature) -> Self { Self { signature: signature.clone(), value: Box::new(Some(value)), } } /// Create a new Nothing (None) `Maybe`, given the signature of the type. pub fn nothing(value_signature: &Signature) -> Self { let signature = Signature::maybe(value_signature.clone()); Self { signature, value: Box::new(None), } } pub(crate) fn nothing_full_signature(signature: &Signature) -> Self { Self { signature: signature.clone(), value: Box::new(None), } } /// Get the inner value as a concrete type pub fn get(&'a self) -> core::result::Result, Error> where T: ?Sized + TryFrom<&'a Value<'a>>, >>::Error: Into, { self.value .as_ref() .as_ref() .map(|v| v.downcast_ref()) .transpose() } /// Get the signature of `Maybe`. pub fn signature(&self) -> &Signature { &self.signature } /// Get the signature of the potential value in the `Maybe`. pub fn value_signature(&self) -> &Signature { match self.signature() { Signature::Maybe(signature) => signature, _ => unreachable!("Invalid `Maybe` signature"), } } pub(crate) fn try_to_owned(&self) -> crate::Result> { Ok(Maybe { value: Box::new( self.value .as_ref() .as_ref() .map(|v| v.try_to_owned().map(Into::into)) .transpose()?, ), signature: self.signature.clone(), }) } /// Attempt to clone `self`. pub fn try_clone(&self) -> Result { Ok(Maybe { value: Box::new( self.value .as_ref() .as_ref() .map(|v| v.try_clone().map(Into::into)) .transpose()?, ), signature: self.signature.clone(), }) } } impl Display for Maybe<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { maybe_display_fmt(self, f, true) } } pub(crate) fn maybe_display_fmt( maybe: &Maybe<'_>, f: &mut std::fmt::Formatter<'_>, type_annotate: bool, ) -> std::fmt::Result { if type_annotate { write!(f, "@{} ", maybe.signature())?; } let (last_inner, depth) = { let mut curr = maybe.inner(); let mut depth = 0; while let Some(Value::Maybe(child_maybe)) = curr { curr = child_maybe.inner(); depth += 1; } (curr, depth) }; if let Some(last_inner) = last_inner { // There are no Nothings, so print out the inner value with no prefixes. value_display_fmt(last_inner, f, false)?; } else { // One of the maybes was Nothing, so print out the right number of justs. for _ in 0..depth { f.write_str("just ")?; } f.write_str("nothing")?; } Ok(()) } impl<'a, T> From> for Maybe<'a> where T: Type + Into>, { fn from(value: Option) -> Self { value .map(|v| Self::just(Value::new(v))) .unwrap_or_else(|| Self::nothing(T::SIGNATURE)) } } impl<'a, T> From<&Option> for Maybe<'a> where T: Type + Into> + Clone, { fn from(value: &Option) -> Self { value .as_ref() .map(|v| Self::just(Value::new(v.clone()))) .unwrap_or_else(|| Self::nothing(T::SIGNATURE)) } } impl<'a> Serialize for Maybe<'a> { fn serialize(&self, serializer: S) -> core::result::Result where S: Serializer, { match &*self.value { Some(value) => value.serialize_value_as_some(serializer), None => serializer.serialize_none(), } } } zvariant-5.2.0/src/object_path.rs000064400000000000000000000227511046102023000151140ustar 00000000000000use core::{fmt::Debug, str}; use serde::{ de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, }; use static_assertions::assert_impl_all; use std::borrow::Cow; use crate::{Basic, Error, Result, Str, Type}; /// String that identifies objects at a given destination on the D-Bus bus. /// /// Mostly likely this is only useful in the D-Bus context. /// /// # Examples /// /// ``` /// use zvariant::ObjectPath; /// /// // Valid object paths /// let o = ObjectPath::try_from("/").unwrap(); /// assert_eq!(o, "/"); /// let o = ObjectPath::try_from("/Path/t0/0bject").unwrap(); /// assert_eq!(o, "/Path/t0/0bject"); /// let o = ObjectPath::try_from("/a/very/looooooooooooooooooooooooo0000o0ng/path").unwrap(); /// assert_eq!(o, "/a/very/looooooooooooooooooooooooo0000o0ng/path"); /// /// // Invalid object paths /// ObjectPath::try_from("").unwrap_err(); /// ObjectPath::try_from("/double//slashes/").unwrap_err(); /// ObjectPath::try_from(".").unwrap_err(); /// ObjectPath::try_from("/end/with/slash/").unwrap_err(); /// ObjectPath::try_from("/ha.d").unwrap_err(); /// ``` #[derive(PartialEq, Eq, Hash, Clone, PartialOrd, Ord)] pub struct ObjectPath<'a>(Str<'a>); assert_impl_all!(ObjectPath<'_>: Send, Sync, Unpin); impl<'a> ObjectPath<'a> { /// This is faster than `Clone::clone` when `self` contains owned data. pub fn as_ref(&self) -> ObjectPath<'_> { ObjectPath(self.0.as_ref()) } /// The object path as a string. pub fn as_str(&self) -> &str { self.0.as_str() } /// The object path as bytes. pub fn as_bytes(&self) -> &[u8] { self.0.as_bytes() } /// Create a new `ObjectPath` from given bytes. /// /// Since the passed bytes are not checked for correctness, prefer using the /// `TryFrom<&[u8]>` implementation. /// /// # Safety /// /// See [`std::str::from_utf8_unchecked`]. pub unsafe fn from_bytes_unchecked<'s: 'a>(bytes: &'s [u8]) -> Self { Self(std::str::from_utf8_unchecked(bytes).into()) } /// Create a new `ObjectPath` from the given string. /// /// Since the passed string is not checked for correctness, prefer using the /// `TryFrom<&str>` implementation. pub fn from_str_unchecked<'s: 'a>(path: &'s str) -> Self { Self(path.into()) } /// Same as `try_from`, except it takes a `&'static str`. pub fn from_static_str(name: &'static str) -> Result { validate(name.as_bytes())?; Ok(Self::from_static_str_unchecked(name)) } /// Same as `from_str_unchecked`, except it takes a `&'static str`. pub const fn from_static_str_unchecked(name: &'static str) -> Self { Self(Str::from_static(name)) } /// Same as `from_str_unchecked`, except it takes an owned `String`. /// /// Since the passed string is not checked for correctness, prefer using the /// `TryFrom` implementation. pub fn from_string_unchecked(path: String) -> Self { Self(path.into()) } /// the object path's length. pub fn len(&self) -> usize { self.0.len() } /// if the object path is empty. pub fn is_empty(&self) -> bool { self.0.is_empty() } /// Creates an owned clone of `self`. pub fn to_owned(&self) -> ObjectPath<'static> { ObjectPath(self.0.to_owned()) } /// Creates an owned clone of `self`. pub fn into_owned(self) -> ObjectPath<'static> { ObjectPath(self.0.into_owned()) } } impl std::default::Default for ObjectPath<'_> { fn default() -> Self { ObjectPath::from_static_str_unchecked("/") } } impl Basic for ObjectPath<'_> { const SIGNATURE_CHAR: char = 'o'; const SIGNATURE_STR: &'static str = "o"; } impl Type for ObjectPath<'_> { const SIGNATURE: &'static crate::Signature = &crate::Signature::ObjectPath; } impl<'a> TryFrom<&'a [u8]> for ObjectPath<'a> { type Error = Error; fn try_from(value: &'a [u8]) -> Result { validate(value)?; // SAFETY: ensure_correct_object_path_str checks UTF-8 unsafe { Ok(Self::from_bytes_unchecked(value)) } } } /// Try to create an ObjectPath from a string. impl<'a> TryFrom<&'a str> for ObjectPath<'a> { type Error = Error; fn try_from(value: &'a str) -> Result { Self::try_from(value.as_bytes()) } } impl TryFrom for ObjectPath<'_> { type Error = Error; fn try_from(value: String) -> Result { validate(value.as_bytes())?; Ok(Self::from_string_unchecked(value)) } } impl<'a> TryFrom> for ObjectPath<'a> { type Error = Error; fn try_from(value: Cow<'a, str>) -> Result { match value { Cow::Borrowed(s) => Self::try_from(s), Cow::Owned(s) => Self::try_from(s), } } } impl<'o> From<&ObjectPath<'o>> for ObjectPath<'o> { fn from(o: &ObjectPath<'o>) -> Self { o.clone() } } impl std::ops::Deref for ObjectPath<'_> { type Target = str; fn deref(&self) -> &Self::Target { self.as_str() } } impl PartialEq for ObjectPath<'_> { fn eq(&self, other: &str) -> bool { self.as_str() == other } } impl PartialEq<&str> for ObjectPath<'_> { fn eq(&self, other: &&str) -> bool { self.as_str() == *other } } impl Debug for ObjectPath<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("ObjectPath").field(&self.as_str()).finish() } } impl std::fmt::Display for ObjectPath<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.as_str(), f) } } impl Serialize for ObjectPath<'_> { fn serialize(&self, serializer: S) -> core::result::Result where S: Serializer, { serializer.serialize_str(self.as_str()) } } impl<'de: 'a, 'a> Deserialize<'de> for ObjectPath<'a> { fn deserialize(deserializer: D) -> core::result::Result where D: Deserializer<'de>, { let visitor = ObjectPathVisitor; deserializer.deserialize_str(visitor) } } struct ObjectPathVisitor; impl<'de> Visitor<'de> for ObjectPathVisitor { type Value = ObjectPath<'de>; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("an ObjectPath") } #[inline] fn visit_borrowed_str(self, value: &'de str) -> core::result::Result, E> where E: serde::de::Error, { ObjectPath::try_from(value).map_err(serde::de::Error::custom) } } fn validate(path: &[u8]) -> Result<()> { use winnow::{combinator::separated, stream::AsChar, token::take_while, Parser}; // Rules // // * At least 1 character. // * First character must be `/` // * No trailing `/` // * No `//` // * Only ASCII alphanumeric, `_` or '/' let allowed_chars = (AsChar::is_alphanum, b'_'); let name = take_while::<_, _, ()>(1.., allowed_chars); let mut full_path = (b'/', separated(0.., name, b'/')).map(|_: (u8, ())| ()); full_path.parse(path).map_err(|_| Error::InvalidObjectPath) } /// Owned [`ObjectPath`](struct.ObjectPath.html) #[derive(Debug, Default, Clone, PartialEq, Eq, Hash, serde::Serialize, Type)] pub struct OwnedObjectPath(ObjectPath<'static>); assert_impl_all!(OwnedObjectPath: Send, Sync, Unpin); impl OwnedObjectPath { pub fn into_inner(self) -> ObjectPath<'static> { self.0 } } impl Basic for OwnedObjectPath { const SIGNATURE_CHAR: char = ObjectPath::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = ObjectPath::SIGNATURE_STR; } impl std::ops::Deref for OwnedObjectPath { type Target = ObjectPath<'static>; fn deref(&self) -> &Self::Target { &self.0 } } impl std::convert::From for ObjectPath<'static> { fn from(o: OwnedObjectPath) -> Self { o.into_inner() } } impl std::convert::From for crate::Value<'_> { fn from(o: OwnedObjectPath) -> Self { o.into_inner().into() } } impl<'unowned, 'owned: 'unowned> From<&'owned OwnedObjectPath> for ObjectPath<'unowned> { fn from(o: &'owned OwnedObjectPath) -> Self { ObjectPath::from_str_unchecked(o.as_str()) } } impl<'a> std::convert::From> for OwnedObjectPath { fn from(o: ObjectPath<'a>) -> Self { OwnedObjectPath(o.into_owned()) } } impl TryFrom<&'_ str> for OwnedObjectPath { type Error = Error; fn try_from(value: &str) -> Result { Ok(Self::from(ObjectPath::try_from(value)?)) } } impl TryFrom for OwnedObjectPath { type Error = Error; fn try_from(value: String) -> Result { Ok(Self::from(ObjectPath::try_from(value)?)) } } impl<'de> Deserialize<'de> for OwnedObjectPath { fn deserialize(deserializer: D) -> core::result::Result where D: Deserializer<'de>, { String::deserialize(deserializer) .and_then(|s| ObjectPath::try_from(s).map_err(|e| de::Error::custom(e.to_string()))) .map(Self) } } impl std::fmt::Display for OwnedObjectPath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.as_str(), f) } } #[cfg(test)] mod unit { use super::*; #[test] fn owned_from_reader() { // See https://github.com/dbus2/zbus/issues/287 let json_str = "\"/some/path\""; serde_json::de::from_reader::<_, OwnedObjectPath>(json_str.as_bytes()).unwrap(); } } zvariant-5.2.0/src/optional.rs000064400000000000000000000116001046102023000144460ustar 00000000000000use std::{ fmt::Display, ops::{Deref, DerefMut}, }; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use crate::Type; /// Type that uses a special value to be used as none. /// /// See [`Optional`] documentation for the rationale for this trait's existence. /// /// # Caveats /// /// Since use of default values as none is typical, this trait is implemented for all types that /// implement [`Default`] for convenience. Unfortunately, this means you can not implement this /// trait manually for types that implement [`Default`]. /// /// Moreoever, since `bool` implements [`Default`], `NoneValue` gets implemented for `bool` as well. /// However, this is unsound since its not possible to distinguish between `false` and `None` in /// this case. This is why you'll get a panic on trying to serialize or deserialize an /// `Optionanl`. pub trait NoneValue { type NoneType; /// The none-equivalent value. fn null_value() -> Self::NoneType; } impl NoneValue for T where T: Default, { type NoneType = Self; fn null_value() -> Self { Default::default() } } /// An optional value. /// /// Since D-Bus doesn't have the concept of nullability, it uses a special value (typically the /// default value) as the null value. For example [this signal][ts] uses empty strings for null /// values. Serde has built-in support for `Option` but unfortunately that doesn't work for us. /// Hence the need for this type. /// /// The serialization and deserialization of `Optional` relies on [`NoneValue`] implementation of /// the underlying type. /// /// # Examples /// /// ``` /// use zvariant::{serialized::Context, Optional, to_bytes, LE}; /// /// // `Null` case. /// let ctxt = Context::new_dbus(LE, 0); /// let s = Optional::<&str>::default(); /// let encoded = to_bytes(ctxt, &s).unwrap(); /// assert_eq!(encoded.bytes(), &[0, 0, 0, 0, 0]); /// let s: Optional<&str> = encoded.deserialize().unwrap().0; /// assert_eq!(*s, None); /// /// // `Some` case. /// let s = Optional::from(Some("hello")); /// let encoded = to_bytes(ctxt, &s).unwrap(); /// assert_eq!(encoded.len(), 10); /// // The first byte is the length of the string in Little-Endian format. /// assert_eq!(encoded[0], 5); /// let s: Optional<&str> = encoded.deserialize().unwrap().0; /// assert_eq!(*s, Some("hello")); /// ``` /// /// [ts]: https://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-name-owner-changed #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Optional(Option); impl Type for Optional where T: Type, { const SIGNATURE: &'static crate::Signature = T::SIGNATURE; } impl Serialize for Optional where T: Type + NoneValue + Serialize, ::NoneType: Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { if T::SIGNATURE == bool::SIGNATURE { panic!("`Optional` type is not supported"); } match &self.0 { Some(value) => value.serialize(serializer), None => T::null_value().serialize(serializer), } } } impl<'de, T, E> Deserialize<'de> for Optional where T: Type + NoneValue + Deserialize<'de>, ::NoneType: Deserialize<'de> + TryInto + PartialEq, E: Display, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if T::SIGNATURE == bool::SIGNATURE { panic!("`Optional` type is not supported"); } let value = <::NoneType>::deserialize(deserializer)?; if value == T::null_value() { Ok(Optional(None)) } else { Ok(Optional(Some(value.try_into().map_err(de::Error::custom)?))) } } } impl From> for Optional { fn from(value: Option) -> Self { Optional(value) } } impl From> for Option { fn from(value: Optional) -> Self { value.0 } } impl Deref for Optional { type Target = Option; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for Optional { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl Default for Optional { fn default() -> Self { Self(None) } } #[cfg(test)] mod tests { use std::panic::catch_unwind; #[test] fn bool_in_optional() { // Ensure trying to encode/decode `bool` in `Optional` fails. use crate::{to_bytes, Optional, LE}; let ctxt = crate::serialized::Context::new_dbus(LE, 0); let res = catch_unwind(|| to_bytes(ctxt, &Optional::::default())); assert!(res.is_err()); let data = crate::serialized::Data::new([0, 0, 0, 0].as_slice(), ctxt); let res = catch_unwind(|| data.deserialize::>()); assert!(res.is_err()); } } zvariant-5.2.0/src/owned_value.rs000064400000000000000000000212501046102023000151330ustar 00000000000000use serde::{Deserialize, Deserializer, Serialize}; use static_assertions::assert_impl_all; use std::{collections::HashMap, hash::BuildHasher}; use crate::{ Array, Dict, NoneValue, ObjectPath, Optional, OwnedObjectPath, Signature, Str, Structure, Type, Value, }; #[cfg(unix)] use crate::Fd; #[cfg(feature = "gvariant")] use crate::Maybe; // FIXME: Replace with a generic impl> TryFrom for T? // https://github.com/dbus2/zbus/issues/138 /// Owned [`Value`](enum.Value.html) #[derive(Debug, PartialEq, Serialize, Type)] pub struct OwnedValue(pub(crate) Value<'static>); assert_impl_all!(OwnedValue: Send, Sync, Unpin); impl OwnedValue { /// Attempt to clone the value. pub fn try_clone(&self) -> Result { self.0.try_clone().map(Self) } pub(crate) fn into_inner(self) -> Value<'static> { self.0 } pub(crate) fn inner(&self) -> &Value<'_> { &self.0 } } macro_rules! ov_try_from { ($to:ty) => { impl TryFrom for $to { type Error = crate::Error; fn try_from(v: OwnedValue) -> Result { <$to>::try_from(v.0) } } }; } macro_rules! ov_try_from_ref { ($to:ty) => { impl<'a> TryFrom<&'a OwnedValue> for $to { type Error = crate::Error; fn try_from(v: &'a OwnedValue) -> Result { <$to>::try_from(&v.0) } } }; } ov_try_from!(u8); ov_try_from!(bool); ov_try_from!(i16); ov_try_from!(u16); ov_try_from!(i32); ov_try_from!(u32); ov_try_from!(i64); ov_try_from!(u64); ov_try_from!(f64); ov_try_from!(String); ov_try_from!(Signature); ov_try_from!(ObjectPath<'static>); ov_try_from!(OwnedObjectPath); ov_try_from!(Array<'static>); ov_try_from!(Dict<'static, 'static>); #[cfg(feature = "gvariant")] ov_try_from!(Maybe<'static>); ov_try_from!(Str<'static>); ov_try_from!(Structure<'static>); #[cfg(unix)] ov_try_from!(Fd<'static>); ov_try_from_ref!(u8); ov_try_from_ref!(bool); ov_try_from_ref!(i16); ov_try_from_ref!(u16); ov_try_from_ref!(i32); ov_try_from_ref!(u32); ov_try_from_ref!(i64); ov_try_from_ref!(u64); ov_try_from_ref!(f64); ov_try_from_ref!(&'a str); ov_try_from_ref!(&'a Signature); ov_try_from_ref!(&'a ObjectPath<'a>); ov_try_from_ref!(&'a Array<'a>); ov_try_from_ref!(&'a Dict<'a, 'a>); ov_try_from_ref!(&'a Str<'a>); ov_try_from_ref!(&'a Structure<'a>); #[cfg(feature = "gvariant")] ov_try_from_ref!(&'a Maybe<'a>); #[cfg(unix)] ov_try_from_ref!(&'a Fd<'a>); impl<'a, T> TryFrom for Vec where T: TryFrom>, T::Error: Into, { type Error = crate::Error; fn try_from(value: OwnedValue) -> Result { if let Value::Array(v) = value.0 { Self::try_from(v) } else { Err(crate::Error::IncorrectType) } } } #[cfg(feature = "enumflags2")] impl<'a, F> TryFrom for enumflags2::BitFlags where F: enumflags2::BitFlag, F::Numeric: TryFrom, Error = crate::Error>, { type Error = crate::Error; fn try_from(value: OwnedValue) -> Result { Self::try_from(value.0) } } impl<'k, 'v, K, V, H> TryFrom for HashMap where K: crate::Basic + TryFrom> + std::hash::Hash + std::cmp::Eq, V: TryFrom>, H: BuildHasher + Default, K::Error: Into, V::Error: Into, { type Error = crate::Error; fn try_from(value: OwnedValue) -> Result { if let Value::Dict(v) = value.0 { Self::try_from(v) } else { Err(crate::Error::IncorrectType) } } } impl From> for OwnedValue where K: Type + Into> + std::hash::Hash + std::cmp::Eq, V: Type + Into>, H: BuildHasher + Default, { fn from(value: HashMap) -> Self { Self(value.into()) } } impl<'a, T> TryFrom for Optional where T: TryFrom> + NoneValue + PartialEq<::NoneType>, T::Error: Into, { type Error = crate::Error; fn try_from(value: OwnedValue) -> Result { Self::try_from(value.0) } } impl From> for OwnedValue where V: Into> + NoneValue, { fn from(v: Optional) -> OwnedValue { Self(Value::from(v)) } } // tuple conversions in `structure` module for avoiding code-duplication. impl<'a> TryFrom> for OwnedValue { type Error = crate::Error; fn try_from(v: Value<'a>) -> crate::Result { // TODO: add into_owned, avoiding copy if already owned.. v.try_to_owned() } } impl<'a> TryFrom<&Value<'a>> for OwnedValue { type Error = crate::Error; fn try_from(v: &Value<'a>) -> crate::Result { v.try_to_owned() } } macro_rules! to_value { ($from:ty, $variant:ident) => { impl<'a> From<$from> for OwnedValue { fn from(v: $from) -> Self { OwnedValue(>::$variant(v.to_owned())) } } }; } to_value!(u8, U8); to_value!(bool, Bool); to_value!(i16, I16); to_value!(u16, U16); to_value!(i32, I32); to_value!(u32, U32); to_value!(i64, I64); to_value!(u64, U64); to_value!(f64, F64); to_value!(Str<'a>, Str); to_value!(ObjectPath<'a>, ObjectPath); impl From for OwnedValue { fn from(v: Signature) -> Self { OwnedValue(>::Signature(v)) } } macro_rules! try_to_value { ($from:ty) => { impl<'a> TryFrom<$from> for OwnedValue { type Error = crate::Error; fn try_from(v: $from) -> crate::Result { OwnedValue::try_from(>::from(v)) } } }; } try_to_value!(Array<'a>); try_to_value!(Dict<'a, 'a>); #[cfg(feature = "gvariant")] try_to_value!(Maybe<'a>); try_to_value!(Structure<'a>); #[cfg(unix)] try_to_value!(Fd<'a>); impl From for Value<'_> { fn from(v: OwnedValue) -> Self { v.into_inner() } } impl<'o> TryFrom<&'o OwnedValue> for Value<'o> { type Error = crate::Error; fn try_from(v: &'o OwnedValue) -> crate::Result> { v.inner().try_clone() } } impl std::ops::Deref for OwnedValue { type Target = Value<'static>; fn deref(&self) -> &Self::Target { &self.0 } } impl<'de> Deserialize<'de> for OwnedValue { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { Value::deserialize(deserializer) .and_then(|v| v.try_to_owned().map_err(serde::de::Error::custom)) } } impl Clone for OwnedValue { /// Clone the value. /// /// # Panics /// /// This method can only fail on Unix platforms for [`Value::Fd`] variant containing an /// [`Fd::Owned`] variant. This happens when the current process exceeds the limit on maximum /// number of open file descriptors. fn clone(&self) -> Self { Self(self.0.clone()) } } #[cfg(test)] mod tests { use std::{collections::HashMap, error::Error}; use crate::{serialized::Context, to_bytes, OwnedValue, Value, LE}; #[cfg(feature = "enumflags2")] #[test] fn bitflags() -> Result<(), Box> { #[repr(u32)] #[enumflags2::bitflags] #[derive(Copy, Clone, Debug)] pub enum Flaggy { One = 0x1, Two = 0x2, } let v = Value::from(0x2u32); let ov: OwnedValue = v.try_into()?; assert_eq!(>::try_from(ov)?, Flaggy::Two); Ok(()) } #[test] fn from_value() -> Result<(), Box> { let v = Value::from("hi!"); let ov: OwnedValue = v.try_into()?; assert_eq!(<&str>::try_from(&ov)?, "hi!"); Ok(()) } #[test] fn serde() -> Result<(), Box> { let ec = Context::new_dbus(LE, 0); let ov: OwnedValue = Value::from("hi!").try_into()?; let ser = to_bytes(ec, &ov)?; let (de, parsed): (Value<'_>, _) = ser.deserialize()?; assert_eq!(<&str>::try_from(&de)?, "hi!"); assert_eq!(parsed, ser.len()); Ok(()) } #[test] fn map_conversion() -> Result<(), Box> { let mut map = HashMap::::new(); map.insert("one".to_string(), "1".to_string()); map.insert("two".to_string(), "2".to_string()); let value = OwnedValue::from(map.clone()); // Now convert back let map2 = >::try_from(value)?; assert_eq!(map, map2); Ok(()) } } zvariant-5.2.0/src/ser.rs000064400000000000000000000224011046102023000134130ustar 00000000000000use serde::Serialize; use std::io::{Seek, Write}; #[cfg(unix)] use std::os::fd::OwnedFd; #[cfg(feature = "gvariant")] use crate::gvariant::Serializer as GVSerializer; use crate::{ container_depths::ContainerDepths, dbus::Serializer as DBusSerializer, serialized::{Context, Data, Format, Size, Written}, utils::*, Basic, DynamicType, Error, Result, Signature, }; struct NullWriteSeek; impl Write for NullWriteSeek { fn write(&mut self, buf: &[u8]) -> std::io::Result { Ok(buf.len()) } fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } impl Seek for NullWriteSeek { fn seek(&mut self, _pos: std::io::SeekFrom) -> std::io::Result { Ok(u64::MAX) // should never read the return value! } } /// Calculate the serialized size of `T`. /// /// # Examples /// /// ``` /// use zvariant::{serialized::Context, serialized_size, LE}; /// /// let ctxt = Context::new_dbus(LE, 0); /// let len = serialized_size(ctxt, "hello world").unwrap(); /// assert_eq!(*len, 16); /// /// let len = serialized_size(ctxt, &("hello world!", 42_u64)).unwrap(); /// assert_eq!(*len, 32); /// ``` pub fn serialized_size(ctxt: Context, value: &T) -> Result where T: ?Sized + Serialize + DynamicType, { let mut null = NullWriteSeek; let signature = value.signature(); #[cfg(unix)] let mut fds = FdList::Number(0); let len = match ctxt.format() { Format::DBus => { let mut ser = DBusSerializer::::new( &signature, &mut null, #[cfg(unix)] &mut fds, ctxt, )?; value.serialize(&mut ser)?; ser.0.bytes_written } #[cfg(feature = "gvariant")] Format::GVariant => { let mut ser = GVSerializer::::new( &signature, &mut null, #[cfg(unix)] &mut fds, ctxt, )?; value.serialize(&mut ser)?; ser.0.bytes_written } }; let size = Size::new(len, ctxt); #[cfg(unix)] let size = match fds { FdList::Number(n) => size.set_num_fds(n), FdList::Fds(_) => unreachable!("`Fds::Fds` is not possible here"), }; Ok(size) } /// Serialize `T` to the given `writer`. /// /// # Examples /// /// ``` /// use zvariant::{serialized::{Context, Data}, to_writer, LE}; /// /// let ctxt = Context::new_dbus(LE, 0); /// let mut cursor = std::io::Cursor::new(vec![]); /// // SAFETY: No FDs are being serialized here so its completely safe. /// unsafe { to_writer(&mut cursor, ctxt, &42u32) }.unwrap(); /// let encoded = Data::new(cursor.get_ref(), ctxt); /// let value: u32 = encoded.deserialize().unwrap().0; /// assert_eq!(value, 42); /// ``` /// /// # Safety /// /// On Unix systems, the returned [`Written`] instance can contain file descriptors and therefore /// the caller is responsible for not dropping the returned [`Written`] instance before the /// `writer`. Otherwise, the file descriptors in the `Written` instance will be closed while /// serialized data will still refer to them. Hence why this function is marked unsafe. /// /// On non-Unix systems, the returned [`Written`] instance will not contain any file descriptors and /// hence is safe to drop. pub unsafe fn to_writer(writer: &mut W, ctxt: Context, value: &T) -> Result where W: Write + Seek, T: ?Sized + Serialize + DynamicType, { let signature = value.signature(); to_writer_for_signature(writer, ctxt, signature, value) } /// Serialize `T` as a byte vector. /// /// See [`Data::deserialize`] documentation for an example of how to use this function. pub fn to_bytes(ctxt: Context, value: &T) -> Result> where T: ?Sized + Serialize + DynamicType, { to_bytes_for_signature(ctxt, value.signature(), value) } /// Serialize `T` that has the given signature, to the given `writer`. /// /// Use this function instead of [`to_writer`] if the value being serialized does not implement /// [`DynamicType`]. /// /// # Safety /// /// On Unix systems, the returned [`Written`] instance can contain file descriptors and therefore /// the caller is responsible for not dropping the returned [`Written`] instance before the /// `writer`. Otherwise, the file descriptors in the `Written` instance will be closed while /// serialized data will still refer to them. Hence why this function is marked unsafe. /// /// On non-Unix systems, the returned [`Written`] instance will not contain any file descriptors and /// hence is safe to drop. /// /// [`to_writer`]: fn.to_writer.html pub unsafe fn to_writer_for_signature( writer: &mut W, ctxt: Context, signature: S, value: &T, ) -> Result where W: Write + Seek, S: TryInto, S::Error: Into, T: ?Sized + Serialize, { let signature = signature.try_into().map_err(Into::into)?; #[cfg(unix)] let mut fds = FdList::Fds(vec![]); let len = match ctxt.format() { Format::DBus => { let mut ser = DBusSerializer::::new( &signature, writer, #[cfg(unix)] &mut fds, ctxt, )?; value.serialize(&mut ser)?; ser.0.bytes_written } #[cfg(feature = "gvariant")] Format::GVariant => { let mut ser = GVSerializer::::new( &signature, writer, #[cfg(unix)] &mut fds, ctxt, )?; value.serialize(&mut ser)?; ser.0.bytes_written } }; let written = Written::new(len, ctxt); #[cfg(unix)] let written = match fds { FdList::Fds(fds) => written.set_fds(fds), FdList::Number(_) => unreachable!("`Fds::Number` is not possible here"), }; Ok(written) } /// Serialize `T` that has the given signature, to a new byte vector. /// /// Use this function instead of [`to_bytes`] if the value being serialized does not implement /// [`DynamicType`]. See [`from_slice_for_signature`] documentation for an example of how to use /// this function. /// /// [`to_bytes`]: fn.to_bytes.html /// [`from_slice_for_signature`]: fn.from_slice_for_signature.html#examples pub fn to_bytes_for_signature( ctxt: Context, signature: S, value: &T, ) -> Result> where S: TryInto, S::Error: Into, T: ?Sized + Serialize, { let mut cursor = std::io::Cursor::new(vec![]); // SAFETY: We put the bytes and FDs in the `Data` to ensure that the data and FDs are only // dropped together. let ret = unsafe { to_writer_for_signature(&mut cursor, ctxt, signature, value) }?; #[cfg(unix)] let encoded = Data::new_fds(cursor.into_inner(), ctxt, ret.into_fds()); #[cfg(not(unix))] let encoded = { let _ = ret; Data::new(cursor.into_inner(), ctxt) }; Ok(encoded) } /// Context for all our serializers and provides shared functionality. pub(crate) struct SerializerCommon<'ser, W> { pub(crate) ctxt: Context, pub(crate) writer: &'ser mut W, pub(crate) bytes_written: usize, #[cfg(unix)] pub(crate) fds: &'ser mut FdList, pub(crate) signature: &'ser Signature, pub(crate) value_sign: Option, pub(crate) container_depths: ContainerDepths, } #[cfg(unix)] pub(crate) enum FdList { Fds(Vec), Number(u32), } impl SerializerCommon<'_, W> where W: Write + Seek, { #[cfg(unix)] pub(crate) fn add_fd(&mut self, fd: std::os::fd::RawFd) -> Result { use std::os::fd::{AsRawFd, BorrowedFd}; match self.fds { FdList::Fds(fds) => { if let Some(idx) = fds.iter().position(|x| x.as_raw_fd() == fd) { return Ok(idx as u32); } let idx = fds.len(); // Cloning implies dup and is unfortunate but we need to return owned fds // and dup is not expensive (at least on Linux). let fd = unsafe { BorrowedFd::borrow_raw(fd) }.try_clone_to_owned()?; fds.push(fd); Ok(idx as u32) } FdList::Number(n) => { let idx = *n; *n += 1; Ok(idx) } } } pub(crate) fn add_padding(&mut self, alignment: usize) -> Result { let padding = padding_for_n_bytes(self.abs_pos(), alignment); if padding > 0 { self.write_all(&[0u8; 8][..padding])?; } Ok(padding) } pub(crate) fn prep_serialize_basic(&mut self) -> Result<()> where T: Basic, { self.add_padding(T::alignment(self.ctxt.format()))?; Ok(()) } fn abs_pos(&self) -> usize { self.ctxt.position() + self.bytes_written } } impl Write for SerializerCommon<'_, W> where W: Write + Seek, { /// Write `buf` and increment internal bytes written counter. fn write(&mut self, buf: &[u8]) -> std::io::Result { self.writer.write(buf).inspect(|&n| { self.bytes_written += n; }) } fn flush(&mut self) -> std::io::Result<()> { self.writer.flush() } } zvariant-5.2.0/src/serialize_value.rs000064400000000000000000000024501046102023000160070ustar 00000000000000use serde::ser::{Serialize, SerializeStruct, Serializer}; use static_assertions::assert_impl_all; use crate::Type; /// A wrapper to serialize `T: Type + Serialize` as a value. /// /// When the type of a value is well-known, you may avoid the cost and complexity of wrapping to a /// generic [`Value`] and instead use this wrapper. /// /// ``` /// # use zvariant::{to_bytes, serialized::Context, SerializeValue, LE}; /// # /// # let ctxt = Context::new_dbus(LE, 0); /// let _ = to_bytes(ctxt, &SerializeValue(&[0, 1, 2])).unwrap(); /// ``` /// /// [`Value`]: enum.Value.html pub struct SerializeValue<'a, T: Type + Serialize>(pub &'a T); assert_impl_all!(SerializeValue<'_, i32>: Send, Sync, Unpin); impl Serialize for SerializeValue<'_, T> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { // Serializer implementation needs to ensure padding isn't added for Value. let mut structure = serializer.serialize_struct("Variant", 2)?; structure.serialize_field("signature", T::SIGNATURE)?; structure.serialize_field("value", self.0)?; structure.end() } } impl Type for SerializeValue<'_, T> { const SIGNATURE: &'static crate::Signature = &crate::Signature::Variant; } zvariant-5.2.0/src/serialized/context.rs000064400000000000000000000044321046102023000164450ustar 00000000000000use static_assertions::assert_impl_all; use crate::{serialized::Format, Endian}; /// The encoding context to use with the [serialization and deserialization] API. /// /// The encoding is dependent on the position of the encoding in the entire message and hence the /// need to [specify] the byte position of the data being serialized or deserialized. Simply pass /// `0` if serializing or deserializing to or from the beginning of message, or the preceding bytes /// end on an 8-byte boundary. /// /// # Examples /// /// ``` /// use zvariant::Endian; /// use zvariant::serialized::Context; /// use zvariant::to_bytes; /// /// let str_vec = vec!["Hello", "World"]; /// let ctxt = Context::new_dbus(Endian::Little, 0); /// let encoded = to_bytes(ctxt, &str_vec).unwrap(); /// /// // Let's decode the 2nd element of the array only /// let slice = encoded.slice(14..); /// let decoded: &str = slice.deserialize().unwrap().0; /// assert_eq!(decoded, "World"); /// ``` /// /// [serialization and deserialization]: index.html#functions /// [specify]: #method.new #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub struct Context { format: Format, position: usize, endian: Endian, } assert_impl_all!(Context: Send, Sync, Unpin); impl Context { /// Create a new encoding context. pub fn new(format: Format, endian: Endian, position: usize) -> Self { Self { format, position, endian, } } /// Convenient wrapper for [`new`] to create a context for D-Bus format. /// /// [`new`]: #method.new pub fn new_dbus(endian: Endian, position: usize) -> Self { Self::new(Format::DBus, endian, position) } /// Convenient wrapper for [`new`] to create a context for GVariant format. /// /// [`new`]: #method.new #[cfg(feature = "gvariant")] pub fn new_gvariant(endian: Endian, position: usize) -> Self { Self::new(Format::GVariant, endian, position) } /// The [`Format`] of this context. pub fn format(self) -> Format { self.format } /// The [`Endian`] of this context. pub fn endian(self) -> Endian { self.endian } /// The byte position of the value to be encoded or decoded, in the entire message. pub fn position(self) -> usize { self.position } } zvariant-5.2.0/src/serialized/data.rs000064400000000000000000000311251046102023000156710ustar 00000000000000#[cfg(unix)] use crate::{Fd, OwnedFd}; use std::{ borrow::Cow, ops::{Bound, Deref, Range, RangeBounds}, sync::Arc, }; use serde::{de::DeserializeSeed, Deserialize}; use crate::{ de::Deserializer, serialized::{Context, Format}, DynamicDeserialize, DynamicType, Error, Result, Signature, Type, }; /// Represents serialized bytes in a specific format. /// /// On Unix platforms, it also contains a list of file descriptors, whose indexes are included in /// the serialized bytes. By packing them together, we ensure that the file descriptors are never /// closed before the serialized bytes are dropped. #[derive(Clone, Debug)] pub struct Data<'bytes, 'fds> { inner: Arc>, context: Context, range: Range, } #[derive(Debug)] pub struct Inner<'bytes, 'fds> { bytes: Cow<'bytes, [u8]>, #[cfg(unix)] fds: Vec>, #[cfg(not(unix))] _fds: std::marker::PhantomData<&'fds ()>, } impl<'bytes, 'fds> Data<'bytes, 'fds> { /// Create a new `Data` instance containing borrowed file descriptors. /// /// This method is only available on Unix platforms. #[cfg(unix)] pub fn new_borrowed_fds( bytes: T, context: Context, fds: impl IntoIterator>>, ) -> Self where T: Into>, { let bytes = bytes.into(); let range = Range { start: 0, end: bytes.len(), }; Data { inner: Arc::new(Inner { bytes, fds: fds.into_iter().map(Into::into).collect(), }), range, context, } } /// The serialized bytes. pub fn bytes(&self) -> &[u8] { &self.inner.bytes[self.range.start..self.range.end] } /// The encoding context. pub fn context(&self) -> Context { self.context } /// The file descriptors that are references by the serialized bytes. /// /// This method is only available on Unix platforms. #[cfg(unix)] pub fn fds(&self) -> &[Fd<'fds>] { &self.inner.fds } /// Returns a slice of `self` for the provided range. /// /// # Panics /// /// Requires that begin <= end and end <= self.len(), otherwise slicing will panic. pub fn slice(&self, range: impl RangeBounds) -> Data<'bytes, 'fds> { let len = self.range.end - self.range.start; let start = match range.start_bound() { Bound::Included(&n) => n, Bound::Excluded(&n) => n + 1, Bound::Unbounded => 0, }; let end = match range.end_bound() { Bound::Included(&n) => n + 1, Bound::Excluded(&n) => n, Bound::Unbounded => len, }; assert!( start <= end, "range start must not be greater than end: {start:?} > {end:?}", ); assert!(end <= len, "range end out of bounds: {end:?} > {len:?}"); let context = Context::new( self.context.format(), self.context.endian(), self.context.position() + start, ); let range = Range { start: self.range.start + start, end: self.range.start + end, }; Data { inner: self.inner.clone(), context, range, } } /// Deserialize `T` from `self`. /// /// # Examples /// /// ``` /// use zvariant::LE; /// use zvariant::to_bytes; /// use zvariant::serialized::Context; /// /// let ctxt = Context::new_dbus(LE, 0); /// let encoded = to_bytes(ctxt, "hello world").unwrap(); /// let decoded: &str = encoded.deserialize().unwrap().0; /// assert_eq!(decoded, "hello world"); /// ``` /// /// # Return value /// /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`. pub fn deserialize<'d, T>(&'d self) -> Result<(T, usize)> where T: Deserialize<'d> + Type, { self.deserialize_for_signature(T::SIGNATURE) } /// Deserialize `T` from `self` with the given signature. /// /// Use this method instead of [`Data::deserialize`] if the value being deserialized does not /// implement [`Type`]. /// /// # Examples /// /// While `Type` derive supports enums, for this example, let's supposed it doesn't and we don't /// want to manually implement `Type` trait either: /// /// ```rust /// use serde::{Deserialize, Serialize}; /// use zvariant::{ /// LE, to_bytes_for_signature, serialized::Context, /// signature::{Signature, Fields}, /// }; /// /// let ctxt = Context::new_dbus(LE, 0); /// #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] /// enum Unit { /// Variant1, /// Variant2, /// Variant3, /// } /// /// let encoded = to_bytes_for_signature(ctxt, &Signature::U32, &Unit::Variant2).unwrap(); /// assert_eq!(encoded.len(), 4); /// let decoded: Unit = encoded.deserialize_for_signature(&Signature::U32).unwrap().0; /// assert_eq!(decoded, Unit::Variant2); /// /// #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] /// enum NewType<'s> { /// Variant1(&'s str), /// Variant2(&'s str), /// Variant3(&'s str), /// } /// /// let signature = Signature::Structure(Fields::Static { /// fields: &[&Signature::U32, &Signature::Str], /// }); /// let encoded = /// to_bytes_for_signature(ctxt, &signature, &NewType::Variant2("hello")).unwrap(); /// assert_eq!(encoded.len(), 14); /// let decoded: NewType<'_> = encoded.deserialize_for_signature(&signature).unwrap().0; /// assert_eq!(decoded, NewType::Variant2("hello")); /// /// #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] /// enum Structs { /// Tuple(u8, u64), /// Struct { y: u8, t: u64 }, /// } /// /// let signature = Signature::Structure(Fields::Static { /// fields: &[ /// &Signature::U32, /// &Signature::Structure(Fields::Static { /// fields: &[&Signature::U8, &Signature::U64], /// }), /// ], /// }); /// let encoded = to_bytes_for_signature(ctxt, &signature, &Structs::Tuple(42, 42)).unwrap(); /// assert_eq!(encoded.len(), 24); /// let decoded: Structs = encoded.deserialize_for_signature(&signature).unwrap().0; /// assert_eq!(decoded, Structs::Tuple(42, 42)); /// /// let s = Structs::Struct { y: 42, t: 42 }; /// let encoded = to_bytes_for_signature(ctxt, &signature, &s).unwrap(); /// assert_eq!(encoded.len(), 24); /// let decoded: Structs = encoded.deserialize_for_signature(&signature).unwrap().0; /// assert_eq!(decoded, Structs::Struct { y: 42, t: 42 }); /// ``` /// /// # Return value /// /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`. pub fn deserialize_for_signature<'d, S, T>(&'d self, signature: S) -> Result<(T, usize)> where T: Deserialize<'d>, S: TryInto, S::Error: Into, { let signature = signature.try_into().map_err(Into::into)?; #[cfg(unix)] let fds = &self.inner.fds; let mut de = match self.context.format() { #[cfg(feature = "gvariant")] Format::GVariant => { #[cfg(unix)] { crate::gvariant::Deserializer::new( self.bytes(), Some(fds), &signature, self.context, ) } #[cfg(not(unix))] { crate::gvariant::Deserializer::<()>::new(self.bytes(), &signature, self.context) } } .map(Deserializer::GVariant)?, Format::DBus => { #[cfg(unix)] { crate::dbus::Deserializer::new( self.bytes(), Some(fds), &signature, self.context, ) } #[cfg(not(unix))] { crate::dbus::Deserializer::<()>::new(self.bytes(), &signature, self.context) } } .map(Deserializer::DBus)?, }; T::deserialize(&mut de).map(|t| match de { #[cfg(feature = "gvariant")] Deserializer::GVariant(de) => (t, de.0.pos), Deserializer::DBus(de) => (t, de.0.pos), }) } /// Deserialize `T` from `self`, with the given dynamic signature. /// /// # Return value /// /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`. pub fn deserialize_for_dynamic_signature<'d, S, T>(&'d self, signature: S) -> Result<(T, usize)> where T: DynamicDeserialize<'d>, S: TryInto, S::Error: Into, { let signature = signature.try_into().map_err(Into::into)?; let seed = T::deserializer_for_signature(&signature)?; self.deserialize_with_seed(seed) } /// Deserialize `T` from `self`, using the given seed. /// /// # Return value /// /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`. pub fn deserialize_with_seed<'d, S>(&'d self, seed: S) -> Result<(S::Value, usize)> where S: DeserializeSeed<'d> + DynamicType, { let signature = S::signature(&seed); #[cfg(unix)] let fds = &self.inner.fds; let mut de = match self.context.format() { #[cfg(feature = "gvariant")] Format::GVariant => { #[cfg(unix)] { crate::gvariant::Deserializer::new( self.bytes(), Some(fds), &signature, self.context, ) } #[cfg(not(unix))] { crate::gvariant::Deserializer::new(self.bytes(), &signature, self.context) } } .map(Deserializer::GVariant)?, Format::DBus => { #[cfg(unix)] { crate::dbus::Deserializer::new( self.bytes(), Some(fds), &signature, self.context, ) } #[cfg(not(unix))] { crate::dbus::Deserializer::<()>::new(self.bytes(), &signature, self.context) } } .map(Deserializer::DBus)?, }; seed.deserialize(&mut de).map(|t| match de { #[cfg(feature = "gvariant")] Deserializer::GVariant(de) => (t, de.0.pos), Deserializer::DBus(de) => (t, de.0.pos), }) } } impl<'bytes> Data<'bytes, 'static> { /// Create a new `Data` instance. pub fn new(bytes: T, context: Context) -> Self where T: Into>, { let bytes = bytes.into(); let range = Range { start: 0, end: bytes.len(), }; Data { inner: Arc::new(Inner { bytes, #[cfg(unix)] fds: vec![], #[cfg(not(unix))] _fds: std::marker::PhantomData, }), context, range, } } /// Create a new `Data` instance containing owned file descriptors. /// /// This method is only available on Unix platforms. #[cfg(unix)] pub fn new_fds( bytes: T, context: Context, fds: impl IntoIterator>, ) -> Self where T: Into>, { let bytes = bytes.into(); let range = Range { start: 0, end: bytes.len(), }; Data { inner: Arc::new(Inner { bytes, fds: fds.into_iter().map(Into::into).map(Fd::from).collect(), }), context, range, } } } impl Deref for Data<'_, '_> { type Target = [u8]; fn deref(&self) -> &Self::Target { self.bytes() } } impl AsRef for Data<'_, '_> where T: ?Sized, for<'bytes, 'fds> as Deref>::Target: AsRef, { fn as_ref(&self) -> &T { self.deref().as_ref() } } zvariant-5.2.0/src/serialized/mod.rs000064400000000000000000000002661046102023000155410ustar 00000000000000mod data; pub use data::Data; mod size; pub use size::Size; mod written; pub use written::Written; pub use zvariant_utils::serialized::Format; mod context; pub use context::Context; zvariant-5.2.0/src/serialized/size.rs000064400000000000000000000025511046102023000157330ustar 00000000000000use std::ops::Deref; use crate::serialized::Context; /// Represents the return value of [`crate::serialized_size`] function. /// /// It mainly contains the size of serialized bytes in a specific format. /// /// On Unix platforms, it also contains the number of file descriptors, whose indexes are included /// in the serialized bytes. #[derive(Debug)] pub struct Size { size: usize, context: Context, #[cfg(unix)] num_fds: u32, } impl Size { /// Create a new `Size` instance. pub fn new(size: usize, context: Context) -> Self { Self { size, context, #[cfg(unix)] num_fds: 0, } } /// Set the number of file descriptors. #[cfg(unix)] pub fn set_num_fds(mut self, num_fds: u32) -> Self { self.num_fds = num_fds; self } /// The size of the serialized bytes. pub fn size(&self) -> usize { self.size } /// The encoding context. pub fn context(&self) -> Context { self.context } /// The number file descriptors that are references by the serialized bytes. /// /// This method is only available on Unix platforms. #[cfg(unix)] pub fn num_fds(&self) -> u32 { self.num_fds } } impl Deref for Size { type Target = usize; fn deref(&self) -> &Self::Target { &self.size } } zvariant-5.2.0/src/serialized/written.rs000064400000000000000000000032161046102023000164540ustar 00000000000000#[cfg(unix)] use crate::OwnedFd; use std::ops::Deref; use crate::serialized::Context; /// Represents the return value of [`crate::to_writer`] function. /// /// It mainly contains the size of serialized bytes in a specific format. /// /// On Unix platforms, it also contains a list of file descriptors, whose indexes are included in /// the serialized bytes. #[derive(Debug)] pub struct Written { size: usize, context: Context, #[cfg(unix)] fds: Vec, } impl Written { /// Create a new `Written` instance. pub fn new(size: usize, context: Context) -> Self { Self { size, context, #[cfg(unix)] fds: vec![], } } /// Set the file descriptors. #[cfg(unix)] pub fn set_fds(mut self, fds: impl IntoIterator>) -> Self { self.fds = fds.into_iter().map(Into::into).collect(); self } /// The size of the serialized bytes. pub fn size(&self) -> usize { self.size } /// The encoding context. pub fn context(&self) -> Context { self.context } /// Consume `self` and return the file descriptors. /// /// This method is only available on Unix platforms. #[cfg(unix)] pub fn into_fds(self) -> Vec { self.fds } /// The file descriptors that are references by the serialized bytes. /// /// This method is only available on Unix platforms. #[cfg(unix)] pub fn fds(&self) -> &[OwnedFd] { &self.fds } } impl Deref for Written { type Target = usize; fn deref(&self) -> &Self::Target { &self.size } } zvariant-5.2.0/src/signature.rs000064400000000000000000000010161046102023000146220ustar 00000000000000use crate::{Basic, Type}; pub use zvariant_utils::signature::*; impl From for crate::Error { fn from(e: Error) -> Self { crate::Error::SignatureParse(e) } } impl Type for Signature { const SIGNATURE: &'static Signature = &Signature::Signature; } impl Basic for Signature { const SIGNATURE_CHAR: char = 'g'; const SIGNATURE_STR: &'static str = "g"; } impl From for crate::Value<'static> { fn from(value: Signature) -> Self { crate::Value::Signature(value) } } zvariant-5.2.0/src/str.rs000064400000000000000000000134131046102023000134350ustar 00000000000000use serde::{Deserialize, Deserializer, Serialize, Serializer}; use static_assertions::assert_impl_all; use std::{ borrow::Cow, cmp::Ordering, hash::{Hash, Hasher}, sync::Arc, }; use crate::{Basic, Type}; /// A string wrapper. /// /// /// This is very similar to the [`std::borrow::Cow`] type, but it: /// /// * is specialized for strings. /// * treats `&'static str` as a separate type. This allows you to avoid allocations and copying /// when turning an `Str` instance created from a `&'static str` into an owned version in generic /// code that doesn't/can't assume the inner lifetime of the source `Str` instance. /// /// This type is used for keeping strings in a [`Value`], among other things. /// /// API is provided to convert from, and to a [`&str`] and [`String`]. /// /// [`Value`]: enum.Value.html#variant.Str /// [`&str`]: https://doc.rust-lang.org/std/str/index.html /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)] pub struct Str<'a>(#[serde(borrow)] Inner<'a>); #[derive(Eq, Clone)] enum Inner<'a> { Static(&'static str), Borrowed(&'a str), Owned(Arc), } impl Default for Inner<'_> { fn default() -> Self { Self::Static("") } } impl<'a> PartialEq for Inner<'a> { fn eq(&self, other: &Inner<'a>) -> bool { self.as_str() == other.as_str() } } impl<'a> Ord for Inner<'a> { fn cmp(&self, other: &Inner<'a>) -> Ordering { self.as_str().cmp(other.as_str()) } } impl<'a> PartialOrd for Inner<'a> { fn partial_cmp(&self, other: &Inner<'a>) -> Option { Some(self.cmp(other)) } } impl Hash for Inner<'_> { fn hash(&self, h: &mut H) { self.as_str().hash(h) } } impl Inner<'_> { /// The underlying string. pub fn as_str(&self) -> &str { match self { Inner::Static(s) => s, Inner::Borrowed(s) => s, Inner::Owned(s) => s, } } } impl Serialize for Inner<'_> { fn serialize(&self, s: S) -> Result { s.serialize_str(self.as_str()) } } impl<'de: 'a, 'a> Deserialize<'de> for Inner<'a> { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { <&'a str>::deserialize(deserializer).map(Inner::Borrowed) } } assert_impl_all!(Str<'_>: Send, Sync, Unpin); impl Str<'_> { /// An owned string without allocations pub const fn from_static(s: &'static str) -> Self { Str(Inner::Static(s)) } /// This is faster than `Clone::clone` when `self` contains owned data. pub fn as_ref(&self) -> Str<'_> { match &self.0 { Inner::Static(s) => Str(Inner::Static(s)), Inner::Borrowed(s) => Str(Inner::Borrowed(s)), Inner::Owned(s) => Str(Inner::Borrowed(s)), } } /// The underlying string. pub fn as_str(&self) -> &str { self.0.as_str() } /// Creates an owned clone of `self`. pub fn to_owned(&self) -> Str<'static> { self.clone().into_owned() } /// Creates an owned clone of `self`. pub fn into_owned(self) -> Str<'static> { match self.0 { Inner::Static(s) => Str(Inner::Static(s)), Inner::Borrowed(s) => Str(Inner::Owned(s.to_owned().into())), Inner::Owned(s) => Str(Inner::Owned(s)), } } } impl Basic for Str<'_> { const SIGNATURE_CHAR: char = <&str>::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = <&str>::SIGNATURE_STR; } impl Type for Str<'_> { const SIGNATURE: &'static crate::Signature = &crate::Signature::Str; } impl<'a> From<&'a str> for Str<'a> { fn from(value: &'a str) -> Self { Self(Inner::Borrowed(value)) } } impl<'a> From<&'a String> for Str<'a> { fn from(value: &'a String) -> Self { Self(Inner::Borrowed(value)) } } impl From for Str<'_> { fn from(value: String) -> Self { Self(Inner::Owned(value.into())) } } impl From> for Str<'_> { fn from(value: Arc) -> Self { Self(Inner::Owned(value)) } } impl<'a> From> for Str<'a> { fn from(value: Cow<'a, str>) -> Self { match value { Cow::Owned(value) => value.into(), Cow::Borrowed(value) => value.into(), } } } impl<'a> From> for String { fn from(value: Str<'a>) -> String { match value.0 { Inner::Static(s) => s.into(), Inner::Borrowed(s) => s.into(), Inner::Owned(s) => s.to_string(), } } } impl<'a> From<&'a Str<'_>> for &'a str { fn from(value: &'a Str<'_>) -> &'a str { value.as_str() } } impl std::ops::Deref for Str<'_> { type Target = str; fn deref(&self) -> &Self::Target { self.as_str() } } impl PartialEq for Str<'_> { fn eq(&self, other: &str) -> bool { self.as_str() == other } } impl PartialEq<&str> for Str<'_> { fn eq(&self, other: &&str) -> bool { self.as_str() == *other } } impl std::fmt::Debug for Str<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Debug::fmt(self.as_str(), f) } } impl std::fmt::Display for Str<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.as_str(), f) } } #[cfg(test)] mod tests { use super::Str; #[test] fn from_string() { let string = String::from("value"); let v = Str::from(&string); assert_eq!(v.as_str(), "value"); } #[test] fn test_ordering() { let first = Str::from("a".to_string()); let second = Str::from_static("b"); assert!(first < second); } } zvariant-5.2.0/src/structure.rs000064400000000000000000000301631046102023000146660ustar 00000000000000#![allow(unknown_lints)] use serde::{ de::{DeserializeSeed, Deserializer, Error, SeqAccess, Visitor}, ser::{Serialize, SerializeTupleStruct, Serializer}, }; use static_assertions::assert_impl_all; use std::fmt::{Display, Write}; use crate::{ value::SignatureSeed, value_display_fmt, DynamicDeserialize, DynamicType, OwnedValue, Signature, Value, }; /// Use this to efficiently build a [`Structure`]. /// /// [`Structure`]: struct.Structure.html #[derive(Debug, Default, PartialEq)] pub struct StructureBuilder<'a>(Vec>); assert_impl_all!(StructureBuilder<'_>: Send, Sync, Unpin); impl<'a> StructureBuilder<'a> { /// Create a new `StructureBuilder`. /// /// Same as `StructureBuilder::default()`. pub fn new() -> Self { Self::default() } /// Append `field` to `self`. /// /// This method returns `Self` so that you can use the builder pattern to create a complex /// structure. #[must_use] pub fn add_field(self, field: T) -> Self where T: DynamicType + Into>, { self.append_field(Value::new(field)) } /// Append `field` to `self`. /// /// Identical to `add_field`, except the field must be in the form of a `Value`. #[must_use] pub fn append_field<'e: 'a>(mut self, field: Value<'e>) -> Self { self.0.push(field); self } /// Append `field` to `self`. /// /// Identical to `add_field`, except it makes changes in-place. pub fn push_field(&mut self, field: T) where T: DynamicType + Into>, { self.push_value(Value::new(field)) } /// Append `field` to `self`. /// /// Identical to `append_field`, except it makes changes in-place. pub fn push_value<'e: 'a>(&mut self, field: Value<'e>) { self.0.push(field) } /// Build the `Structure`. /// /// [`Structure`]: struct.Structure.html pub fn build(self) -> crate::Result> { if self.0.is_empty() { return Err(crate::Error::EmptyStructure); } let fields_signatures: Box<[Signature]> = self.0.iter().map(Value::value_signature).cloned().collect(); let signature = Signature::structure(fields_signatures); Ok(Structure { fields: self.0, signature, }) } /// Same as `build` except Signature is provided. pub(crate) fn build_with_signature<'s: 'a>(self, signature: &Signature) -> Structure<'a> { Structure { fields: self.0, signature: signature.clone(), } } } /// Use this to deserialize a [`Structure`]. /// /// The lifetime `'a` is now redundant and kept only for backward compatibility. All instances now /// has a `'static` lifetime. This will be removed in the next major release. #[derive(Debug, Clone, PartialEq, Eq)] pub struct StructureSeed<'a> { signature: Signature, phantom: std::marker::PhantomData<&'a ()>, } assert_impl_all!(StructureSeed<'_>: Unpin); impl StructureSeed<'static> { /// Create a new `StructureSeed` /// /// The given signature must be a valid structure signature. #[must_use] pub fn new_unchecked(signature: &Signature) -> Self { StructureSeed { signature: signature.clone(), phantom: std::marker::PhantomData, } } } impl TryFrom for StructureSeed<'static> { type Error = zvariant::Error; fn try_from(signature: Signature) -> Result { if !matches!(signature, Signature::Structure(_)) { return Err(zvariant::Error::IncorrectType); } Ok(StructureSeed { signature, phantom: std::marker::PhantomData, }) } } impl<'de> DeserializeSeed<'de> for StructureSeed<'_> { type Value = Structure<'de>; fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_seq(StructureVisitor { signature: self.signature, }) } } #[derive(Debug, Clone, PartialEq, Eq)] struct StructureVisitor { signature: Signature, } impl<'de> Visitor<'de> for StructureVisitor { type Value = Structure<'de>; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("a Structure value") } fn visit_seq(self, visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { SignatureSeed { signature: &self.signature, } .visit_struct(visitor) } } /// A helper type to wrap structs in [`Value`]. /// /// API is provided to convert from, and to tuples. /// /// [`Value`]: enum.Value.html #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Structure<'a> { fields: Vec>, signature: Signature, } assert_impl_all!(Structure<'_>: Send, Sync, Unpin); impl<'a> Structure<'a> { /// Get a reference to all the fields of `self`. pub fn fields(&self) -> &[Value<'a>] { &self.fields } /// Converts `self` to a `Vec` containing all its fields. pub fn into_fields(self) -> Vec> { self.fields } /// Get the signature of this `Structure`. pub fn signature(&self) -> &Signature { &self.signature } pub(crate) fn try_to_owned(&self) -> crate::Result> { Ok(Structure { fields: self .fields .iter() .map(|v| v.try_to_owned().map(Into::into)) .collect::>()?, signature: self.signature.to_owned(), }) } /// Attempt to clone `self`. pub fn try_clone(&self) -> Result { let fields = self .fields .iter() .map(|v| v.try_clone()) .collect::>>()?; Ok(Self { fields, signature: self.signature.clone(), }) } } impl Display for Structure<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { structure_display_fmt(self, f, true) } } pub(crate) fn structure_display_fmt( structure: &Structure<'_>, f: &mut std::fmt::Formatter<'_>, type_annotate: bool, ) -> std::fmt::Result { f.write_char('(')?; let fields = structure.fields(); match fields.len() { 0 => {} 1 => { value_display_fmt(&fields[0], f, type_annotate)?; f.write_char(',')?; } _ => { for (i, field) in fields.iter().enumerate() { value_display_fmt(field, f, type_annotate)?; if i + 1 < fields.len() { f.write_str(", ")?; } } } } f.write_char(')') } impl DynamicType for Structure<'_> { fn signature(&self) -> Signature { self.signature.clone() } } impl DynamicType for StructureSeed<'_> { fn signature(&self) -> Signature { self.signature.clone() } } impl<'a> DynamicDeserialize<'a> for Structure<'a> { type Deserializer = StructureSeed<'static>; fn deserializer_for_signature(signature: &Signature) -> zvariant::Result { let signature = match signature { Signature::Structure(_) => signature.clone(), s => Signature::structure([s.clone()]), }; Ok(StructureSeed { signature, phantom: std::marker::PhantomData, }) } } impl Serialize for Structure<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut structure = serializer.serialize_tuple_struct("Structure", self.fields.len())?; for field in &self.fields { field.serialize_value_as_tuple_struct_field(&mut structure)?; } structure.end() } } macro_rules! tuple_impls { ($($len:expr => ($($n:tt $name:ident)+))+) => { $( impl<'a, $($name),+> From<($($name),+,)> for Structure<'a> where $($name: DynamicType + Into>,)+ { #[inline] fn from(value: ($($name),+,)) -> Self { StructureBuilder::new() $( .add_field(value. $n) )+ .build().unwrap() } } impl<'a, E, $($name),+> TryFrom> for ($($name),+,) where $($name: TryFrom, Error = E>,)+ crate::Error: From, { type Error = crate::Error; fn try_from(mut s: Structure<'a>) -> core::result::Result { Ok(( $( $name::try_from(s.fields.remove(0))?, )+ )) } } impl<'a, E, $($name),+> TryFrom> for ($($name),+,) where $($name: TryFrom, Error = E>,)+ crate::Error: From, { type Error = crate::Error; fn try_from(v: Value<'a>) -> core::result::Result { Self::try_from(Structure::try_from(v)?) } } impl TryFrom for ($($name),+,) where $($name: TryFrom, Error = E>,)+ crate::Error: From, { type Error = crate::Error; fn try_from(v: OwnedValue) -> core::result::Result { Self::try_from(Value::from(v)) } } )+ } } tuple_impls! { 1 => (0 T0) 2 => (0 T0 1 T1) 3 => (0 T0 1 T1 2 T2) 4 => (0 T0 1 T1 2 T2 3 T3) 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) 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) 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) 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) 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) 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) } /// Owned [`Structure`] #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct OwnedStructure(pub Structure<'static>); /// Use this to deserialize an [`OwnedStructure`]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct OwnedStructureSeed(Signature); impl DynamicType for OwnedStructure { fn signature(&self) -> Signature { self.0.signature().clone() } } impl DynamicType for OwnedStructureSeed { fn signature(&self) -> Signature { self.0.clone() } } impl DynamicDeserialize<'_> for OwnedStructure { type Deserializer = OwnedStructureSeed; fn deserializer_for_signature(signature: &Signature) -> zvariant::Result { Structure::deserializer_for_signature(signature) .map(|StructureSeed { signature, .. }| OwnedStructureSeed(signature)) } } impl<'de> DeserializeSeed<'de> for OwnedStructureSeed { type Value = OwnedStructure; fn deserialize>(self, deserializer: D) -> Result { deserializer .deserialize_seq(StructureVisitor { signature: self.0 }) .and_then(|s| match s.try_to_owned() { Ok(s) => Ok(OwnedStructure(s)), Err(e) => Err(D::Error::custom(e)), }) } } impl Serialize for OwnedStructure { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.0.serialize(serializer) } } zvariant-5.2.0/src/tuple.rs000064400000000000000000000131341046102023000137560ustar 00000000000000use crate::{DynamicDeserialize, DynamicType, Signature}; use serde::{ de::{Deserialize, DeserializeSeed, Deserializer, Error, Visitor}, Serialize, Serializer, }; use std::marker::PhantomData; /// A helper type to serialize or deserialize a tuple whose elements implement [DynamicType] but /// not [Type]. /// /// This is required because tuples already have an implementation of [DynamicType] via the blanket /// implementation of [DynamicType] where `T: Type`, but that results in a bound of [Type] on each /// element, which is stronger than needed for serializing. /// /// [Type]: trait.Type.html #[derive(Debug, Copy, Clone)] pub struct DynamicTuple(pub T); impl DynamicType for DynamicTuple<()> { fn signature(&self) -> Signature { Signature::Unit } } impl Serialize for DynamicTuple { fn serialize(&self, serializer: S) -> Result { self.0.serialize(serializer) } } impl<'de> Deserialize<'de> for DynamicTuple<()> { fn deserialize>(deserializer: D) -> Result { <()>::deserialize(deserializer).map(DynamicTuple) } } /// A helper type for [DynamicTuple]'s [DynamicDeserialize] implementation. #[derive(Debug, Clone, PartialEq, Eq)] pub struct TupleSeed<'a, T, S> { sig: Signature, seeds: S, markers: (PhantomData, PhantomData<&'a ()>), } impl DynamicType for TupleSeed<'_, T, S> { fn signature(&self) -> Signature { self.sig.clone() } } struct TupleVisitor { seeds: S, marker: PhantomData, } macro_rules! tuple_impls { ($($len:expr => ($($n:tt $name:ident)+))+) => { $( impl<$($name),+> DynamicType for DynamicTuple<($($name,)+)> where $($name: DynamicType,)+ { fn signature(&self) -> Signature { Signature::structure( [ $( self.0.$n.signature(), )+ ] ) } } impl<'de, $($name),+> DeserializeSeed<'de> for TupleSeed<'de, ($($name,)+), ($(<$name as DynamicDeserialize<'de>>::Deserializer,)+)> where $($name: DynamicDeserialize<'de>,)+ { type Value = DynamicTuple<($($name,)+)>; fn deserialize>(self, deserializer: D) -> Result { deserializer.deserialize_tuple($len, TupleVisitor { seeds: self.seeds, marker: self.markers.0 }) } } impl<'de, $($name),+> Visitor<'de> for TupleVisitor<($($name,)+), ($(<$name as DynamicDeserialize<'de>>::Deserializer,)+)> where $($name: DynamicDeserialize<'de>,)+ { type Value = DynamicTuple<($($name,)+)>; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("a tuple") } fn visit_seq(self, mut visitor: V) -> Result, V::Error> where V: serde::de::SeqAccess<'de>, { Ok(DynamicTuple(($({ match visitor.next_element_seed(self.seeds.$n) { Ok(Some(elt)) => elt, Ok(None) => return Err(V::Error::invalid_length($len, &"")), Err(e) => return Err(e), } },)+))) } } impl<'de, $($name),+> DynamicDeserialize<'de> for DynamicTuple<($($name,)+)> where $($name: DynamicDeserialize<'de>,)+ { type Deserializer = TupleSeed<'de, ($($name,)+), ($(<$name as DynamicDeserialize<'de>>::Deserializer,)+)>; fn deserializer_for_signature( signature: &Signature, ) -> zvariant::Result { let mut fields_iter = match &signature { crate::Signature::Structure(fields) => fields.iter(), _ => return Err(zvariant::Error::IncorrectType), }; let seeds = ($({ let elt_sig = fields_iter.next().ok_or(zvariant::Error::IncorrectType)?; $name::deserializer_for_signature(elt_sig)? },)+); Ok(TupleSeed { sig: signature.clone(), seeds, markers: (PhantomData, PhantomData) }) } } )+ } } tuple_impls! { 1 => (0 T0) 2 => (0 T0 1 T1) 3 => (0 T0 1 T1 2 T2) 4 => (0 T0 1 T1 2 T2 3 T3) 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) 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) 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) 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) 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) 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) } zvariant-5.2.0/src/type/bytes.rs000064400000000000000000000004321046102023000147310ustar 00000000000000use crate::Signature; impl crate::Type for serde_bytes::Bytes { const SIGNATURE: &'static Signature = &Signature::static_array(&Signature::U8); } impl crate::Type for serde_bytes::ByteBuf { const SIGNATURE: &'static Signature = &Signature::static_array(&Signature::U8); } zvariant-5.2.0/src/type/dynamic.rs000064400000000000000000000043761046102023000152420ustar 00000000000000use crate::{Signature, Type}; use serde::de::{Deserialize, DeserializeSeed}; use std::marker::PhantomData; /// Types with dynamic signatures. /// /// Prefer implementing [Type] if possible, but if the actual signature of your type cannot be /// determined until runtime, you can implement this type to support serialization. You should /// also implement [DynamicDeserialize] for deserialization. pub trait DynamicType { /// The type signature for `self`. /// /// See [`Type::SIGNATURE`] for details. fn signature(&self) -> Signature; } /// Types that deserialize based on dynamic signatures. /// /// Prefer implementing [Type] and [Deserialize] if possible, but if the actual signature of your /// type cannot be determined until runtime, you should implement this type to support /// deserialization given a signature. pub trait DynamicDeserialize<'de>: DynamicType { /// A [DeserializeSeed] implementation for this type. type Deserializer: DeserializeSeed<'de, Value = Self> + DynamicType; /// Get a deserializer compatible with this parsed signature. fn deserializer_for_signature(signature: &Signature) -> zvariant::Result; } impl DynamicType for T where T: Type + ?Sized, { fn signature(&self) -> Signature { ::SIGNATURE.clone() } } impl<'de, T> DynamicDeserialize<'de> for T where T: Type + Deserialize<'de>, { type Deserializer = PhantomData; fn deserializer_for_signature(signature: &Signature) -> zvariant::Result { let expected = ::SIGNATURE; if expected != signature { match expected { Signature::Structure(fields) if fields.len() == 1 && fields.iter().next().unwrap() == signature => { // This is likely a D-Bus message body containing a single type being // deserialized as a single-field struct. No need to be super strict here. } _ => { return Err(zvariant::Error::SignatureMismatch( signature.clone(), format!("`{expected}`"), )) } } } Ok(PhantomData) } } zvariant-5.2.0/src/type/enumflags2.rs000064400000000000000000000002711046102023000156470ustar 00000000000000use crate::{Signature, Type}; // BitFlags impl Type for enumflags2::BitFlags where F: Type + enumflags2::BitFlag, { const SIGNATURE: &'static Signature = F::SIGNATURE; } zvariant-5.2.0/src/type/libstd.rs000064400000000000000000000221531046102023000150700ustar 00000000000000use crate::{impl_type_with_repr, Signature, Type}; use std::{ cell::{Cell, RefCell}, cmp::Reverse, marker::PhantomData, num::{Saturating, Wrapping}, ops::{Range, RangeFrom, RangeInclusive, RangeTo}, rc::{Rc, Weak as RcWeak}, sync::{ atomic::{ AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU64, AtomicU8, AtomicUsize, }, Arc, Mutex, RwLock, Weak as ArcWeak, }, time::Duration, }; impl Type for PhantomData where T: Type + ?Sized, { const SIGNATURE: &'static Signature = T::SIGNATURE; } macro_rules! array_type { ($arr:ty) => { impl Type for $arr where T: Type, { const SIGNATURE: &'static Signature = &Signature::static_array(T::SIGNATURE); } }; } array_type!([T]); array_type!(Vec); array_type!(std::collections::VecDeque); array_type!(std::collections::LinkedList); impl Type for std::collections::HashSet where T: Type + Eq + Hash, S: BuildHasher, { const SIGNATURE: &'static Signature = <[T]>::SIGNATURE; } impl Type for std::collections::BTreeSet where T: Type + Ord, { const SIGNATURE: &'static Signature = <[T]>::SIGNATURE; } impl Type for std::collections::BinaryHeap where T: Type + Ord, { const SIGNATURE: &'static Signature = <[T]>::SIGNATURE; } #[cfg(feature = "arrayvec")] impl Type for arrayvec::ArrayVec where T: Type, { const SIGNATURE: &'static Signature = <[T]>::SIGNATURE; } #[cfg(feature = "arrayvec")] impl Type for arrayvec::ArrayString { const SIGNATURE: &'static Signature = &Signature::Str; } #[cfg(feature = "heapless")] impl Type for heapless::Vec where T: Type, { const SIGNATURE: &'static Signature = <[T]>::SIGNATURE; } #[cfg(feature = "heapless")] impl Type for heapless::String { const SIGNATURE: &'static Signature = &Signature::Str; } // Empty type deserves empty signature impl Type for () { const SIGNATURE: &'static Signature = &Signature::Unit; } macro_rules! deref_impl { ( $type:ty, <$($desc:tt)+ ) => { impl <$($desc)+ { const SIGNATURE: &'static Signature = <$type>::SIGNATURE; } }; } deref_impl!(T, Type for &T); deref_impl!(T, Type for &mut T); deref_impl!(T, Type for Cow<'_, T>); deref_impl!(T, Type for Arc); deref_impl!(T, Type for ArcWeak); deref_impl!(T, Type for Mutex); deref_impl!(T, Type for RwLock); deref_impl!(T, Type for Box); deref_impl!(T, Type for Rc); deref_impl!(T, Type for RcWeak); deref_impl!(T, Type for Cell); deref_impl!(T, Type for RefCell); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] impl Type for Option where T: Type, { const SIGNATURE: &'static Signature = &Signature::static_maybe(T::SIGNATURE); } #[cfg(feature = "option-as-array")] impl Type for Option where T: Type, { const SIGNATURE: &'static Signature = &Signature::static_array(T::SIGNATURE); } //////////////////////////////////////////////////////////////////////////////// macro_rules! tuple_impls { ($($len:expr => ($($n:tt $name:ident)+))+) => { $( impl<$($name),+> Type for ($($name,)+) where $($name: Type,)+ { const SIGNATURE: &'static Signature = &Signature::static_structure(&[ $( $name::SIGNATURE, )+ ]); } )+ } } tuple_impls! { 1 => (0 T0) 2 => (0 T0 1 T1) 3 => (0 T0 1 T1 2 T2) 4 => (0 T0 1 T1 2 T2 3 T3) 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) 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) 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) 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) 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) 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) } //////////////////////////////////////////////////////////////////////////////// // Arrays are serialized as tuples/structs by Serde so we treat them as such too even though // it's very strange. Slices and arrayvec::ArrayVec can be used anyway so I guess it's no big // deal. impl Type for [T; N] where T: Type, { const SIGNATURE: &'static Signature = &Signature::static_structure(&[T::SIGNATURE; N]); } //////////////////////////////////////////////////////////////////////////////// use std::{ borrow::Cow, collections::{BTreeMap, HashMap}, hash::{BuildHasher, Hash}, }; macro_rules! map_impl { ($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)* >) => { impl Type for $ty where K: Type $(+ $kbound1 $(+ $kbound2)*)*, V: Type, $($typaram: $bound,)* { const SIGNATURE: &'static Signature = &Signature::static_dict(K::SIGNATURE, V::SIGNATURE); } } } map_impl!(BTreeMap); map_impl!(HashMap); //////////////////////////////////////////////////////////////////////////////// impl_type_with_repr! { // usize is serialized as u64: // https://github.com/serde-rs/serde/blob/9b868ef831c95f50dd4bde51a7eb52e3b9ee265a/serde/src/ser/impls.rs#L28 usize => u64 { usize { samples = [usize::MAX, usize::MIN], repr(n) = n as u64, } } } impl_type_with_repr! { // isize is serialized as i64: // https://github.com/serde-rs/serde/blob/9b868ef831c95f50dd4bde51a7eb52e3b9ee265a/serde/src/ser/impls.rs#L22 isize => i64 { isize { samples = [isize::MAX, isize::MIN], repr(n) = n as i64, } } } //////////////////////////////////////////////////////////////////////////////// impl_type_with_repr! { Duration => (u64, u32) { duration { samples = [Duration::ZERO, Duration::MAX], repr(d) = (d.as_secs(), d.subsec_nanos()), } } } //////////////////////////////////////////////////////////////////////////////// macro_rules! impl_type_for_wrapper { ($($wrapper:ident<$T:ident>),+) => { $( impl<$T: Type> Type for $wrapper<$T> { const SIGNATURE: &'static Signature = <$T>::SIGNATURE; } )+ }; } impl_type_for_wrapper!(Wrapping, Saturating, Reverse); //////////////////////////////////////////////////////////////////////////////// macro_rules! atomic_impl { ($($ty:ident $size:expr => $primitive:ident)*) => { $( static_assertions::assert_impl_all!($ty: From<$primitive>); #[cfg(target_has_atomic = $size)] impl Type for $ty { const SIGNATURE: &'static Signature = <$primitive as Type>::SIGNATURE; } )* } } atomic_impl! { AtomicBool "8" => bool AtomicI8 "8" => i8 AtomicI16 "16" => i16 AtomicI32 "32" => i32 AtomicIsize "ptr" => isize AtomicI64 "64" => i64 AtomicU8 "8" => u8 AtomicU16 "16" => u16 AtomicU32 "32" => u32 AtomicU64 "64" => u64 AtomicUsize "ptr" => usize } //////////////////////////////////////////////////////////////////////////////// impl_type_with_repr! { Range => (Idx, Idx) { range { samples = [0..42, 17..100], repr(range) = (range.start, range.end), } } } impl_type_with_repr! { RangeFrom => (Idx,) { range_from { samples = [0.., 17..], repr(range) = (range.start,), } } } impl_type_with_repr! { RangeInclusive => (Idx, Idx) { range_inclusive { samples = [0..=42, 17..=100], repr(range) = (*range.start(), *range.end()), } } } impl_type_with_repr! { RangeTo => (Idx,) { range_to { samples = [..42, ..100], repr(range) = (range.end,), } } } // serde::Serialize is not implemented for `RangeToInclusive` and `RangeFull`: // https://github.com/serde-rs/serde/issues/2685 // TODO: Blanket implementation for more types: https://github.com/serde-rs/serde/blob/master/serde/src/ser/impls.rs zvariant-5.2.0/src/type/mod.rs000064400000000000000000000154561046102023000143760ustar 00000000000000mod dynamic; pub use dynamic::{DynamicDeserialize, DynamicType}; #[cfg(feature = "serde_bytes")] mod bytes; #[cfg(feature = "enumflags2")] mod enumflags2; mod libstd; mod net; mod paths; mod time; #[cfg(feature = "uuid")] mod uuid; use crate::Signature; /// Trait implemented by all serializable types. /// /// This very simple trait provides the signature for the implementing type. Since the [D-Bus type /// system] relies on these signatures, our [serialization and deserialization] API requires this /// trait in addition to [`Serialize`] and [`Deserialize`], respectively. /// /// Implementation is provided for all the [basic types] and blanket implementations for common /// container types, such as, arrays, slices, tuples, [`Vec`] and [`HashMap`]. For easy /// implementation for custom types, use `Type` derive macro from [zvariant_derive] crate. /// /// If your type's signature cannot be determined statically, you should implement the /// [DynamicType] trait instead, which is otherwise automatically implemented if you implement this /// trait. /// /// [D-Bus type system]: https://dbus.freedesktop.org/doc/dbus-specification.html#type-system /// [serialization and deserialization]: index.html#functions /// [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html /// [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html /// [basic types]: trait.Basic.html /// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html /// [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html /// [zvariant_derive]: https://docs.rs/zvariant_derive/latest/zvariant_derive/ pub trait Type { /// The signature for the implementing type, in parsed format. /// /// # Example /// /// ``` /// use std::collections::HashMap; /// use zvariant::{Type, signature::{Child, Signature}}; /// /// assert_eq!(u32::SIGNATURE, &Signature::U32); /// assert_eq!(String::SIGNATURE, &Signature::Str); /// assert_eq!( /// <(u32, &str, u64)>::SIGNATURE, /// &Signature::static_structure(&[&Signature::U32, &Signature::Str, &Signature::U64]), /// ); /// assert_eq!( /// <(u32, &str, &[u64])>::SIGNATURE, /// &Signature::static_structure(&[ /// &Signature::U32, /// &Signature::Str, /// &Signature::Array(Child::Static { child: &Signature::U64 }), /// ]), /// ); /// assert_eq!( /// >::SIGNATURE, /// &Signature::static_dict(&Signature::U8, &Signature::Str), /// ); /// ``` const SIGNATURE: &'static Signature; } /// Implements the [`Type`] trait by delegating the signature to a simpler type (usually a tuple). /// Tests that ensure that the two types are serialize-compatible are auto-generated. /// /// Example: /// ```no_compile /// impl_type_with_repr! { /// // Duration is serialized as a (u64, u32) pair. /// Duration => (u64, u32) { /// // The macro auto-generates tests for us, /// // so we need to provide a test name. /// duration { /// // Sample values used to test serialize compatibility. /// samples = [Duration::ZERO, Duration::MAX], /// // Converts our type into the simpler "repr" type. /// repr(d) = (d.as_secs(), d.subsec_nanos()), /// } /// } /// } /// ``` #[macro_export] macro_rules! impl_type_with_repr { ($($ty:ident)::+ $(<$typaram:ident $(: $($tbound:ident)::+)?>)? => $repr:ty { $test_mod:ident $(<$($typaram_sample:ident = $typaram_sample_value:ty),*>)? { $(signature = $signature:literal,)? samples = $samples:expr, repr($sample_ident:ident) = $into_repr:expr, } }) => { impl $(<$typaram $(: $($tbound)::+)?>)? $crate::Type for $($ty)::+ $(<$typaram>)? { const SIGNATURE: &'static $crate::Signature = <$repr>::SIGNATURE; } #[cfg(test)] #[allow(unused_imports)] mod $test_mod { use super::*; use $crate::{serialized::Context, to_bytes, LE}; $($(type $typaram_sample = $typaram_sample_value;)*)? type Ty = $($ty)::+$(<$typaram>)?; const _: fn() = || { fn assert_impl_all<'de, T: ?Sized + serde::Serialize + serde::Deserialize<'de>>() {} assert_impl_all::(); }; #[test] fn type_can_be_deserialized_from_encoded_type() { let ctx = Context::new_dbus(LE, 0); let samples = $samples; let _: &[Ty] = &samples; for $sample_ident in samples { let encoded = to_bytes(ctx, &$sample_ident).unwrap(); let (decoded, _): (Ty, _) = encoded.deserialize().unwrap(); assert_eq!($sample_ident, decoded); } } #[test] fn repr_can_be_deserialized_from_encoded_type() { let ctx = Context::new_dbus(LE, 0); let samples = $samples; let _: &[Ty] = &samples; for $sample_ident in samples { let repr: $repr = $into_repr; let encoded = to_bytes(ctx, &$sample_ident).unwrap(); let (decoded, _): ($repr, _) = encoded.deserialize().unwrap(); assert_eq!(repr, decoded); } } #[test] fn type_can_be_deserialized_from_encoded_repr() { let ctx = Context::new_dbus(LE, 0); let samples = $samples; let _: &[Ty] = &samples; for $sample_ident in samples { let repr: $repr = $into_repr; let encoded = to_bytes(ctx, &repr).unwrap(); let (decoded, _): (Ty, _) = encoded.deserialize().unwrap(); assert_eq!($sample_ident, decoded); } } #[test] fn encoding_of_type_and_repr_match() { let ctx = Context::new_dbus(LE, 0); let samples = $samples; let _: &[Ty] = &samples; for $sample_ident in samples { let repr: $repr = $into_repr; let encoded = to_bytes(ctx, &$sample_ident).unwrap(); let encoded_repr = to_bytes(ctx, &repr).unwrap(); assert_eq!(encoded.bytes(), encoded_repr.bytes()); } } $( #[test] fn signature_equals() { assert_eq!(::SIGNATURE, $signature); } )? } }; } #[macro_export] #[allow(unused)] macro_rules! static_str_type { ($ty:ty) => { impl Type for $ty { const SIGNATURE: &'static Signature = &Signature::Str; } }; } zvariant-5.2.0/src/type/net.rs000064400000000000000000000031541046102023000143750ustar 00000000000000use crate::impl_type_with_repr; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6}; #[cfg(feature = "url")] impl_type_with_repr! { url::Url => &str { url_ { samples = [url::Url::parse("https://example.com").unwrap()], repr(url) = &url.to_string(), } } } impl_type_with_repr! { Ipv4Addr => [u8; 4] { ipv4_addr { samples = [Ipv4Addr::LOCALHOST], repr(addr) = addr.octets(), } } } impl_type_with_repr! { Ipv6Addr => [u8; 16] { ipv6_addr { samples = [Ipv6Addr::LOCALHOST], repr(addr) = addr.octets(), } } } impl_type_with_repr! { IpAddr => (u32, &[u8]) { ip_addr { samples = [IpAddr::V4(Ipv4Addr::LOCALHOST), IpAddr::V6(Ipv6Addr::LOCALHOST)], repr(addr) = match addr { IpAddr::V4(v4) => (0, &v4.octets()), IpAddr::V6(v6) => (1, &v6.octets()), }, } } } impl_type_with_repr! { SocketAddrV4 => (Ipv4Addr, u16) { socket_addr_v4 { samples = [SocketAddrV4::new(Ipv4Addr::LOCALHOST, 8080)], repr(addr) = (*addr.ip(), addr.port()), } } } impl_type_with_repr! { SocketAddrV6 => (Ipv6Addr, u16) { socket_addr_v6 { samples = [SocketAddrV6::new(Ipv6Addr::LOCALHOST, 8080, 0, 0)], // https://github.com/serde-rs/serde/blob/9b868ef831c95f50dd4bde51a7eb52e3b9ee265a/serde/src/ser/impls.rs#L966 repr(addr) = (*addr.ip(), addr.port()), } } } // TODO(bash): Implement DynamicType for SocketAddr zvariant-5.2.0/src/type/paths.rs000064400000000000000000000003731046102023000147260ustar 00000000000000use crate::{static_str_type, Signature, Type}; static_str_type!(std::path::Path); static_str_type!(std::path::PathBuf); #[cfg(feature = "camino")] static_str_type!(camino::Utf8Path); #[cfg(feature = "camino")] static_str_type!(camino::Utf8PathBuf); zvariant-5.2.0/src/type/time.rs000064400000000000000000000143471046102023000145530ustar 00000000000000use crate::impl_type_with_repr; impl_type_with_repr! { std::time::SystemTime => (u64, u32) { system_time { samples = [std::time::SystemTime::now()], repr(t) = { let since_epoch = t.duration_since(std::time::SystemTime::UNIX_EPOCH).unwrap(); (since_epoch.as_secs(), since_epoch.subsec_nanos()) }, } } } #[cfg(feature = "time")] impl_type_with_repr! { time::Date => (i32, u16) { time_date { samples = [time::Date::MIN, time::Date::MAX, time::Date::from_calendar_date(2011, time::Month::June, 21).unwrap()], // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L92 repr(d) = (d.year(), d.ordinal()), } } } #[cfg(feature = "time")] impl_type_with_repr! { time::Duration => (i64, i32) { time_duration { samples = [time::Duration::MIN, time::Duration::MAX, time::Duration::new(42, 123456789)], // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L119 repr(d) = (d.whole_seconds(), d.subsec_nanoseconds()), } } } #[cfg(feature = "time")] impl_type_with_repr! { time::OffsetDateTime => (i32, u16, u8, u8, u8, u32, i8, i8, i8) { time_offset_date_time { samples = [ time::OffsetDateTime::now_utc(), time::OffsetDateTime::new_in_offset( time::Date::from_calendar_date(2024, time::Month::May, 4).unwrap(), time::Time::from_hms_nano(15, 32, 43, 2_000).unwrap(), time::UtcOffset::from_hms(1, 2, 3).unwrap()) ], // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L155 repr(d) = ( d.year(), d.ordinal(), d.hour(), d.minute(), d.second(), d.nanosecond(), d.offset().whole_hours(), d.offset().minutes_past_hour(), d.offset().seconds_past_minute() ), } } } #[cfg(feature = "time")] impl_type_with_repr! { time::PrimitiveDateTime => (i32, u16, u8, u8, u8, u32) { time_primitive_date_time { samples = [ time::PrimitiveDateTime::MIN, time::PrimitiveDateTime::MAX, time::PrimitiveDateTime::new( time::Date::from_calendar_date(2024, time::Month::May, 4).unwrap(), time::Time::from_hms_nano(15, 32, 43, 2_000).unwrap()) ], // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L200 repr(d) = ( d.year(), d.ordinal(), d.hour(), d.minute(), d.second(), d.nanosecond() ), } } } #[cfg(feature = "time")] impl_type_with_repr! { time::Time => (u8, u8, u8, u32) { time_time { samples = [time::Time::MIDNIGHT, time::Time::from_hms(23, 42, 59).unwrap(), time::Time::from_hms_nano(15, 32, 43, 2_000).unwrap()], // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L246 repr(t) = (t.hour(), t.minute(), t.second(), t.nanosecond()), } } } #[cfg(feature = "time")] impl_type_with_repr! { time::UtcOffset => (i8, i8, i8) { time_utc_offset { samples = [time::UtcOffset::UTC, time::UtcOffset::from_hms(1, 2, 3).unwrap()], // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L282 repr(offset) = (offset.whole_hours(), offset.minutes_past_hour(), offset.seconds_past_minute()), } } } #[cfg(feature = "time")] impl_type_with_repr! { time::Weekday => u8 { time_weekday { samples = [time::Weekday::Monday, time::Weekday::Wednesday, time::Weekday::Friday], // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L312 repr(weekday) = weekday.number_from_monday(), } } } #[cfg(feature = "time")] impl_type_with_repr! { time::Month => u8 { time_month { samples = [time::Month::January, time::Month::July, time::Month::December], // Serialized as month number: // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L337 repr(month) = month as u8, } } } #[cfg(feature = "chrono")] impl_type_with_repr! { chrono::DateTime => &str { chrono_date_time { samples = [chrono::DateTime::::MIN_UTC, chrono::DateTime::::MAX_UTC], repr(date) = &date.format("%Y-%m-%dT%H:%M:%S%.fZ").to_string(), } } } #[cfg(feature = "chrono")] impl_type_with_repr! { chrono::Month => &str { chrono_month { samples = [chrono::Month::January, chrono::Month::December], repr(month) = month.name(), } } } #[cfg(feature = "chrono")] impl_type_with_repr! { chrono::NaiveDate => &str { chrono_naive_date { samples = [chrono::NaiveDate::from_ymd_opt(2016, 7, 8).unwrap()], repr(d) = &format!("{d:?}"), } } } #[cfg(feature = "chrono")] impl_type_with_repr! { chrono::NaiveDateTime => &str { chrono_naive_date_time { samples = [chrono::NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap()], repr(dt) = &format!("{dt:?}"), } } } #[cfg(feature = "chrono")] impl_type_with_repr! { chrono::NaiveTime => &str { chrono_naive_time { samples = [chrono::NaiveTime::from_hms_opt(9, 10, 11).unwrap()], repr(t) = &format!("{t:?}"), } } } #[cfg(feature = "chrono")] impl_type_with_repr! { chrono::Weekday => &str { chrono_weekday { samples = [chrono::Weekday::Mon, chrono::Weekday::Fri], // Serialized as the weekday's name. repr(weekday) = &weekday.to_string(), } } } zvariant-5.2.0/src/type/uuid.rs000064400000000000000000000004261046102023000145540ustar 00000000000000use crate::impl_type_with_repr; impl_type_with_repr! { uuid::Uuid => &[u8] { uuid_ { signature = "ay", samples = [uuid::Uuid::parse_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap()], repr(u) = u.as_bytes(), } } } zvariant-5.2.0/src/utils.rs000064400000000000000000000061341046102023000137670ustar 00000000000000use std::slice::SliceIndex; use crate::{Error, Result}; /// The prefix of ARRAY type signature, as a character. Provided for manual signature creation. pub const ARRAY_SIGNATURE_CHAR: char = 'a'; /// The prefix of ARRAY type signature, as a string. Provided for manual signature creation. pub const ARRAY_SIGNATURE_STR: &str = "a"; pub(crate) const ARRAY_ALIGNMENT_DBUS: usize = 4; /// The opening character of STRUCT type signature. Provided for manual signature creation. pub const STRUCT_SIG_START_CHAR: char = '('; /// The closing character of STRUCT type signature. Provided for manual signature creation. pub const STRUCT_SIG_END_CHAR: char = ')'; /// The opening character of STRUCT type signature, as a string. Provided for manual signature /// creation. pub const STRUCT_SIG_START_STR: &str = "("; /// The closing character of STRUCT type signature, as a string. Provided for manual signature /// creation. pub const STRUCT_SIG_END_STR: &str = ")"; pub(crate) const STRUCT_ALIGNMENT_DBUS: usize = 8; /// The opening character of DICT_ENTRY type signature. Provided for manual signature creation. pub const DICT_ENTRY_SIG_START_CHAR: char = '{'; /// The closing character of DICT_ENTRY type signature. Provided for manual signature creation. pub const DICT_ENTRY_SIG_END_CHAR: char = '}'; /// The opening character of DICT_ENTRY type signature, as a string. Provided for manual signature /// creation. pub const DICT_ENTRY_SIG_START_STR: &str = "{"; /// The closing character of DICT_ENTRY type signature, as a string. Provided for manual signature /// creation. pub const DICT_ENTRY_SIG_END_STR: &str = "}"; pub(crate) const DICT_ENTRY_ALIGNMENT_DBUS: usize = 8; /// The VARIANT type signature. Provided for manual signature creation. pub const VARIANT_SIGNATURE_CHAR: char = 'v'; /// The VARIANT type signature, as a string. Provided for manual signature creation. pub const VARIANT_SIGNATURE_STR: &str = "v"; #[cfg(feature = "gvariant")] pub(crate) const VARIANT_ALIGNMENT_GVARIANT: usize = 8; /// The prefix of MAYBE (GVariant-specific) type signature, as a character. Provided for manual /// signature creation. #[cfg(feature = "gvariant")] pub const MAYBE_SIGNATURE_CHAR: char = 'm'; /// The prefix of MAYBE (GVariant-specific) type signature, as a string. Provided for manual /// signature creation. #[cfg(feature = "gvariant")] pub const MAYBE_SIGNATURE_STR: &str = "m"; pub(crate) fn padding_for_n_bytes(value: usize, align: usize) -> usize { let len_rounded_up = value.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); len_rounded_up.wrapping_sub(value) } pub(crate) fn usize_to_u32(value: usize) -> u32 { assert!( value <= (u32::MAX as usize), "{} too large for `u32`", value, ); value as u32 } pub(crate) fn usize_to_u8(value: usize) -> u8 { assert!(value <= (u8::MAX as usize), "{} too large for `u8`", value,); value as u8 } /// Slice the given slice of bytes safely and return an error if the slice is too small. pub(crate) fn subslice(input: &[T], index: I) -> Result<&I::Output> where I: SliceIndex<[T]>, { input.get(index).ok_or(Error::OutOfBounds) } zvariant-5.2.0/src/value.rs000064400000000000000000001144021046102023000137410ustar 00000000000000use core::{ cmp::Ordering, fmt::{Display, Write}, hash::{Hash, Hasher}, marker::PhantomData, mem::discriminant, str, }; use serde::{ de::{ Deserialize, DeserializeSeed, Deserializer, Error, MapAccess, SeqAccess, Unexpected, Visitor, }, ser::{ Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeTupleStruct, Serializer, }, }; use static_assertions::assert_impl_all; use crate::{ array_display_fmt, dict_display_fmt, structure_display_fmt, utils::*, Array, Basic, Dict, DynamicType, ObjectPath, OwnedValue, Signature, Str, Structure, StructureBuilder, Type, }; #[cfg(feature = "gvariant")] use crate::{maybe_display_fmt, Maybe}; #[cfg(unix)] use crate::Fd; /// A generic container, in the form of an enum that holds exactly one value of any of the other /// types. /// /// Note that this type corresponds to the `VARIANT` data type defined by the [D-Bus specification] /// and as such, its encoding is not the same as that of the enclosed value. /// /// # Examples /// /// ``` /// use zvariant::{to_bytes, serialized::Context, Value, LE}; /// /// // Create a Value from an i16 /// let v = Value::new(i16::max_value()); /// /// // Encode it /// let ctxt = Context::new_dbus(LE, 0); /// let encoding = to_bytes(ctxt, &v).unwrap(); /// /// // Decode it back /// let v: Value = encoding.deserialize().unwrap().0; /// /// // Check everything is as expected /// assert_eq!(i16::try_from(&v).unwrap(), i16::max_value()); /// ``` /// /// Now let's try a more complicated example: /// /// ``` /// use zvariant::{to_bytes, serialized::Context, LE}; /// use zvariant::{Structure, Value, Str}; /// /// // Create a Value from a tuple this time /// let v = Value::new((i16::max_value(), "hello", true)); /// /// // Same drill as previous example /// let ctxt = Context::new_dbus(LE, 0); /// let encoding = to_bytes(ctxt, &v).unwrap(); /// let v: Value = encoding.deserialize().unwrap().0; /// /// // Check everything is as expected /// let s = Structure::try_from(v).unwrap(); /// assert_eq!( /// <(i16, Str, bool)>::try_from(s).unwrap(), /// (i16::max_value(), Str::from("hello"), true), /// ); /// ``` /// /// [D-Bus specification]: https://dbus.freedesktop.org/doc/dbus-specification.html#container-types #[derive(Debug, PartialEq, PartialOrd)] pub enum Value<'a> { // Simple types U8(u8), Bool(bool), I16(i16), U16(u16), I32(i32), U32(u32), I64(i64), U64(u64), F64(f64), Str(Str<'a>), Signature(Signature), ObjectPath(ObjectPath<'a>), Value(Box>), // Container types Array(Array<'a>), Dict(Dict<'a, 'a>), Structure(Structure<'a>), #[cfg(feature = "gvariant")] Maybe(Maybe<'a>), #[cfg(unix)] Fd(Fd<'a>), } impl Hash for Value<'_> { fn hash(&self, state: &mut H) { discriminant(self).hash(state); match self { Self::U8(inner) => inner.hash(state), Self::Bool(inner) => inner.hash(state), Self::I16(inner) => inner.hash(state), Self::U16(inner) => inner.hash(state), Self::I32(inner) => inner.hash(state), Self::U32(inner) => inner.hash(state), Self::I64(inner) => inner.hash(state), Self::U64(inner) => inner.hash(state), // To hold the +0.0 == -0.0 => hash(+0.0) == hash(-0.0) property. // See https://doc.rust-lang.org/beta/std/hash/trait.Hash.html#hash-and-eq Self::F64(inner) if *inner == 0. => 0f64.to_le_bytes().hash(state), Self::F64(inner) => inner.to_le_bytes().hash(state), Self::Str(inner) => inner.hash(state), Self::Signature(inner) => inner.hash(state), Self::ObjectPath(inner) => inner.hash(state), Self::Value(inner) => inner.hash(state), Self::Array(inner) => inner.hash(state), Self::Dict(inner) => inner.hash(state), Self::Structure(inner) => inner.hash(state), #[cfg(feature = "gvariant")] Self::Maybe(inner) => inner.hash(state), #[cfg(unix)] Self::Fd(inner) => inner.hash(state), } } } impl Eq for Value<'_> {} impl Ord for Value<'_> { fn cmp(&self, other: &Self) -> Ordering { self.partial_cmp(other) .unwrap_or_else(|| match (self, other) { (Self::F64(lhs), Self::F64(rhs)) => lhs.total_cmp(rhs), // `partial_cmp` returns `Some(_)` if either the discriminants are different // or if both the left hand side and right hand side is `Self::F64(_)`. We can only // reach this arm, if only one of the sides is `Self::F64(_)`. So we can just // pretend the ordering is equal. _ => Ordering::Equal, }) } } assert_impl_all!(Value<'_>: Send, Sync, Unpin); macro_rules! serialize_value { ($self:ident $serializer:ident.$method:ident $($first_arg:expr)*) => { match $self { Value::U8(value) => $serializer.$method($($first_arg,)* value), Value::Bool(value) => $serializer.$method($($first_arg,)* value), Value::I16(value) => $serializer.$method($($first_arg,)* value), Value::U16(value) => $serializer.$method($($first_arg,)* value), Value::I32(value) => $serializer.$method($($first_arg,)* value), Value::U32(value) => $serializer.$method($($first_arg,)* value), Value::I64(value) => $serializer.$method($($first_arg,)* value), Value::U64(value) => $serializer.$method($($first_arg,)* value), Value::F64(value) => $serializer.$method($($first_arg,)* value), Value::Str(value) => $serializer.$method($($first_arg,)* value), Value::Signature(value) => $serializer.$method($($first_arg,)* value), Value::ObjectPath(value) => $serializer.$method($($first_arg,)* value), Value::Value(value) => $serializer.$method($($first_arg,)* value), // Container types Value::Array(value) => $serializer.$method($($first_arg,)* value), Value::Dict(value) => $serializer.$method($($first_arg,)* value), Value::Structure(value) => $serializer.$method($($first_arg,)* value), #[cfg(feature = "gvariant")] Value::Maybe(value) => $serializer.$method($($first_arg,)* value), #[cfg(unix)] Value::Fd(value) => $serializer.$method($($first_arg,)* value), } } } impl<'a> Value<'a> { /// Make a [`Value`] for a given value. /// /// In general, you can use [`Into`] trait on basic types, except /// when you explicitly need to wrap [`Value`] itself, in which /// case this constructor comes handy. /// /// # Examples /// /// ``` /// use zvariant::Value; /// /// let s = Value::new("hello"); /// let u: Value = 51.into(); /// assert_ne!(s, u); /// ``` /// /// [`Value`]: enum.Value.html /// [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html pub fn new(value: T) -> Self where T: Into + DynamicType, { // With specialization, we wouldn't have this if value.signature() == VARIANT_SIGNATURE_STR { Self::Value(Box::new(value.into())) } else { value.into() } } /// Try to create an owned version of `self`. /// /// # Errors /// /// This method can currently only fail on Unix platforms for [`Value::Fd`] variant. This /// happens when the current process exceeds the maximum number of open file descriptors. pub fn try_to_owned(&self) -> crate::Result { Ok(OwnedValue(match self { Value::U8(v) => Value::U8(*v), Value::Bool(v) => Value::Bool(*v), Value::I16(v) => Value::I16(*v), Value::U16(v) => Value::U16(*v), Value::I32(v) => Value::I32(*v), Value::U32(v) => Value::U32(*v), Value::I64(v) => Value::I64(*v), Value::U64(v) => Value::U64(*v), Value::F64(v) => Value::F64(*v), Value::Str(v) => Value::Str(v.to_owned()), Value::Signature(v) => Value::Signature(v.to_owned()), Value::ObjectPath(v) => Value::ObjectPath(v.to_owned()), Value::Value(v) => { let o = OwnedValue::try_from(&**v)?; Value::Value(Box::new(o.into_inner())) } Value::Array(v) => Value::Array(v.try_to_owned()?), Value::Dict(v) => Value::Dict(v.try_to_owned()?), Value::Structure(v) => Value::Structure(v.try_to_owned()?), #[cfg(feature = "gvariant")] Value::Maybe(v) => Value::Maybe(v.try_to_owned()?), #[cfg(unix)] Value::Fd(v) => Value::Fd(v.try_to_owned()?), })) } /// Get the signature of the enclosed value. pub fn value_signature(&self) -> &Signature { match self { Value::U8(_) => u8::SIGNATURE, Value::Bool(_) => bool::SIGNATURE, Value::I16(_) => i16::SIGNATURE, Value::U16(_) => u16::SIGNATURE, Value::I32(_) => i32::SIGNATURE, Value::U32(_) => u32::SIGNATURE, Value::I64(_) => i64::SIGNATURE, Value::U64(_) => u64::SIGNATURE, Value::F64(_) => f64::SIGNATURE, Value::Str(_) => <&str>::SIGNATURE, Value::Signature(_) => Signature::SIGNATURE, Value::ObjectPath(_) => ObjectPath::SIGNATURE, Value::Value(_) => &Signature::Variant, // Container types Value::Array(value) => value.signature(), Value::Dict(value) => value.signature(), Value::Structure(value) => value.signature(), #[cfg(feature = "gvariant")] Value::Maybe(value) => value.signature(), #[cfg(unix)] Value::Fd(_) => Fd::SIGNATURE, } } /// Try to clone the value. /// /// # Errors /// /// This method can currently only fail on Unix platforms for [`Value::Fd`] variant containing /// an [`Fd::Owned`] variant. This happens when the current process exceeds the maximum number /// of open file descriptors. pub fn try_clone(&self) -> crate::Result { Ok(match self { Value::U8(v) => Value::U8(*v), Value::Bool(v) => Value::Bool(*v), Value::I16(v) => Value::I16(*v), Value::U16(v) => Value::U16(*v), Value::I32(v) => Value::I32(*v), Value::U32(v) => Value::U32(*v), Value::I64(v) => Value::I64(*v), Value::U64(v) => Value::U64(*v), Value::F64(v) => Value::F64(*v), Value::Str(v) => Value::Str(v.clone()), Value::Signature(v) => Value::Signature(v.clone()), Value::ObjectPath(v) => Value::ObjectPath(v.clone()), Value::Value(v) => Value::Value(Box::new(v.try_clone()?)), Value::Array(v) => Value::Array(v.try_clone()?), Value::Dict(v) => Value::Dict(v.try_clone()?), Value::Structure(v) => Value::Structure(v.try_clone()?), #[cfg(feature = "gvariant")] Value::Maybe(v) => Value::Maybe(v.try_clone()?), #[cfg(unix)] Value::Fd(v) => Value::Fd(v.try_clone()?), }) } pub(crate) fn serialize_value_as_struct_field( &self, name: &'static str, serializer: &mut S, ) -> Result<(), S::Error> where S: SerializeStruct, { serialize_value!(self serializer.serialize_field name) } pub(crate) fn serialize_value_as_tuple_struct_field( &self, serializer: &mut S, ) -> Result<(), S::Error> where S: SerializeTupleStruct, { serialize_value!(self serializer.serialize_field) } // Really crappy that we need to do this separately for struct and seq cases. :( pub(crate) fn serialize_value_as_seq_element( &self, serializer: &mut S, ) -> Result<(), S::Error> where S: SerializeSeq, { serialize_value!(self serializer.serialize_element) } pub(crate) fn serialize_value_as_dict_key(&self, serializer: &mut S) -> Result<(), S::Error> where S: SerializeMap, { serialize_value!(self serializer.serialize_key) } pub(crate) fn serialize_value_as_dict_value( &self, serializer: &mut S, ) -> Result<(), S::Error> where S: SerializeMap, { serialize_value!(self serializer.serialize_value) } #[cfg(feature = "gvariant")] pub(crate) fn serialize_value_as_some(&self, serializer: S) -> Result where S: Serializer, { serialize_value!(self serializer.serialize_some) } /// Try to get the underlying type `T`. /// /// Note that [`TryFrom`] is implemented for various types, and it's usually best to use /// that instead. However, in generic code where you also want to unwrap [`Value::Value`], /// you should use this function (because [`TryFrom`] can not be implemented for `Value` /// itself as [`From`] is implicitly implemented for `Value`). /// /// # Examples /// /// ``` /// use zvariant::{Error, Result, Value}; /// /// fn value_vec_to_type_vec<'a, T>(values: Vec>) -> Result> /// where /// T: TryFrom>, /// >>::Error: Into, /// { /// let mut res = vec![]; /// for value in values.into_iter() { /// res.push(value.downcast()?); /// } /// /// Ok(res) /// } /// /// // Let's try u32 values first /// let v = vec![Value::U32(42), Value::U32(43)]; /// let v = value_vec_to_type_vec::(v).unwrap(); /// assert_eq!(v[0], 42); /// assert_eq!(v[1], 43); /// /// // Now try Value values /// let v = vec![Value::new(Value::U32(42)), Value::new(Value::U32(43))]; /// let v = value_vec_to_type_vec::(v).unwrap(); /// assert_eq!(v[0], Value::U32(42)); /// assert_eq!(v[1], Value::U32(43)); /// ``` /// /// [`Value::Value`]: enum.Value.html#variant.Value /// [`TryFrom`]: https://doc.rust-lang.org/std/convert/trait.TryFrom.html /// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html pub fn downcast(self) -> Result where T: TryFrom>, >>::Error: Into, { if let Value::Value(v) = self { T::try_from(*v) } else { T::try_from(self) } .map_err(Into::into) } /// Try to get the underlying type `T`. /// /// Same as [`downcast`] except it doesn't consume `self` and hence requires /// `T: TryFrom<&Value<_>>`. /// /// # Examples /// /// ``` /// use zvariant::{Error, Result, Value}; /// /// fn value_vec_to_type_vec<'a, T>(values: &'a Vec>) -> Result> /// where /// &'a T: TryFrom<&'a Value<'a>>, /// <&'a T as TryFrom<&'a Value<'a>>>::Error: Into, /// { /// let mut res = vec![]; /// for value in values.into_iter() { /// res.push(value.downcast_ref()?); /// } /// /// Ok(res) /// } /// /// // Let's try u32 values first /// let v = vec![Value::U32(42), Value::U32(43)]; /// let v = value_vec_to_type_vec::(&v).unwrap(); /// assert_eq!(*v[0], 42); /// assert_eq!(*v[1], 43); /// /// // Now try Value values /// let v = vec![Value::new(Value::U32(42)), Value::new(Value::U32(43))]; /// let v = value_vec_to_type_vec::(&v).unwrap(); /// assert_eq!(*v[0], Value::U32(42)); /// assert_eq!(*v[1], Value::U32(43)); /// ``` /// /// [`downcast`]: enum.Value.html#method.downcast pub fn downcast_ref(&'a self) -> Result where T: TryFrom<&'a Value<'a>>, >>::Error: Into, { if let Value::Value(v) = self { ::try_from(v) } else { ::try_from(self) } .map_err(Into::into) } } impl Display for Value<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { value_display_fmt(self, f, true) } } /// Implemented based on https://gitlab.gnome.org/GNOME/glib/-/blob/e1d47f0b0d0893ac9171e24cc7bf635495376546/glib/gvariant.c#L2213 pub(crate) fn value_display_fmt( value: &Value<'_>, f: &mut std::fmt::Formatter<'_>, type_annotate: bool, ) -> std::fmt::Result { match value { Value::U8(num) => { if type_annotate { f.write_str("byte ")?; } write!(f, "0x{:02x}", num) } Value::Bool(boolean) => { write!(f, "{}", boolean) } Value::I16(num) => { if type_annotate { f.write_str("int16 ")?; } write!(f, "{}", num) } Value::U16(num) => { if type_annotate { f.write_str("uint16 ")?; } write!(f, "{}", num) } Value::I32(num) => { // Never annotate this type because it is the default for numbers write!(f, "{}", num) } Value::U32(num) => { if type_annotate { f.write_str("uint32 ")?; } write!(f, "{}", num) } Value::I64(num) => { if type_annotate { f.write_str("int64 ")?; } write!(f, "{}", num) } Value::U64(num) => { if type_annotate { f.write_str("uint64 ")?; } write!(f, "{}", num) } Value::F64(num) => { if num.fract() == 0. { // Add a dot to make it clear that this is a float write!(f, "{}.", num) } else { write!(f, "{}", num) } } Value::Str(string) => { write!(f, "{:?}", string.as_str()) } Value::Signature(val) => { if type_annotate { f.write_str("signature ")?; } write!(f, "{:?}", val.to_string()) } Value::ObjectPath(val) => { if type_annotate { f.write_str("objectpath ")?; } write!(f, "{:?}", val.as_str()) } Value::Value(child) => { f.write_char('<')?; // Always annotate types in nested variants, because they are (by nature) of // variable type. value_display_fmt(child, f, true)?; f.write_char('>')?; Ok(()) } Value::Array(array) => array_display_fmt(array, f, type_annotate), Value::Dict(dict) => dict_display_fmt(dict, f, type_annotate), Value::Structure(structure) => structure_display_fmt(structure, f, type_annotate), #[cfg(feature = "gvariant")] Value::Maybe(maybe) => maybe_display_fmt(maybe, f, type_annotate), #[cfg(unix)] Value::Fd(handle) => { if type_annotate { f.write_str("handle ")?; } write!(f, "{}", handle) } } } impl Serialize for Value<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { // Serializer implementation needs to ensure padding isn't added for Value. let mut structure = serializer.serialize_struct("Variant", 2)?; let signature = self.value_signature(); structure.serialize_field("signature", &signature)?; self.serialize_value_as_struct_field("value", &mut structure)?; structure.end() } } impl<'de: 'a, 'a> Deserialize<'de> for Value<'a> { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let visitor = ValueVisitor; deserializer.deserialize_any(visitor) } } // Note that the Visitor implementations don't check for validity of the // signature. That's left to the Deserialize implementation of Signature // itself. struct ValueVisitor; impl<'de> Visitor<'de> for ValueVisitor { type Value = Value<'de>; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("a Value") } fn visit_seq(self, mut visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { let signature = visitor.next_element::()?.ok_or_else(|| { Error::invalid_value(Unexpected::Other("nothing"), &"a Value signature") })?; let seed = ValueSeed::> { signature: &signature, phantom: PhantomData, }; visitor .next_element_seed(seed)? .ok_or_else(|| Error::invalid_value(Unexpected::Other("nothing"), &"a Value value")) } fn visit_map(self, mut visitor: V) -> Result, V::Error> where V: MapAccess<'de>, { let (_, signature) = visitor.next_entry::<&str, Signature>()?.ok_or_else(|| { Error::invalid_value(Unexpected::Other("nothing"), &"a Value signature") })?; let _ = visitor.next_key::<&str>()?; let seed = ValueSeed::> { signature: &signature, phantom: PhantomData, }; visitor.next_value_seed(seed) } } pub(crate) struct SignatureSeed<'sig> { pub signature: &'sig Signature, } impl SignatureSeed<'_> { pub(crate) fn visit_array<'de, V>(self, mut visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { let element_signature = match self.signature { Signature::Array(child) => child.signature(), _ => { return Err(Error::invalid_type( Unexpected::Str(&self.signature.to_string()), &"an array signature", )) } }; let mut array = Array::new_full_signature(self.signature); while let Some(elem) = visitor.next_element_seed(ValueSeed::> { signature: element_signature, phantom: PhantomData, })? { elem.value_signature(); array.append(elem).map_err(Error::custom)?; } Ok(array) } pub(crate) fn visit_struct<'de, V>(self, mut visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { let fields_signatures = match self.signature { Signature::Structure(fields) => fields.iter(), _ => { return Err(Error::invalid_type( Unexpected::Str(&self.signature.to_string()), &"a structure signature", )) } }; let mut builder = StructureBuilder::new(); for field_signature in fields_signatures { if let Some(field) = visitor.next_element_seed(ValueSeed::> { signature: field_signature, phantom: PhantomData, })? { builder = builder.append_field(field); } } Ok(builder.build_with_signature(self.signature)) } } impl<'sig, T> From> for SignatureSeed<'sig> { fn from(seed: ValueSeed<'sig, T>) -> Self { SignatureSeed { signature: seed.signature, } } } struct ValueSeed<'sig, T> { signature: &'sig Signature, phantom: PhantomData, } impl<'de, T> ValueSeed<'_, T> where T: Deserialize<'de>, { #[inline] fn visit_array(self, visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { SignatureSeed::from(self) .visit_array(visitor) .map(Value::Array) } #[inline] fn visit_struct(self, visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { SignatureSeed::from(self) .visit_struct(visitor) .map(Value::Structure) } #[inline] fn visit_variant_as_seq(self, visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { ValueVisitor .visit_seq(visitor) .map(|v| Value::Value(Box::new(v))) } #[inline] fn visit_variant_as_map(self, visitor: V) -> Result, V::Error> where V: MapAccess<'de>, { ValueVisitor .visit_map(visitor) .map(|v| Value::Value(Box::new(v))) } } macro_rules! value_seed_basic_method { ($name:ident, $type:ty) => { #[inline] fn $name(self, value: $type) -> Result, E> where E: serde::de::Error, { Ok(value.into()) } }; } impl<'de, T> Visitor<'de> for ValueSeed<'_, T> where T: Deserialize<'de>, { type Value = Value<'de>; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("a Value value") } value_seed_basic_method!(visit_bool, bool); value_seed_basic_method!(visit_i16, i16); value_seed_basic_method!(visit_i64, i64); value_seed_basic_method!(visit_u8, u8); value_seed_basic_method!(visit_u16, u16); value_seed_basic_method!(visit_u32, u32); value_seed_basic_method!(visit_u64, u64); value_seed_basic_method!(visit_f64, f64); fn visit_i32(self, value: i32) -> Result, E> where E: serde::de::Error, { let v = match &self.signature { #[cfg(unix)] Signature::Fd => { // SAFETY: The `'de` lifetimes will ensure the borrow won't outlive the raw FD. let fd = unsafe { std::os::fd::BorrowedFd::borrow_raw(value) }; Fd::Borrowed(fd).into() } _ => value.into(), }; Ok(v) } #[inline] fn visit_str(self, value: &str) -> Result, E> where E: serde::de::Error, { self.visit_string(String::from(value)) } fn visit_borrowed_str(self, v: &'de str) -> Result where E: Error, { match &self.signature { Signature::Str => Ok(Value::Str(Str::from(v))), Signature::Signature => Signature::try_from(v) .map(Value::Signature) .map_err(Error::custom), Signature::ObjectPath => Ok(Value::ObjectPath(ObjectPath::from_str_unchecked(v))), _ => { let expected = format!( "`{}`, `{}` or `{}`", <&str>::SIGNATURE_STR, Signature::SIGNATURE_STR, ObjectPath::SIGNATURE_STR, ); Err(Error::invalid_type( Unexpected::Str(&self.signature.to_string()), &expected.as_str(), )) } } } fn visit_seq(self, visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { match &self.signature { // For some reason rustc doesn't like us using ARRAY_SIGNATURE_CHAR const Signature::Array(_) => self.visit_array(visitor), Signature::Structure(_) => self.visit_struct(visitor), Signature::Variant => self.visit_variant_as_seq(visitor), s => Err(Error::invalid_value( Unexpected::Str(&s.to_string()), &"a Value signature", )), } } fn visit_map(self, mut visitor: V) -> Result, V::Error> where V: MapAccess<'de>, { let (key_signature, value_signature) = match &self.signature { Signature::Dict { key, value } => (key.signature().clone(), value.signature().clone()), Signature::Variant => return self.visit_variant_as_map(visitor), _ => { return Err(Error::invalid_type( Unexpected::Str(&self.signature.to_string()), &"a dict signature", )) } }; let mut dict = Dict::new_full_signature(self.signature); while let Some((key, value)) = visitor.next_entry_seed( ValueSeed::> { signature: &key_signature, phantom: PhantomData, }, ValueSeed::> { signature: &value_signature, phantom: PhantomData, }, )? { dict.append(key, value).map_err(Error::custom)?; } Ok(Value::Dict(dict)) } #[cfg(feature = "gvariant")] fn visit_some(self, deserializer: D) -> Result where D: Deserializer<'de>, { let child_signature = match &self.signature { Signature::Maybe(child) => child.signature().clone(), _ => { return Err(Error::invalid_type( Unexpected::Str(&self.signature.to_string()), &"a maybe signature", )) } }; let visitor = ValueSeed:: { signature: &child_signature, phantom: PhantomData, }; deserializer .deserialize_any(visitor) .map(|v| Value::Maybe(Maybe::just_full_signature(v, self.signature))) } #[cfg(not(feature = "gvariant"))] fn visit_some(self, _deserializer: D) -> Result where D: Deserializer<'de>, { panic!("`Maybe` type is only supported for GVariant format but it's disabled"); } #[cfg(feature = "gvariant")] fn visit_none(self) -> Result where E: Error, { let value = Maybe::nothing_full_signature(self.signature); Ok(Value::Maybe(value)) } #[cfg(not(feature = "gvariant"))] fn visit_none(self) -> Result where E: Error, { panic!("`Maybe` type is only supported for GVariant format but it's disabled"); } } impl<'de, T> DeserializeSeed<'de> for ValueSeed<'_, T> where T: Deserialize<'de>, { type Value = Value<'de>; fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_any(self) } } impl Type for Value<'_> { const SIGNATURE: &'static Signature = &Signature::Variant; } impl<'a> TryFrom<&Value<'a>> for Value<'a> { type Error = crate::Error; fn try_from(value: &Value<'a>) -> crate::Result> { value.try_clone() } } impl Clone for Value<'_> { /// Clone the value. /// /// # Panics /// /// This method can only fail on Unix platforms for [`Value::Fd`] variant containing an /// [`Fd::Owned`] variant. This happens when the current process exceeds the limit on maximum /// number of open file descriptors. fn clone(&self) -> Self { self.try_clone() .expect("Process exceeded limit on maximum number of open file descriptors") } } #[cfg(test)] mod tests { use std::collections::HashMap; use super::*; #[test] fn value_display() { assert_eq!( Value::new(( 255_u8, true, -1_i16, 65535_u16, -1, 1_u32, -9223372036854775808_i64, 18446744073709551615_u64, (-1., 1.0, 11000000000., 1.1e-10) )) .to_string(), "(byte 0xff, true, int16 -1, uint16 65535, -1, uint32 1, \ int64 -9223372036854775808, uint64 18446744073709551615, \ (-1., 1., 11000000000., 0.00000000011))" ); assert_eq!( Value::new(vec![ "", " ", "a", r#"""#, "'", "a'b", "a'\"b", "\\", "\n'\"", ]) .to_string(), r#"["", " ", "a", "\"", "'", "a'b", "a'\"b", "\\", "\n'\""]"# ); assert_eq!( Value::new(vec![ "\x07\x08\x09\x0A\x0B\x0C\x0D", "\x7F", char::from_u32(0xD8000).unwrap().to_string().as_str() ]) .to_string(), r#"["\u{7}\u{8}\t\n\u{b}\u{c}\r", "\u{7f}", "\u{d8000}"]"# ); assert_eq!( Value::new(( vec![ Signature::try_from("").unwrap(), Signature::try_from("(ysa{sd})").unwrap(), ], vec![ ObjectPath::from_static_str("/").unwrap(), ObjectPath::from_static_str("/a/very/looooooooooooooooooooooooo0000o0ng/path") .unwrap(), ], vec![ Value::new(0_u8), Value::new((Value::new(51), Value::new(Value::new(1_u32)))), ] )) .to_string(), "([signature \"\", \"(ysa{sd})\"], \ [objectpath \"/\", \"/a/very/looooooooooooooooooooooooo0000o0ng/path\"], \ [, <(<51>, <>)>])" ); assert_eq!(Value::new(vec![] as Vec>).to_string(), "@aax []"); assert_eq!( Value::new(vec![ vec![0_i16, 1_i16], vec![2_i16, 3_i16], vec![4_i16, 5_i16] ]) .to_string(), "[[int16 0, 1], [2, 3], [4, 5]]" ); assert_eq!( Value::new(vec![ b"Hello".to_vec(), b"Hell\0o".to_vec(), b"H\0ello\0".to_vec(), b"Hello\0".to_vec(), b"\0".to_vec(), b" \0".to_vec(), b"'\0".to_vec(), b"\n'\"\0".to_vec(), b"\\\0".to_vec(), ]) .to_string(), "[[byte 0x48, 0x65, 0x6c, 0x6c, 0x6f], \ [0x48, 0x65, 0x6c, 0x6c, 0x00, 0x6f], \ [0x48, 0x00, 0x65, 0x6c, 0x6c, 0x6f, 0x00], \ b\"Hello\", b\"\", b\" \", b\"'\", b\"\\n'\\\"\", b\"\\\\\"]" ); assert_eq!( Value::new(HashMap::::new()).to_string(), "@a{bb} {}" ); assert_eq!( Value::new(vec![(true, 0_i64)].into_iter().collect::>()).to_string(), "{true: int64 0}", ); // The order of the entries may vary let val = Value::new( vec![(32_u16, 64_i64), (100_u16, 200_i64)] .into_iter() .collect::>(), ) .to_string(); assert!(val.starts_with('{')); assert!(val.ends_with('}')); assert_eq!(val.matches("uint16").count(), 1); assert_eq!(val.matches("int64").count(), 1); let items_str = val.split(", ").collect::>(); assert_eq!(items_str.len(), 2); assert!(items_str .iter() .any(|str| str.contains("32") && str.contains(": ") && str.contains("64"))); assert!(items_str .iter() .any(|str| str.contains("100") && str.contains(": ") && str.contains("200"))); assert_eq!( Value::new(((true,), (true, false), (true, true, false))).to_string(), "((true,), (true, false), (true, true, false))" ); #[cfg(any(feature = "gvariant", feature = "option-as-array"))] { #[cfg(unix)] use std::os::fd::BorrowedFd; #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] let s = "((@mn 0, @mmn 0, @mmmn 0), \ (@mn nothing, @mmn just nothing, @mmmn just just nothing), \ (@mmn nothing, @mmmn just nothing))"; #[cfg(feature = "option-as-array")] let s = "(([int16 0], [[int16 0]], [[[int16 0]]]), \ (@an [], [@an []], [[@an []]]), \ (@aan [], [@aan []]))"; assert_eq!( Value::new(( (Some(0_i16), Some(Some(0_i16)), Some(Some(Some(0_i16))),), (None::, Some(None::), Some(Some(None::)),), (None::>, Some(None::>)), )) .to_string(), s, ); #[cfg(unix)] assert_eq!( Value::new(vec![ Fd::from(unsafe { BorrowedFd::borrow_raw(0) }), Fd::from(unsafe { BorrowedFd::borrow_raw(-100) }) ]) .to_string(), "[handle 0, -100]" ); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] let s = "(@mb nothing, @mb nothing, \ @ma{sv} {\"size\": <(800, 600)>}, \ [<1>, <{\"dimension\": <([2.4, 1.], \ @mmn 200, <(byte 0x03, \"Hello!\")>)>}>], \ 7777, objectpath \"/\", 8888)"; #[cfg(feature = "option-as-array")] let s = "(@ab [], @ab [], [{\"size\": <(800, 600)>}], \ [<1>, <{\"dimension\": <([2.4, 1.], [[int16 200]], \ <(byte 0x03, \"Hello!\")>)>}>], 7777, objectpath \"/\", 8888)"; assert_eq!( Value::new(( None::, None::, Some( vec![("size", Value::new((800, 600)))] .into_iter() .collect::>() ), vec![ Value::new(1), Value::new( vec![( "dimension", Value::new(( vec![2.4, 1.], Some(Some(200_i16)), Value::new((3_u8, "Hello!")) )) )] .into_iter() .collect::>() ) ], 7777, ObjectPath::from_static_str("/").unwrap(), 8888 )) .to_string(), s, ); } } }