zvariant-4.1.2/.cargo_vcs_info.json0000644000000001460000000000100126770ustar { "git": { "sha1": "6f7efc9448cf02fb97dd5920da3de45164854a63" }, "path_in_vcs": "zvariant" }zvariant-4.1.2/Cargo.toml0000644000000040430000000000100106750ustar # 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.75" name = "zvariant" version = "4.1.2" authors = ["Zeeshan Ali Khan "] 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] bench = false [[bench]] name = "benchmarks" harness = false [dependencies.arrayvec] version = "0.7.4" features = ["serde"] 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.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.zvariant_derive] version = "=4.1.2" [dev-dependencies.criterion] version = "0.5.1" [dev-dependencies.glib] version = "0.19.5" [dev-dependencies.rand] version = "0.8.5" [dev-dependencies.serde_json] version = "1.0.116" [dev-dependencies.serde_repr] version = "0.1.19" [features] default = [] gvariant = [] option-as-array = [] ostree-tests = ["gvariant"] zvariant-4.1.2/Cargo.toml.orig000064400000000000000000000033661046102023000143650ustar 00000000000000[package] name = "zvariant" version = "4.1.2" authors = ["Zeeshan Ali Khan "] edition = "2021" rust-version = "1.75" 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 = [] ostree-tests = ["gvariant"] # Enables ser/de of `Option` as an array of 0 or 1 elements. option-as-array = [] [dependencies] endi = "1.1.0" serde = { version = "1.0.200", features = ["derive"] } arrayvec = { version = "0.7.4", features = ["serde"], optional = true } enumflags2 = { version = "0.7.9", features = ["serde"], optional = true } zvariant_derive = { version = "=4.1.2", path = "../zvariant_derive" } serde_bytes = { version = "0.11.14", optional = true } static_assertions = "1.1.0" 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 } [dev-dependencies] serde_json = "1.0.116" serde_repr = "0.1.19" # If you want to avoid compiling glib even when compiling tests or examples, comment out the glib # dev-dependency. Dev-dependencies can't be made optional, and hence can't be disabled with a # feature so you have to do it manually. Also, don't enable the gvariant default feature. glib = "0.19.5" rand = "0.8.5" criterion = "0.5.1" [lib] bench = false [[bench]] name = "benchmarks" harness = false [package.metadata.docs.rs] all-features = true zvariant-4.1.2/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-4.1.2/README.md000064400000000000000000000176321046102023000127560ustar 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-4.1.2/benches/benchmarks.rs000064400000000000000000000110131046102023000155540ustar 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_for_signature, Type, Value, LE}; #[cfg(feature = "serde_bytes")] fn byte_array(c: &mut Criterion) { let ay = ByteBuf::from(vec![77u8; 100_000]); let ctxt = Context::new_dbus(LE, 0); let signature = ByteBuf::signature(); c.bench_function("byte_array_ser", |b| { b.iter(|| { to_bytes_for_signature(black_box(ctxt), black_box(&signature), black_box(&ay)).unwrap() }) }); let enc = to_bytes_for_signature(ctxt, &signature, &ay).unwrap(); c.bench_function("byte_array_de", |b| { b.iter(|| { let _: (ByteBuf, _) = enc .deserialize_for_signature(black_box(&signature)) .unwrap(); }) }); } fn fixed_size_array(c: &mut Criterion) { let ay = vec![77u8; 100_000]; let ctxt = Context::new_dbus(LE, 0); let signature = Vec::::signature(); c.bench_function("fixed_size_array_ser", |b| { b.iter(|| { to_bytes_for_signature(black_box(ctxt), black_box(&signature), black_box(&ay)).unwrap() }) }); let enc = to_bytes_for_signature(ctxt, &signature, &ay).unwrap(); c.bench_function("fixed_size_array_de", |b| { b.iter(|| { let _: (Vec, _) = enc .deserialize_for_signature(black_box(&signature)) .unwrap(); }) }); } fn big_array_ser_and_de(c: &mut Criterion) { #[derive(Deserialize, Serialize, Type, PartialEq, Debug, Clone)] struct ZVField<'f> { int2: u64, string2: &'f str, } #[derive(Deserialize, Serialize, Type, PartialEq, Debug)] struct ZVStruct<'s> { string1: &'s str, int1: u64, field: ZVField<'s>, dict: HashMap<&'s str, Value<'s>>, int_array: Vec, string_array: Vec<&'s str>, } let mut 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()); dict.insert(s.as_str(), Value::from(s.as_str())); } let element = ZVStruct { string1: "Testtest", int1: 0xFFFFFFFFFFFFFFFFu64, field: ZVField { string2: "TesttestTestest", int2: 0xFFFFFFFFFFFFFFFFu64, }, int_array, string_array, dict, }; // Let's try with DBus format first let ctxt = Context::new_dbus(LE, 0); let signature = ZVStruct::signature(); c.bench_function("big_array_ser_dbus", |b| { b.iter(|| { let encoded = to_bytes_for_signature(black_box(ctxt), black_box(&signature), black_box(&element)) .unwrap(); black_box(encoded); }) }); let encoded = to_bytes_for_signature(ctxt, &signature, &element).unwrap(); c.bench_function("big_array_de_dbus", |b| { b.iter(|| { let (s, _): (ZVStruct, _) = encoded .deserialize_for_signature(black_box(&signature)) .unwrap(); black_box(s); }) }); // Now GVariant. #[cfg(feature = "gvariant")] { let ctxt = Context::new_gvariant(LE, 0); c.bench_function("big_array_ser_gvariant", |b| { b.iter(|| { let encoded = to_bytes_for_signature( black_box(ctxt), black_box(&signature), black_box(&element), ) .unwrap(); black_box(encoded); }) }); let encoded = to_bytes_for_signature(ctxt, &signature, &element).unwrap(); c.bench_function("big_array_de_gvariant", |b| { b.iter(|| { let (s, _): (ZVStruct, _) = encoded .deserialize_for_signature(black_box(&signature)) .unwrap(); black_box(s); }) }); } } #[cfg(feature = "serde_bytes")] criterion_group!(benches, big_array_ser_and_de, byte_array, fixed_size_array); #[cfg(not(feature = "serde_bytes"))] criterion_group!(benches, big_array_ser_and_de, fixed_size_array); criterion_main!(benches); zvariant-4.1.2/src/array.rs000064400000000000000000000235311046102023000137450ustar 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> { element_signature: Signature<'a>, elements: Vec>, signature: Signature<'a>, } 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<'_> { let signature = create_signature(&element_signature); Array { element_signature, elements: vec![], signature, } } pub(crate) fn new_full_signature(signature: Signature<'_>) -> Array<'_> { let element_signature = signature.slice(1..); Array { element_signature, elements: vec![], signature, } } /// 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<()> { check_child_value_signature!(self.element_signature, element.value_signature(), "element"); 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: ?Sized + 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 } /// Get the signature of this `Array`. /// /// NB: This method potentially allocates and copies. Use [`full_signature`] if you'd like to /// avoid that. /// /// [`full_signature`]: #method.full_signature pub fn signature(&self) -> Signature<'static> { self.signature.to_owned() } /// Get the signature of this `Array`. pub fn full_signature(&self) -> &Signature<'_> { &self.signature } /// Get the signature of the elements in the `Array`. pub fn element_signature(&self) -> &Signature<'_> { &self.element_signature } pub(crate) fn try_to_owned(&self) -> Result> { Ok(Array { element_signature: self.element_signature.to_owned(), elements: self .elements .iter() .map(|v| v.try_to_owned().map(Into::into)) .collect::>()?, signature: self.signature.to_owned(), }) } /// 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 { element_signature: self.element_signature.clone(), 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.full_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<'a> { signature: Signature<'a>, } impl<'a> ArraySeed<'a> { /// Create a new empty `Array`, given the signature of the elements. pub fn new(element_signature: Signature<'_>) -> ArraySeed<'_> { let signature = create_signature(&element_signature); ArraySeed { signature } } pub(crate) fn new_full_signature(signature: Signature<'_>) -> ArraySeed<'_> { ArraySeed { signature } } } assert_impl_all!(ArraySeed<'_>: Send, Sync, Unpin); impl<'a> DynamicType for Array<'a> { fn dynamic_signature(&self) -> Signature<'_> { self.signature.clone() } } impl<'a> DynamicType for ArraySeed<'a> { fn dynamic_signature(&self) -> Signature<'_> { self.signature.clone() } } impl<'a> DynamicDeserialize<'a> for Array<'a> { type Deserializer = ArraySeed<'a>; fn deserializer_for_signature(signature: S) -> zvariant::Result where S: TryInto>, S::Error: Into, { let signature = signature.try_into().map_err(Into::into)?; if signature.starts_with(zvariant::ARRAY_SIGNATURE_CHAR) { Ok(ArraySeed::new_full_signature(signature)) } else { Err(zvariant::Error::SignatureMismatch( signature.to_owned(), "an array signature".to_owned(), )) } } } 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(); let elements = values.into_iter().map(Value::new).collect(); let signature = create_signature(&element_signature); Self { element_signature, 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(); let elements = values .iter() .map(|value| Value::new(value.clone())) .collect(); let signature = create_signature(&element_signature); Self { element_signature, 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<'a> Serialize for Array<'a> { 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<'de> { 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<'a> { signature: Signature<'a>, } impl<'de> Visitor<'de> for ArrayVisitor<'de> { 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) } } fn create_signature(element_signature: &Signature<'_>) -> Signature<'static> { Signature::from_string_unchecked(format!("a{element_signature}")) } zvariant-4.1.2/src/basic.rs000064400000000000000000000131151046102023000137050ustar 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. fn alignment(format: Format) -> usize; } impl Basic for &B where B: Basic, { const SIGNATURE_CHAR: char = B::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = B::SIGNATURE_STR; fn alignment(format: Format) -> usize { B::alignment(format) } } macro_rules! impl_type { ($for:ty) => { impl Type for $for { fn signature() -> Signature<'static> { Signature::from_static_str_unchecked(<$for>::SIGNATURE_STR) } } }; } macro_rules! alignment_method { ($alignment:expr) => { alignment_method!($alignment, $alignment); }; ($dbus_alignment:expr, $gvariant_alignment:expr) => { fn alignment(format: Format) -> usize { match format { Format::DBus => $dbus_alignment, #[cfg(feature = "gvariant")] Format::GVariant => $gvariant_alignment, } } }; } impl Basic for u8 { const SIGNATURE_CHAR: char = 'y'; const SIGNATURE_STR: &'static str = "y"; alignment_method!(1); } impl_type!(u8); impl Basic for std::num::NonZeroU8 { const SIGNATURE_CHAR: char = u8::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = u8::SIGNATURE_STR; alignment_method!(1); } 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; alignment_method!( i16::alignment(Format::DBus), i16::alignment(Format::GVariant) ); } impl_type!(i8); impl Basic for std::num::NonZeroI8 { const SIGNATURE_CHAR: char = i8::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = i8::SIGNATURE_STR; alignment_method!( i16::alignment(Format::DBus), i16::alignment(Format::GVariant) ); } impl_type!(std::num::NonZeroI8); impl Basic for bool { const SIGNATURE_CHAR: char = 'b'; const SIGNATURE_STR: &'static str = "b"; alignment_method!(4); } impl_type!(bool); impl Basic for i16 { const SIGNATURE_CHAR: char = 'n'; const SIGNATURE_STR: &'static str = "n"; alignment_method!(2); } impl_type!(i16); impl Basic for std::num::NonZeroI16 { const SIGNATURE_CHAR: char = i16::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = i16::SIGNATURE_STR; alignment_method!(2); } impl_type!(std::num::NonZeroI16); impl Basic for u16 { const SIGNATURE_CHAR: char = 'q'; const SIGNATURE_STR: &'static str = "q"; alignment_method!(2); } impl_type!(u16); impl Basic for std::num::NonZeroU16 { const SIGNATURE_CHAR: char = u16::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = u16::SIGNATURE_STR; alignment_method!(2); } impl_type!(std::num::NonZeroU16); impl Basic for i32 { const SIGNATURE_CHAR: char = 'i'; const SIGNATURE_STR: &'static str = "i"; alignment_method!(4); } impl_type!(i32); impl Basic for std::num::NonZeroI32 { const SIGNATURE_CHAR: char = i32::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = i32::SIGNATURE_STR; alignment_method!(4); } impl_type!(std::num::NonZeroI32); impl Basic for u32 { const SIGNATURE_CHAR: char = 'u'; const SIGNATURE_STR: &'static str = "u"; alignment_method!(4); } impl_type!(u32); impl Basic for std::num::NonZeroU32 { const SIGNATURE_CHAR: char = u32::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = u32::SIGNATURE_STR; alignment_method!(4); } impl_type!(std::num::NonZeroU32); impl Basic for i64 { const SIGNATURE_CHAR: char = 'x'; const SIGNATURE_STR: &'static str = "x"; alignment_method!(8); } impl_type!(i64); impl Basic for std::num::NonZeroI64 { const SIGNATURE_CHAR: char = i64::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = i64::SIGNATURE_STR; alignment_method!(8); } impl_type!(std::num::NonZeroI64); impl Basic for u64 { const SIGNATURE_CHAR: char = 't'; const SIGNATURE_STR: &'static str = "t"; alignment_method!(8); } impl_type!(u64); impl Basic for std::num::NonZeroU64 { const SIGNATURE_CHAR: char = u64::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = u64::SIGNATURE_STR; alignment_method!(8); } 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; alignment_method!( f64::alignment(Format::DBus), f64::alignment(Format::GVariant) ); } impl_type!(f32); impl Basic for f64 { const SIGNATURE_CHAR: char = 'd'; const SIGNATURE_STR: &'static str = "d"; alignment_method!(8); } impl_type!(f64); impl Basic for str { const SIGNATURE_CHAR: char = 's'; const SIGNATURE_STR: &'static str = "s"; alignment_method!(4, 1); } impl_type!(str); impl Basic for String { const SIGNATURE_CHAR: char = 's'; const SIGNATURE_STR: &'static str = "s"; alignment_method!(4, 1); } impl_type!(String); impl Basic for char { const SIGNATURE_CHAR: char = <&str>::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = <&str>::SIGNATURE_STR; alignment_method!(4, 1); } impl_type!(char); zvariant-4.1.2/src/complete_type.rs000064400000000000000000000023761046102023000155040ustar 00000000000000use core::fmt::{self, Debug, Display, Formatter}; use serde::de::{Deserialize, Deserializer}; use static_assertions::assert_impl_all; use crate::{Error, Result, Signature, Type}; /// [`Signature`] that identifies a complete type. #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, Type)] pub struct CompleteType<'a>(Signature<'a>); assert_impl_all!(CompleteType<'_>: Send, Sync, Unpin); impl<'a> CompleteType<'a> { /// Returns the underlying [`Signature`] pub fn signature(&self) -> &Signature<'a> { &self.0 } } impl<'a> Display for CompleteType<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { std::fmt::Display::fmt(&self.0.as_str(), f) } } impl<'a> TryFrom> for CompleteType<'a> { type Error = Error; fn try_from(sig: Signature<'a>) -> Result { if sig.n_complete_types() != Ok(1) { return Err(Error::IncorrectType); } Ok(Self(sig)) } } impl<'de: 'a, 'a> Deserialize<'de> for CompleteType<'a> { fn deserialize(deserializer: D) -> core::result::Result where D: Deserializer<'de>, { let val = Signature::deserialize(deserializer)?; Self::try_from(val).map_err(serde::de::Error::custom) } } zvariant-4.1.2/src/container_depths.rs000064400000000000000000000044341046102023000161610ustar 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(all(feature = "gvariant", not(feature = "option-as-array")))] pub fn inc_maybe(mut self) -> Result { self.maybe += 1; self.check() } #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] 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-4.1.2/src/dbus/de.rs000064400000000000000000000504171046102023000141570ustar 00000000000000use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Visitor}; use static_assertions::assert_impl_all; use std::{marker::PhantomData, str}; #[cfg(unix)] use std::os::fd::AsFd; use crate::{ de::{DeserializerCommon, ValueParseStage}, serialized::{Context, Format}, signature_parser::SignatureParser, utils::*, Basic, Error, ObjectPath, Result, Signature, }; #[cfg(unix)] use crate::Fd; /// Our D-Bus deserialization implementation. #[derive(Debug)] pub(crate) struct Deserializer<'de, 'sig, 'f, F>(pub(crate) DeserializerCommon<'de, 'sig, 'f, F>); assert_impl_all!(Deserializer<'_, '_, '_, ()>: Send, Sync, Unpin); 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, S>( bytes: &'r [u8], #[cfg(unix)] fds: Option<&'f [F]>, signature: S, ctxt: Context, ) -> Result where S: TryInto>, S::Error: Into, { assert_eq!(ctxt.format(), Format::DBus); let signature = signature.try_into().map_err(Into::into)?; let sig_parser = SignatureParser::new(signature); Ok(Self(DeserializerCommon { ctxt, sig_parser, 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, '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>, { let c = self.0.sig_parser.next_char()?; crate::de::deserialize_any::(self, c, 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.sig_parser.next_char()? { #[cfg(unix)] Fd::SIGNATURE_CHAR => { self.0.sig_parser.skip_char()?; 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::()?); visitor.visit_f32(f64_to_f32(v)) } fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de>, { let len = match self.0.sig_parser.next_char()? { Signature::SIGNATURE_CHAR | VARIANT_SIGNATURE_CHAR => { let len_slice = self.0.next_slice(1)?; len_slice[0] as usize } <&str>::SIGNATURE_CHAR | ObjectPath::SIGNATURE_CHAR => { 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 } c => { let expected = format!( "`{}`, `{}`, `{}` or `{}`", <&str>::SIGNATURE_STR, Signature::SIGNATURE_STR, ObjectPath::SIGNATURE_STR, VARIANT_SIGNATURE_CHAR, ); return Err(de::Error::invalid_type( de::Unexpected::Char(c), &expected.as_str(), )); } }; 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)?; self.0.sig_parser.skip_char()?; visitor.visit_borrowed_str(s) } fn deserialize_option(self, #[allow(unused)] visitor: V) -> Result where V: Visitor<'de>, { #[cfg(feature = "option-as-array")] { let c = self.0.sig_parser.next_char()?; if c != ARRAY_SIGNATURE_CHAR { return Err(de::Error::invalid_type( de::Unexpected::Char(c), &ARRAY_SIGNATURE_STR, )); } self.0.sig_parser.skip_char()?; // This takes care of parsing all the padding and getting the byte length. let len = ArrayDeserializer::new(self)?.len; if len == 0 { self.0.sig_parser.parse_next_signature()?; visitor.visit_none() } else { visitor.visit_some(self) } } #[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>, { match self.0.sig_parser.next_char()? { VARIANT_SIGNATURE_CHAR => { let value_de = ValueDeserializer::new(self); visitor.visit_seq(value_de) } ARRAY_SIGNATURE_CHAR => { self.0.sig_parser.skip_char()?; let next_signature_char = self.0.sig_parser.next_char()?; let array_de = ArrayDeserializer::new(self)?; if next_signature_char == DICT_ENTRY_SIG_START_CHAR { visitor.visit_map(ArrayMapDeserializer(array_de)) } else { visitor.visit_seq(ArraySeqDeserializer(array_de)) } } STRUCT_SIG_START_CHAR => { let signature = self.0.sig_parser.next_signature()?; let alignment = alignment_for_signature(&signature, Format::DBus)?; self.0.parse_padding(alignment)?; self.0.sig_parser.skip_char()?; self.0.container_depths = self.0.container_depths.inc_structure()?; let v = visitor.visit_seq(StructureDeserializer { de: self }); self.0.container_depths = self.0.container_depths.dec_structure(); v } u8::SIGNATURE_CHAR => { // Empty struct: encoded as a `0u8`. let _: u8 = serde::Deserialize::deserialize(&mut *self)?; visitor.visit_seq(StructureDeserializer { de: self }) } c => Err(de::Error::invalid_type( de::Unexpected::Char(c), &format!( "`{VARIANT_SIGNATURE_CHAR}`, `{ARRAY_SIGNATURE_CHAR}` or `{STRUCT_SIG_START_CHAR}`", ) .as_str(), )), } } fn deserialize_enum( self, name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { let signature = self.0.sig_parser.next_signature()?; let alignment = alignment_for_signature(&signature, self.0.ctxt.format())?; self.0.parse_padding(alignment)?; let non_unit = if self.0.sig_parser.next_char()? == STRUCT_SIG_START_CHAR { // This means we've a non-unit enum. Let's skip the `(`. self.0.sig_parser.skip_char()?; true } else { false }; let v = visitor.visit_enum(crate::de::Enum { de: &mut *self, name, _phantom: PhantomData, })?; if non_unit { // For non-unit enum, we need to skip the closing paren. self.0.sig_parser.skip_char()?; } Ok(v) } fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de>, { if self.0.sig_parser.next_char()? == <&str>::SIGNATURE_CHAR { self.deserialize_str(visitor) } else { self.deserialize_u32(visitor) } } 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, // where value signature starts element_signature_len: usize, } 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; let element_signature = de.0.sig_parser.next_signature()?; let element_alignment = alignment_for_signature(&element_signature, Format::DBus)?; let mut element_signature_len = element_signature.len(); // D-Bus requires padding for the first element even when there is no first element // (i-e empty array) so we parse padding already. de.0.parse_padding(element_alignment)?; let start = de.0.pos; if de.0.sig_parser.next_char()? == DICT_ENTRY_SIG_START_CHAR { de.0.sig_parser.skip_char()?; element_signature_len -= 1; } Ok(Self { de, len, start, element_alignment, element_signature_len, }) } fn next(&mut self, seed: T, sig_parser: SignatureParser<'_>) -> Result where T: DeserializeSeed<'de>, { let ctxt = Context::new_dbus( self.de.0.ctxt.endian(), self.de.0.ctxt.position() + self.de.0.pos, ); let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser, bytes: subslice(self.de.0.bytes, self.de.0.pos..)?, 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 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 } fn next_element( &mut self, seed: T, sig_parser: SignatureParser<'_>, ) -> Result> where T: DeserializeSeed<'de>, { if self.done() { self.de .0 .sig_parser .skip_chars(self.element_signature_len)?; self.de.0.container_depths = self.de.0.container_depths.dec_array(); return Ok(None); } self.de.0.parse_padding(self.element_alignment)?; self.next(seed, sig_parser).map(Some) } fn done(&self) -> bool { self.de.0.pos == self.start + self.len } } fn deserialize_ay<'de, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F>( de: &mut Deserializer<'de, '_, '_, F>, ) -> Result<&'de [u8]> { if de.0.sig_parser.next_signature()? != "ay" { return Err(de::Error::invalid_type(de::Unexpected::Seq, &"ay")); } de.0.sig_parser.skip_char()?; let ad = ArrayDeserializer::new(de)?; let len = ad.len; de.0.sig_parser.skip_char()?; de.0.next_slice(len) } struct ArraySeqDeserializer<'d, 'de, 'sig, 'f, F>(ArrayDeserializer<'d, 'de, 'sig, 'f, F>); impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de> for ArraySeqDeserializer<'d, 'de, 'sig, 'f, F> { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> where T: DeserializeSeed<'de>, { let sig_parser = self.0.de.0.sig_parser.clone(); self.0.next_element(seed, sig_parser) } } struct ArrayMapDeserializer<'d, 'de, 'sig, 'f, F>(ArrayDeserializer<'d, 'de, 'sig, 'f, F>); impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> MapAccess<'de> for ArrayMapDeserializer<'d, 'de, 'sig, 'f, F> { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: DeserializeSeed<'de>, { let sig_parser = self.0.de.0.sig_parser.clone(); self.0.next_element(seed, sig_parser) } fn next_value_seed(&mut self, seed: V) -> Result where V: DeserializeSeed<'de>, { let mut sig_parser = self.0.de.0.sig_parser.clone(); // Skip key signature (always 1 char) sig_parser.skip_char()?; self.0.next(seed, sig_parser) } } #[derive(Debug)] struct StructureDeserializer<'d, 'de, 'sig, 'f, F> { de: &'d mut Deserializer<'de, 'sig, 'f, F>, } 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>, { let v = seed.deserialize(&mut *self.de).map(Some); if self.de.0.sig_parser.next_char()? == STRUCT_SIG_END_CHAR { // Last item in the struct self.de.0.sig_parser.skip_char()?; } 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<'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; 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::try_from(slice)?; let sig_parser = SignatureParser::new(signature); let ctxt = Context::new( Format::DBus, self.de.0.ctxt.endian(), self.de.0.ctxt.position() + value_start, ); let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser, 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, '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-4.1.2/src/dbus/mod.rs000064400000000000000000000000671046102023000143420ustar 00000000000000mod de; pub(crate) use de::*; mod ser; pub use ser::*; zvariant-4.1.2/src/dbus/ser.rs000064400000000000000000000525761046102023000143700ustar 00000000000000use serde::{ser, ser::SerializeSeq, Serialize}; use static_assertions::assert_impl_all; use std::{ io::{Seek, Write}, str, }; use crate::{ container_depths::ContainerDepths, serialized::{Context, Format}, signature_parser::SignatureParser, utils::*, Basic, Error, ObjectPath, Result, Signature, WriteBytes, }; #[cfg(unix)] use crate::Fd; /// Our D-Bus serialization implementation. pub(crate) struct Serializer<'ser, 'sig, W>(pub(crate) crate::SerializerCommon<'ser, 'sig, W>); assert_impl_all!(Serializer<'_, '_, i32>: Send, Sync, Unpin); impl<'ser, 'sig, W> Serializer<'ser, 'sig, 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, S>( signature: S, writer: &'w mut W, #[cfg(unix)] fds: &'f mut crate::ser::FdList, ctxt: Context, ) -> Result where S: TryInto>, S::Error: Into, { assert_eq!(ctxt.format(), Format::DBus); let signature = signature.try_into().map_err(Into::into)?; let sig_parser = SignatureParser::new(signature); Ok(Self(crate::SerializerCommon { ctxt, sig_parser, 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, 'sig, 'b, W> ser::Serializer for &'b mut Serializer<'ser, 'sig, W> where W: Write + Seek, { type Ok = (); type Error = Error; type SerializeSeq = SeqSerializer<'ser, 'sig, 'b, W>; type SerializeTuple = StructSeqSerializer<'ser, 'sig, 'b, W>; type SerializeTupleStruct = StructSeqSerializer<'ser, 'sig, 'b, W>; type SerializeTupleVariant = StructSeqSerializer<'ser, 'sig, 'b, W>; type SerializeMap = SeqSerializer<'ser, 'sig, 'b, W>; type SerializeStruct = StructSeqSerializer<'ser, 'sig, 'b, W>; type SerializeStructVariant = StructSeqSerializer<'ser, 'sig, '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.sig_parser.next_char()? { #[cfg(unix)] Fd::SIGNATURE_CHAR => { self.0.sig_parser.skip_char()?; 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<()> { if v.contains('\0') { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char('\0'), &"D-Bus string type must not contain interior null bytes", )); } let c = self.0.sig_parser.next_char()?; if c == VARIANT_SIGNATURE_CHAR { self.0.value_sign = Some(signature_string!(v)); } match c { ObjectPath::SIGNATURE_CHAR | <&str>::SIGNATURE_CHAR => { self.0.add_padding(<&str>::alignment(Format::DBus))?; self.0 .write_u32(self.0.ctxt.endian(), usize_to_u32(v.len())) .map_err(|e| Error::InputOutput(e.into()))?; } Signature::SIGNATURE_CHAR | VARIANT_SIGNATURE_CHAR => { 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(serde::de::Error::invalid_type( serde::de::Unexpected::Char(c), &expected.as_str(), )); } } self.0.sig_parser.skip_char()?; 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<()> { #[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 self.0.sig_parser.next_char()? == <&str>::SIGNATURE_CHAR { 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, { self.0.prep_serialize_enum_variant(variant_index)?; value.serialize(&mut *self)?; // Skip the `)`. self.0.sig_parser.skip_char()?; Ok(()) } fn serialize_seq(self, _len: Option) -> Result { self.0.sig_parser.skip_char()?; 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()))?; let element_signature = self.0.sig_parser.next_signature()?; let element_signature_len = element_signature.len(); let element_alignment = alignment_for_signature(&element_signature, self.0.ctxt.format())?; // 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 first_padding = self.0.add_padding(element_alignment)?; let start = self.0.bytes_written; self.0.container_depths = self.0.container_depths.inc_array()?; Ok(SeqSerializer { ser: self, start, element_alignment, element_signature_len, first_padding, }) } 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 { self.0.prep_serialize_enum_variant(variant_index)?; StructSerializer::enum_variant(self).map(StructSeqSerializer::Struct) } fn serialize_map(self, len: Option) -> Result { self.serialize_seq(len) } fn serialize_struct(self, _name: &'static str, len: usize) -> Result { if len == 0 { return StructSerializer::unit(self).map(StructSeqSerializer::Struct); } match self.0.sig_parser.next_char()? { VARIANT_SIGNATURE_CHAR => { StructSerializer::variant(self).map(StructSeqSerializer::Struct) } ARRAY_SIGNATURE_CHAR => self.serialize_seq(Some(len)).map(StructSeqSerializer::Seq), _ => StructSerializer::structure(self).map(StructSeqSerializer::Struct), } } fn serialize_struct_variant( self, _name: &'static str, variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { self.0.prep_serialize_enum_variant(variant_index)?; StructSerializer::enum_variant(self).map(StructSeqSerializer::Struct) } fn is_human_readable(&self) -> bool { false } } #[doc(hidden)] pub struct SeqSerializer<'ser, 'sig, 'b, W> { ser: &'b mut Serializer<'ser, 'sig, W>, start: usize, // alignment of element element_alignment: usize, // size of element signature element_signature_len: usize, // First element's padding first_padding: usize, } impl<'ser, 'sig, 'b, W> SeqSerializer<'ser, 'sig, 'b, W> where W: Write + Seek, { pub(self) fn end_seq(self) -> Result<()> { self.ser .0 .sig_parser .skip_chars(self.element_signature_len)?; // 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(); Ok(()) } } impl<'ser, 'sig, 'b, W> ser::SerializeSeq for SeqSerializer<'ser, 'sig, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { // We want to keep parsing the same signature repeatedly for each element so we use a // disposable clone. let sig_parser = self.ser.0.sig_parser.clone(); self.ser.0.sig_parser = sig_parser.clone(); value.serialize(&mut *self.ser)?; self.ser.0.sig_parser = sig_parser; Ok(()) } fn end(self) -> Result<()> { self.end_seq() } } #[doc(hidden)] pub struct StructSerializer<'ser, 'sig, 'b, W> { ser: &'b mut Serializer<'ser, 'sig, W>, // The number of `)` in the signature to skip at the end. end_parens: u8, // The original container depths. We restore to that at the end. container_depths: ContainerDepths, } impl<'ser, 'sig, 'b, W> StructSerializer<'ser, 'sig, 'b, W> where W: Write + Seek, { fn variant(ser: &'b mut Serializer<'ser, 'sig, W>) -> Result { ser.0.add_padding(VARIANT_ALIGNMENT_DBUS)?; let container_depths = ser.0.container_depths; ser.0.container_depths = ser.0.container_depths.inc_variant()?; Ok(Self { ser, end_parens: 0, container_depths, }) } fn structure(ser: &'b mut Serializer<'ser, 'sig, W>) -> Result { let c = ser.0.sig_parser.next_char()?; if c != STRUCT_SIG_START_CHAR && c != DICT_ENTRY_SIG_START_CHAR { let expected = format!("`{STRUCT_SIG_START_STR}` or `{DICT_ENTRY_SIG_START_STR}`",); return Err(serde::de::Error::invalid_type( serde::de::Unexpected::Char(c), &expected.as_str(), )); } let signature = ser.0.sig_parser.next_signature()?; let alignment = alignment_for_signature(&signature, Format::DBus)?; ser.0.add_padding(alignment)?; ser.0.sig_parser.skip_char()?; let container_depths = ser.0.container_depths; ser.0.container_depths = ser.0.container_depths.inc_structure()?; Ok(Self { ser, end_parens: 1, container_depths, }) } fn unit(ser: &'b mut Serializer<'ser, 'sig, W>) -> Result { // serialize as a `0u8` serde::Serializer::serialize_u8(&mut *ser, 0)?; let container_depths = ser.0.container_depths; Ok(Self { ser, end_parens: 0, container_depths, }) } fn enum_variant(ser: &'b mut Serializer<'ser, 'sig, W>) -> Result { let mut ser = Self::structure(ser)?; ser.end_parens += 1; Ok(ser) } fn serialize_struct_element(&mut self, name: Option<&'static str>, value: &T) -> Result<()> where T: ?Sized + Serialize, { match name { Some("zvariant::Value::Value") => { // Serializing the value of a Value, which means signature was serialized // already, and also put aside for us to be picked here. let signature = self .ser .0 .value_sign .take() .expect("Incorrect Value encoding"); let sig_parser = SignatureParser::new(signature); let bytes_written = self.ser.0.bytes_written; let mut ser = Serializer(crate::SerializerCommon:: { ctxt: self.ser.0.ctxt, sig_parser, 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; Ok(()) } _ => value.serialize(&mut *self.ser), } } fn end_struct(self) -> Result<()> { if self.end_parens > 0 { self.ser.0.sig_parser.skip_chars(self.end_parens as usize)?; } // 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, 'sig, 'b, W> { Struct(StructSerializer<'ser, 'sig, 'b, W>), Seq(SeqSerializer<'ser, 'sig, 'b, W>), } macro_rules! serialize_struct_anon_fields { ($trait:ident $method:ident) => { impl<'ser, 'sig, 'b, W> ser::$trait for StructSerializer<'ser, 'sig, '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(None, value) } fn end(self) -> Result<()> { self.end_struct() } } impl<'ser, 'sig, 'b, W> ser::$trait for StructSeqSerializer<'ser, 'sig, '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); impl<'ser, 'sig, 'b, W> ser::SerializeMap for SeqSerializer<'ser, 'sig, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<()> where T: ?Sized + Serialize, { self.ser.0.add_padding(self.element_alignment)?; // We want to keep parsing the same signature repeatedly for each key so we use a // disposable clone. let sig_parser = self.ser.0.sig_parser.clone(); self.ser.0.sig_parser = sig_parser.clone(); // skip `{` self.ser.0.sig_parser.skip_char()?; key.serialize(&mut *self.ser)?; self.ser.0.sig_parser = sig_parser; Ok(()) } fn serialize_value(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { // We want to keep parsing the same signature repeatedly for each key so we use a // disposable clone. let sig_parser = self.ser.0.sig_parser.clone(); self.ser.0.sig_parser = sig_parser.clone(); // skip `{` and key char self.ser.0.sig_parser.skip_chars(2)?; value.serialize(&mut *self.ser)?; // Restore the original parser self.ser.0.sig_parser = sig_parser; Ok(()) } fn end(self) -> Result<()> { self.end_seq() } } macro_rules! serialize_struct_named_fields { ($trait:ident) => { impl<'ser, 'sig, 'b, W> ser::$trait for StructSerializer<'ser, 'sig, '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(Some(key), value) } fn end(self) -> Result<()> { self.end_struct() } } impl<'ser, 'sig, 'b, W> ser::$trait for StructSeqSerializer<'ser, 'sig, '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-4.1.2/src/de.rs000064400000000000000000000201761046102023000132210ustar 00000000000000use serde::de::{self, DeserializeSeed, VariantAccess, Visitor}; use static_assertions::assert_impl_all; 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, signature_parser::SignatureParser, utils::*, Basic, Error, ObjectPath, Result, Signature, }; #[cfg(unix)] use crate::Fd; /// 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) sig_parser: SignatureParser<'sig>, 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>), } assert_impl_all!(Deserializer<'_, '_, '_, ()>: Send, Sync, Unpin); #[cfg(unix)] impl<'de, 'sig, 'f, F> DeserializerCommon<'de, 'sig, 'f, 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, 'sig, 'f, F> DeserializerCommon<'de, 'sig, 'f, 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.sig_parser.skip_char()?; 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, '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; 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, 'sig, 'f, D, V>( de: D, next_char: char, visitor: V, ) -> Result where D: de::Deserializer<'de, Error = Error>, V: Visitor<'de>, { match next_char { u8::SIGNATURE_CHAR => de.deserialize_u8(visitor), bool::SIGNATURE_CHAR => de.deserialize_bool(visitor), i16::SIGNATURE_CHAR => de.deserialize_i16(visitor), u16::SIGNATURE_CHAR => de.deserialize_u16(visitor), i32::SIGNATURE_CHAR => de.deserialize_i32(visitor), #[cfg(unix)] Fd::SIGNATURE_CHAR => de.deserialize_i32(visitor), u32::SIGNATURE_CHAR => de.deserialize_u32(visitor), i64::SIGNATURE_CHAR => de.deserialize_i64(visitor), u64::SIGNATURE_CHAR => de.deserialize_u64(visitor), f64::SIGNATURE_CHAR => de.deserialize_f64(visitor), <&str>::SIGNATURE_CHAR | ObjectPath::SIGNATURE_CHAR | Signature::SIGNATURE_CHAR => { de.deserialize_str(visitor) } VARIANT_SIGNATURE_CHAR => de.deserialize_seq(visitor), ARRAY_SIGNATURE_CHAR => de.deserialize_seq(visitor), STRUCT_SIG_START_CHAR => de.deserialize_seq(visitor), #[cfg(feature = "gvariant")] MAYBE_SIGNATURE_CHAR => de.deserialize_option(visitor), c => Err(de::Error::invalid_value( de::Unexpected::Char(c), &"a valid signature character", )), } } // 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-4.1.2/src/deserialize_value.rs000064400000000000000000000050121046102023000163150ustar 00000000000000use core::str; use std::marker::PhantomData; use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; use static_assertions::assert_impl_all; use crate::{Signature, Type, Value}; /// 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] = &["zvariant::Value::Signature", "zvariant::Value::Value"]; Ok(DeserializeValue( deserializer.deserialize_struct( "zvariant::Value", 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("zvariant::Value") } 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 sig != T::signature() { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Str(&sig), &"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> { fn signature() -> Signature<'static> { Value::signature() } } zvariant-4.1.2/src/dict.rs000064400000000000000000000231171046102023000135520ustar 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>>, key_signature: Signature<'k>, value_signature: Signature<'v>, // should use a separate lifetime or everything should use the same but API break. signature: Signature<'k>, } 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<'k>, value_signature: Signature<'v>) -> Self { let signature = create_signature(&key_signature, &value_signature); Self { map: BTreeMap::new(), key_signature, value_signature, 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> { check_child_value_signature!(self.key_signature, key.value_signature(), "key"); check_child_value_signature!(self.value_signature, value.value_signature(), "value"); 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, { check_child_value_signature!(self.key_signature, K::signature(), "key"); check_child_value_signature!(self.value_signature, value.dynamic_signature(), "value"); self.map.insert(Value::new(key), Value::new(value)); Ok(()) } /// 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`. /// /// NB: This method potentially allocates and copies. Use [`full_signature`] if you'd like to /// avoid that. /// /// [`full_signature`]: #method.full_signature pub fn signature(&self) -> Signature<'static> { self.signature.to_owned() } /// Get the signature of this `Dict`. pub fn full_signature(&self) -> &Signature<'_> { &self.signature } pub(crate) fn try_to_owned(&self) -> crate::Result> { Ok(Dict { key_signature: self.key_signature.to_owned(), value_signature: self.value_signature.to_owned(), signature: self.signature.to_owned(), 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, key_signature: self.key_signature.clone(), value_signature: self.value_signature.clone(), signature: self.signature.clone(), }) } /// Create a new empty `Dict`, given the complete signature. pub(crate) fn new_full_signature<'s: 'k + 'v>(signature: Signature<'s>) -> Self { let key_signature = signature.slice(2..3); let value_signature = signature.slice(3..signature.len() - 1); Self { map: BTreeMap::new(), key_signature, value_signature, signature, } } 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.full_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<'k, 'v> Serialize for Dict<'k, 'v> { 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(); let value_signature = V::signature(); let signature = create_signature(&key_signature, &value_signature); Self { map: entries, key_signature, value_signature, signature, } } } }; } to_dict!(HashMap); to_dict!(BTreeMap); fn create_signature( key_signature: &Signature<'_>, value_signature: &Signature<'_>, ) -> Signature<'static> { Signature::from_string_unchecked(format!("a{{{key_signature}{value_signature}}}",)) } zvariant-4.1.2/src/error.rs000064400000000000000000000142531046102023000137610ustar 00000000000000use serde::{de, ser}; use static_assertions::assert_impl_all; use std::{convert::Infallible, error, fmt, io, result, sync::Arc}; /// 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(crate::Signature<'static>, 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(crate::Signature<'static>, String), /// Out of bounds range specified. OutOfBounds, /// The maximum allowed depth for containers in encoding was exceeded. MaxDepthExceeded(MaxDepthExceeded), } 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, (_, _) => 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}"), } } } 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), } } } 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-4.1.2/src/fd.rs000064400000000000000000000131241046102023000132150ustar 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::{serialized::Format, Basic, Signature, 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<'f> Fd<'f> { /// 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"; fn alignment(format: Format) -> usize { u32::alignment(format) } } impl Type for $i { fn signature() -> Signature<'static> { Signature::from_static_str_unchecked(Self::SIGNATURE_STR) } } }; } 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-4.1.2/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-4.1.2/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-4.1.2/src/from_value.rs000064400000000000000000000141441046102023000147660ustar 00000000000000#[cfg(feature = "gvariant")] use crate::Maybe; use crate::{ Array, Dict, Error, NoneValue, ObjectPath, Optional, OwnedObjectPath, OwnedSignature, 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<'a>); 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) } } impl TryFrom> for OwnedSignature { type Error = Error; fn try_from(value: Value<'_>) -> Result { Signature::try_from(value).map(OwnedSignature::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-4.1.2/src/gvariant/de.rs000064400000000000000000000717141046102023000150400ustar 00000000000000use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Visitor}; use static_assertions::assert_impl_all; 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}, signature_parser::SignatureParser, utils::*, Basic, Error, Result, Signature, }; /// Our GVariant deserialization implementation. #[derive(Debug)] pub struct Deserializer<'de, 'sig, 'f, F>(pub(crate) DeserializerCommon<'de, 'sig, 'f, F>); assert_impl_all!(Deserializer<'_, '_,'_, ()>: Send, Sync, Unpin); 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, S>( bytes: &'r [u8], #[cfg(unix)] fds: Option<&'f [F]>, signature: S, ctxt: Context, ) -> Result where S: TryInto>, S::Error: Into, { assert_eq!(ctxt.format(), Format::GVariant); let signature = signature.try_into().map_err(Into::into)?; let sig_parser = SignatureParser::new(signature); Ok(Self(DeserializerCommon { ctxt, sig_parser, 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, sig_parser: self.0.sig_parser.clone(), 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.sig_parser = dbus_de.0.sig_parser; 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>, { let c = self.0.sig_parser.next_char()?; crate::de::deserialize_any::(self, c, 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 = if self.0.sig_parser.next_char()? == VARIANT_SIGNATURE_CHAR { 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)? } else { 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 }; self.0.sig_parser.skip_char()?; visitor.visit_borrowed_str(s) } #[cfg(feature = "option-as-array")] fn deserialize_option(self, _visitor: V) -> Result where V: Visitor<'de>, { panic!("`option-as-array` and `gvariant` features are incompatible. Don't enable both."); } #[cfg(not(feature = "option-as-array"))] fn deserialize_option(self, visitor: V) -> Result where V: Visitor<'de>, { let signature = self.0.sig_parser.next_signature()?; let alignment = alignment_for_signature(&signature, self.0.ctxt.format())?; let child_sig_parser = self.0.sig_parser.slice(1..); let child_signature = child_sig_parser.next_signature()?; let child_sig_len = child_signature.len(); let fixed_sized_child = crate::utils::is_fixed_sized_signature(&child_signature)?; self.0.sig_parser.skip_char()?; self.0.parse_padding(alignment)?; if self.0.pos == self.0.bytes.len() { // Empty sequence means None self.0.sig_parser.skip_chars(child_sig_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, sig_parser: self.0.sig_parser.clone(), 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; } self.0.sig_parser = de.0.sig_parser; 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>, { match self.0.sig_parser.next_char()? { VARIANT_SIGNATURE_CHAR => { self.0.sig_parser.skip_char()?; self.0.parse_padding(VARIANT_ALIGNMENT_GVARIANT)?; let value_de = ValueDeserializer::new(self)?; visitor.visit_seq(value_de) } ARRAY_SIGNATURE_CHAR => { self.0.sig_parser.skip_char()?; let next_signature_char = self.0.sig_parser.next_char()?; let array_de = ArrayDeserializer::new(self)?; if next_signature_char == DICT_ENTRY_SIG_START_CHAR { visitor.visit_map(array_de) } else { visitor.visit_seq(array_de) } } STRUCT_SIG_START_CHAR => { let signature = self.0.sig_parser.next_signature()?; let alignment = alignment_for_signature(&signature, self.0.ctxt.format())?; self.0.parse_padding(alignment)?; self.0.sig_parser.skip_char()?; let start = self.0.pos; let end = self.0.bytes.len(); let offset_size = FramingOffsetSize::for_encoded_container(end - start); self.0.container_depths = self.0.container_depths.inc_structure()?; let v = visitor.visit_seq(StructureDeserializer { de: self, start, end, offsets_len: 0, offset_size, }); self.0.container_depths = self.0.container_depths.dec_structure(); v } ::SIGNATURE_CHAR => { // 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, offsets_len: 0, offset_size: FramingOffsetSize::U8, }) } c => Err(de::Error::invalid_type( de::Unexpected::Char(c), &format!( "`{VARIANT_SIGNATURE_CHAR}`, `{ARRAY_SIGNATURE_CHAR}` or `{STRUCT_SIG_START_CHAR}`", ) .as_str(), )), } } fn deserialize_enum( self, name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { let signature = self.0.sig_parser.next_signature()?; let alignment = alignment_for_signature(&signature, self.0.ctxt.format())?; self.0.parse_padding(alignment)?; let non_unit = if self.0.sig_parser.next_char()? == STRUCT_SIG_START_CHAR { // This means we've a non-unit enum. Let's skip the `(`. self.0.sig_parser.skip_char()?; true } else { false }; let v = visitor.visit_enum(crate::de::Enum { de: &mut *self, name, _phantom: PhantomData, })?; if non_unit { // For non-unit enum, we need to skip the closing paren. self.0.sig_parser.skip_char()?; } 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 de.0.sig_parser.next_signature()? != "ay" { return Err(de::Error::invalid_type(de::Unexpected::Seq, &"ay")); } de.0.sig_parser.skip_char()?; let ad = ArrayDeserializer::new(de)?; let len = dbg!(ad.len); 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, // where value signature starts element_signature_len: usize, // 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 mut len = de.0.bytes.len() - de.0.pos; let element_signature = de.0.sig_parser.next_signature()?; let element_alignment = alignment_for_signature(&element_signature, de.0.ctxt.format())?; let element_signature_len = element_signature.len(); let fixed_sized_child = crate::utils::is_fixed_sized_signature(&element_signature)?; let fixed_sized_key = if de.0.sig_parser.next_char()? == DICT_ENTRY_SIG_START_CHAR { // Key signature can only be 1 char let key_signature = Signature::from_str_unchecked(&element_signature[1..2]); crate::utils::is_fixed_sized_signature(&key_signature)? } else { false }; // D-Bus requires padding for the first element even when there is no first element // (i-e empty array) so we parse padding already. In case of GVariant this is just // the padding of the array itself since array starts with first element. let padding = de.0.parse_padding(element_alignment)?; len -= padding; 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; if de.0.sig_parser.next_char()? == DICT_ENTRY_SIG_START_CHAR { de.0.sig_parser.skip_char()?; } Ok(Self { de, len, start, element_alignment, element_signature_len, 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 .sig_parser .skip_chars(self.element_signature_len)?; 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, sig_parser: self.de.0.sig_parser.clone(), 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() { // Starting bracket was already skipped self.de .0 .sig_parser .skip_chars(self.element_signature_len - 1)?; self.de.0.pos += self.offsets_len; 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(_) => { 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, sig_parser: self.de.0.sig_parser.clone(), 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) => element_end - key_offset_size as usize, None => element_end, }; let mut sig_parser = self.de.0.sig_parser.clone(); // Skip key signature (always 1 char) sig_parser.skip_char()?; let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser, 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, // 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> 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>, { 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_signature = self.de.0.sig_parser.next_signature()?; let fixed_sized_element = crate::utils::is_fixed_sized_signature(&element_signature)?; let element_end = if !fixed_sized_element { let next_sig_pos = element_signature.len(); let parser = self.de.0.sig_parser.slice(next_sig_pos..); if !parser.done() && parser.next_char()? == STRUCT_SIG_END_CHAR { // 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 sig_parser = self.de.0.sig_parser.clone(); let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser, 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 de.0.sig_parser.next_char()? == STRUCT_SIG_END_CHAR { // Last item in the struct de.0.sig_parser.skip_char()?; // Skip over the framing offsets (if any) self.de.0.pos += self.offsets_len; } self.de.0.sig_parser = de.0.sig_parser; 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 { // 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 signature = Signature::from_static_str_unchecked(VARIANT_SIGNATURE_STR); let sig_parser = SignatureParser::new(signature); let mut de = Deserializer::(DeserializerCommon { // No padding in signatures so just pass the same context ctxt: self.de.0.ctxt, sig_parser, 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)?; // FIXME: Can we just use `Signature::from_bytes_unchecked`? let signature = Signature::try_from(slice)?; let sig_parser = SignatureParser::new(signature); 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, sig_parser, 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-4.1.2/src/gvariant/mod.rs000064400000000000000000000000601046102023000152110ustar 00000000000000mod de; pub use de::*; mod ser; pub use ser::*; zvariant-4.1.2/src/gvariant/ser.rs000064400000000000000000000574001046102023000152350ustar 00000000000000use serde::{ser, ser::SerializeSeq, Serialize}; use static_assertions::assert_impl_all; use std::{ io::{Seek, Write}, str, }; use crate::{ container_depths::ContainerDepths, framing_offset_size::FramingOffsetSize, framing_offsets::FramingOffsets, serialized::{Context, Format}, signature_parser::SignatureParser, utils::*, Basic, Error, Result, Signature, }; /// Our serialization implementation. pub(crate) struct Serializer<'ser, 'sig, W>(pub(crate) crate::SerializerCommon<'ser, 'sig, W>); assert_impl_all!(Serializer<'_, '_, i32>: Send, Sync, Unpin); impl<'ser, 'sig, W> Serializer<'ser, 'sig, 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, S>( signature: S, writer: &'w mut W, #[cfg(unix)] fds: &'f mut crate::ser::FdList, ctxt: Context, ) -> Result where S: TryInto>, S::Error: Into, { assert_eq!(ctxt.format(), Format::GVariant); let signature = signature.try_into().map_err(Into::into)?; let sig_parser = SignatureParser::new(signature); Ok(Self(crate::SerializerCommon { ctxt, sig_parser, writer, #[cfg(unix)] fds, bytes_written: 0, value_sign: None, container_depths: Default::default(), })) } #[cfg(not(feature = "option-as-array"))] fn serialize_maybe(&mut self, value: Option<&T>) -> Result<()> where T: ?Sized + Serialize, { let signature = self.0.sig_parser.next_signature()?; let alignment = alignment_for_signature(&signature, self.0.ctxt.format())?; let child_sig_parser = self.0.sig_parser.slice(1..); let child_signature = child_sig_parser.next_signature()?; let child_sig_len = child_signature.len(); let fixed_sized_child = crate::utils::is_fixed_sized_signature(&child_signature)?; self.0.sig_parser.skip_char()?; self.0.add_padding(alignment)?; match value { Some(value) => { self.0.container_depths = self.0.container_depths.inc_maybe()?; value.serialize(&mut *self)?; self.0.container_depths = self.0.container_depths.dec_maybe(); if !fixed_sized_child { self.0 .write_all(&b"\0"[..]) .map_err(|e| Error::InputOutput(e.into()))?; } } None => { self.0.sig_parser.skip_chars(child_sig_len)?; } } 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, sig_parser: self.0.sig_parser.clone(), 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; self.0.sig_parser = dbus_ser.0.sig_parser; Ok(()) } }; } impl<'ser, 'sig, 'b, W> ser::Serializer for &'b mut Serializer<'ser, 'sig, W> where W: Write + Seek, { type Ok = (); type Error = Error; type SerializeSeq = SeqSerializer<'ser, 'sig, 'b, W>; type SerializeTuple = StructSeqSerializer<'ser, 'sig, 'b, W>; type SerializeTupleStruct = StructSeqSerializer<'ser, 'sig, 'b, W>; type SerializeTupleVariant = StructSeqSerializer<'ser, 'sig, 'b, W>; type SerializeMap = SeqSerializer<'ser, 'sig, 'b, W>; type SerializeStruct = StructSeqSerializer<'ser, 'sig, 'b, W>; type SerializeStructVariant = StructSeqSerializer<'ser, 'sig, '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<()> { if v.contains('\0') { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char('\0'), &"GVariant string type must not contain interior null bytes", )); } let c = self.0.sig_parser.next_char()?; if c == VARIANT_SIGNATURE_CHAR { self.0.value_sign = Some(signature_string!(v)); // signature is serialized after the value in GVariant return Ok(()); } // Strings in GVariant format require no alignment. self.0.sig_parser.skip_char()?; 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() } #[cfg(not(feature = "option-as-array"))] fn serialize_none(self) -> Result<()> { self.serialize_maybe::<()>(None) } #[cfg(feature = "option-as-array")] fn serialize_none(self) -> Result<()> { panic!("`option-as-array` and `gvariant` features are incompatible. Don't enable both."); } #[cfg(not(feature = "option-as-array"))] fn serialize_some(self, value: &T) -> Result<()> where T: ?Sized + Serialize, { self.serialize_maybe(Some(value)) } #[cfg(feature = "option-as-array")] fn serialize_some(self, _value: &T) -> Result<()> where T: ?Sized + Serialize, { panic!("`option-as-array` and `gvariant` features are incompatible. Don't enable both."); } 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 self.0.sig_parser.next_char()? == <&str>::SIGNATURE_CHAR { 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, { self.0.prep_serialize_enum_variant(variant_index)?; value.serialize(self) } fn serialize_seq(self, _len: Option) -> Result { self.0.sig_parser.skip_char()?; let element_signature = self.0.sig_parser.next_signature()?; let element_signature_len = element_signature.len(); let element_alignment = alignment_for_signature(&element_signature, self.0.ctxt.format())?; let fixed_sized_child = crate::utils::is_fixed_sized_signature(&element_signature)?; let offsets = (!fixed_sized_child).then(FramingOffsets::new); let key_start = if self.0.sig_parser.next_char()? == DICT_ENTRY_SIG_START_CHAR { let key_signature = Signature::from_str_unchecked(&element_signature[1..2]); (!crate::utils::is_fixed_sized_signature(&key_signature)?).then_some(0) } else { None }; self.0.add_padding(element_alignment)?; self.0.container_depths = self.0.container_depths.inc_array()?; let start = self.0.bytes_written; Ok(SeqSerializer { ser: self, start, element_alignment, element_signature_len, offsets, key_start, }) } 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 { self.0.prep_serialize_enum_variant(variant_index)?; StructSerializer::enum_variant(self).map(StructSeqSerializer::Struct) } fn serialize_map(self, len: Option) -> Result { self.serialize_seq(len) } fn serialize_struct(self, _name: &'static str, len: usize) -> Result { if len == 0 { return StructSerializer::unit(self).map(StructSeqSerializer::Struct); } match self.0.sig_parser.next_char()? { VARIANT_SIGNATURE_CHAR => { StructSerializer::variant(self).map(StructSeqSerializer::Struct) } ARRAY_SIGNATURE_CHAR => self.serialize_seq(Some(len)).map(StructSeqSerializer::Seq), _ => StructSerializer::structure(self).map(StructSeqSerializer::Struct), } } fn serialize_struct_variant( self, _name: &'static str, variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { self.0.prep_serialize_enum_variant(variant_index)?; StructSerializer::enum_variant(self).map(StructSeqSerializer::Struct) } fn is_human_readable(&self) -> bool { false } } #[doc(hidden)] pub struct SeqSerializer<'ser, 'sig, 'b, W> { ser: &'b mut Serializer<'ser, 'sig, W>, start: usize, // alignment of element element_alignment: usize, // size of element signature element_signature_len: usize, // All offsets offsets: Option, // start of last dict-entry key written key_start: Option, } impl<'ser, 'sig, 'b, W> SeqSerializer<'ser, 'sig, 'b, W> where W: Write + Seek, { pub(self) fn end_seq(self) -> Result<()> { self.ser .0 .sig_parser .skip_chars(self.element_signature_len)?; self.ser.0.container_depths = self.ser.0.container_depths.dec_array(); 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, 'sig, 'b, W> ser::SerializeSeq for SeqSerializer<'ser, 'sig, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { // We want to keep parsing the same signature repeatedly for each element so we use a // disposable clone. let sig_parser = self.ser.0.sig_parser.clone(); self.ser.0.sig_parser = sig_parser.clone(); value.serialize(&mut *self.ser)?; self.ser.0.sig_parser = sig_parser; 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, 'sig, 'b, W> { ser: &'b mut Serializer<'ser, 'sig, W>, start: usize, // The number of `)` in the signature to skip at the end. end_parens: u8, // All offsets offsets: Option, // The original container depths. We restore to that at the end. container_depths: ContainerDepths, } impl<'ser, 'sig, 'b, W> StructSerializer<'ser, 'sig, 'b, W> where W: Write + Seek, { fn variant(ser: &'b mut Serializer<'ser, 'sig, W>) -> Result { ser.0.add_padding(VARIANT_ALIGNMENT_GVARIANT)?; let offsets = if ser.0.sig_parser.next_char()? == STRUCT_SIG_START_CHAR { Some(FramingOffsets::new()) } else { 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, end_parens: 0, offsets, start, container_depths, }) } fn structure(ser: &'b mut Serializer<'ser, 'sig, W>) -> Result { let c = ser.0.sig_parser.next_char()?; if c != STRUCT_SIG_START_CHAR && c != DICT_ENTRY_SIG_START_CHAR { let expected = format!("`{STRUCT_SIG_START_STR}` or `{DICT_ENTRY_SIG_START_STR}`",); return Err(serde::de::Error::invalid_type( serde::de::Unexpected::Char(c), &expected.as_str(), )); } let signature = ser.0.sig_parser.next_signature()?; let alignment = alignment_for_signature(&signature, Format::GVariant)?; ser.0.add_padding(alignment)?; ser.0.sig_parser.skip_char()?; let offsets = if c == STRUCT_SIG_START_CHAR { Some(FramingOffsets::new()) } else { 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, end_parens: 1, offsets, start, container_depths, }) } fn unit(ser: &'b mut Serializer<'ser, 'sig, 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, end_parens: 0, offsets: None, start, container_depths, }) } fn enum_variant(ser: &'b mut Serializer<'ser, 'sig, W>) -> Result { let mut ser = Self::structure(ser)?; ser.end_parens += 1; Ok(ser) } fn serialize_struct_element(&mut self, name: Option<&'static str>, value: &T) -> Result<()> where T: ?Sized + Serialize, { match name { Some("zvariant::Value::Value") => { // Serializing the value of a Value, which means signature was serialized // already, and also put aside for us to be picked here. let signature = self .ser .0 .value_sign .take() .expect("Incorrect Value encoding"); let sig_parser = SignatureParser::new(signature.clone()); let bytes_written = self.ser.0.bytes_written; let mut ser = Serializer(crate::SerializerCommon:: { ctxt: self.ser.0.ctxt, sig_parser, 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 .write_all(&b"\0"[..]) .map_err(|e| Error::InputOutput(e.into()))?; self.ser .0 .write_all(signature.as_bytes()) .map_err(|e| Error::InputOutput(e.into()))?; Ok(()) } _ => { let element_signature = self.ser.0.sig_parser.next_signature()?; let fixed_sized_element = crate::utils::is_fixed_sized_signature(&element_signature)?; value.serialize(&mut *self.ser)?; if let Some(ref mut offsets) = self.offsets { if !fixed_sized_element { offsets.push_front(self.ser.0.bytes_written - self.start); } } Ok(()) } } } fn end_struct(self) -> Result<()> { if self.end_parens > 0 { self.ser.0.sig_parser.skip_chars(self.end_parens as usize)?; } // 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, 'sig, 'b, W> { Struct(StructSerializer<'ser, 'sig, 'b, W>), Seq(SeqSerializer<'ser, 'sig, 'b, W>), } macro_rules! serialize_struct_anon_fields { ($trait:ident $method:ident) => { impl<'ser, 'sig, 'b, W> ser::$trait for StructSerializer<'ser, 'sig, '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(None, value) } fn end(self) -> Result<()> { self.end_struct() } } impl<'ser, 'sig, 'b, W> ser::$trait for StructSeqSerializer<'ser, 'sig, '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); impl<'ser, 'sig, 'b, W> ser::SerializeMap for SeqSerializer<'ser, 'sig, 'b, W> where W: Write + Seek, { type Ok = (); type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<()> where T: ?Sized + Serialize, { self.ser.0.add_padding(self.element_alignment)?; if self.key_start.is_some() { self.key_start.replace(self.ser.0.bytes_written); } // We want to keep parsing the same signature repeatedly for each key so we use a // disposable clone. let sig_parser = self.ser.0.sig_parser.clone(); self.ser.0.sig_parser = sig_parser.clone(); // skip `{` self.ser.0.sig_parser.skip_char()?; key.serialize(&mut *self.ser)?; self.ser.0.sig_parser = sig_parser; Ok(()) } 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.ser.0.bytes_written - start); // We want to keep parsing the same signature repeatedly for each key so we use a // disposable clone. let sig_parser = self.ser.0.sig_parser.clone(); self.ser.0.sig_parser = sig_parser.clone(); // skip `{` and key char self.ser.0.sig_parser.skip_chars(2)?; value.serialize(&mut *self.ser)?; // Restore the original parser self.ser.0.sig_parser = sig_parser; if let Some(key_offset) = key_offset { let entry_size = self.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.ser.0, key_offset)?; } // And now the offset of the array element end (which is encoded later) 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() } } macro_rules! serialize_struct_named_fields { ($trait:ident) => { impl<'ser, 'sig, 'b, W> ser::$trait for StructSerializer<'ser, 'sig, '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(Some(key), value) } fn end(self) -> Result<()> { self.end_struct() } } impl<'ser, 'sig, 'b, W> ser::$trait for StructSeqSerializer<'ser, 'sig, '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-4.1.2/src/into_value.rs000064400000000000000000000101641046102023000147720ustar 00000000000000use std::{collections::HashMap, hash::BuildHasher}; #[cfg(feature = "gvariant")] use crate::Maybe; use crate::{Array, Dict, NoneValue, ObjectPath, Optional, Signature, 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!(Signature<'a>, Signature); 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-4.1.2/src/lib.rs000064400000000000000000002313131046102023000133740ustar 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::*; #[deprecated(since = "4.0.0", note = "Use `serialized::Context` instead")] #[doc(hidden)] pub type EncodingContext = serialized::Context; #[deprecated(since = "4.0.0", note = "Use `serialized::Format` instead")] #[doc(hidden)] pub type EncodingFormat = serialized::Format; 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; mod signature; pub use crate::signature::*; mod complete_type; pub use complete_type::*; 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 signature_parser; 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}, net::{IpAddr, Ipv4Addr, Ipv6Addr}, }; #[cfg(feature = "arrayvec")] use arrayvec::{ArrayString, ArrayVec}; #[cfg(feature = "arrayvec")] use std::str::FromStr; #[cfg(feature = "gvariant")] use glib::{variant::FromVariant, Bytes, Variant}; use serde::{Deserialize, Serialize}; use crate::{serialized::Data, 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, Signature, 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`"); } /// Decode with gvariant and compare with expected value (if provided). #[cfg(feature = "gvariant")] fn decode_with_gvariant(encoded: B, expected_value: Option) -> T where B: AsRef<[u8]> + Send + 'static, T: glib::variant::FromVariant + std::fmt::Debug + PartialEq, { let bytes = Bytes::from_owned(encoded); let gv = Variant::from_bytes::(&bytes); let v = gv.get::().unwrap(); if let Some(expected_value) = expected_value { assert_eq!(v, expected_value); } v } /// Decode a number with gvariant and compare with expected value (if provided). /// /// `expected_value` is a tuple of (little endian value, big endian value). #[cfg(feature = "gvariant")] fn decode_num_with_gvariant(encoded: B, expected_value: Option<(T, T)>) -> T where B: AsRef<[u8]> + Send + 'static, T: glib::variant::FromVariant + std::fmt::Debug + PartialEq, { #[allow(unused_variables)] let expected_value = expected_value.map(|(le, be)| { #[cfg(target_endian = "little")] { le } #[cfg(target_endian = "big")] { be } }); decode_with_gvariant(encoded, expected_value) } // 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")] { decode_num_with_gvariant::<_, u8>(encoded, Some((77u8, 77u8))); 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")] { decode_num_with_gvariant::<_, u16>(encoded, Some((0xBAAB_u16, 0xABBA_u16))); 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")] { decode_num_with_gvariant::<_, i16>(encoded, Some((0x50F5_i16, -0xAB0_i16))); 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")] { decode_num_with_gvariant::<_, u32>(encoded, Some((0xBAAB_BAAB_u32, 0xABBA_ABBA_u32))); 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")] { decode_num_with_gvariant::<_, i32>(encoded, Some((0x5055_44F5_i32, -0xABBA_AB0_i32))); 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")] { decode_num_with_gvariant::<_, i64>( encoded, Some((0x5055_4455_4455_44F5_i64, -0xABBA_ABBA_ABBA_AB0_i64)), ); 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")] { assert!( (decode_with_gvariant::<_, f64>(encoded, None) - 99999.99999_f64).abs() < f64::EPSILON ); 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")] { let encoded = basic_type_test!(LE, GVariant, string, 12, String, 1); decode_with_gvariant::<_, String>(encoded, Some(String::from("hello world"))); } 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")] { let encoded = value_test!(LE, GVariant, v, 14); // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let gv = Variant::from_bytes::(&bytes); let variant = gv.as_variant().unwrap(); assert_eq!(variant.str().unwrap(), "hello world"); } let v: String = v.try_into().unwrap(); assert_eq!(v, "hello world"); // Check for interior null bytes which are not allowed let ctxt = Context::new_dbus(LE, 0); assert!(Data::new(&b"\x0b\0\0\0hello\0world\0"[..], ctxt) .deserialize::<&str>() .is_err()); assert!(to_bytes(ctxt, &"hello\0world").is_err()); // GVariant format doesn't allow null bytes either #[cfg(feature = "gvariant")] { let ctxt = Context::new_gvariant(LE, 0); assert!(Data::new(&b"\x0b\0\0\0hello\0world\0"[..], ctxt) .deserialize::<&str>() .is_err()); assert!(to_bytes(ctxt, &"hello\0world").is_err()); } // 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!"); } #[test] fn signature_value() { let sig = Signature::try_from("yys").unwrap(); basic_type_test!(LE, DBus, sig, 5, Signature<'_>, 1); #[cfg(feature = "gvariant")] { let encoded = basic_type_test!(LE, GVariant, sig, 4, Signature<'_>, 1); decode_with_gvariant::<_, String>(encoded, Some(String::from("yys"))); } // As Value let v: Value<'_> = sig.into(); assert_eq!(v.value_signature(), "g"); let encoded = value_test!(LE, DBus, v, 8); 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, 6); 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")] { let encoded = basic_type_test!(LE, GVariant, o, 13, ObjectPath<'_>, 1); decode_with_gvariant::<_, String>(encoded, Some(String::from("/hello/world"))); } // 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 or Vec #[cfg(feature = "arrayvec")] let ay = ArrayVec::from([77u8, 88]); #[cfg(not(feature = "arrayvec"))] 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(not(feature = "arrayvec"))] 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); // Check encoding against GLib let bytes = Bytes::from_owned(gv_encoded); let variant = Variant::from_bytes::<&[u8]>(&bytes); assert_eq!(variant.n_children(), 2); assert_eq!(variant.child_value(0).get::().unwrap(), 77); assert_eq!(variant.child_value(1).get::().unwrap(), 88); } 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!(); } // Check encoding against GLib let bytes = Bytes::from_owned(gv_encoded); let variant = Variant::from_bytes::<&[&str]>(&bytes); assert_eq!(variant.n_children(), 0); } 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); // Check encoding against GLib let bytes = Bytes::from_owned(gv_encoded); let variant = Variant::from_bytes::(&bytes); assert_eq!(variant.n_children(), 1); let decoded: Vec = variant.child_value(0).get().unwrap(); assert_eq!(decoded[0], "Hello"); assert_eq!(decoded[1], "World"); } // 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"); // Check encoding against GLib let bytes = Bytes::from_owned(gv_encoded); let variant = Variant::from_bytes::< Vec<(u8, u32, (i64, bool, i64, Vec), String)>, >(&bytes); assert_eq!(variant.n_children(), 1); let r: (u8, u32, (i64, bool, i64, Vec), String) = variant.child_value(0).get().unwrap(); assert_eq!(r.0, u8::MAX); assert_eq!(r.1, u32::MAX); } 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!(); } // Check encoding against GLib let bytes = Bytes::from_owned(gv_encoded); let variant = Variant::from_bytes::(&bytes); assert_eq!(variant.n_children(), 1); let child: Variant = variant.child_value(0); let r: (u8, u32, (i64, bool, i64, Vec), String) = child.child_value(0).get().unwrap(); assert_eq!(r.0, u8::MAX); assert_eq!(r.1, u32::MAX); 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 encoding against GLib let bytes = Bytes::from_owned(gv_encoded.to_owned()); let variant = Variant::from_bytes::>(&bytes); assert_eq!(variant.n_children(), 2); assert_eq!(variant.child_value(0).get::().unwrap(), as_[0]); assert_eq!(variant.child_value(1).get::().unwrap(), as_[1]); // Also 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"); // Check encoding against GLib let bytes = Bytes::from_owned(gv_encoded); let variant = Variant::from_bytes::>(&bytes); assert_eq!(variant.n_children(), 2); let map: HashMap = HashMap::from_variant(&variant).unwrap(); 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.as_ref(), gv_ser_value_encoded.as_ref()); // Check encoding against GLib let bytes = Bytes::from_owned(gv_encoded); let variant = Variant::from_bytes::>(&bytes); assert_eq!(variant.n_children(), 2); let map: HashMap = HashMap::from_variant(&variant).unwrap(); assert_eq!(map["hi"], "1234"); assert_eq!(map["world"], "561"); // 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)); } #[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); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] { // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::>(&bytes); assert_eq!(variant.get::>().unwrap(), 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:?}"), } #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] { // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::(&bytes); let decoded = variant.child_value(0).get::>().unwrap(); assert_eq!(decoded, mn); } // 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()); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] { // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::>(&bytes); assert!(variant.get::>().unwrap().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); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] { // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::>(&bytes); assert_eq!( &variant.get::>().unwrap().unwrap(), ms.unwrap() ); } // 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:?}"), } #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] { // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::(&bytes); let decoded = variant.child_value(0).get::>().unwrap(); assert_eq!(decoded.as_deref(), ms); } // 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()); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] { // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::>(&bytes); assert!(variant.get::>().unwrap().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); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] { // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::>>(&bytes); let decoded = variant.get::>>().unwrap(); 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); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] { // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::(&bytes); let decoded = variant.child_value(0).get::>>().unwrap(); assert_eq!(decoded, ams); } // 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); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] { // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::<(Option, u64, Option)>(&bytes); let decoded = variant .get::<(Option, u64, Option)>() .unwrap(); 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); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] { // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::(&bytes); let decoded = variant .child_value(0) .get::<(Option, u64, Option)>() .unwrap(); assert_eq!(decoded, structure); } } #[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() { #[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 ip_addr() { let ctxt = Context::new_dbus(LE, 0); // First the bare specific types. let localhost_v4 = Ipv4Addr::new(127, 0, 0, 1); let encoded = to_bytes(ctxt, &localhost_v4).unwrap(); let decoded: Ipv4Addr = encoded.deserialize().unwrap().0; assert_eq!(localhost_v4, decoded); let localhost_v6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); let encoded = to_bytes(ctxt, &localhost_v6).unwrap(); let decoded: Ipv6Addr = encoded.deserialize().unwrap().0; assert_eq!(localhost_v6, decoded); // Now wrapper under the generic IpAddr. let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); let encoded = to_bytes(ctxt, &localhost_v4).unwrap(); let decoded: IpAddr = encoded.deserialize().unwrap().0; assert_eq!(localhost_v4, decoded); let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); let encoded = to_bytes(ctxt, &localhost_v6).unwrap(); let decoded: IpAddr = encoded.deserialize().unwrap().0; assert_eq!(localhost_v6, decoded); } #[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 = 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] #[cfg(feature = "time")] fn time() { // time::Date let date = time::Date::from_calendar_date(2011, time::Month::June, 21).unwrap(); let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &date).unwrap(); let decoded: time::Date = encoded.deserialize().unwrap().0; assert_eq!(date, decoded); // time::Duration let duration = time::Duration::new(42, 123456789); let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &duration).unwrap(); let decoded: time::Duration = encoded.deserialize().unwrap().0; assert_eq!(duration, decoded); // time::OffsetDateTime let offset = time::OffsetDateTime::now_utc(); let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &offset).unwrap(); let decoded: time::OffsetDateTime = encoded.deserialize().unwrap().0; assert_eq!(offset, decoded); // time::Time let time = time::Time::from_hms(23, 42, 59).unwrap(); let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &time).unwrap(); let decoded: time::Time = encoded.deserialize().unwrap().0; assert_eq!(time, decoded); // time::PrimitiveDateTime let date = time::PrimitiveDateTime::new(date, time); let ctxt = Context::new_dbus(LE, 0); let encoded = to_bytes(ctxt, &date).unwrap(); let decoded: time::PrimitiveDateTime = encoded.deserialize().unwrap().0; assert_eq!(date, decoded); } #[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-4.1.2/src/maybe.rs000064400000000000000000000132751046102023000137300ustar 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>>, value_signature: Signature<'a>, signature: Signature<'a>, } 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().to_owned(); let signature = create_signature(&value_signature); Self { value_signature, signature, value: Box::new(Some(value)), } } pub(crate) fn just_full_signature<'v: 'a, 's: 'a>( value: Value<'v>, signature: Signature<'s>, ) -> Self { Self { value_signature: signature.slice(1..), signature, value: Box::new(Some(value)), } } /// Create a new Nothing (None) `Maybe`, given the signature of the type. pub fn nothing<'s: 'a>(value_signature: Signature<'s>) -> Self { let signature = create_signature(&value_signature); Self { value_signature, signature, value: Box::new(None), } } pub(crate) fn nothing_full_signature<'s: 'a>(signature: Signature<'s>) -> Self { Self { value_signature: signature.slice(1..), signature, 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`. /// /// NB: This method potentially allocates and copies. Use [`full_signature`] if you'd like to /// avoid that. /// /// [`full_signature`]: #method.full_signature pub fn signature(&self) -> Signature<'static> { self.signature.to_owned() } /// Get the signature of `Maybe`. pub fn full_signature(&self) -> &Signature<'_> { &self.signature } /// Get the signature of the potential value in the `Maybe`. pub fn value_signature(&self) -> &Signature<'_> { &self.value_signature } pub(crate) fn try_to_owned(&self) -> crate::Result> { Ok(Maybe { value_signature: self.value_signature.to_owned(), value: Box::new( self.value .as_ref() .as_ref() .map(|v| v.try_to_owned().map(Into::into)) .transpose()?, ), signature: self.signature.to_owned(), }) } /// Attempt to clone `self`. pub fn try_clone(&self) -> Result { Ok(Maybe { value_signature: self.value_signature.clone(), 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.full_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(), } } } fn create_signature(value_signature: &Signature<'_>) -> Signature<'static> { Signature::from_string_unchecked(format!("m{value_signature}")) } zvariant-4.1.2/src/object_path.rs000064400000000000000000000253231046102023000151120ustar 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::{serialized::Format, Basic, Error, Result, Signature, 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 { ensure_correct_object_path_str(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_str_unchecked("/") } } impl<'a> Basic for ObjectPath<'a> { const SIGNATURE_CHAR: char = 'o'; const SIGNATURE_STR: &'static str = "o"; fn alignment(format: Format) -> usize { match format { Format::DBus => <&str>::alignment(format), #[cfg(feature = "gvariant")] Format::GVariant => 1, } } } impl<'a> Type for ObjectPath<'a> { fn signature() -> Signature<'static> { Signature::from_static_str_unchecked(Self::SIGNATURE_STR) } } impl<'a> TryFrom<&'a [u8]> for ObjectPath<'a> { type Error = Error; fn try_from(value: &'a [u8]) -> Result { ensure_correct_object_path_str(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<'a> TryFrom for ObjectPath<'a> { type Error = Error; fn try_from(value: String) -> Result { ensure_correct_object_path_str(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<'a> std::ops::Deref for ObjectPath<'a> { type Target = str; fn deref(&self) -> &Self::Target { self.as_str() } } impl<'a> PartialEq for ObjectPath<'a> { fn eq(&self, other: &str) -> bool { self.as_str() == other } } impl<'a> PartialEq<&str> for ObjectPath<'a> { fn eq(&self, other: &&str) -> bool { self.as_str() == *other } } impl<'a> Debug for ObjectPath<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("ObjectPath").field(&self.as_str()).finish() } } impl<'a> std::fmt::Display for ObjectPath<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.as_str(), f) } } impl<'a> Serialize for ObjectPath<'a> { 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 ensure_correct_object_path_str(path: &[u8]) -> Result<()> { let mut prev = b'\0'; // Rules // // * At least 1 character. // * First character must be `/` // * No trailing `/` // * No `//` // * Only ASCII alphanumeric, `_` or '/' if path.is_empty() { return Err(serde::de::Error::invalid_length(0, &"> 0 character")); } for i in 0..path.len() { let c = path[i]; if i == 0 && c != b'/' { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char(c as char), &"/", )); } else if c == b'/' && prev == b'/' { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Str("//"), &"/", )); } else if path.len() > 1 && i == (path.len() - 1) && c == b'/' { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char('/'), &"an alphanumeric character or `_`", )); } else if !c.is_ascii_alphanumeric() && c != b'/' && c != b'_' { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char(c as char), &"an alphanumeric character, `_` or `/`", )); } prev = c; } Ok(()) } /// 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; fn alignment(format: Format) -> usize { ObjectPath::alignment(format) } } 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-4.1.2/src/optional.rs000064400000000000000000000116301046102023000144510ustar 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, { fn signature() -> crate::Signature<'static> { 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-4.1.2/src/owned_value.rs000064400000000000000000000204011046102023000151300ustar 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, OwnedSignature, 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<'static>); ov_try_from!(OwnedSignature); 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<'a>); 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!(Signature<'a>, Signature); to_value!(ObjectPath<'a>, ObjectPath); 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)) } } #[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-4.1.2/src/ser.rs000064400000000000000000000250371046102023000134230ustar 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}, signature_parser::SignatureParser, utils::*, Basic, DynamicType, Error, Result, Signature, WriteBytes, }; 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.dynamic_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. /// /// [`to_writer_fds`]: fn.to_writer_fds.html pub unsafe fn to_writer(writer: &mut W, ctxt: Context, value: &T) -> Result where W: Write + Seek, T: ?Sized + Serialize + DynamicType, { let signature = value.dynamic_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.dynamic_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<'s, W, S, T>( writer: &mut W, ctxt: Context, signature: S, value: &T, ) -> Result where W: Write + Seek, S: TryInto>, S::Error: Into, T: ?Sized + Serialize, { #[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<'s, S, T>( 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, 'sig, 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) sig_parser: SignatureParser<'sig>, pub(crate) value_sign: Option>, pub(crate) container_depths: ContainerDepths, } #[cfg(unix)] pub(crate) enum FdList { Fds(Vec), Number(u32), } impl<'ser, 'sig, W> SerializerCommon<'ser, 'sig, 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 { let byte = [0_u8; 1]; for _ in 0..padding { self.write_all(&byte) .map_err(|e| Error::InputOutput(e.into()))?; } } Ok(padding) } pub(crate) fn prep_serialize_basic(&mut self) -> Result<()> where T: Basic, { self.sig_parser.skip_char()?; self.add_padding(T::alignment(self.ctxt.format()))?; Ok(()) } /// This starts the enum serialization. /// /// It's up to the caller to do the rest: serialize the variant payload and skip the `). pub(crate) fn prep_serialize_enum_variant(&mut self, variant_index: u32) -> Result<()> { // Encode enum variants as a struct with first field as variant index let signature = self.sig_parser.next_signature()?; if self.sig_parser.next_char()? != STRUCT_SIG_START_CHAR { return Err(Error::SignatureMismatch( signature.to_owned(), format!("expected `{STRUCT_SIG_START_CHAR}`"), )); } let alignment = alignment_for_signature(&signature, self.ctxt.format())?; self.add_padding(alignment)?; // Now serialize the veriant index. self.write_u32(self.ctxt.endian(), variant_index) .map_err(|e| Error::InputOutput(e.into()))?; // Skip the `(`, `u`. self.sig_parser.skip_chars(2)?; Ok(()) } fn abs_pos(&self) -> usize { self.ctxt.position() + self.bytes_written } } impl<'ser, 'sig, W> Write for SerializerCommon<'ser, 'sig, 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).map(|n| { self.bytes_written += n; n }) } fn flush(&mut self) -> std::io::Result<()> { self.writer.flush() } } zvariant-4.1.2/src/serialize_value.rs000064400000000000000000000026231046102023000160110ustar 00000000000000use serde::ser::{Serialize, SerializeStruct, Serializer}; use static_assertions::assert_impl_all; use crate::{Signature, Type, Value}; /// 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<'a, T: Type + Serialize> Serialize for SerializeValue<'a, 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("zvariant::Value", 2)?; let signature = T::signature(); structure.serialize_field("zvariant::Value::Signature", &signature)?; structure.serialize_field("zvariant::Value::Value", self.0)?; structure.end() } } impl<'a, T: Type + Serialize> Type for SerializeValue<'a, T> { fn signature() -> Signature<'static> { Value::signature() } } zvariant-4.1.2/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-4.1.2/src/serialized/data.rs000064400000000000000000000277371046102023000157070ustar 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: ?Sized + Deserialize<'d> + Type, { let signature = T::signature(); self.deserialize_for_signature(&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: /// /// ``` /// use serde::{Deserialize, Serialize}; /// use zvariant::LE; /// /// use zvariant::to_bytes_for_signature; /// use zvariant::serialized::Context; /// /// 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, "u", &Unit::Variant2).unwrap(); /// assert_eq!(encoded.len(), 4); /// 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 signature = "(us)"; /// 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 = "(u(yt))"; /// 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: ?Sized + 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 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::dynamic_signature(&seed).to_owned(); #[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-4.1.2/src/serialized/format.rs000064400000000000000000000013641046102023000162520ustar 00000000000000use static_assertions::assert_impl_all; /// The encoding format. #[derive(Debug, Default, PartialEq, Eq, Copy, Clone)] pub enum Format { /// [D-Bus](https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling) /// format. #[default] DBus, /// [GVariant](https://developer.gnome.org/glib/stable/glib-GVariant.html) format. #[cfg(feature = "gvariant")] GVariant, } assert_impl_all!(Format: Send, Sync, Unpin); impl std::fmt::Display for Format { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Format::DBus => write!(f, "D-Bus"), #[cfg(feature = "gvariant")] Format::GVariant => write!(f, "GVariant"), } } } zvariant-4.1.2/src/serialized/mod.rs000064400000000000000000000002561046102023000155400ustar 00000000000000mod data; pub use data::Data; mod size; pub use size::Size; mod written; pub use written::Written; mod format; pub use format::Format; mod context; pub use context::Context; zvariant-4.1.2/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-4.1.2/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-4.1.2/src/signature.rs000064400000000000000000000427001046102023000146270ustar 00000000000000use core::{ cmp::Ordering, fmt::{self, Debug, Display, Formatter}, hash::{Hash, Hasher}, str, }; use serde::{ de::{Deserialize, Deserializer}, ser::{Serialize, Serializer}, }; use static_assertions::assert_impl_all; use std::{ borrow::Cow, ops::{Bound, RangeBounds}, sync::Arc, }; use crate::{serialized::Format, signature_parser::SignatureParser, Basic, Error, Result, Type}; // A data type similar to Cow and [`bytes::Bytes`] but unlike the former won't allow us to only keep // the owned bytes in Arc and latter doesn't have a notion of borrowed data and would require API // breakage. // // [`bytes::Bytes`]: https://docs.rs/bytes/0.5.6/bytes/struct.Bytes.html #[derive(Debug, Clone)] enum Bytes<'b> { Borrowed(&'b [u8]), Static(&'static [u8]), Owned(Arc<[u8]>), } impl<'b> Bytes<'b> { const fn borrowed<'s: 'b>(bytes: &'s [u8]) -> Self { Self::Borrowed(bytes) } fn owned(bytes: Vec) -> Self { Self::Owned(bytes.into()) } /// This is faster than `Clone::clone` when `self` contains owned data. fn as_ref(&self) -> Bytes<'_> { match &self { Bytes::Static(s) => Bytes::Static(s), Bytes::Borrowed(s) => Bytes::Borrowed(s), Bytes::Owned(s) => Bytes::Borrowed(s), } } } impl std::ops::Deref for Bytes<'_> { type Target = [u8]; fn deref(&self) -> &[u8] { match self { Bytes::Borrowed(borrowed) => borrowed, Bytes::Static(borrowed) => borrowed, Bytes::Owned(owned) => owned, } } } impl Eq for Bytes<'_> {} impl PartialEq for Bytes<'_> { fn eq(&self, other: &Self) -> bool { **self == **other } } impl Ord for Bytes<'_> { fn cmp(&self, other: &Self) -> Ordering { (**self).cmp(&**other) } } impl PartialOrd for Bytes<'_> { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Hash for Bytes<'_> { fn hash(&self, state: &mut H) { (**self).hash(state) } } /// String that [identifies] the type of an encoded value. /// /// # Examples /// /// ``` /// use zvariant::Signature; /// /// // Valid signatures /// let s = Signature::try_from("").unwrap(); /// assert_eq!(s, ""); /// # assert_eq!(s.n_complete_types(), Ok(0)); /// let s = Signature::try_from("y").unwrap(); /// assert_eq!(s, "y"); /// # assert_eq!(s.n_complete_types(), Ok(1)); /// let s = Signature::try_from("xs").unwrap(); /// assert_eq!(s, "xs"); /// # assert_eq!(s.n_complete_types(), Ok(2)); /// let s = Signature::try_from("(ysa{sd})").unwrap(); /// assert_eq!(s, "(ysa{sd})"); /// # assert_eq!(s.n_complete_types(), Ok(1)); /// let s = Signature::try_from("a{sd}").unwrap(); /// assert_eq!(s, "a{sd}"); /// # assert_eq!(s.n_complete_types(), Ok(1)); /// /// // Invalid signatures /// Signature::try_from("z").unwrap_err(); /// Signature::try_from("(xs").unwrap_err(); /// Signature::try_from("xs)").unwrap_err(); /// Signature::try_from("s/").unwrap_err(); /// Signature::try_from("a").unwrap_err(); /// Signature::try_from("a{yz}").unwrap_err(); /// ``` /// /// This is implemented so that multiple instances can share the same underlying signature string. /// Use [`slice`] method to create new signature that represents a portion of a signature /// /// [identifies]: https://dbus.freedesktop.org/doc/dbus-specification.html#type-system /// [`slice`]: #method.slice #[derive(Hash, Clone, PartialOrd, Ord)] pub struct Signature<'a> { bytes: Bytes<'a>, pos: usize, end: usize, } assert_impl_all!(Signature<'_>: Send, Sync, Unpin); impl<'a> Signature<'a> { /// The signature as a string. pub fn as_str(&self) -> &str { // SAFETY: non-UTF8 characters in Signature are rejected by safe constructors unsafe { str::from_utf8_unchecked(self.as_bytes()) } } /// The signature bytes. pub fn as_bytes(&self) -> &[u8] { &self.bytes[self.pos..self.end] } /// This is faster than `Clone::clone` when `self` contains owned data. pub fn as_ref(&self) -> Signature<'_> { Signature { bytes: self.bytes.as_ref(), pos: self.pos, end: self.end, } } /// Create a new Signature from given bytes. /// /// Since the passed bytes are not checked for correctness, it's provided for ease of /// `Type` implementations. /// /// # Safety /// /// This method is unsafe as it allows creating a `str` that is not valid UTF-8. pub unsafe fn from_bytes_unchecked<'s: 'a>(bytes: &'s [u8]) -> Self { Self { bytes: Bytes::borrowed(bytes), pos: 0, end: bytes.len(), } } /// Same as `from_bytes_unchecked`, except it takes a static reference. /// /// # Safety /// /// This method is unsafe as it allows creating a `str` that is not valid UTF-8. pub unsafe fn from_static_bytes_unchecked(bytes: &'static [u8]) -> Self { Self { bytes: Bytes::Static(bytes), pos: 0, end: bytes.len(), } } /// Same as `from_bytes_unchecked`, except it takes a string reference. pub const fn from_str_unchecked<'s: 'a>(signature: &'s str) -> Self { Self { bytes: Bytes::borrowed(signature.as_bytes()), pos: 0, end: signature.len(), } } /// Same as `from_str_unchecked`, except it takes a static string reference. pub const fn from_static_str_unchecked(signature: &'static str) -> Self { Self { bytes: Bytes::Static(signature.as_bytes()), pos: 0, end: signature.len(), } } /// Same as `from_str_unchecked`, except it takes an owned `String`. pub fn from_string_unchecked(signature: String) -> Self { let bytes = signature.into_bytes(); let end = bytes.len(); Self { bytes: Bytes::owned(bytes), pos: 0, end, } } /// Same as `from_static_str_unchecked`, except it checks validity of the signature. /// /// It's recommended to use this method instead of `TryFrom<&str>` implementation for /// `&'static str`. The former will ensure that [`Signature::to_owned`] and /// [`Signature::into_owned`] do not clone the underlying bytes. pub fn from_static_str(signature: &'static str) -> Result { let bytes = signature.as_bytes(); SignatureParser::validate(bytes)?; Ok(Self { bytes: Bytes::Static(bytes), pos: 0, end: signature.len(), }) } /// Same as `from_static_bytes_unchecked`, except it checks validity of the signature. /// /// It's recommended to use this method instead of the `TryFrom<&[u8]>` implementation for /// `&'static [u8]`. The former will ensure that [`Signature::to_owned`] and /// [`Signature::into_owned`] do not clone the underlying bytes. pub fn from_static_bytes(bytes: &'static [u8]) -> Result { SignatureParser::validate(bytes)?; Ok(Self { bytes: Bytes::Static(bytes), pos: 0, end: bytes.len(), }) } /// the signature's length. pub fn len(&self) -> usize { self.end - self.pos } /// if the signature is empty. pub fn is_empty(&self) -> bool { self.as_bytes().is_empty() } /// Creates an owned clone of `self`. pub fn to_owned(&self) -> Signature<'static> { match &self.bytes { Bytes::Borrowed(_) => { let bytes = Bytes::owned(self.as_bytes().to_vec()); let pos = 0; let end = bytes.len(); Signature { bytes, pos, end } } Bytes::Static(b) => Signature { bytes: Bytes::Static(b), pos: self.pos, end: self.end, }, Bytes::Owned(owned) => Signature { bytes: Bytes::Owned(owned.clone()), pos: self.pos, end: self.end, }, } } /// Creates an owned clone of `self`. pub fn into_owned(self) -> Signature<'static> { self.to_owned() } /// Returns a slice of `self` for the provided range. /// /// # Panics /// /// Requires that begin <= end and end <= self.len(), otherwise slicing will panic. #[must_use] pub fn slice(&self, range: impl RangeBounds) -> Self { let len = self.len(); let pos = 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!( pos <= end, "range start must not be greater than end: {:?} > {:?}", pos, end, ); assert!(end <= len, "range end out of bounds: {:?} > {:?}", end, len,); if end == pos { return Self::from_str_unchecked(""); } let mut clone = self.clone(); clone.pos += pos; clone.end = self.pos + end; clone } /// The number of complete types for the signature. /// /// # Errors /// /// If the signature is invalid, returns the first error. pub fn n_complete_types(&self) -> Result { let mut count = 0; // SAFETY: the parser is only used to do counting for s in unsafe { SignatureParser::from_bytes_unchecked(self.as_bytes())? } { s?; count += 1; } Ok(count) } } impl<'a> Debug for Signature<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Signature").field(&self.as_str()).finish() } } impl<'a> Basic for Signature<'a> { const SIGNATURE_CHAR: char = 'g'; const SIGNATURE_STR: &'static str = "g"; fn alignment(format: Format) -> usize { match format { Format::DBus => 1, #[cfg(feature = "gvariant")] Format::GVariant => 1, } } } impl<'a> Type for Signature<'a> { fn signature() -> Signature<'static> { Signature::from_static_str_unchecked(Self::SIGNATURE_STR) } } impl<'a> From<&Signature<'a>> for Signature<'a> { fn from(signature: &Signature<'a>) -> Signature<'a> { signature.clone() } } impl<'a> TryFrom<&'a [u8]> for Signature<'a> { type Error = Error; fn try_from(value: &'a [u8]) -> Result { SignatureParser::validate(value)?; // SAFETY: validate checks UTF8 unsafe { Ok(Self::from_bytes_unchecked(value)) } } } /// Try to create a Signature from a string. impl<'a> TryFrom<&'a str> for Signature<'a> { type Error = Error; fn try_from(value: &'a str) -> Result { Self::try_from(value.as_bytes()) } } /// Try to create a Signature from a `Cow.` impl<'a> TryFrom> for Signature<'a> { type Error = Error; fn try_from(value: Cow<'a, str>) -> Result { match value { Cow::Borrowed(v) => Self::try_from(v), Cow::Owned(v) => Self::try_from(v), } } } impl<'a> TryFrom for Signature<'a> { type Error = Error; fn try_from(value: String) -> Result { SignatureParser::validate(value.as_bytes())?; Ok(Self::from_string_unchecked(value)) } } impl<'a> From> for String { fn from(value: Signature<'a>) -> String { String::from(value.as_str()) } } impl<'a> From<&Signature<'a>> for String { fn from(value: &Signature<'a>) -> String { String::from(value.as_str()) } } impl<'a> std::ops::Deref for Signature<'a> { type Target = str; fn deref(&self) -> &Self::Target { self.as_str() } } /// Checks whether the string slice has balanced parentheses. fn has_balanced_parentheses(signature_str: &str) -> bool { signature_str.chars().fold(0, |count, ch| match ch { '(' => count + 1, ')' if count != 0 => count - 1, _ => count, }) == 0 } /// Determines whether the signature has outer parentheses and if so, return the /// string slice without those parentheses. fn without_outer_parentheses<'a, 'b>(sig: &'a Signature<'b>) -> &'a str where 'b: 'a, { let sig_str = sig.as_str(); if let Some(subslice) = sig_str.strip_prefix('(').and_then(|s| s.strip_suffix(')')) { if has_balanced_parentheses(subslice) { return subslice; } } sig_str } /// Evaluate equality of two signatures, ignoring outer parentheses if needed. impl<'a, 'b> PartialEq> for Signature<'b> { fn eq(&self, other: &Signature<'_>) -> bool { without_outer_parentheses(self) == without_outer_parentheses(other) } } impl<'a> PartialEq for Signature<'a> { fn eq(&self, other: &str) -> bool { self.as_bytes() == other.as_bytes() } } impl<'a> PartialEq<&str> for Signature<'a> { fn eq(&self, other: &&str) -> bool { self.as_bytes() == other.as_bytes() } } // According to the docs, `Eq` derive should only be used on structs if all its fields are // are `Eq`. Hence the manual implementation. impl Eq for Signature<'_> {} impl<'a> Display for Signature<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { std::fmt::Display::fmt(&self.as_str(), f) } } impl<'a> Serialize for Signature<'a> { fn serialize(&self, serializer: S) -> core::result::Result where S: Serializer, { serializer.serialize_str(self.as_str()) } } impl<'de: 'a, 'a> Deserialize<'de> for Signature<'a> { fn deserialize(deserializer: D) -> core::result::Result where D: Deserializer<'de>, { let val = >::deserialize(deserializer)?; Self::try_from(val).map_err(serde::de::Error::custom) } } /// Owned [`Signature`](struct.Signature.html) #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, Type)] pub struct OwnedSignature(Signature<'static>); assert_impl_all!(OwnedSignature: Send, Sync, Unpin); impl OwnedSignature { pub fn into_inner(self) -> Signature<'static> { self.0 } } impl Basic for OwnedSignature { const SIGNATURE_CHAR: char = Signature::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = Signature::SIGNATURE_STR; fn alignment(format: Format) -> usize { Signature::alignment(format) } } impl std::ops::Deref for OwnedSignature { type Target = Signature<'static>; fn deref(&self) -> &Self::Target { &self.0 } } impl std::convert::From for Signature<'static> { fn from(o: OwnedSignature) -> Self { o.into_inner() } } impl<'a> std::convert::From> for OwnedSignature { fn from(o: Signature<'a>) -> Self { OwnedSignature(o.into_owned()) } } impl std::convert::From for crate::Value<'static> { fn from(o: OwnedSignature) -> Self { o.into_inner().into() } } impl TryFrom for OwnedSignature { type Error = Error; fn try_from(value: String) -> Result { Ok(Self(Signature::try_from(value)?)) } } impl<'de> Deserialize<'de> for OwnedSignature { fn deserialize(deserializer: D) -> core::result::Result where D: Deserializer<'de>, { let val = String::deserialize(deserializer)?; OwnedSignature::try_from(val).map_err(serde::de::Error::custom) } } impl std::fmt::Display for OwnedSignature { 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::{Bytes, Signature}; use std::sync::Arc; #[test] fn bytes_equality() { let borrowed1 = Bytes::Borrowed(b"foo"); let borrowed2 = Bytes::Borrowed(b"foo"); let static1 = Bytes::Static(b"foo"); let static2 = Bytes::Static(b"foo"); let owned1 = Bytes::Owned(Arc::new(*b"foo")); let owned2 = Bytes::Owned(Arc::new(*b"foo")); assert_eq!(borrowed1, borrowed2); assert_eq!(static1, static2); assert_eq!(owned1, owned2); assert_eq!(borrowed1, static1); assert_eq!(static1, borrowed1); assert_eq!(static1, owned1); assert_eq!(owned1, static1); assert_eq!(borrowed1, owned1); assert_eq!(owned1, borrowed1); } #[test] fn signature_slicing() { let sig = Signature::from_str_unchecked("(asta{sv})"); assert_eq!(sig, "(asta{sv})"); let slice = sig.slice(1..); assert_eq!(slice.len(), sig.len() - 1); assert_eq!(slice, &sig[1..]); assert_eq!(slice.as_bytes()[1], b's'); assert_eq!(slice.as_bytes()[2], b't'); let slice = slice.slice(2..3); assert_eq!(slice.len(), 1); assert_eq!(slice, "t"); assert_eq!(slice.slice(1..), ""); } #[test] fn signature_equality() { let sig_a = Signature::from_str_unchecked("(asta{sv})"); let sig_b = Signature::from_str_unchecked("asta{sv}"); assert_eq!(sig_a, sig_b); let sig_a = Signature::from_str_unchecked("((so)ii(uu))"); let sig_b = Signature::from_str_unchecked("(so)ii(uu)"); assert_eq!(sig_a, sig_b); let sig_a = Signature::from_str_unchecked("(so)i"); let sig_b = Signature::from_str_unchecked("(so)u"); assert_ne!(sig_a, sig_b); } } zvariant-4.1.2/src/signature_parser.rs000064400000000000000000000246521046102023000162110ustar 00000000000000use std::ops::{Bound, RangeBounds}; use crate::{subslice, Basic, ObjectPath, Result, Signature, STRUCT_SIG_END_CHAR}; #[cfg(unix)] use crate::Fd; #[cfg(feature = "gvariant")] use crate::utils::MAYBE_SIGNATURE_CHAR; use crate::utils::{ ARRAY_SIGNATURE_CHAR, DICT_ENTRY_SIG_END_CHAR, DICT_ENTRY_SIG_START_CHAR, STRUCT_SIG_START_CHAR, VARIANT_SIGNATURE_CHAR, }; #[derive(Debug, Clone)] pub(crate) struct SignatureParser<'s> { signature: Signature<'s>, pos: usize, end: usize, } impl<'s> SignatureParser<'s> { pub fn new(signature: Signature<'s>) -> Self { let end = signature.len(); Self { signature, pos: 0, end, } } pub(crate) unsafe fn from_bytes_unchecked(signature: &'s [u8]) -> Result { if signature.len() > 255 { return Err(serde::de::Error::invalid_length( signature.len(), &"<= 255 characters", )); } let signature = Signature::from_bytes_unchecked(signature); Ok(Self::new(signature)) } pub fn validate(signature: &'s [u8]) -> Result<()> { // SAFETY: the parser is only used to validate the signature for s in unsafe { Self::from_bytes_unchecked(signature)? } { s?; } Ok(()) } pub fn signature(&self) -> Signature<'_> { self.signature.slice(self.pos..self.end) } pub fn next_char(&self) -> Result { subslice(self.signature.as_bytes(), self.pos).map(|b| *b as char) } #[inline] pub fn skip_char(&mut self) -> Result<()> { self.skip_chars(1) } pub fn skip_chars(&mut self, num_chars: usize) -> Result<()> { self.pos += num_chars; // We'll be going one char beyond at the end of parsing but not beyond that. if self.pos > self.end { return Err(serde::de::Error::invalid_length( self.signature.len(), &format!(">= {} characters", self.pos).as_str(), )); } Ok(()) } #[inline] pub fn len(&self) -> usize { self.end - self.pos } #[inline] pub fn done(&self) -> bool { self.pos == self.end } /// 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) -> Self { let len = self.len(); let pos = 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!( pos <= end, "range start must not be greater than end: {:?} > {:?}", pos, end, ); assert!(end <= len, "range end out of bounds: {:?} > {:?}", end, len,); let mut clone = self.clone(); clone.pos += pos; clone.end = self.pos + end; clone } /// Get the next signature and increment the position. pub fn parse_next_signature(&mut self) -> Result> { let len = &self.next_signature()?.len(); let pos = self.pos; self.pos += len; // We'll be going one char beyond at the end of parsing but not beyond that. if self.pos > self.end { return Err(serde::de::Error::invalid_length( self.signature.len(), &format!(">= {} characters", self.pos).as_str(), )); } Ok(self.signature.slice(pos..self.pos)) } /// Get the next signature but don't increment the position. pub fn next_signature(&self) -> Result> { match self .signature() .as_bytes() .first() .map(|b| *b as char) .ok_or_else(|| -> crate::Error { serde::de::Error::invalid_length(0, &">= 1 character") })? { u8::SIGNATURE_CHAR | bool::SIGNATURE_CHAR | i16::SIGNATURE_CHAR | u16::SIGNATURE_CHAR | i32::SIGNATURE_CHAR | u32::SIGNATURE_CHAR | i64::SIGNATURE_CHAR | u64::SIGNATURE_CHAR | f64::SIGNATURE_CHAR | <&str>::SIGNATURE_CHAR | ObjectPath::SIGNATURE_CHAR | Signature::SIGNATURE_CHAR | VARIANT_SIGNATURE_CHAR => Ok(self.signature_slice(0, 1)), #[cfg(unix)] Fd::SIGNATURE_CHAR => Ok(self.signature_slice(0, 1)), ARRAY_SIGNATURE_CHAR => self.next_array_signature(), STRUCT_SIG_START_CHAR => self.next_structure_signature(), DICT_ENTRY_SIG_START_CHAR => self.next_dict_entry_signature(), #[cfg(feature = "gvariant")] MAYBE_SIGNATURE_CHAR => self.next_maybe_signature(), c => Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char(c), &"a valid signature character", )), } } fn next_single_child_type_container_signature( &self, expected_sig_prefix: char, ) -> Result> { let signature = self.signature(); if signature.len() < 2 { return Err(serde::de::Error::invalid_length( signature.len(), &">= 2 characters", )); } // We can't get None here cause we already established there is are least 2 chars above let c = signature .as_bytes() .first() .map(|b| *b as char) .expect("empty signature"); if c != expected_sig_prefix { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char(c), &expected_sig_prefix.to_string().as_str(), )); } // There should be a valid complete signature after 'a' but not more than 1 let child_parser = self.slice(1..); let child_len = child_parser.next_signature()?.len(); Ok(self.signature_slice(0, child_len + 1)) } fn next_array_signature(&self) -> Result> { self.next_single_child_type_container_signature(ARRAY_SIGNATURE_CHAR) } #[cfg(feature = "gvariant")] fn next_maybe_signature(&self) -> Result> { self.next_single_child_type_container_signature(MAYBE_SIGNATURE_CHAR) } fn next_structure_signature(&self) -> Result> { let signature = self.signature(); if signature.len() < 3 { return Err(serde::de::Error::invalid_length( signature.len(), &">= 2 characters", )); } let mut bytes = signature.as_bytes().iter(); // We can't get None here cause we already established there are at least 2 chars above let c = bytes.next().map(|b| *b as char).expect("empty signature"); if c != STRUCT_SIG_START_CHAR { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char(c), &crate::STRUCT_SIG_START_STR, )); } if bytes.next().map(|b| *b as char).expect("empty signature") == STRUCT_SIG_END_CHAR { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Str("()"), &"at least one field signature between `(` and `)`", )); } let mut fields_sig_len = 0; let mut fields_parser = self.slice(1..); while !fields_parser.done() && fields_parser.next_char()? != STRUCT_SIG_END_CHAR { fields_sig_len += fields_parser.parse_next_signature()?.len(); } let c = fields_parser.next_char()?; if c != STRUCT_SIG_END_CHAR { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char(c), &crate::STRUCT_SIG_END_STR, )); } // The `(`, fields signatures and `)`. Ok(self.signature_slice(0, fields_sig_len + 2)) } fn next_dict_entry_signature(&self) -> Result> { let signature = self.signature(); if signature.len() < 4 { return Err(serde::de::Error::invalid_length( signature.len(), &">= 4 characters", )); } // We can't get None here cause we already established there are at least 4 chars above let bytes = signature.as_bytes(); let c = bytes.first().map(|b| *b as char).expect("empty signature"); if c != DICT_ENTRY_SIG_START_CHAR { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char(c), &crate::DICT_ENTRY_SIG_START_STR, )); } let key_parser = self.slice(1..); let key_signature = key_parser.next_signature()?; // Key's signature will always be just 1 character. if key_signature.len() != 1 { return Err(serde::de::Error::invalid_length( key_signature.len(), &"dict-entry key's signature can only be a single character", )); } // There should be one valid complete signature for value. let value_parser = self.slice(2..); let value_len = value_parser.next_signature()?.len(); // signature of value + `{` + 1 char of the key signature + `}` let end = value_len + 3; if signature.len() < end { return Err(serde::de::Error::invalid_length( signature.len(), &format!(">= {end} characters").as_str(), )); } if bytes[end - 1] as char != DICT_ENTRY_SIG_END_CHAR { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Char(c), &crate::DICT_ENTRY_SIG_END_STR, )); } Ok(self.signature_slice(0, end)) } fn signature_slice(&self, idx: usize, end: usize) -> Signature<'_> { self.signature.slice(self.pos + idx..self.pos + end) } } impl<'a> Iterator for SignatureParser<'a> { type Item = Result>; fn next(&mut self) -> Option { if self.done() { None } else { Some(self.parse_next_signature()) } } } zvariant-4.1.2/src/str.rs000064400000000000000000000132041046102023000134330ustar 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::{serialized::Format, Basic, Signature, Type}; /// A string wrapper. /// /// This is used for keeping strings in a [`Value`]. 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)] #[serde(rename(serialize = "zvariant::Str", deserialize = "zvariant::Str"))] pub struct Str<'a>(#[serde(borrow)] Inner<'a>); #[derive(Eq, Clone)] enum Inner<'a> { Static(&'static str), Borrowed(&'a str), Owned(Arc), } impl<'a> Default for Inner<'a> { 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<'a> Hash for Inner<'a> { fn hash(&self, h: &mut H) { self.as_str().hash(h) } } impl<'a> Inner<'a> { /// The underlying string. pub fn as_str(&self) -> &str { match self { Inner::Static(s) => s, Inner::Borrowed(s) => s, Inner::Owned(s) => s, } } } impl<'a> Serialize for Inner<'a> { 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<'a> Str<'a> { /// 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<'a> Basic for Str<'a> { const SIGNATURE_CHAR: char = <&str>::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = <&str>::SIGNATURE_STR; fn alignment(format: Format) -> usize { <&str>::alignment(format) } } impl<'a> Type for Str<'a> { fn signature() -> Signature<'static> { Signature::from_static_str_unchecked(Self::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<'a> From for Str<'a> { fn from(value: String) -> Self { Self(Inner::Owned(value.into())) } } impl<'a> From> for Str<'a> { 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<'a> std::ops::Deref for Str<'a> { type Target = str; fn deref(&self) -> &Self::Target { self.as_str() } } impl<'a> PartialEq for Str<'a> { fn eq(&self, other: &str) -> bool { self.as_str() == other } } impl<'a> PartialEq<&str> for Str<'a> { fn eq(&self, other: &&str) -> bool { self.as_str() == *other } } impl<'a> std::fmt::Debug for Str<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Debug::fmt(self.as_str(), f) } } impl<'a> std::fmt::Display for Str<'a> { 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-4.1.2/src/structure.rs000064400000000000000000000321071046102023000146660ustar 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::{ signature_parser::SignatureParser, 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) -> Structure<'a> { let signature = create_signature_from_fields(&self.0); Structure { fields: self.0, signature, } } /// Same as `build` except Signature is provided. pub(crate) fn build_with_signature<'s: 'a>(self, signature: Signature<'s>) -> Structure<'a> { Structure { fields: self.0, signature, } } } /// Use this to deserialize a [`Structure`]. /// /// [`Structure`]: struct.Structure.html #[derive(Debug, Clone, PartialEq, Eq)] pub struct StructureSeed<'a>(Signature<'a>); assert_impl_all!(StructureSeed<'_>: Send, Sync, Unpin); impl<'a> StructureSeed<'a> { /// Create a new `StructureSeed` /// /// The given signature must be a valid structure signature. #[must_use] pub fn new_unchecked(signature: Signature<'a>) -> Self { StructureSeed(signature) } } impl<'a> TryFrom> for StructureSeed<'a> { type Error = zvariant::Error; fn try_from(signature: Signature<'a>) -> Result { if signature.starts_with(zvariant::STRUCT_SIG_START_CHAR) { Ok(StructureSeed(signature)) } else { Err(zvariant::Error::IncorrectType) } } } impl<'de> DeserializeSeed<'de> for StructureSeed<'de> { type Value = Structure<'de>; fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_seq(StructureVisitor { signature: self.0 }) } } #[derive(Debug, Clone, PartialEq, Eq)] struct StructureVisitor<'a> { signature: Signature<'a>, } impl<'de> Visitor<'de> for StructureVisitor<'de> { 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<'a>, } 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`. /// /// NB: This method potentially allocates and copies. Use [`full_signature`] if you'd like to /// avoid that. /// /// [`full_signature`]: #method.full_signature pub fn signature(&self) -> Signature<'static> { self.signature.to_owned() } /// Get the signature of this `Structure`. pub fn full_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<'a> Default for Structure<'a> { fn default() -> Self { let signature = Signature::from_static_str_unchecked("()"); Self { fields: vec![], signature, } } } impl<'a> DynamicType for Structure<'a> { fn dynamic_signature(&self) -> Signature<'_> { self.signature.as_ref() } } impl<'a> DynamicType for StructureSeed<'a> { fn dynamic_signature(&self) -> Signature<'_> { self.0.as_ref() } } impl<'a> DynamicDeserialize<'a> for Structure<'a> { type Deserializer = StructureSeed<'a>; fn deserializer_for_signature(signature: S) -> zvariant::Result where S: TryInto>, S::Error: Into, { let mut signature = signature.try_into().map_err(Into::into)?; if !signature.starts_with(zvariant::STRUCT_SIG_START_CHAR) { // This is certainly not a valid struct signature signature = format!("({signature})").try_into()?; return signature.try_into(); } // The signature might be something like "(i)u(i)" - we need to parse it to check. let mut parser = SignatureParser::new(signature.as_ref()); parser.parse_next_signature()?; if !parser.done() { // more than one element - we must wrap it signature = format!("({signature})").try_into()?; } signature.try_into() } } impl<'a> Serialize for Structure<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut structure = serializer.serialize_tuple_struct("zvariant::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() } } 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) } fn create_signature_from_fields(fields: &[Value<'_>]) -> Signature<'static> { let mut signature = String::with_capacity(255); signature.push('('); for field in fields { signature.push_str(&field.value_signature()); } signature.push(')'); Signature::from_string_unchecked(signature) } /// 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<'static>); impl DynamicType for OwnedStructure { fn dynamic_signature(&self) -> Signature<'_> { self.0.dynamic_signature() } } impl DynamicType for OwnedStructureSeed { fn dynamic_signature(&self) -> Signature<'_> { self.0.clone() } } impl<'de> DynamicDeserialize<'de> for OwnedStructure { type Deserializer = OwnedStructureSeed; fn deserializer_for_signature(signature: S) -> zvariant::Result where S: TryInto>, S::Error: Into, { Structure::deserializer_for_signature(signature) .map(|StructureSeed(s)| OwnedStructureSeed(s.to_owned())) } } 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-4.1.2/src/tuple.rs000064400000000000000000000141361046102023000137610ustar 00000000000000use crate::{ signature_parser::SignatureParser, utils::*, 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 dynamic_signature(&self) -> Signature<'_> { Signature::from_static_str_unchecked("") } } 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<'a>, seeds: S, marker: PhantomData, } impl<'a, T, S> DynamicType for TupleSeed<'a, T, S> { fn dynamic_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 dynamic_signature(&self) -> Signature<'_> { let mut sig = String::with_capacity(255); sig.push(STRUCT_SIG_START_CHAR); $( sig.push_str(DynamicType::dynamic_signature(&self.0.$n).as_str()); )+ sig.push(STRUCT_SIG_END_CHAR); Signature::from_string_unchecked(sig) } } 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.marker }) } } 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: S) -> zvariant::Result where S: TryInto>, S::Error: Into { let sig = signature.try_into().map_err(Into::into)?; if !sig.starts_with(zvariant::STRUCT_SIG_START_CHAR) { return Err(zvariant::Error::IncorrectType); } if !sig.ends_with(zvariant::STRUCT_SIG_END_CHAR) { return Err(zvariant::Error::IncorrectType); } let end = sig.len() - 1; let mut sig_parser = SignatureParser::new(sig.slice(1..end)); let seeds = ($({ let elt_sig = sig_parser.parse_next_signature()?; $name::deserializer_for_signature(elt_sig)? },)+); Ok(TupleSeed { sig, seeds, marker: 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-4.1.2/src/type.rs000064400000000000000000000370611046102023000136130ustar 00000000000000use crate::{utils::*, Signature}; use serde::de::{Deserialize, DeserializeSeed}; use std::{ marker::PhantomData, net::{IpAddr, Ipv4Addr, Ipv6Addr}, path::{Path, PathBuf}, rc::Rc, sync::{Arc, Mutex, RwLock}, time::Duration, }; /// 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 { /// Get the signature for the implementing type. /// /// # Example /// /// ``` /// use std::collections::HashMap; /// use zvariant::Type; /// /// assert_eq!(u32::signature(), "u"); /// assert_eq!(String::signature(), "s"); /// assert_eq!(<(u32, &str, u64)>::signature(), "(ust)"); /// assert_eq!(<(u32, &str, &[u64])>::signature(), "(usat)"); /// assert_eq!(>::signature(), "a{ys}"); /// ``` fn signature() -> Signature<'static>; } /// 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 { /// Get the signature for the implementing type. /// /// See [Type::signature] for details. fn dynamic_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 signature. fn deserializer_for_signature(signature: S) -> zvariant::Result where S: TryInto>, S::Error: Into; } impl DynamicType for T where T: Type + ?Sized, { fn dynamic_signature(&self) -> Signature<'_> { ::signature() } } impl Type for PhantomData where T: Type + ?Sized, { fn signature() -> Signature<'static> { T::signature() } } impl<'de, T> DynamicDeserialize<'de> for T where T: Type + ?Sized + Deserialize<'de>, { type Deserializer = PhantomData; fn deserializer_for_signature(signature: S) -> zvariant::Result where S: TryInto>, S::Error: Into, { let mut expected = ::signature(); let original = signature.try_into().map_err(Into::into)?; if original == expected { return Ok(PhantomData); } let mut signature = original.as_ref(); while expected.len() < signature.len() && signature.starts_with(STRUCT_SIG_START_CHAR) && signature.ends_with(STRUCT_SIG_END_CHAR) { signature = signature.slice(1..signature.len() - 1); } while signature.len() < expected.len() && expected.starts_with(STRUCT_SIG_START_CHAR) && expected.ends_with(STRUCT_SIG_END_CHAR) { expected = expected.slice(1..expected.len() - 1); } if signature == expected { Ok(PhantomData) } else { let expected = ::signature(); Err(zvariant::Error::SignatureMismatch( original.to_owned(), format!("`{expected}`"), )) } } } macro_rules! array_type { ($arr:ty) => { impl Type for $arr where T: Type, { #[inline] fn signature() -> Signature<'static> { Signature::from_string_unchecked(format!("a{}", T::signature())) } } }; } array_type!([T]); array_type!(Vec); impl Type for std::collections::HashSet where T: Type + Eq + Hash, S: BuildHasher, { #[inline] fn signature() -> Signature<'static> { <[T]>::signature() } } #[cfg(feature = "arrayvec")] impl Type for arrayvec::ArrayVec where T: Type, { #[inline] fn signature() -> Signature<'static> { <[T]>::signature() } } #[cfg(feature = "arrayvec")] impl Type for arrayvec::ArrayString { #[inline] fn signature() -> Signature<'static> { <&str>::signature() } } // Empty type deserves empty signature impl Type for () { #[inline] fn signature() -> Signature<'static> { Signature::from_static_str_unchecked("") } } macro_rules! deref_impl { ( $type:ty, <$($desc:tt)+ ) => { impl <$($desc)+ { #[inline] fn signature() -> Signature<'static> { <$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 Mutex); deref_impl!(T, Type for RwLock); deref_impl!(T, Type for Box); deref_impl!(T, Type for Rc); #[cfg(all(feature = "gvariant", not(feature = "option-as-array")))] impl Type for Option where T: Type, { #[inline] fn signature() -> Signature<'static> { Signature::from_string_unchecked(format!("m{}", T::signature())) } } #[cfg(feature = "option-as-array")] impl Type for Option where T: Type, { #[inline] fn signature() -> Signature<'static> { Signature::from_string_unchecked(format!("a{}", T::signature())) } } //////////////////////////////////////////////////////////////////////////////// macro_rules! tuple_impls { ($($len:expr => ($($n:tt $name:ident)+))+) => { $( impl<$($name),+> Type for ($($name,)+) where $($name: Type,)+ { fn signature() -> Signature<'static> { let mut sig = String::with_capacity(255); sig.push(STRUCT_SIG_START_CHAR); $( sig.push_str($name::signature().as_str()); )+ sig.push(STRUCT_SIG_END_CHAR); Signature::from_string_unchecked(sig) } } )+ } } 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, { #[allow(clippy::reversed_empty_ranges)] fn signature() -> Signature<'static> { let mut sig = String::with_capacity(255); sig.push(STRUCT_SIG_START_CHAR); for _ in 0..N { sig.push_str(T::signature().as_str()); } sig.push(STRUCT_SIG_END_CHAR); Signature::from_string_unchecked(sig) } } //////////////////////////////////////////////////////////////////////////////// use std::{ borrow::Cow, collections::{BTreeMap, HashMap}, hash::{BuildHasher, Hash}, time::SystemTime, }; 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,)* { #[inline] fn signature() -> Signature<'static> { Signature::from_string_unchecked(format!("a{{{}{}}}", K::signature(), V::signature())) } } } } map_impl!(BTreeMap); map_impl!(HashMap); impl Type for Duration { fn signature() -> Signature<'static> { <(u64, u32)>::signature() } } impl Type for SystemTime { #[inline] fn signature() -> Signature<'static> { <( // seconds u64, // nano u32, )>::signature() } } impl Type for Ipv4Addr { #[inline] fn signature() -> Signature<'static> { <[u8; 4]>::signature() } } impl Type for Ipv6Addr { #[inline] fn signature() -> Signature<'static> { <[u8; 16]>::signature() } } impl Type for IpAddr { #[inline] fn signature() -> Signature<'static> { <(u32, &[u8])>::signature() } } // BitFlags #[cfg(feature = "enumflags2")] impl Type for enumflags2::BitFlags where F: Type + enumflags2::BitFlag, { #[inline] fn signature() -> Signature<'static> { F::signature() } } #[cfg(feature = "serde_bytes")] impl Type for serde_bytes::Bytes { fn signature() -> Signature<'static> { Signature::from_static_str_unchecked("ay") } } #[cfg(feature = "serde_bytes")] impl Type for serde_bytes::ByteBuf { fn signature() -> Signature<'static> { Signature::from_static_str_unchecked("ay") } } #[allow(unused)] macro_rules! static_str_type { ($ty:ty) => { impl Type for $ty { fn signature() -> Signature<'static> { <&str>::signature() } } }; } static_str_type!(Path); static_str_type!(PathBuf); #[cfg(feature = "uuid")] impl Type for uuid::Uuid { fn signature() -> Signature<'static> { Signature::from_static_str_unchecked("ay") } } #[cfg(feature = "url")] static_str_type!(url::Url); // FIXME: Ignoring the `serde-human-readable` feature of `time` crate in these impls: // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L110 #[cfg(feature = "time")] impl Type for time::Date { fn signature() -> Signature<'static> { // Serialized as a (year, ordinal) tuple: // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L92 <(i32, u16)>::signature() } } #[cfg(feature = "time")] impl Type for time::Duration { fn signature() -> Signature<'static> { // Serialized as a (whole seconds, nanoseconds) tuple: // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L119 <(i64, i32)>::signature() } } #[cfg(feature = "time")] impl Type for time::OffsetDateTime { fn signature() -> Signature<'static> { // Serialized as a tuple: // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L155 <( // year i32, // ordinal u16, // hour u8, // minute u8, // second u8, // nanosecond u32, // offset.whole_hours i8, // offset.minutes_past_hour i8, // offset.seconds_past_minute i8, )>::signature() } } #[cfg(feature = "time")] impl Type for time::PrimitiveDateTime { fn signature() -> Signature<'static> { // Serialized as a tuple: // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L200 <( // year i32, // ordinal u16, // hour u8, // minute u8, // second u8, // nanosecond u32, )>::signature() } } #[cfg(feature = "time")] impl Type for time::Time { fn signature() -> Signature<'static> { // Serialized as a tuple: // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L246 <( // hour u8, // minute u8, // second u8, // nanosecond u32, )>::signature() } } #[cfg(feature = "time")] impl Type for time::UtcOffset { fn signature() -> Signature<'static> { // Serialized as a (whole hours, minutes past hour, seconds past minute) tuple: // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L282 <(i8, i8, i8)>::signature() } } #[cfg(feature = "time")] impl Type for time::Weekday { fn signature() -> Signature<'static> { // Serialized as number from Monday: // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L312 u8::signature() } } #[cfg(feature = "time")] impl Type for time::Month { fn signature() -> Signature<'static> { // Serialized as month number: // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L337 u8::signature() } } #[cfg(feature = "chrono")] impl Type for chrono::DateTime { fn signature() -> Signature<'static> { <&str>::signature() } } #[cfg(feature = "chrono")] static_str_type!(chrono::NaiveDateTime); #[cfg(feature = "chrono")] static_str_type!(chrono::NaiveTime); // TODO: Blanket implementation for more types: https://github.com/serde-rs/serde/blob/master/serde/src/ser/impls.rs zvariant-4.1.2/src/utils.rs000064400000000000000000000262521046102023000137720ustar 00000000000000use std::slice::SliceIndex; #[cfg(feature = "gvariant")] use crate::signature_parser::SignatureParser; use crate::{serialized::Format, Basic, Error, ObjectPath, Result, Signature}; #[cfg(unix)] use crate::Fd; /// 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"; pub(crate) const VARIANT_ALIGNMENT_DBUS: usize = 1; #[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 } pub(crate) fn f64_to_f32(value: f64) -> f32 { assert!(value <= (f32::MAX as f64), "{} too large for `f32`", value,); value as f32 } // `signature` must be **one** complete and correct signature. Expect panics otherwise! pub(crate) fn alignment_for_signature(signature: &Signature<'_>, format: Format) -> Result { let alignment = match signature .as_bytes() .first() .map(|b| *b as char) .ok_or_else(|| -> Error { serde::de::Error::invalid_length(0, &">= 1 character") })? { u8::SIGNATURE_CHAR => u8::alignment(format), bool::SIGNATURE_CHAR => bool::alignment(format), i16::SIGNATURE_CHAR => i16::alignment(format), u16::SIGNATURE_CHAR => u16::alignment(format), i32::SIGNATURE_CHAR => i32::alignment(format), u32::SIGNATURE_CHAR => u32::alignment(format), #[cfg(unix)] Fd::SIGNATURE_CHAR => u32::alignment(format), i64::SIGNATURE_CHAR => i64::alignment(format), u64::SIGNATURE_CHAR => u64::alignment(format), f64::SIGNATURE_CHAR => f64::alignment(format), <&str>::SIGNATURE_CHAR => <&str>::alignment(format), ObjectPath::SIGNATURE_CHAR => ObjectPath::alignment(format), Signature::SIGNATURE_CHAR => Signature::alignment(format), VARIANT_SIGNATURE_CHAR => match format { Format::DBus => VARIANT_ALIGNMENT_DBUS, #[cfg(feature = "gvariant")] Format::GVariant => VARIANT_ALIGNMENT_GVARIANT, }, ARRAY_SIGNATURE_CHAR => alignment_for_array_signature(signature, format)?, STRUCT_SIG_START_CHAR => alignment_for_struct_signature(signature, format)?, DICT_ENTRY_SIG_START_CHAR => alignment_for_dict_entry_signature(signature, format)?, #[cfg(feature = "gvariant")] MAYBE_SIGNATURE_CHAR => alignment_for_maybe_signature(signature, format)?, _ => { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Str(signature), &"a valid signature", )) } }; Ok(alignment) } #[cfg(feature = "gvariant")] pub(crate) fn is_fixed_sized_signature<'a>(signature: &'a Signature<'a>) -> Result { match signature .as_bytes() .first() .map(|b| *b as char) .ok_or_else(|| -> Error { serde::de::Error::invalid_length(0, &">= 1 character") })? { u8::SIGNATURE_CHAR | bool::SIGNATURE_CHAR | i16::SIGNATURE_CHAR | u16::SIGNATURE_CHAR | i32::SIGNATURE_CHAR | u32::SIGNATURE_CHAR | i64::SIGNATURE_CHAR | u64::SIGNATURE_CHAR | f64::SIGNATURE_CHAR => Ok(true), #[cfg(unix)] Fd::SIGNATURE_CHAR => Ok(true), STRUCT_SIG_START_CHAR => is_fixed_sized_struct_signature(signature), DICT_ENTRY_SIG_START_CHAR => is_fixed_sized_dict_entry_signature(signature), _ => Ok(false), } } // Given an &str, create an owned (String-based) Signature w/ appropriate capacity macro_rules! signature_string { ($signature:expr) => {{ let mut s = String::with_capacity(255); s.push_str($signature); Signature::from_string_unchecked(s) }}; } macro_rules! check_child_value_signature { ($expected_signature:expr, $child_signature:expr, $child_name:literal) => {{ if $child_signature != $expected_signature { let unexpected = format!("{} with signature `{}`", $child_name, $child_signature,); let expected = format!("{} with signature `{}`", $child_name, $expected_signature); return Err(serde::de::Error::invalid_type( serde::de::Unexpected::Str(&unexpected), &expected.as_str(), )); } }}; } fn alignment_for_single_child_type_signature( #[allow(unused)] signature: &Signature<'_>, format: Format, dbus_align: usize, ) -> Result { match format { Format::DBus => Ok(dbus_align), #[cfg(feature = "gvariant")] Format::GVariant => { let child_signature = signature.slice(1..); alignment_for_signature(&child_signature, format) } } } fn alignment_for_array_signature(signature: &Signature<'_>, format: Format) -> Result { alignment_for_single_child_type_signature(signature, format, ARRAY_ALIGNMENT_DBUS) } #[cfg(feature = "gvariant")] fn alignment_for_maybe_signature(signature: &Signature<'_>, format: Format) -> Result { alignment_for_single_child_type_signature(signature, format, 1) } fn alignment_for_struct_signature( #[allow(unused)] signature: &Signature<'_>, format: Format, ) -> Result { match format { Format::DBus => Ok(STRUCT_ALIGNMENT_DBUS), #[cfg(feature = "gvariant")] Format::GVariant => { if signature.len() < 3 { return Err(serde::de::Error::invalid_length( signature.len(), &">= 3 characters in struct signature", )); } let inner_signature = Signature::from_str_unchecked(&signature[1..signature.len() - 1]); let mut sig_parser = SignatureParser::new(inner_signature); let mut alignment = 0; while !sig_parser.done() { let child_signature = sig_parser.parse_next_signature()?; let child_alignment = alignment_for_signature(&child_signature, format)?; if child_alignment > alignment { alignment = child_alignment; if alignment == 8 { // 8 bytes is max alignment so we can short-circuit here break; } } } Ok(alignment) } } } fn alignment_for_dict_entry_signature( #[allow(unused)] signature: &Signature<'_>, format: Format, ) -> Result { match format { Format::DBus => Ok(DICT_ENTRY_ALIGNMENT_DBUS), #[cfg(feature = "gvariant")] Format::GVariant => { if signature.len() < 4 { return Err(serde::de::Error::invalid_length( signature.len(), &">= 4 characters in dict entry signature", )); } let key_signature = Signature::from_str_unchecked(&signature[1..2]); let key_alignment = alignment_for_signature(&key_signature, format)?; if key_alignment == 8 { // 8 bytes is max alignment so we can short-circuit here return Ok(8); } let value_signature = Signature::from_str_unchecked(&signature[2..signature.len() - 1]); let value_alignment = alignment_for_signature(&value_signature, format)?; if value_alignment > key_alignment { Ok(value_alignment) } else { Ok(key_alignment) } } } } #[cfg(feature = "gvariant")] fn is_fixed_sized_struct_signature<'a>(signature: &'a Signature<'a>) -> Result { let inner_signature = Signature::from_str_unchecked(&signature[1..signature.len() - 1]); let mut sig_parser = SignatureParser::new(inner_signature); let mut fixed_sized = true; while !sig_parser.done() { let child_signature = sig_parser.parse_next_signature()?; if !is_fixed_sized_signature(&child_signature)? { // STRUCT is fixed-sized only if all its children are fixed_sized = false; break; } } Ok(fixed_sized) } #[cfg(feature = "gvariant")] fn is_fixed_sized_dict_entry_signature<'a>(signature: &'a Signature<'a>) -> Result { let key_signature = Signature::from_str_unchecked(&signature[1..2]); if !is_fixed_sized_signature(&key_signature)? { return Ok(false); } let value_signature = Signature::from_str_unchecked(&signature[2..signature.len() - 1]); is_fixed_sized_signature(&value_signature) } /// 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-4.1.2/src/value.rs000064400000000000000000001136101046102023000137410ustar 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, signature_parser::SignatureParser, 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<'a>), 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(_)`, // because `f64` is the only type in this enum, that does not implement `Ord`. // This `match`-arm is therefore unreachable. _ => unreachable!(), }) } } 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.dynamic_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::from_static_str_unchecked("v"), // Container types Value::Array(value) => value.full_signature().as_ref(), Value::Dict(value) => value.full_signature().as_ref(), Value::Structure(value) => value.full_signature().as_ref(), #[cfg(feature = "gvariant")] Value::Maybe(value) => value.full_signature().as_ref(), #[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: ?Sized + 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: ?Sized + 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.as_str()) } 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<'a> Serialize for Value<'a> { 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("zvariant::Value", 2)?; let signature = self.value_signature(); structure.serialize_field("zvariant::Value::Signature", &signature)?; self.serialize_value_as_struct_field("zvariant::Value::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, 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, phantom: PhantomData, }; visitor.next_value_seed(seed) } } pub(crate) struct SignatureSeed<'de> { pub signature: Signature<'de>, } impl<'de> SignatureSeed<'de> { pub(crate) fn visit_array(self, mut visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { let element_signature = self.signature.slice(1..); let mut array = Array::new_full_signature(self.signature.clone()); while let Some(elem) = visitor.next_element_seed(ValueSeed::> { signature: element_signature.clone(), phantom: PhantomData, })? { elem.value_signature(); array.append(elem).map_err(Error::custom)?; } Ok(array) } pub(crate) fn visit_struct(self, mut visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { let mut i = 1; let signature_end = self.signature.len() - 1; let mut builder = StructureBuilder::new(); while i < signature_end { let fields_signature = self.signature.slice(i..signature_end); let parser = SignatureParser::new(fields_signature.as_ref()); let len = parser.next_signature().map_err(Error::custom)?.len(); let field_signature = fields_signature.slice(0..len); i += field_signature.len(); 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<'de, T> From> for SignatureSeed<'de> { fn from(seed: ValueSeed<'de, T>) -> Self { SignatureSeed { signature: seed.signature, } } } struct ValueSeed<'de, T> { signature: Signature<'de>, phantom: PhantomData, } impl<'de, T> ValueSeed<'de, 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(self, visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { ValueVisitor .visit_seq(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()) } }; } macro_rules! value_seed_str_method { ($name:ident, $type:ty, $constructor:ident) => { fn $name(self, value: $type) -> Result, E> where E: serde::de::Error, { match self.signature.as_str() { <&str>::SIGNATURE_STR => Ok(Value::Str(Str::from(value))), Signature::SIGNATURE_STR => Ok(Value::Signature(Signature::$constructor(value))), ObjectPath::SIGNATURE_STR => Ok(Value::ObjectPath(ObjectPath::$constructor(value))), _ => { let expected = format!( "`{}`, `{}` or `{}`", <&str>::SIGNATURE_STR, Signature::SIGNATURE_STR, ObjectPath::SIGNATURE_STR, ); Err(Error::invalid_type( Unexpected::Str(self.signature.as_str()), &expected.as_str(), )) } } } }; } impl<'de, T> Visitor<'de> for ValueSeed<'de, 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.as_bytes().first().ok_or_else(|| { Error::invalid_value( Unexpected::Other("nothing"), &"i32 or fd signature character", ) })? { #[cfg(unix)] b'h' => { // 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)) } value_seed_str_method!(visit_borrowed_str, &'de str, from_str_unchecked); fn visit_seq(self, visitor: V) -> Result, V::Error> where V: SeqAccess<'de>, { match self.signature.as_bytes().first().ok_or_else(|| { Error::invalid_value( Unexpected::Other("nothing"), &"Array or Struct signature character", ) })? { // For some reason rustc doesn't like us using ARRAY_SIGNATURE_CHAR const b'a' => self.visit_array(visitor), b'(' => self.visit_struct(visitor), b'v' => self.visit_variant(visitor), b => Err(Error::invalid_value( Unexpected::Char(*b as char), &"a Value signature", )), } } fn visit_map(self, mut visitor: V) -> Result, V::Error> where V: MapAccess<'de>, { if self.signature.len() < 5 { return Err(serde::de::Error::invalid_length( self.signature.len(), &">= 5 characters in dict entry signature", )); } let key_signature = self.signature.slice(2..3); let signature_end = self.signature.len() - 1; let value_signature = self.signature.slice(3..signature_end); let mut dict = Dict::new_full_signature(self.signature.clone()); while let Some((key, value)) = visitor.next_entry_seed( ValueSeed::> { signature: key_signature.clone(), phantom: PhantomData, }, ValueSeed::> { signature: value_signature.clone(), 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 visitor = ValueSeed:: { signature: self.signature.slice(1..), 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<'de, T> where T: Deserialize<'de>, { type Value = Value<'de>; fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_any(self) } } impl<'a> Type for Value<'a> { fn signature() -> Signature<'static> { Signature::from_static_str_unchecked(VARIANT_SIGNATURE_STR) } } impl<'a> TryFrom<&Value<'a>> for Value<'a> { type Error = crate::Error; fn try_from(value: &Value<'a>) -> crate::Result> { value.try_clone() } } #[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::from_static_str("").unwrap(), Signature::from_static_str("(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(Structure::default()).to_string(), "()"); 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, ); } } }