zvariant-2.10.0/.cargo_vcs_info.json0000644000000001120000000000100127440ustar { "git": { "sha1": "98e4fa1d424e40ca925d6117edc191b30b170048" } } zvariant-2.10.0/Cargo.toml0000644000000031570000000000100107560ustar # 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 = "2018" name = "zvariant" version = "2.10.0" authors = ["Zeeshan Ali "] description = "D-Bus & GVariant encoding & decoding" readme = "../README.md" keywords = ["D-Bus", "DBus", "IPC", "GVariant"] categories = ["data-structures", "encoding", "parsing"] license = "MIT" repository = "https://gitlab.freedesktop.org/dbus/zbus/" resolver = "2" [lib] bench = false [[bench]] name = "benchmarks" harness = false [dependencies.arrayvec] version = "0.5.1" features = ["serde"] optional = true [dependencies.byteorder] version = "1.3.1" [dependencies.enumflags2] version = "0.6.4" features = ["serde"] optional = true [dependencies.libc] version = "0.2.92" [dependencies.serde] version = "1.0" features = ["derive"] [dependencies.serde_bytes] version = "0.11" optional = true [dependencies.static_assertions] version = "1.1.0" [dependencies.zvariant_derive] version = "=2.10.0" [dev-dependencies.criterion] version = "0.3" [dev-dependencies.rand] version = "0.8.3" [dev-dependencies.serde_json] version = "1.0" [dev-dependencies.serde_repr] version = "0.1.5" [features] default = ["gvariant"] gvariant = [] ostree-tests = ["gvariant"] zvariant-2.10.0/Cargo.toml.orig000064400000000000000000000021310072674642500144560ustar 00000000000000[package] name = "zvariant" version = "2.10.0" authors = ["Zeeshan Ali "] edition = "2018" description = "D-Bus & GVariant encoding & decoding" repository = "https://gitlab.freedesktop.org/dbus/zbus/" keywords = ["D-Bus", "DBus", "IPC", "GVariant"] license = "MIT" categories = ["data-structures", "encoding", "parsing"] readme = "../README.md" [features] default = ["gvariant"] # Also allow disabling D-Bus support gvariant = [] ostree-tests = ["gvariant"] [dependencies] byteorder = "1.3.1" serde = { version = "1.0", features = ["derive"] } arrayvec = { version = "0.5.1", features = ["serde"], optional = true } enumflags2 = { version = "0.6.4", features = ["serde"], optional = true } zvariant_derive = { version = "=2.10.0", path = "../zvariant_derive" } serde_bytes = { version = "0.11", optional = true } static_assertions = "1.1.0" libc = "0.2.92" [dev-dependencies] serde_json = "1.0" serde_repr = "0.1.5" glib = { git = "https://github.com/gtk-rs/glib", rev = "c9ee583cea0" } rand = "0.8.3" criterion = "0.3" [lib] bench = false [[bench]] name = "benchmarks" harness = false zvariant-2.10.0/LICENSE000064400000000000000000000017770072674642500126130ustar 00000000000000Permission 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-2.10.0/benches/benchmarks.rs000064400000000000000000000074250072674642500156740ustar 00000000000000use byteorder::LE; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use zvariant::{ from_slice_for_signature, to_bytes_for_signature, EncodingContext as Context, Type, Value, }; use zvariant_derive::Type; fn fixed_size_array(c: &mut Criterion) { let ay = vec![77u8; 100_000]; let ctxt = Context::::new_dbus(0); let signature = Vec::::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 _: Vec = from_slice_for_signature(black_box(&enc), black_box(ctxt), 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 mut int_array = Vec::new(); int_array.resize(1024 * 10, 0u64); 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(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 = from_slice_for_signature( black_box(&encoded), black_box(ctxt), black_box(&signature), ) .unwrap(); black_box(s); }) }); // Now GVariant. let ctxt = Context::::new_gvariant(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 = from_slice_for_signature( black_box(&encoded), black_box(ctxt), black_box(&signature), ) .unwrap(); black_box(s); }) }); } criterion_group!(benches, big_array_ser_and_de, fixed_size_array); criterion_main!(benches); zvariant-2.10.0/src/array.rs000064400000000000000000000166310072674642500140540ustar 00000000000000use serde::{ de::{DeserializeSeed, Deserializer, SeqAccess, Visitor}, ser::{Serialize, SerializeSeq, Serializer}, }; use static_assertions::assert_impl_all; use std::convert::{TryFrom, TryInto}; use crate::{ value::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, Clone, PartialEq)] 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 get(&self) -> &[Value<'a>] { &self.elements } /// 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 to_owned(&self) -> Array<'static> { Array { element_signature: self.element_signature.to_owned(), elements: self.elements.iter().map(|v| v.to_owned()).collect(), signature: self.signature.to_owned(), } } } /// 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.get() } } 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)] 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-2.10.0/src/basic.rs000064400000000000000000000112520072674642500140110ustar 00000000000000// FIXME: Drop this when the deprecated `Basic::ALIGNMENT` is dropped in the next API break. #![allow(deprecated)] use crate::{EncodingFormat, 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; #[deprecated(since = "2.0.2", note = "Please use the `alignment` function instead")] /// The required padding alignment. const ALIGNMENT: usize; /// The required padding alignment for the given format. fn alignment(format: EncodingFormat) -> usize; } impl Basic for &B where B: Basic, { const SIGNATURE_CHAR: char = B::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = B::SIGNATURE_STR; const ALIGNMENT: usize = B::ALIGNMENT; fn alignment(format: EncodingFormat) -> 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: EncodingFormat) -> usize { match format { EncodingFormat::DBus => $dbus_alignment, #[cfg(feature = "gvariant")] EncodingFormat::GVariant => $gvariant_alignment, } } }; } impl Basic for u8 { const SIGNATURE_CHAR: char = 'y'; const SIGNATURE_STR: &'static str = "y"; const ALIGNMENT: usize = 1; alignment_method!(Self::ALIGNMENT); } impl_type!(u8); // 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; const ALIGNMENT: usize = i16::ALIGNMENT; alignment_method!(Self::ALIGNMENT); } impl_type!(i8); impl Basic for bool { const SIGNATURE_CHAR: char = 'b'; const SIGNATURE_STR: &'static str = "b"; const ALIGNMENT: usize = 4; alignment_method!(Self::ALIGNMENT); } impl_type!(bool); impl Basic for i16 { const SIGNATURE_CHAR: char = 'n'; const SIGNATURE_STR: &'static str = "n"; const ALIGNMENT: usize = 2; alignment_method!(Self::ALIGNMENT); } impl_type!(i16); impl Basic for u16 { const SIGNATURE_CHAR: char = 'q'; const SIGNATURE_STR: &'static str = "q"; const ALIGNMENT: usize = 2; alignment_method!(Self::ALIGNMENT); } impl_type!(u16); impl Basic for i32 { const SIGNATURE_CHAR: char = 'i'; const SIGNATURE_STR: &'static str = "i"; const ALIGNMENT: usize = 4; alignment_method!(Self::ALIGNMENT); } impl_type!(i32); impl Basic for u32 { const SIGNATURE_CHAR: char = 'u'; const SIGNATURE_STR: &'static str = "u"; const ALIGNMENT: usize = 4; alignment_method!(Self::ALIGNMENT); } impl_type!(u32); impl Basic for i64 { const SIGNATURE_CHAR: char = 'x'; const SIGNATURE_STR: &'static str = "x"; const ALIGNMENT: usize = 8; alignment_method!(Self::ALIGNMENT); } impl_type!(i64); impl Basic for u64 { const SIGNATURE_CHAR: char = 't'; const SIGNATURE_STR: &'static str = "t"; const ALIGNMENT: usize = 8; alignment_method!(Self::ALIGNMENT); } impl_type!(u64); // 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; const ALIGNMENT: usize = f64::ALIGNMENT; alignment_method!(Self::ALIGNMENT); } impl_type!(f32); impl Basic for f64 { const SIGNATURE_CHAR: char = 'd'; const SIGNATURE_STR: &'static str = "d"; const ALIGNMENT: usize = 8; alignment_method!(Self::ALIGNMENT); } impl_type!(f64); impl Basic for str { const SIGNATURE_CHAR: char = 's'; const SIGNATURE_STR: &'static str = "s"; const ALIGNMENT: usize = 4; alignment_method!(Self::ALIGNMENT, 1); } impl_type!(str); impl Basic for String { const SIGNATURE_CHAR: char = 's'; const SIGNATURE_STR: &'static str = "s"; const ALIGNMENT: usize = 4; alignment_method!(Self::ALIGNMENT, 1); } impl_type!(String); impl Basic for char { const SIGNATURE_CHAR: char = <&str>::SIGNATURE_CHAR; const SIGNATURE_STR: &'static str = <&str>::SIGNATURE_STR; const ALIGNMENT: usize = <&str>::ALIGNMENT; alignment_method!(Self::ALIGNMENT, 1); } impl_type!(char); zvariant-2.10.0/src/dbus/de.rs000064400000000000000000000434760072674642500142720ustar 00000000000000use core::convert::TryFrom; use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Visitor}; use static_assertions::assert_impl_all; use std::{marker::PhantomData, os::unix::io::RawFd, str}; use crate::{ de::ValueParseStage, signature_parser::SignatureParser, utils::*, Basic, EncodingContext, EncodingFormat, Error, Fd, ObjectPath, Result, Signature, }; /// Our D-Bus deserialization implementation. #[derive(Debug)] pub struct Deserializer<'de, 'sig, 'f, B>(pub(crate) crate::DeserializerCommon<'de, 'sig, 'f, B>); assert_impl_all!(Deserializer<'_, '_, '_, i32>: Send, Sync, Unpin); impl<'de, 'sig, 'f, B> Deserializer<'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { /// Create a Deserializer struct instance. pub fn new<'r: 'de>( bytes: &'r [u8], fds: Option<&'f [RawFd]>, signature: &Signature<'sig>, ctxt: EncodingContext, ) -> Self { assert_eq!(ctxt.format(), EncodingFormat::DBus); let sig_parser = SignatureParser::new(signature.clone()); Self(crate::DeserializerCommon { ctxt, sig_parser, bytes, fds, pos: 0, b: PhantomData, }) } } 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 = B::$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, B> de::Deserializer<'de> for &'d mut Deserializer<'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { 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 = B::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() { Fd::SIGNATURE_CHAR => { self.0.sig_parser.skip_char()?; let alignment = u32::alignment(EncodingFormat::DBus); self.0.parse_padding(alignment)?; let idx = B::read_u32(self.0.next_slice(alignment)?); self.0.get_fd(idx)? } _ => B::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 = B::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(EncodingFormat::DBus); self.0.parse_padding(alignment)?; let len_slice = self.0.next_slice(alignment)?; B::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, _visitor: V) -> Result where V: Visitor<'de>, { unreachable!("DBus format can't support `Option`"); } 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, EncodingFormat::DBus); self.0.parse_padding(alignment)?; self.0.sig_parser.skip_char()?; visitor.visit_seq(StructureDeserializer { de: self }) } c => Err(de::Error::invalid_type( de::Unexpected::Char(c), &format!( "`{}`, `{}` or `{}`", VARIANT_SIGNATURE_CHAR, ARRAY_SIGNATURE_CHAR, STRUCT_SIG_START_CHAR, ) .as_str(), )), } } fn deserialize_enum( self, name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { visitor.visit_enum(crate::de::Enum { de: self, name, phantom: PhantomData, }) } fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de>, { // Not using serialize_u32 cause identifier isn't part of the signature let alignment = u32::alignment(EncodingFormat::DBus); self.0.parse_padding(alignment)?; let variant_index = crate::from_slice_fds::(&self.0.bytes[self.0.pos..], self.0.fds, self.0.ctxt)?; self.0.pos += alignment; visitor.visit_u32(variant_index) } } struct ArrayDeserializer<'d, 'de, 'sig, 'f, B> { de: &'d mut Deserializer<'de, 'sig, 'f, B>, len: usize, start: usize, // alignment of element element_alignment: usize, // where value signature starts element_signature_len: usize, } impl<'d, 'de, 'sig, 'f, B> ArrayDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { fn new(de: &'d mut Deserializer<'de, 'sig, 'f, B>) -> Result { de.0.parse_padding(ARRAY_ALIGNMENT_DBUS)?; let len = B::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, EncodingFormat::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 = EncodingContext::new_dbus(self.de.0.ctxt.position() + self.de.0.pos); let mut de = Deserializer::(crate::DeserializerCommon { ctxt, sig_parser, bytes: &self.de.0.bytes[self.de.0.pos..], fds: self.de.0.fds, pos: 0, b: PhantomData, }); let v = seed.deserialize(&mut de); self.de.0.pos += de.0.pos; 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)?; 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, 'sig, 'f, B>(de: &mut Deserializer<'de, 'sig, 'f, B>) -> Result<&'de [u8]> where B: byteorder::ByteOrder, { 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, B>(ArrayDeserializer<'d, 'de, 'sig, 'f, B>); impl<'d, 'de, 'sig, 'f, B> SeqAccess<'de> for ArraySeqDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { 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, B>(ArrayDeserializer<'d, 'de, 'sig, 'f, B>); impl<'d, 'de, 'sig, 'f, B> MapAccess<'de> for ArrayMapDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { 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, B> { de: &'d mut Deserializer<'de, 'sig, 'f, B>, } impl<'d, 'de, 'sig, 'f, B> SeqAccess<'de> for StructureDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { 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, B> { de: &'d mut Deserializer<'de, 'sig, 'f, B>, stage: ValueParseStage, sig_start: usize, } impl<'d, 'de, 'sig, 'f, B> ValueDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { fn new(de: &'d mut Deserializer<'de, 'sig, 'f, B>) -> Self { let sig_start = de.0.pos; ValueDeserializer:: { de, stage: ValueParseStage::Signature, sig_start, } } } impl<'d, 'de, 'sig, 'f, B> SeqAccess<'de> for ValueDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { 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 = &self.de.0.bytes[sig_start..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 = EncodingContext::new( EncodingFormat::DBus, self.de.0.ctxt.position() + value_start, ); let mut de = Deserializer::(crate::DeserializerCommon { ctxt, sig_parser, bytes: &self.de.0.bytes[value_start..], fds: self.de.0.fds, pos: 0, b: PhantomData, }); 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, B> crate::de::GetDeserializeCommon<'de, 'sig, 'f, B> for &'d mut Deserializer<'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { fn common_mut<'dr>(self) -> &'dr mut crate::de::DeserializerCommon<'de, 'sig, 'f, B> where Self: 'dr, { &mut self.0 } } impl<'de, 'd, 'sig, 'f, B> EnumAccess<'de> for crate::de::Enum> where B: byteorder::ByteOrder, { 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-2.10.0/src/dbus/mod.rs000064400000000000000000000000600072674642500144370ustar 00000000000000mod de; pub use de::*; mod ser; pub use ser::*; zvariant-2.10.0/src/dbus/ser.rs000064400000000000000000000405520072674642500144630ustar 00000000000000use byteorder::WriteBytesExt; use serde::{ser, ser::SerializeSeq, Serialize}; use static_assertions::assert_impl_all; use std::{ io::{Seek, Write}, marker::PhantomData, os::unix::io::RawFd, str, }; use crate::{ signature_parser::SignatureParser, utils::*, Basic, EncodingContext, EncodingFormat, Error, Fd, ObjectPath, Result, Signature, }; /// Our D-Bus serialization implementation. pub struct Serializer<'ser, 'sig, B, W>(pub(crate) crate::SerializerCommon<'ser, 'sig, B, W>); assert_impl_all!(Serializer<'_, '_, i32, i32>: Send, Sync, Unpin); impl<'ser, 'sig, B, W> Serializer<'ser, 'sig, B, W> where B: byteorder::ByteOrder, W: Write + Seek, { /// Create a D-Bus Serializer struct instance. pub fn new<'w: 'ser, 'f: 'ser>( signature: &Signature<'sig>, writer: &'w mut W, fds: &'f mut Vec, ctxt: EncodingContext, ) -> Self { assert_eq!(ctxt.format(), EncodingFormat::DBus); let sig_parser = SignatureParser::new(signature.clone()); Self(crate::SerializerCommon { ctxt, sig_parser, writer, fds, bytes_written: 0, value_sign: None, b: PhantomData, }) } } 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::(v as $as).map_err(Error::Io) } }; } impl<'ser, 'sig, 'b, B, W> ser::Serializer for &'b mut Serializer<'ser, 'sig, B, W> where B: byteorder::ByteOrder, W: Write + Seek, { type Ok = (); type Error = Error; type SerializeSeq = SeqSerializer<'ser, 'sig, 'b, B, W>; type SerializeTuple = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeTupleStruct = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeTupleVariant = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeMap = SeqSerializer<'ser, 'sig, 'b, B, W>; type SerializeStruct = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeStructVariant = StructSerializer<'ser, 'sig, 'b, 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() { Fd::SIGNATURE_CHAR => { self.0.sig_parser.skip_char()?; self.0.add_padding(u32::alignment(EncodingFormat::DBus))?; let v = self.0.add_fd(v); self.0.write_u32::(v).map_err(Error::Io) } _ => { self.0.prep_serialize_basic::()?; self.0.write_i32::(v).map_err(Error::Io) } } } fn serialize_u8(self, v: u8) -> Result<()> { self.0.prep_serialize_basic::()?; // Endianness is irrelevant for single bytes. self.0.write_u8(v).map_err(Error::Io) } 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(EncodingFormat::DBus))?; self.0 .write_u32::(usize_to_u32(v.len())) .map_err(Error::Io)?; } Signature::SIGNATURE_CHAR | VARIANT_SIGNATURE_CHAR => { self.0.write_u8(usize_to_u8(v.len())).map_err(Error::Io)?; } _ => { 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(Error::Io)?; self.0.write_all(&b"\0"[..]).map_err(Error::Io)?; Ok(()) } fn serialize_bytes(self, v: &[u8]) -> Result<()> { let seq = self.serialize_seq(Some(v.len()))?; seq.ser.0.write(v).map_err(Error::Io)?; seq.end() } fn serialize_none(self) -> Result<()> { unreachable!("Option can not be encoded in D-Bus format"); } fn serialize_some(self, _value: &T) -> Result<()> where T: ?Sized + Serialize, { unreachable!("Option can not be encoded in D-Bus format"); } 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<()> { 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()?; 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::(0_u32).map_err(Error::Io)?; 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; 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)?; self.serialize_struct(name, len) } fn serialize_map(self, len: Option) -> Result { self.serialize_seq(len) } fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { let c = self.0.sig_parser.next_char(); let end_parens; if c == VARIANT_SIGNATURE_CHAR { self.0.add_padding(VARIANT_ALIGNMENT_DBUS)?; end_parens = false; } else { let signature = self.0.sig_parser.next_signature()?; let alignment = alignment_for_signature(&signature, EncodingFormat::DBus); self.0.add_padding(alignment)?; self.0.sig_parser.skip_char()?; if c == STRUCT_SIG_START_CHAR || c == DICT_ENTRY_SIG_START_CHAR { end_parens = true; } else { let expected = format!( "`{}` or `{}`", STRUCT_SIG_START_STR, DICT_ENTRY_SIG_START_STR, ); return Err(serde::de::Error::invalid_type( serde::de::Unexpected::Char(c), &expected.as_str(), )); } } Ok(StructSerializer { ser: self, end_parens, }) } 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)?; self.serialize_struct(name, len) } } #[doc(hidden)] pub struct SeqSerializer<'ser, 'sig, 'b, B, W> { ser: &'b mut Serializer<'ser, 'sig, B, 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, B, W> SeqSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, 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(Error::Io)?; self.ser.0.writer.write_u32::(len).map_err(Error::Io)?; self.ser .0 .writer .seek(std::io::SeekFrom::Current(total_array_len - 4)) .map_err(Error::Io)?; Ok(()) } } impl<'ser, 'sig, 'b, B, W> ser::SerializeSeq for SeqSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, 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, B, W> { ser: &'b mut Serializer<'ser, 'sig, B, W>, end_parens: bool, } impl<'ser, 'sig, 'b, B, W> StructSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, W: Write + Seek, { 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 fds = vec![]; let mut ser = Serializer(crate::SerializerCommon:: { ctxt: self.ser.0.ctxt, sig_parser, writer: self.ser.0.writer, fds: &mut fds, bytes_written, value_sign: None, b: PhantomData, }); value.serialize(&mut ser)?; self.ser.0.bytes_written = ser.0.bytes_written; self.ser.0.fds.extend(fds.iter()); Ok(()) } _ => value.serialize(&mut *self.ser), } } fn end_struct(self) -> Result<()> { if self.end_parens { self.ser.0.sig_parser.skip_char()?; } Ok(()) } } macro_rules! serialize_struct_anon_fields { ($trait:ident $method:ident) => { impl<'ser, 'sig, 'b, B, W> ser::$trait for StructSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, 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() } } }; } 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, B, W> ser::SerializeMap for SeqSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, 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, B, W> ser::$trait for StructSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, 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() } } }; } serialize_struct_named_fields!(SerializeStruct); serialize_struct_named_fields!(SerializeStructVariant); zvariant-2.10.0/src/de.rs000064400000000000000000000425120072674642500133230ustar 00000000000000use serde::{ de::{self, DeserializeSeed, VariantAccess, Visitor}, Deserialize, }; use static_assertions::assert_impl_all; use std::{marker::PhantomData, os::unix::io::RawFd, str}; #[cfg(feature = "gvariant")] use crate::gvariant::Deserializer as GVDeserializer; use crate::{ dbus::Deserializer as DBusDeserializer, signature_parser::SignatureParser, utils::*, Basic, DynamicDeserialize, DynamicType, EncodingContext, EncodingFormat, Error, Fd, ObjectPath, Result, Signature, Type, }; /// Deserialize `T` from a given slice of bytes, containing file descriptor indices. /// /// Please note that actual file descriptors are not part of the encoding and need to be transferred /// via an out-of-band platform specific mechanism. The encoding only contain the indices of the /// file descriptors and hence the reason, caller must pass a slice of file descriptors. /// /// # Examples /// /// ``` /// use zvariant::{to_bytes_fds, from_slice_fds}; /// use zvariant::{EncodingContext, Fd}; /// /// let ctxt = EncodingContext::::new_dbus(0); /// let (encoded, fds) = to_bytes_fds(ctxt, &Fd::from(42)).unwrap(); /// let decoded: Fd = from_slice_fds(&encoded, Some(&fds), ctxt).unwrap(); /// assert_eq!(decoded, Fd::from(42)); /// ``` /// /// [`from_slice`]: fn.from_slice.html pub fn from_slice_fds<'d, 'r: 'd, B, T: ?Sized>( bytes: &'r [u8], fds: Option<&[RawFd]>, ctxt: EncodingContext, ) -> Result where B: byteorder::ByteOrder, T: Deserialize<'d> + Type, { let signature = T::signature(); from_slice_fds_for_signature(bytes, fds, ctxt, &signature) } /// Deserialize `T` from a given slice of bytes. /// /// If `T` is an, or (potentially) contains an [`Fd`], use [`from_slice_fds`] instead. /// /// # Examples /// /// ``` /// use zvariant::{to_bytes, from_slice}; /// use zvariant::EncodingContext; /// /// let ctxt = EncodingContext::::new_dbus(0); /// let encoded = to_bytes(ctxt, "hello world").unwrap(); /// let decoded: &str = from_slice(&encoded, ctxt).unwrap(); /// assert_eq!(decoded, "hello world"); /// ``` /// /// [`Fd`]: struct.Fd.html /// [`from_slice_fds`]: fn.from_slice_fds.html pub fn from_slice<'d, 'r: 'd, B, T: ?Sized>(bytes: &'r [u8], ctxt: EncodingContext) -> Result where B: byteorder::ByteOrder, T: Deserialize<'d> + Type, { let signature = T::signature(); from_slice_for_signature(bytes, ctxt, &signature) } /// Deserialize `T` from a given slice of bytes with the given signature. /// /// Use this function instead of [`from_slice`] if the value being deserialized does not implement /// [`Type`]. Also, if `T` is an, or (potentially) contains an [`Fd`], use /// [`from_slice_fds_for_signature`] instead. /// /// # Examples /// /// One known case where `Type` implementation isn't possible, is enum types (except simple ones /// with unit variants only). /// /// ``` /// use std::convert::TryInto; /// use serde::{Deserialize, Serialize}; /// /// use zvariant::{to_bytes_for_signature, from_slice_for_signature}; /// use zvariant::EncodingContext; /// /// #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] /// enum Test { /// Unit, /// NewType(u8), /// Tuple(u8, u64), /// Struct { y: u8, t: u64 }, /// } /// /// let ctxt = EncodingContext::::new_dbus(0); /// let signature = "u".try_into().unwrap(); /// let encoded = to_bytes_for_signature(ctxt, &signature, &Test::Unit).unwrap(); /// let decoded: Test = from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); /// assert_eq!(decoded, Test::Unit); /// /// let signature = "y".try_into().unwrap(); /// let encoded = to_bytes_for_signature(ctxt, &signature, &Test::NewType(42)).unwrap(); /// let decoded: Test = from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); /// assert_eq!(decoded, Test::NewType(42)); /// /// let signature = "(yt)".try_into().unwrap(); /// let encoded = to_bytes_for_signature(ctxt, &signature, &Test::Tuple(42, 42)).unwrap(); /// let decoded: Test = from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); /// assert_eq!(decoded, Test::Tuple(42, 42)); /// /// let s = Test::Struct { y: 42, t: 42 }; /// let encoded = to_bytes_for_signature(ctxt, &signature, &s).unwrap(); /// let decoded: Test = from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); /// assert_eq!(decoded, Test::Struct { y: 42, t: 42 }); /// ``` /// /// [`Type`]: trait.Type.html /// [`Fd`]: struct.Fd.html /// [`from_slice_fds_for_signature`]: fn.from_slice_fds_for_signature.html // TODO: Return number of bytes parsed? pub fn from_slice_for_signature<'d, 'r: 'd, B, T: ?Sized>( bytes: &'r [u8], ctxt: EncodingContext, signature: &Signature<'_>, ) -> Result where B: byteorder::ByteOrder, T: Deserialize<'d>, { from_slice_fds_for_signature(bytes, None, ctxt, signature) } /// Deserialize `T` from a given slice of bytes containing file descriptor indices, with the given signature. /// /// Please note that actual file descriptors are not part of the encoding and need to be transferred /// via an out-of-band platform specific mechanism. The encoding only contain the indices of the /// file descriptors and hence the reason, caller must pass a slice of file descriptors. /// /// [`from_slice`]: fn.from_slice.html /// [`from_slice_for_signature`]: fn.from_slice_for_signature.html // TODO: Return number of bytes parsed? pub fn from_slice_fds_for_signature<'d, 'r: 'd, B, T: ?Sized>( bytes: &'r [u8], fds: Option<&[RawFd]>, ctxt: EncodingContext, signature: &Signature<'_>, ) -> Result where B: byteorder::ByteOrder, T: Deserialize<'d>, { let mut de = match ctxt.format() { #[cfg(feature = "gvariant")] EncodingFormat::GVariant => { Deserializer::GVariant(GVDeserializer::new(bytes, fds, signature, ctxt)) } EncodingFormat::DBus => { Deserializer::DBus(DBusDeserializer::new(bytes, fds, signature, ctxt)) } }; T::deserialize(&mut de) } /// Deserialize `T` from a given slice of bytes containing file descriptor indices, with the given /// signature. /// /// Please note that actual file descriptors are not part of the encoding and need to be transferred /// via an out-of-band platform specific mechanism. The encoding only contain the indices of the /// file descriptors and hence the reason, caller must pass a slice of file descriptors. pub fn from_slice_for_dynamic_signature<'d, B, T>( bytes: &'d [u8], ctxt: EncodingContext, signature: &Signature<'d>, ) -> Result where B: byteorder::ByteOrder, T: DynamicDeserialize<'d>, { from_slice_fds_for_dynamic_signature(bytes, None, ctxt, signature) } /// Deserialize `T` from a given slice of bytes containing file descriptor indices, with the given /// signature. /// /// Please note that actual file descriptors are not part of the encoding and need to be transferred /// via an out-of-band platform specific mechanism. The encoding only contain the indices of the /// file descriptors and hence the reason, caller must pass a slice of file descriptors. pub fn from_slice_fds_for_dynamic_signature<'d, B, T>( bytes: &'d [u8], fds: Option<&[RawFd]>, ctxt: EncodingContext, signature: &Signature<'d>, ) -> Result where B: byteorder::ByteOrder, T: DynamicDeserialize<'d>, { let seed = T::deserializer_for_signature(signature)?; from_slice_fds_with_seed(bytes, fds, ctxt, seed) } /// Deserialize `T` from a given slice of bytes containing file descriptor indices, using the given /// seed. /// /// Please note that actual file descriptors are not part of the encoding and need to be transferred /// via an out-of-band platform specific mechanism. The encoding only contain the indices of the /// file descriptors and hence the reason, caller must pass a slice of file descriptors. pub fn from_slice_with_seed<'d, B, S>( bytes: &'d [u8], ctxt: EncodingContext, seed: S, ) -> Result where B: byteorder::ByteOrder, S: DeserializeSeed<'d> + DynamicType, { from_slice_fds_with_seed(bytes, None, ctxt, seed) } /// Deserialize `T` from a given slice of bytes containing file descriptor indices, using the given /// seed. /// /// Please note that actual file descriptors are not part of the encoding and need to be transferred /// via an out-of-band platform specific mechanism. The encoding only contain the indices of the /// file descriptors and hence the reason, caller must pass a slice of file descriptors. pub fn from_slice_fds_with_seed<'d, B, S>( bytes: &'d [u8], fds: Option<&[RawFd]>, ctxt: EncodingContext, seed: S, ) -> Result where B: byteorder::ByteOrder, S: DeserializeSeed<'d> + DynamicType, { let signature = S::dynamic_signature(&seed).to_owned(); let mut de = match ctxt.format() { #[cfg(feature = "gvariant")] EncodingFormat::GVariant => { Deserializer::GVariant(GVDeserializer::new(bytes, fds, &signature, ctxt)) } EncodingFormat::DBus => { Deserializer::DBus(DBusDeserializer::new(bytes, fds, &signature, ctxt)) } }; seed.deserialize(&mut de) } /// Our deserialization implementation. #[derive(Debug)] pub(crate) struct DeserializerCommon<'de, 'sig, 'f, B> { pub(crate) ctxt: EncodingContext, pub(crate) bytes: &'de [u8], pub(crate) fds: Option<&'f [RawFd]>, pub(crate) pos: usize, pub(crate) sig_parser: SignatureParser<'sig>, pub(crate) b: PhantomData, } /// 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 enum Deserializer<'ser, 'sig, 'f, B> { DBus(DBusDeserializer<'ser, 'sig, 'f, B>), #[cfg(feature = "gvariant")] GVariant(GVDeserializer<'ser, 'sig, 'f, B>), } assert_impl_all!(Deserializer<'_, '_, '_, u8>: Send, Sync, Unpin); impl<'de, 'sig, 'f, B> Deserializer<'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { /// Create a Deserializer struct instance. pub fn new<'r: 'de>( bytes: &'r [u8], fds: Option<&'f [RawFd]>, signature: &Signature<'sig>, ctxt: EncodingContext, ) -> Self { match ctxt.format() { #[cfg(feature = "gvariant")] EncodingFormat::GVariant => { Self::GVariant(GVDeserializer::new(bytes, fds, signature, ctxt)) } EncodingFormat::DBus => Self::DBus(DBusDeserializer::new(bytes, fds, signature, ctxt)), } } } impl<'de, 'sig, 'f, B> DeserializerCommon<'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { pub fn get_fd(&self, idx: u32) -> Result { self.fds .map(|fds| fds.get(idx as usize)) .flatten() .copied() .ok_or(Error::UnknownFd) } 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, B> de::Deserializer<'de> for &'d mut Deserializer<'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { 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()); } #[derive(Debug)] pub(crate) enum ValueParseStage { Signature, Value, Done, } pub(crate) fn deserialize_any<'de, 'sig, 'f, B, D, V>( de: D, next_char: char, visitor: V, ) -> Result where D: de::Deserializer<'de, Error = Error>, V: Visitor<'de>, B: byteorder::ByteOrder, { 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 | 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", )), } } pub(crate) trait GetDeserializeCommon<'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { fn common_mut<'d>(self) -> &'d mut DeserializerCommon<'de, 'sig, 'f, B> where Self: 'd; } // 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, 'sig, 'f, B, D> VariantAccess<'de> for Enum where B: byteorder::ByteOrder, D: de::Deserializer<'de, Error = Error> + GetDeserializeCommon<'de, 'sig, 'f, B>, { type Error = Error; fn unit_variant(self) -> std::result::Result<(), Self::Error> { self.de.common_mut().sig_parser.skip_char() } 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-2.10.0/src/deserialize_value.rs000064400000000000000000000050460072674642500164300ustar 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, EncodingContext, DeserializeValue, SerializeValue, from_slice}; /// # /// # let ctxt = EncodingContext::::new_dbus(0); /// # let array = [0, 1, 2]; /// # let v = SerializeValue(&array); /// # let encoded = to_bytes(ctxt, &v).unwrap(); /// let decoded: DeserializeValue<[u8; 3]> = from_slice(&encoded, ctxt).unwrap(); /// # 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-2.10.0/src/dict.rs000064400000000000000000000171420072674642500136570ustar 00000000000000use std::{collections::HashMap, convert::TryFrom, hash::BuildHasher}; use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer}; use static_assertions::assert_impl_all; use crate::{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, Clone, PartialEq)] pub struct Dict<'k, 'v> { entries: Vec>, 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 { entries: vec![], 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.entries.push(DictEntry { key, value }); Ok(()) } /// Add a new entry. pub fn add(&mut self, key: K, value: V) -> Result<(), Error> where K: Basic + Into> + std::hash::Hash + std::cmp::Eq, 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.entries.push(DictEntry { key: Value::new(key), value: Value::new(value), }); Ok(()) } /// Get the value for the given key. pub fn get<'d, K, V>(&'d self, key: &K) -> Result, Error> where 'd: 'k + 'v, K: ?Sized + std::cmp::Eq + 'k, V: ?Sized, &'k K: TryFrom<&'k Value<'k>>, &'v V: TryFrom<&'v Value<'v>>, { for entry in &self.entries { let entry_key = entry.key.downcast_ref::().ok_or(Error::IncorrectType)?; if *entry_key == *key { return entry .value .downcast_ref() .ok_or(Error::IncorrectType) .map(Some); } } Ok(None) } /// 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 to_owned(&self) -> Dict<'static, 'static> { Dict { key_signature: self.key_signature.to_owned(), value_signature: self.value_signature.to_owned(), signature: self.signature.to_owned(), entries: self.entries.iter().map(|v| v.to_owned()).collect(), } } /// 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 { entries: vec![], key_signature, value_signature, signature, } } // TODO: Provide more API like https://docs.rs/toml/0.5.5/toml/map/struct.Map.html } impl<'k, 'v> Serialize for Dict<'k, 'v> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut seq = serializer.serialize_seq(Some(self.entries.len()))?; for entry in &self.entries { seq.serialize_element(entry)?; } seq.end() } } // Conversion of Dict to HashMap impl<'k, 'v, K, V, H> TryFrom> for HashMap where K: Basic + TryFrom> + std::hash::Hash + std::cmp::Eq, V: TryFrom>, H: BuildHasher + Default, K::Error: Into, V::Error: Into, { type Error = Error; fn try_from(v: Dict<'k, 'v>) -> Result { let mut map = HashMap::default(); for e in v.entries.into_iter() { let key = if let Value::Value(v) = e.key { K::try_from(*v) } else { K::try_from(e.key) } .map_err(Into::into)?; let value = if let Value::Value(v) = e.value { V::try_from(*v) } else { V::try_from(e.value) } .map_err(Into::into)?; map.insert(key, value); } Ok(map) } } // 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 impl<'k, 'v, K, V> From> for Dict<'k, 'v> where K: Type + Into> + std::hash::Hash + std::cmp::Eq, V: Type + Into>, { fn from(value: HashMap) -> Self { let entries = value .into_iter() .map(|(key, value)| DictEntry { key: Value::new(key), value: Value::new(value), }) .collect(); let key_signature = K::signature(); let value_signature = V::signature(); let signature = create_signature(&key_signature, &value_signature); Self { entries, key_signature, value_signature, signature, } } } // TODO: Conversion of Dict from/to BTreeMap #[derive(Debug, Clone, PartialEq)] struct DictEntry<'k, 'v> { key: Value<'k>, value: Value<'v>, } impl<'k, 'v> DictEntry<'k, 'v> { fn to_owned(&self) -> DictEntry<'static, 'static> { DictEntry { key: self.key.to_owned(), value: self.value.to_owned(), } } } impl<'k, 'v> Serialize for DictEntry<'k, 'v> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut entry = serializer.serialize_struct("zvariant::DictEntry", 2)?; self.key .serialize_value_as_struct_field("zvariant::DictEntry::Key", &mut entry)?; self.value .serialize_value_as_struct_field("zvariant::DictEntry::Value", &mut entry)?; entry.end() } } fn create_signature( key_signature: &Signature<'_>, value_signature: &Signature<'_>, ) -> Signature<'static> { Signature::from_string_unchecked(format!("a{{{}{}}}", key_signature, value_signature,)) } zvariant-2.10.0/src/encoding_context.rs000064400000000000000000000064460072674642500162730ustar 00000000000000use std::marker::PhantomData; use static_assertions::assert_impl_all; /// The encoding format. /// #[derive(Debug, PartialEq, Copy, Clone)] pub enum EncodingFormat { /// [D-Bus](https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling) /// format. DBus, /// [GVariant](https://developer.gnome.org/glib/stable/glib-GVariant.html) format. #[cfg(feature = "gvariant")] GVariant, } assert_impl_all!(EncodingFormat: Send, Sync, Unpin); impl Default for EncodingFormat { fn default() -> Self { EncodingFormat::DBus } } impl std::fmt::Display for EncodingFormat { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { EncodingFormat::DBus => write!(f, "D-Bus"), #[cfg(feature = "gvariant")] EncodingFormat::GVariant => write!(f, "GVariant"), } } } /// The encoding context to use with the [serialization and deserialization] API. /// /// This type is generic over the [ByteOrder] trait. Moreover, 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 byteorder::LE; /// /// use zvariant::EncodingContext as Context; /// use zvariant::{from_slice, to_bytes}; /// /// let str_vec = vec!["Hello", "World"]; /// let ctxt = Context::::new_dbus(0); /// let encoded = to_bytes(ctxt, &str_vec).unwrap(); /// /// // Let's decode the 2nd element of the array only /// let ctxt = Context::::new_dbus(14); /// let decoded: &str = from_slice(&encoded[14..], ctxt).unwrap(); /// assert_eq!(decoded, "World"); /// ``` /// /// [serialization and deserialization]: index.html#functions /// [ByteOrder]: https://docs.rs/byteorder/1.3.4/byteorder/trait.ByteOrder.html /// [specify]: #method.new #[derive(Debug, PartialEq, Copy, Clone)] pub struct EncodingContext { format: EncodingFormat, position: usize, b: PhantomData, } assert_impl_all!(EncodingContext: Send, Sync, Unpin); impl EncodingContext where B: byteorder::ByteOrder, { /// Create a new encoding context. pub fn new(format: EncodingFormat, position: usize) -> Self { Self { format, position, b: PhantomData, } } /// Convenient wrapper for [`new`] to create a context for D-Bus format. /// /// [`new`]: #method.new pub fn new_dbus(position: usize) -> Self { Self::new(EncodingFormat::DBus, position) } /// Convenient wrapper for [`new`] to create a context for GVariant format. /// /// [`new`]: #method.new #[cfg(feature = "gvariant")] pub fn new_gvariant(position: usize) -> Self { Self::new(EncodingFormat::GVariant, position) } /// The [`EncodingFormat`] of this context. /// /// [`EncodingFormat`]: enum.EncodingFormat.html pub fn format(self) -> EncodingFormat { self.format } /// The byte position of the value to be encoded or decoded, in the entire message. pub fn position(self) -> usize { self.position } } zvariant-2.10.0/src/error.rs000064400000000000000000000076710072674642500140730ustar 00000000000000use serde::{de, ser}; use static_assertions::assert_impl_all; use std::{convert::Infallible, error, fmt, result}; /// 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) Io(std::io::Error), /// 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::EncodingFormat), /// 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), /// Only exists to allow `TryFrom for T` conversions. You should never actually be getting /// this error from any API. #[deprecated] Infallible, } 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, (_, _) => false, } } } impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { Error::Io(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::Io(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 `{}` is not compatible with `{}` format", sig, format, ), Error::SignatureMismatch(provided, expected) => write!( f, "Signature mismatch: got `{}`, expected {}", provided, expected, ), #[allow(deprecated)] Error::Infallible => write!(f, "Infallible conversion failed"), } } } 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()) } } /// Alias for a `Result` with the error type `zvariant::Error`. pub type Result = result::Result; zvariant-2.10.0/src/fd.rs000064400000000000000000000076520072674642500133320ustar 00000000000000// FIXME: Drop this when the deprecated `Basic::ALIGNMENT` is dropped in the next API break. #![allow(deprecated)] use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use static_assertions::assert_impl_all; use std::os::unix::io; use crate::{Basic, EncodingFormat, Signature, Type}; /// A [`RawFd`](https://doc.rust-lang.org/std/os/unix/io/type.RawFd.html) wrapper. /// /// See also `OwnedFd` if you need a wrapper that takes ownership of the file. /// /// We wrap the `RawFd` type so that we can implement [`Serialize`] and [`Deserialize`] for it. /// File descriptors are serialized in a special way and you need to use specific [serializer] and /// [deserializer] API when file descriptors are or could be involved. /// /// [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html /// [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html /// [deserializer]: fn.from_slice_fds.html /// [serializer]: fn.to_bytes_fds.html #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub struct Fd(io::RawFd); macro_rules! fd_impl { ($i:ident) => { assert_impl_all!($i: Send, Sync, Unpin); impl Basic for $i { const SIGNATURE_CHAR: char = 'h'; const SIGNATURE_STR: &'static str = "h"; const ALIGNMENT: usize = ::ALIGNMENT; fn alignment(format: EncodingFormat) -> 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.0) } } impl<'de> Deserialize<'de> for Fd { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { Ok(Fd(i32::deserialize(deserializer)?)) } } impl From for Fd { fn from(value: io::RawFd) -> Self { Self(value) } } impl From<&T> for Fd where T: io::AsRawFd, { fn from(t: &T) -> Self { Self(t.as_raw_fd()) } } impl io::AsRawFd for Fd { fn as_raw_fd(&self) -> io::RawFd { self.0 } } impl std::fmt::Display for Fd { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } } /// An owned [`RawFd`](https://doc.rust-lang.org/std/os/unix/io/type.RawFd.html) wrapper. /// /// See also [`Fd`]. This type owns the file and will close it on drop. On deserialize, it will /// duplicate the file descriptor. #[derive(Debug, PartialEq, Eq, Hash)] pub struct OwnedFd { inner: io::RawFd, } impl Drop for OwnedFd { fn drop(&mut self) { unsafe { libc::close(self.inner); } } } fd_impl!(OwnedFd); impl Serialize for OwnedFd { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_i32(self.inner) } } impl<'de> Deserialize<'de> for OwnedFd { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let fd = unsafe { libc::dup(i32::deserialize(deserializer)?) }; if fd < 0 { return Err(D::Error::custom(std::io::Error::last_os_error())); } Ok(OwnedFd { inner: fd }) } } impl io::FromRawFd for OwnedFd { unsafe fn from_raw_fd(fd: io::RawFd) -> Self { Self { inner: fd } } } impl io::AsRawFd for OwnedFd { fn as_raw_fd(&self) -> io::RawFd { self.inner } } impl io::IntoRawFd for OwnedFd { fn into_raw_fd(self) -> io::RawFd { let fd = self.inner; std::mem::forget(self); fd } } impl std::fmt::Display for OwnedFd { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.inner.fmt(f) } } zvariant-2.10.0/src/framing_offset_size.rs000064400000000000000000000077300072674642500167610ustar 00000000000000use crate::{Error, Result}; use byteorder::{ByteOrder, WriteBytesExt, 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)] #[repr(usize)] pub(crate) enum FramingOffsetSize { U8 = 1, U16 = 2, U32 = 4, U64 = 8, U128 = 16, } 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 128-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(offset as u8), FramingOffsetSize::U16 => writer.write_u16::(offset as u16), FramingOffsetSize::U32 => writer.write_u32::(offset as u32), FramingOffsetSize::U64 => writer.write_u64::(offset as u64), FramingOffsetSize::U128 => writer.write_u128::(offset as u128), } .map_err(Error::Io) } 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, FramingOffsetSize::U64 => LE::read_u64(&buffer[end - 8..end]) as usize, FramingOffsetSize::U128 => LE::read_u128(&buffer[end - 16..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, FramingOffsetSize::U64 => std::u64::MAX as usize, FramingOffsetSize::U128 => std::u128::MAX as usize, } } fn bump_up(self) -> Option { match self { FramingOffsetSize::U8 => Some(FramingOffsetSize::U16), FramingOffsetSize::U16 => Some(FramingOffsetSize::U32), FramingOffsetSize::U32 => Some(FramingOffsetSize::U64), FramingOffsetSize::U64 => Some(FramingOffsetSize::U128), FramingOffsetSize::U128 => 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 ); assert_eq!( FramingOffsetSize::for_bare_container(std::u32::MAX as usize - 11, 3), FramingOffsetSize::U64 ); } } zvariant-2.10.0/src/framing_offsets.rs000064400000000000000000000037450072674642500161140ustar 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]) -> (Self, usize) { let offset_size = FramingOffsetSize::for_encoded_container(container.len()); // The last offset tells us the start of offsets. let mut i = offset_size.read_last_offset_from_buffer(container); 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; let offset = offset_size.read_last_offset_from_buffer(&container[i..end]); offsets.push(offset); i += slice_len; } (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-2.10.0/src/from_value.rs000064400000000000000000000107410072674642500150710ustar 00000000000000#[cfg(feature = "gvariant")] use crate::Maybe; use crate::{ Array, Dict, Error, Fd, ObjectPath, OwnedObjectPath, OwnedSignature, Signature, Str, Structure, Value, }; use std::{collections::HashMap, convert::TryFrom, 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<'a>> for &'a $to { type Error = Error; fn try_from(value: &'a Value<'a>) -> 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<&'a Value<'a>> for $to { type Error = Error; fn try_from(value: &'a Value<'_>) -> 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!(Fd, Fd); value_try_from_all!(Str, Str<'a>); value_try_from_all!(Signature, Signature<'a>); value_try_from_all!(ObjectPath, ObjectPath<'a>); value_try_from_all!(Structure, Structure<'a>); value_try_from_all!(Dict, Dict<'a, 'a>); value_try_from_all!(Array, Array<'a>); #[cfg(feature = "gvariant")] value_try_from_all!(Maybe, Maybe<'a>); value_try_from!(Str, String); value_try_from_ref!(Str, str); value_try_from_ref_clone!(Str, String); 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::RawBitFlags, F::Type: TryFrom, Error = Error>, { type Error = Error; fn try_from(value: Value<'a>) -> Result { Self::from_bits(F::Type::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) } } } // 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-2.10.0/src/gvariant/de.rs000064400000000000000000000627300072674642500151420ustar 00000000000000use core::convert::TryFrom; use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Visitor}; use static_assertions::assert_impl_all; use std::{ffi::CStr, marker::PhantomData, os::unix::io::RawFd, str}; use crate::{ de::ValueParseStage, framing_offset_size::FramingOffsetSize, framing_offsets::FramingOffsets, signature_parser::SignatureParser, utils::*, EncodingContext, EncodingFormat, Error, Result, Signature, }; /// Our GVariant deserialization implementation. #[derive(Debug)] pub struct Deserializer<'de, 'sig, 'f, B>(pub(crate) crate::DeserializerCommon<'de, 'sig, 'f, B>); assert_impl_all!(Deserializer<'_, '_,'_, i32>: Send, Sync, Unpin); impl<'de, 'sig, 'f, B> Deserializer<'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { /// Create a Deserializer struct instance. pub fn new<'r: 'de>( bytes: &'r [u8], fds: Option<&'f [RawFd]>, signature: &Signature<'sig>, ctxt: EncodingContext, ) -> Self { assert_eq!(ctxt.format(), EncodingFormat::GVariant); let sig_parser = SignatureParser::new(signature.clone()); Self(crate::DeserializerCommon { ctxt, sig_parser, bytes, fds, pos: 0, b: PhantomData, }) } } macro_rules! deserialize_basic { ($method:ident) => { #[inline] fn $method(self, visitor: V) -> Result where V: Visitor<'de>, { let ctxt = EncodingContext::new_dbus(self.0.ctxt.position() + self.0.pos); let mut dbus_de = crate::dbus::Deserializer::(crate::DeserializerCommon:: { ctxt, sig_parser: self.0.sig_parser.clone(), bytes: &self.0.bytes[self.0.pos..], fds: self.0.fds, pos: 0, b: PhantomData, }); let v = dbus_de.$method(visitor)?; self.0.sig_parser = dbus_de.0.sig_parser; self.0.pos += dbus_de.0.pos; 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, B> de::Deserializer<'de> for &'d mut Deserializer<'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { 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 s = if self.0.sig_parser.next_char() == VARIANT_SIGNATURE_CHAR { let slice = &self.0.bytes[self.0.pos..]; 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(&self.0.bytes[self.0.pos..]).map_err(|_| -> Error { let c = self.0.bytes[self.0.bytes.len() - 1] as char; de::Error::invalid_value( de::Unexpected::Char(c), &"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) } 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 = EncodingContext::new(self.0.ctxt.format(), 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::(crate::DeserializerCommon { ctxt, sig_parser: self.0.sig_parser.clone(), bytes: &self.0.bytes[self.0.pos..end], fds: self.0.fds, pos: 0, b: PhantomData, }); let v = visitor.visit_some(&mut de)?; self.0.pos += de.0.pos; if !fixed_sized_child { let byte = 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 = self.0.bytes[self.0.pos]; if byte != 0 { return Err(de::Error::invalid_value( de::Unexpected::Bytes(&self.0.bytes[self.0.pos..self.0.pos + 1]), &"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); visitor.visit_seq(StructureDeserializer { de: self, start, end, offsets_len: 0, offset_size, }) } c => Err(de::Error::invalid_type( de::Unexpected::Char(c), &format!( "`{}`, `{}` or `{}`", VARIANT_SIGNATURE_CHAR, ARRAY_SIGNATURE_CHAR, STRUCT_SIG_START_CHAR, ) .as_str(), )), } } fn deserialize_enum( self, name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { visitor.visit_enum(crate::de::Enum { de: self, name, phantom: PhantomData, }) } } fn deserialize_ay<'de, 'sig, 'f, B>(de: &mut Deserializer<'de, 'sig, 'f, B>) -> Result<&'de [u8]> where B: byteorder::ByteOrder, { 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, B> { de: &'d mut Deserializer<'de, 'sig, 'f, B>, 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, B> ArrayDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { fn new(de: &'d mut Deserializer<'de, 'sig, 'f, B>) -> Result { 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(&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(), EncodingFormat::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, B> SeqAccess<'de> for ArrayDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { 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; return Ok(None); } let ctxt = EncodingContext::new( self.de.0.ctxt.format(), self.de.0.ctxt.position() + self.de.0.pos, ); let end = self.element_end(true)?; let mut de = Deserializer::(crate::DeserializerCommon { ctxt, sig_parser: self.de.0.sig_parser.clone(), bytes: &self.de.0.bytes[self.de.0.pos..end], fds: self.de.0.fds, pos: 0, b: PhantomData, }); let v = seed.deserialize(&mut de).map(Some); self.de.0.pos += de.0.pos; 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, B> MapAccess<'de> for ArrayDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { 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 = EncodingContext::new( self.de.0.ctxt.format(), 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::(crate::DeserializerCommon { ctxt, sig_parser: self.de.0.sig_parser.clone(), bytes: &self.de.0.bytes[self.de.0.pos..key_end], fds: self.de.0.fds, pos: 0, b: PhantomData, }); let v = seed.deserialize(&mut de).map(Some); self.de.0.pos += de.0.pos; 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 = EncodingContext::new( self.de.0.ctxt.format(), 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::(crate::DeserializerCommon { ctxt, sig_parser, bytes: &self.de.0.bytes[self.de.0.pos..value_end], fds: self.de.0.fds, pos: 0, b: PhantomData, }); let v = seed.deserialize(&mut de); self.de.0.pos += de.0.pos; 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, B> { de: &'d mut Deserializer<'de, 'sig, 'f, B>, 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, B> SeqAccess<'de> for StructureDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> where T: DeserializeSeed<'de>, { let ctxt = EncodingContext::new( self.de.0.ctxt.format(), 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(&self.de.0.bytes[self.start..self.end]) + self.start; self.end -= self.offset_size as usize; self.offsets_len += self.offset_size as usize; end } } else { self.end }; let sig_parser = self.de.0.sig_parser.clone(); let mut de = Deserializer::(crate::DeserializerCommon { ctxt, sig_parser, bytes: &self.de.0.bytes[self.de.0.pos..element_end], fds: self.de.0.fds, pos: 0, b: PhantomData, }); let v = seed.deserialize(&mut de).map(Some); self.de.0.pos += de.0.pos; 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, B> { de: &'d mut Deserializer<'de, 'sig, 'f, B>, stage: ValueParseStage, sig_start: usize, sig_end: usize, value_start: usize, value_end: usize, } impl<'d, 'de, 'sig, 'f, B> ValueDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { fn new(de: &'d mut Deserializer<'de, 'sig, 'f, B>) -> Result { // GVariant format has signature at the end let mut separator_pos = None; // 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, B> SeqAccess<'de> for ValueDeserializer<'d, 'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { 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::(crate::DeserializerCommon { // No padding in signatures so just pass the same context ctxt: self.de.0.ctxt, sig_parser, bytes: &self.de.0.bytes[self.sig_start..self.sig_end], fds: self.de.0.fds, pos: 0, b: PhantomData, }); seed.deserialize(&mut de).map(Some) } ValueParseStage::Value => { self.stage = ValueParseStage::Done; let slice = &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 = EncodingContext::new( self.de.0.ctxt.format(), self.de.0.ctxt.position() + self.value_start, ); let mut de = Deserializer::(crate::DeserializerCommon { ctxt, sig_parser, bytes: &self.de.0.bytes[self.value_start..self.value_end], fds: self.de.0.fds, pos: 0, b: PhantomData, }); 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, B> crate::de::GetDeserializeCommon<'de, 'sig, 'f, B> for &'d mut Deserializer<'de, 'sig, 'f, B> where B: byteorder::ByteOrder, { fn common_mut<'dr>(self) -> &'dr mut crate::de::DeserializerCommon<'de, 'sig, 'f, B> where Self: 'dr, { &mut self.0 } } impl<'de, 'd, 'sig, 'f, B> EnumAccess<'de> for crate::de::Enum> where B: byteorder::ByteOrder, { 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-2.10.0/src/gvariant/mod.rs000064400000000000000000000000600072674642500153150ustar 00000000000000mod de; pub use de::*; mod ser; pub use ser::*; zvariant-2.10.0/src/gvariant/ser.rs000064400000000000000000000456250072674642500153470ustar 00000000000000use serde::{ser, ser::SerializeSeq, Serialize}; use static_assertions::assert_impl_all; use std::{ io::{Seek, Write}, marker::PhantomData, os::unix::io::RawFd, str, }; use crate::{ framing_offset_size::FramingOffsetSize, framing_offsets::FramingOffsets, signature_parser::SignatureParser, utils::*, EncodingContext, EncodingFormat, Error, Result, Signature, }; /// Our serialization implementation. pub struct Serializer<'ser, 'sig, B, W>(pub(crate) crate::SerializerCommon<'ser, 'sig, B, W>); assert_impl_all!(Serializer<'_, '_, i32, i32>: Send, Sync, Unpin); impl<'ser, 'sig, B, W> Serializer<'ser, 'sig, B, W> where B: byteorder::ByteOrder, W: Write + Seek, { /// Create a GVariant Serializer struct instance. pub fn new<'w: 'ser, 'f: 'ser>( signature: &Signature<'sig>, writer: &'w mut W, fds: &'f mut Vec, ctxt: EncodingContext, ) -> Self { assert_eq!(ctxt.format(), EncodingFormat::GVariant); let sig_parser = SignatureParser::new(signature.clone()); Self(crate::SerializerCommon { ctxt, sig_parser, writer, fds, bytes_written: 0, value_sign: None, b: PhantomData, }) } 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) => { value.serialize(&mut *self)?; if !fixed_sized_child { self.0.write_all(&b"\0"[..]).map_err(Error::Io)?; } } None => { self.0.sig_parser.skip_chars(child_sig_len)?; } } Ok(()) } } macro_rules! serialize_basic { ($method:ident, $type:ty) => { #[inline] fn $method(self, v: $type) -> Result<()> { let ctxt = EncodingContext::new_dbus(self.0.ctxt.position()); let bytes_written = self.0.bytes_written; let mut fds = vec![]; let mut dbus_ser = crate::dbus::Serializer(crate::SerializerCommon:: { ctxt, sig_parser: self.0.sig_parser.clone(), writer: &mut self.0.writer, fds: &mut fds, bytes_written, value_sign: None, b: PhantomData, }); dbus_ser.$method(v)?; self.0.bytes_written = dbus_ser.0.bytes_written; self.0.sig_parser = dbus_ser.0.sig_parser; self.0.fds.extend(fds.iter()); Ok(()) } }; } impl<'ser, 'sig, 'b, B, W> ser::Serializer for &'b mut Serializer<'ser, 'sig, B, W> where B: byteorder::ByteOrder, W: Write + Seek, { type Ok = (); type Error = Error; type SerializeSeq = SeqSerializer<'ser, 'sig, 'b, B, W>; type SerializeTuple = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeTupleStruct = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeTupleVariant = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeMap = SeqSerializer<'ser, 'sig, 'b, B, W>; type SerializeStruct = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeStructVariant = StructSerializer<'ser, 'sig, 'b, 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(Error::Io)?; self.0.write_all(&b"\0"[..]).map_err(Error::Io)?; Ok(()) } fn serialize_bytes(self, v: &[u8]) -> Result<()> { let seq = self.serialize_seq(Some(v.len()))?; seq.ser.0.write(v).map_err(Error::Io)?; seq.end() } fn serialize_none(self) -> Result<()> { self.serialize_maybe::<()>(None) } fn serialize_some(self, value: &T) -> Result<()> where T: ?Sized + Serialize, { self.serialize_maybe(Some(value)) } fn serialize_unit(self) -> Result<()> { self.0.write_all(&b"\0"[..]).map_err(Error::Io) } 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<()> { 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 = if !fixed_sized_child { Some(FramingOffsets::new()) } else { None }; 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]); if !crate::utils::is_fixed_sized_signature(&key_signature)? { Some(0) } else { None } } else { None }; self.0.add_padding(element_alignment)?; 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)?; self.serialize_struct(name, len) } fn serialize_map(self, len: Option) -> Result { self.serialize_seq(len) } fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { let c = self.0.sig_parser.next_char(); let end_parens; if c == VARIANT_SIGNATURE_CHAR { self.0.add_padding(VARIANT_ALIGNMENT_GVARIANT)?; end_parens = false; } else { let signature = self.0.sig_parser.next_signature()?; let alignment = alignment_for_signature(&signature, EncodingFormat::GVariant); self.0.add_padding(alignment)?; self.0.sig_parser.skip_char()?; if c == STRUCT_SIG_START_CHAR || c == DICT_ENTRY_SIG_START_CHAR { end_parens = true; } else { let expected = format!( "`{}` or `{}`", STRUCT_SIG_START_STR, DICT_ENTRY_SIG_START_STR, ); return Err(serde::de::Error::invalid_type( serde::de::Unexpected::Char(c), &expected.as_str(), )); } } let offsets = if c == STRUCT_SIG_START_CHAR { Some(FramingOffsets::new()) } else { None }; let start = self.0.bytes_written; Ok(StructSerializer { ser: self, start, end_parens, offsets, }) } 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)?; self.serialize_struct(name, len) } } #[doc(hidden)] pub struct SeqSerializer<'ser, 'sig, 'b, B, W> { ser: &'b mut Serializer<'ser, 'sig, B, 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, B, W> SeqSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, W: Write + Seek, { pub(self) fn end_seq(self) -> Result<()> { self.ser .0 .sig_parser .skip_chars(self.element_signature_len)?; 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 assert!(offsets.is_empty()); return Ok(()); } offsets.write_all(&mut self.ser.0, array_len)?; Ok(()) } } impl<'ser, 'sig, 'b, B, W> ser::SerializeSeq for SeqSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, 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, B, W> { ser: &'b mut Serializer<'ser, 'sig, B, W>, start: usize, end_parens: bool, // All offsets offsets: Option, } impl<'ser, 'sig, 'b, B, W> StructSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, W: Write + Seek, { 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 fds = vec![]; let mut ser = Serializer(crate::SerializerCommon:: { ctxt: self.ser.0.ctxt, sig_parser, writer: self.ser.0.writer, fds: &mut fds, bytes_written, value_sign: None, b: PhantomData, }); value.serialize(&mut ser)?; self.ser.0.bytes_written = ser.0.bytes_written; self.ser.0.fds.extend(fds.iter()); self.ser.0.write_all(&b"\0"[..]).map_err(Error::Io)?; self.ser .0 .write_all(signature.as_bytes()) .map_err(Error::Io)?; 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 { self.ser.0.sig_parser.skip_char()?; } 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 assert!(offsets.is_empty()); 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(()) } } macro_rules! serialize_struct_anon_fields { ($trait:ident $method:ident) => { impl<'ser, 'sig, 'b, B, W> ser::$trait for StructSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, 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() } } }; } 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, B, W> ser::SerializeMap for SeqSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, 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, B, W> ser::$trait for StructSerializer<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, 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() } } }; } serialize_struct_named_fields!(SerializeStruct); serialize_struct_named_fields!(SerializeStructVariant); zvariant-2.10.0/src/into_value.rs000064400000000000000000000046270072674642500151050ustar 00000000000000use std::collections::HashMap; #[cfg(feature = "gvariant")] use crate::Maybe; use crate::{Array, Dict, Fd, ObjectPath, Signature, Str, Structure, Type, Value}; // // 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()) } } impl<'a> From<&'a $from> for Value<'a> { fn from(v: &'a $from) -> Self { Value::from(v.clone()) } } }; } into_value!(u8, U8); into_value!(i8, I16); into_value!(bool, Bool); into_value!(u16, U16); into_value!(i16, I16); into_value!(u32, U32); into_value!(i32, I32); into_value!(u64, U64); into_value!(i64, I64); into_value!(f32, F64); into_value!(f64, F64); into_value!(Fd, Fd); into_value!(&'a str, Str); into_value!(Str<'a>, Str); into_value!(Signature<'a>, Signature); into_value!(ObjectPath<'a>, ObjectPath); into_value!(Array<'a>, Array); into_value!(Dict<'a, 'a>, Dict); #[cfg(feature = "gvariant")] into_value!(Maybe<'a>, Maybe); impl<'s> From for Value<'s> { 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> From> for Value<'a> where 'k: 'a, 'v: 'a, K: Type + Into> + std::hash::Hash + std::cmp::Eq, V: Type + Into>, { 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()) } } #[cfg(feature = "gvariant")] impl<'v, V> From> for Value<'v> where Option: Into>, { fn from(v: Option) -> Value<'v> { Value::Maybe(v.into()) } } zvariant-2.10.0/src/lib.rs000064400000000000000000001754470072674642500135170ustar 00000000000000#![allow(clippy::unusual_byte_groupings)] #![deny(rust_2018_idioms)] #![doc( html_logo_url = "https://storage.googleapis.com/fdo-gitlab-uploads/project/avatar/3213/zbus-logomark.png" )] //! This crate provides API for serialization/deserialization of data to/from [D-Bus] wire format. //! 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. //! //! 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. //! //! Serialization and deserialization is achieved through the [toplevel functions]: //! //! ```rust //! use std::collections::HashMap; //! use byteorder::LE; //! use zvariant::{from_slice, to_bytes}; //! use zvariant::EncodingContext as Context; //! //! // All serialization and deserialization API, needs a context. //! let ctxt = Context::::new_dbus(0); //! // You can also use the more efficient GVariant format: //! // let ctxt = Context::::new_gvariant(0); //! //! // i16 //! let encoded = to_bytes(ctxt, &42i16).unwrap(); //! let decoded: i16 = from_slice(&encoded, ctxt).unwrap(); //! assert_eq!(decoded, 42); //! //! // strings //! let encoded = to_bytes(ctxt, &"hello").unwrap(); //! let decoded: &str = from_slice(&encoded, ctxt).unwrap(); //! assert_eq!(decoded, "hello"); //! //! // tuples //! let t = ("hello", 42i32, true); //! let encoded = to_bytes(ctxt, &t).unwrap(); //! let decoded: (&str, i32, bool) = from_slice(&encoded, ctxt).unwrap(); //! assert_eq!(decoded, t); //! //! // Vec //! let v = vec!["hello", "world!"]; //! let encoded = to_bytes(ctxt, &v).unwrap(); //! let decoded: Vec<&str> = from_slice(&encoded, ctxt).unwrap(); //! 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 = from_slice(&encoded, ctxt).unwrap(); //! assert_eq!(decoded[&1], "123"); //! assert_eq!(decoded[&2], "456"); //! ``` //! //! Apart from the obvious requirement of [`EncodingContext`] 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 | //! | --- | ----------- | //! | arrayvec | Implement `Type` for [`arrayvec::ArrayVec`] and [`arrayvec::ArrayString`] | //! | enumflags2 | Implement `Type` for [`struct@enumflags2::BitFlags`] | //! //! # Portability //! //! zvariant is currently Unix-only and will fail to build on non-unix. This is hopefully a //! temporary limitation. //! //! [D-Bus]: https://dbus.freedesktop.org/doc/dbus-specification.html //! [GVariant]: https://developer.gnome.org/glib/stable/glib-GVariant.html //! [serde]: https://crates.io/crates/serde //! [tutorial]: https://serde.rs/ //! [toplevel functions]: #functions //! [`EncodingContext`]: struct.EncodingContext.html //! [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html //! [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html //! [`Type` module documentation]: trait.Type.html //! [basic types]: https://dbus.freedesktop.org/doc/dbus-specification.html#basic-types //! [`Signature`]: struct.Signature.html //! [`ObjectPath`]: struct.ObjectPath.html //! [`Basic`]: 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.5.1/arrayvec/struct.ArrayVec.html //! [`arrayvec::ArrayString`]: https://docs.rs/arrayvec/0.5.1/arrayvec/struct.ArrayString.html //! [`Value` module documentation]: enum.Value.html #[macro_use] mod utils; pub use utils::*; mod array; pub use array::*; mod basic; pub use basic::*; mod dict; pub use dict::*; mod encoding_context; pub use encoding_context::*; mod fd; pub use fd::*; mod object_path; pub use crate::object_path::*; mod ser; pub use ser::*; mod de; pub use de::*; pub mod dbus; #[cfg(feature = "gvariant")] pub mod gvariant; mod signature; pub use crate::signature::*; mod str; pub use crate::str::*; mod structure; pub use crate::structure::*; #[cfg(feature = "gvariant")] mod maybe; #[cfg(feature = "gvariant")] pub use crate::maybe::*; mod optional; pub use crate::optional::*; mod value; pub use value::*; mod serialize_value; pub use serialize_value::*; mod deserialize_value; pub use deserialize_value::*; mod error; pub use error::*; #[macro_use] mod r#type; pub use r#type::*; mod from_value; pub use from_value::*; mod into_value; pub use 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; // FIXME: Re-export derive macros from the crate root with the next breaking-change release. pub mod derive { pub use zvariant_derive::{DeserializeDict, OwnedValue, SerializeDict, Type, TypeDict, 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; } #[cfg(test)] #[allow(clippy::blacklisted_name)] mod tests { use std::{ collections::HashMap, convert::{TryFrom, TryInto}, }; #[cfg(feature = "arrayvec")] use arrayvec::{ArrayString, ArrayVec}; use byteorder::{self, ByteOrder, BE, LE}; #[cfg(feature = "arrayvec")] use std::str::FromStr; #[cfg(feature = "gvariant")] use glib::{Bytes, FromVariant, Variant}; use serde::{Deserialize, Serialize}; use zvariant_derive::{DeserializeDict, SerializeDict, Type, TypeDict}; use crate::{ from_slice, from_slice_fds, from_slice_for_signature, to_bytes, to_bytes_fds, to_bytes_for_signature, }; use crate::{ Array, Basic, DeserializeValue, Dict, EncodingContext as Context, EncodingFormat, Error, Fd, ObjectPath, Result, SerializeValue, Signature, Str, Structure, Type, Value, }; // Test through both generic and specific API (wrt byte order) macro_rules! basic_type_test { ($trait:ty, $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::<$trait>::new(EncodingFormat::$format, 1); let (encoded, fds) = to_bytes_fds(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: $expected_ty = from_slice_fds(&encoded, Some(&fds), ctxt).unwrap(); assert!( decoded == $test_value, "invalid decoding using `from_slice`" ); // Now encode w/o padding let ctxt = Context::<$trait>::new(EncodingFormat::$format, 0); let (encoded, _) = to_bytes_fds(ctxt, &$test_value).unwrap(); assert_eq!( encoded.len(), $expected_len, "invalid encoding using `to_bytes`" ); encoded }}; ($trait:ty, $format:ident, $test_value:expr, $expected_len:expr, $expected_ty:ty, $align:literal, $kind:ident, $expected_value_len:expr) => {{ let encoded = basic_type_test!( $trait, $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 { ($trait:ty, $format:ident, $test_value:expr, $expected_len:expr) => {{ let ctxt = Context::<$trait>::new(EncodingFormat::$format, 0); let (encoded, fds) = to_bytes_fds(ctxt, &$test_value).unwrap(); assert_eq!( encoded.len(), $expected_len, "invalid encoding using `to_bytes`" ); let decoded: Value<'_> = from_slice_fds(&encoded, Some(&fds), ctxt).unwrap(); assert!( decoded == $test_value, "invalid decoding using `from_slice`" ); encoded }}; } fn f64_type_test( format: EncodingFormat, value: f64, expected_len: usize, expected_value_len: usize, ) -> Vec { // Lie that we're starting at byte 1 in the overall message to test padding let ctxt = Context::::new(format, 1); let (encoded, fds) = to_bytes_fds(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 = from_slice_fds(&encoded, Some(&fds), ctxt).unwrap(); assert!( (decoded - value).abs() < f64::EPSILON, "invalid decoding using `from_slice`" ); // Now encode w/o padding let ctxt = Context::::new(format, 0); let (encoded, _) = to_bytes_fds(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: EncodingFormat, 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.clone(), expected_value_len); let v: f64 = v.try_into().unwrap(); assert!((v - value).abs() < f64::EPSILON); } fn f64_value_test(format: EncodingFormat, v: Value<'_>, expected_value_len: usize) { let ctxt = Context::::new(format, 0); let (encoded, fds) = to_bytes_fds(ctxt, &v).unwrap(); assert_eq!( encoded.len(), expected_value_len, "invalid encoding using `to_bytes`" ); let decoded: Value<'_> = from_slice_fds(&encoded, Some(&fds), ctxt).unwrap(); assert!(decoded == v, "invalid decoding using `from_slice`"); } #[cfg(feature = "gvariant")] fn decode_with_gvariant(encoded: B) -> T where B: AsRef<[u8]> + Send + 'static, T: glib::variant::FromVariant, { let bytes = Bytes::from_owned(encoded); let gv = Variant::from_bytes::(&bytes); gv.get::().unwrap() } // 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")] { assert_eq!(decode_with_gvariant::<_, u8>(encoded), 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); } #[test] fn fd_value() { basic_type_test!(LE, DBus, Fd::from(42), 4, Fd, 4, Fd, 8); #[cfg(feature = "gvariant")] basic_type_test!(LE, GVariant, Fd::from(42), 4, Fd, 4, Fd, 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")] { assert_eq!(decode_with_gvariant::<_, u16>(encoded), 0xBAAB_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")] { assert_eq!(decode_with_gvariant::<_, i16>(encoded), 0x50F5_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")] { assert_eq!(decode_with_gvariant::<_, u32>(encoded), 0xBAAB_BAAB_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")] { assert_eq!(decode_with_gvariant::<_, i32>(encoded), 0x5055_44F5_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")] { assert_eq!( decode_with_gvariant::<_, i64>(encoded), 0x5055_4455_4455_44F5_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(EncodingFormat::DBus, 99999.99999_f64, 8, 16); assert!((LE::read_f64(&encoded) - -5.759340900185448e-128).abs() < f64::EPSILON); #[cfg(feature = "gvariant")] { assert!( (decode_with_gvariant::<_, f64>(encoded) - -5.759340900185448e-128).abs() < f64::EPSILON ); f64_type_test(EncodingFormat::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); assert_eq!(decode_with_gvariant::<_, String>(encoded), "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.get_variant().unwrap(); assert_eq!(variant.get_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(0); assert!(from_slice::<_, &str>(b"\x0b\0\0\0hello\0world\0", ctxt).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(0); assert!(from_slice::<_, &str>(b"hello\0world\0", ctxt).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(0); let encoded = to_bytes::(ctxt, &v).unwrap(); assert_eq!(encoded.len(), 10); let v = from_slice::>(&encoded, ctxt).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(0); let encoded = to_bytes(ctxt, &s).unwrap(); assert_eq!(encoded.len(), 17); let decoded: ArrayString<[_; 32]> = from_slice(&encoded, ctxt).unwrap(); 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); assert_eq!(decode_with_gvariant::<_, String>(encoded), "yys"); } // As Value let v: Value<'_> = sig.into(); assert_eq!(v.value_signature(), "g"); let encoded = value_test!(LE, DBus, v, 8); let ctxt = Context::new_dbus(0); let v = from_slice::>(&encoded, ctxt).unwrap(); 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 ctxt = Context::new_gvariant(0); let v = from_slice::>(&encoded, ctxt).unwrap(); 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); assert_eq!(decode_with_gvariant::<_, String>(encoded), "/hello/world"); } // As Value let v: Value<'_> = o.into(); assert_eq!(v.value_signature(), "o"); let encoded = value_test!(LE, DBus, v, 21); let ctxt = Context::new_dbus(0); let v = from_slice::>(&encoded, ctxt).unwrap(); 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 ctxt = Context::new_gvariant(0); let v = from_slice::>(&encoded, ctxt).unwrap(); assert_eq!( v, Value::ObjectPath(ObjectPath::try_from("/hello/world").unwrap()) ); } } #[test] fn unit() { let ctxt = Context::::new_dbus(0); let (encoded, fds) = to_bytes_fds(ctxt, &()).unwrap(); assert_eq!(encoded.len(), 0, "invalid encoding using `to_bytes`"); let _decoded: () = from_slice_fds(&encoded, Some(&fds), ctxt) .expect("invalid decoding using `from_slice`"); } #[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!) let ay = [77u8, 88]; let ctxt = Context::::new_dbus(0); let encoded = to_bytes(ctxt, &ay).unwrap(); assert_eq!(encoded.len(), 2); let decoded: [u8; 2] = from_slice(&encoded, ctxt).unwrap(); 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(0); let encoded = to_bytes(ctxt, &ay).unwrap(); assert_eq!(encoded.len(), 6); #[cfg(feature = "arrayvec")] let decoded: ArrayVec<[u8; 2]> = from_slice(&encoded, ctxt).unwrap(); #[cfg(not(feature = "arrayvec"))] let decoded: Vec = from_slice(&encoded, ctxt).unwrap(); assert_eq!(&decoded.as_slice(), &[77u8, 88]); // GVariant format now #[cfg(feature = "gvariant")] { let ctxt = Context::::new_gvariant(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.get_child_value(0).get::().unwrap(), 77); assert_eq!(variant.get_child_value(1).get::().unwrap(), 88); } let ctxt = Context::::new_dbus(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 = from_slice::>(&encoded, ctxt).unwrap(); if let Value::Array(array) = v { assert_eq!(*array.element_signature(), "y"); assert_eq!(array.len(), 2); assert_eq!(array.get()[0], Value::U8(77)); assert_eq!(array.get()[1], Value::U8(88)); } 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(0); let gv_encoded = to_bytes(ctxt, &at).unwrap(); assert_eq!(gv_encoded.len(), 0); let at = from_slice::>(&gv_encoded, ctxt).unwrap(); assert_eq!(at.len(), 0); } let ctxt = Context::::new_dbus(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 = from_slice::>(&encoded, ctxt).unwrap(); 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(0); let v: Value<'_> = at[..].into(); let gv_encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(gv_encoded.len(), 3); let v = from_slice::>(&gv_encoded, ctxt).unwrap(); 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(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 = from_slice::>(&encoded, ctxt).unwrap(); assert_eq!(decoded.len(), 4); assert_eq!(decoded[0], "Hello"); assert_eq!(decoded[1], "World"); let decoded = from_slice::>(&encoded, ctxt).unwrap(); assert_eq!(decoded.as_slice(), as_.as_slice()); // Decode just the second string let ctxt = Context::::new_dbus(14); let decoded: &str = from_slice(&encoded[14..], ctxt).unwrap(); assert_eq!(decoded, "World"); let ctxt = Context::::new_dbus(0); // 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 = from_slice(&encoded, ctxt).unwrap(); if let Value::Array(array) = v { assert_eq!(*array.element_signature(), "s"); assert_eq!(array.len(), 4); assert_eq!(array.get()[0], Value::new("Hello")); assert_eq!(array.get()[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(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.get_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_value(), u32::max_value(), ( // 2nd level simple fields i64::max_value(), true, i64::max_value(), // 2nd level array field &["Hello", "World"][..], ), // one more top-most simple field "hello", )]; let ctxt = Context::::new_dbus(0); let encoded = to_bytes(ctxt, &ar).unwrap(); assert_eq!(encoded.len(), 78); let decoded = from_slice::), &str)>>(&encoded, ctxt) .unwrap(); assert_eq!(decoded.len(), 1); let r = &decoded[0]; assert_eq!(r.0, u8::max_value()); assert_eq!(r.1, u32::max_value()); let inner_r = &r.2; assert_eq!(inner_r.0, i64::max_value()); assert!(inner_r.1); assert_eq!(inner_r.2, i64::max_value()); 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(0); let gv_encoded = to_bytes(ctxt, &ar).unwrap(); assert_eq!(gv_encoded.len(), 54); let decoded = from_slice::), &str)>>( &gv_encoded, ctxt, ) .unwrap(); assert_eq!(decoded.len(), 1); let r = &decoded[0]; assert_eq!(r.0, u8::max_value()); assert_eq!(r.1, u32::max_value()); let inner_r = &r.2; assert_eq!(inner_r.0, i64::max_value()); assert!(inner_r.1); assert_eq!(inner_r.2, i64::max_value()); 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.get_child_value(0).get().unwrap(); assert_eq!(r.0, u8::max_value()); assert_eq!(r.1, u32::max_value()); } let ctxt = Context::::new_dbus(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 = from_slice::>(&encoded, ctxt).unwrap(); if let Value::Array(array) = v.clone() { assert_eq!(*array.element_signature(), "(yu(xbxas)s)"); assert_eq!(array.len(), 1); let r = &array.get()[0]; if let Value::Structure(r) = r { let fields = r.fields(); assert_eq!(fields[0], Value::U8(u8::max_value())); assert_eq!(fields[1], Value::U32(u32::max_value())); if let Value::Structure(r) = &fields[2] { let fields = r.fields(); assert_eq!(fields[0], Value::I64(i64::max_value())); assert_eq!(fields[1], Value::Bool(true)); assert_eq!(fields[2], Value::I64(i64::max_value())); if let Value::Array(as_) = &fields[3] { assert_eq!(as_.len(), 2); assert_eq!(as_.get()[0], Value::new("Hello")); assert_eq!(as_.get()[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(0); let gv_encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(gv_encoded.len(), 68); let v = from_slice::>(&gv_encoded, ctxt).unwrap(); if let Value::Array(array) = v { assert_eq!(*array.element_signature(), "(yu(xbxas)s)"); assert_eq!(array.len(), 1); let r = &array.get()[0]; if let Value::Structure(r) = r { let fields = r.fields(); assert_eq!(fields[0], Value::U8(u8::max_value())); assert_eq!(fields[1], Value::U32(u32::max_value())); if let Value::Structure(r) = &fields[2] { let fields = r.fields(); assert_eq!(fields[0], Value::I64(i64::max_value())); assert_eq!(fields[1], Value::Bool(true)); assert_eq!(fields[2], Value::I64(i64::max_value())); if let Value::Array(as_) = &fields[3] { assert_eq!(as_.len(), 2); assert_eq!(as_.get()[0], Value::new("Hello")); assert_eq!(as_.get()[1], Value::new("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.get_child_value(0); let r: (u8, u32, (i64, bool, i64, Vec), String) = child.get_child_value(0).get().unwrap(); assert_eq!(r.0, u8::max_value()); assert_eq!(r.1, u32::max_value()); 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.clone()); let variant = Variant::from_bytes::>(&bytes); assert_eq!(variant.n_children(), 2); assert_eq!(variant.get_child_value(0).get::().unwrap(), as_[0]); assert_eq!(variant.get_child_value(1).get::().unwrap(), as_[1]); // Also check if our own deserializer does the right thing let as2 = from_slice::>(&gv_encoded, ctxt).unwrap(); 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(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<'_>>) = zvariant::from_slice(&value, ctxt) .expect("Could not deserialize serde_bytes::Bytes in struct."); #[cfg(not(feature = "serde_bytes"))] let (bytes, map): (&[u8], HashMap<&str, Value<'_>>) = zvariant::from_slice(&value, ctxt).expect("Could not deserialize u8 slice in struct"); 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(0); let encoded = to_bytes(ctxt, &s).unwrap(); assert_eq!(dbg!(encoded.len()), 40); let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); 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> = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded.0, foo); } #[test] fn struct_ref() { let ctxt = Context::::new_dbus(0); let encoded = to_bytes(ctxt, &(&1u32, &2u32)).unwrap(); let decoded: [u32; 2] = from_slice(&encoded, ctxt).unwrap(); 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(0); let encoded = to_bytes(ctxt, &map).unwrap(); assert_eq!(dbg!(encoded.len()), 40); let decoded: HashMap = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded[&1], "123"); assert_eq!(decoded[&2], "456"); // GVariant format now #[cfg(feature = "gvariant")] { let ctxt = Context::::new_gvariant(0); let gv_encoded = to_bytes(ctxt, &map).unwrap(); assert_eq!(gv_encoded.len(), 30); let map: HashMap = from_slice(&gv_encoded, ctxt).unwrap(); 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(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_into().unwrap(); assert_eq!(map[&1], "123"); assert_eq!(map[&2], "456"); // Also decode it back let v = from_slice(&encoded, ctxt).unwrap(); if let Value::Dict(dict) = v { assert_eq!(dict.get::(&1).unwrap().unwrap(), "123"); assert_eq!(dict.get::(&2).unwrap().unwrap(), "456"); } else { panic!(); } #[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(0); let gv_encoded = to_bytes(ctxt, &map).unwrap(); assert_eq!(gv_encoded.len(), 22); let map: HashMap<&str, &str> = from_slice(&gv_encoded, ctxt).unwrap(); assert_eq!(map["hi"], "1234"); assert_eq!(map["world"], "561"); // 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> = from_slice(&gv_encoded, ctxt).unwrap(); assert_eq!(map.len(), 0); } let ctxt = Context::::new_dbus(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()), 68); let v: Value<'_> = from_slice(&encoded, ctxt).unwrap(); if let Value::Dict(dict) = v { assert_eq!( *dict.get::<_, 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).unwrap(); assert_eq!(map["hello"], Value::new("there")); assert_eq!(map["bye"], Value::new("now")); } else { panic!(); } #[derive(SerializeDict, DeserializeDict, TypeDict, PartialEq, Debug)] 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<'_>> = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded["process_id"], Value::U32(42)); assert_eq!(decoded["user"], Value::new("me")); assert!(!decoded.contains_key("group_id")); let decoded: Test = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, test); #[derive(SerializeDict, DeserializeDict, TypeDict, PartialEq, Debug)] struct TestMissing { process_id: Option, group_id: Option, user: String, quota: u8, } let decoded: Result = from_slice(&encoded, ctxt); assert_eq!( decoded.unwrap_err(), Error::Message("missing field `quota`".to_string()) ); #[derive(SerializeDict, DeserializeDict, TypeDict, PartialEq, Debug)] struct TestSkipUnknown { process_id: Option, group_id: Option, } let _: TestSkipUnknown = from_slice(&encoded, ctxt).unwrap(); #[derive(SerializeDict, DeserializeDict, TypeDict, PartialEq, Debug)] #[zvariant(deny_unknown_fields)] struct TestUnknown { process_id: Option, group_id: Option, } let decoded: Result = from_slice(&encoded, ctxt); assert_eq!( decoded.unwrap_err(), Error::Message("unknown field `user`, expected `process_id` or `group_id`".to_string()) ); } #[test] fn value_value() { let ctxt = Context::::new_dbus(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 = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, 0xABBA_ABBA_ABBA_ABBA); // Lie about there being bytes before let ctxt = Context::::new_dbus(2); let encoded = to_bytes(ctxt, &0xABBA_ABBA_ABBA_ABBA_u64).unwrap(); assert_eq!(encoded.len(), 14); let decoded: u64 = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, 0xABBA_ABBA_ABBA_ABBA_u64); let ctxt = Context::::new_dbus(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 = from_slice(&encoded, ctxt).unwrap(); 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 = from_slice(&encoded, ctxt).unwrap(); 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() { // TODO: Document enum handling. // // 1. `Value`. // 2. custom (de)serialize impl. // 3. to/from_*_for_signature() use serde::{Deserialize, Serialize}; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] enum Test { Unit, NewType(u8), Tuple(u8, u64), Struct { y: u8, t: u64 }, } let ctxt = Context::::new_dbus(0); let signature = "u".try_into().unwrap(); let encoded = to_bytes_for_signature(ctxt, &signature, &Test::Unit).unwrap(); assert_eq!(encoded.len(), 4); let decoded: Test = from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); assert_eq!(decoded, Test::Unit); let signature = "y".try_into().unwrap(); let encoded = to_bytes_for_signature(ctxt, &signature, &Test::NewType(42)).unwrap(); assert_eq!(encoded.len(), 5); let decoded: Test = from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); assert_eq!(decoded, Test::NewType(42)); // TODO: Provide convenience API to create complex signatures let signature = "(yt)".try_into().unwrap(); let encoded = to_bytes_for_signature(ctxt, &signature, &Test::Tuple(42, 42)).unwrap(); assert_eq!(encoded.len(), 24); let decoded: Test = from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); assert_eq!(decoded, Test::Tuple(42, 42)); let s = Test::Struct { y: 42, t: 42 }; let encoded = to_bytes_for_signature(ctxt, &signature, &s).unwrap(); assert_eq!(encoded.len(), 24); let decoded: Test = from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); assert_eq!(decoded, Test::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(0); let encoded = to_bytes(ctxt, &s).unwrap(); assert_eq!(encoded.len(), 26); let decoded: Struct<'_> = from_slice(&encoded, ctxt).unwrap(); 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 = from_slice(&encoded, ctxt).unwrap(); #[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 = from_slice(&encoded, ctxt).unwrap(); 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 = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, Enum2::Variant2); #[derive(Deserialize, Serialize, Type, Debug, PartialEq)] enum NoReprEnum { Variant1, Variant2, Variant3, } assert_eq!(NoReprEnum::signature(), u32::signature()); let encoded = to_bytes(ctxt, &NoReprEnum::Variant2).unwrap(); assert_eq!(encoded.len(), 4); let decoded: NoReprEnum = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, NoReprEnum::Variant2); #[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<'_> = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, s); } #[test] fn serialized_size() { let ctxt = Context::::new_dbus(0); let l = crate::serialized_size(ctxt, &()).unwrap(); assert_eq!(l, 0); let stdout = std::io::stdout(); let l = crate::serialized_size_fds(ctxt, &Fd::from(&stdout)).unwrap(); assert_eq!(l, (4, 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(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 = from_slice(&encoded, ctxt).unwrap(); 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<'_> = from_slice(&encoded, ctxt).unwrap(); 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(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 = from_slice(&encoded, ctxt).unwrap(); 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<'_> = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, s); } #[test] #[cfg(feature = "gvariant")] fn option_value() { let ctxt = Context::::new_gvariant(0); // First a Some fixed-sized value let mn = Some(16i16); let encoded = to_bytes(ctxt, &mn).unwrap(); assert_eq!(encoded.len(), 2); let decoded: Option = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, mn); // 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(); assert_eq!(encoded.len(), 5); let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); if let Value::Maybe(maybe) = decoded { assert_eq!(maybe.get().unwrap(), mn); } else { panic!(); } // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::(&bytes); let decoded = variant.get_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(); assert_eq!(encoded.len(), 0); let decoded: Option = from_slice(&encoded, ctxt).unwrap(); assert!(decoded.is_none()); // 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(); assert_eq!(encoded.len(), 13); let decoded: Option<&str> = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, ms); // 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(); let encoded = to_bytes(ctxt, &v).unwrap(); assert_eq!(encoded.len(), 16); let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); if let Value::Maybe(maybe) = decoded { assert_eq!(maybe.get::().unwrap().as_deref(), ms); } else { panic!(); } // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::(&bytes); let decoded = variant.get_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(); assert_eq!(encoded.len(), 0); let decoded: Option<&str> = from_slice(&encoded, ctxt).unwrap(); assert!(decoded.is_none()); // 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(); assert_eq!(encoded.len(), 26); let decoded: Vec> = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, ams); // 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(); assert_eq!(encoded.len(), 30); let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); assert_eq!(v, decoded); // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::(&bytes); let decoded = variant .get_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(); assert_eq!(encoded.len(), 25); let decoded: (Option, u64, Option) = from_slice(&encoded, ctxt).unwrap(); assert_eq!(decoded, structure); // 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(); assert_eq!(encoded.len(), 33); let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); assert_eq!(v, decoded); // Check encoding against GLib let bytes = Bytes::from_owned(encoded); let variant = Variant::from_bytes::(&bytes); let decoded = variant .get_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(0); let encoded = to_bytes(ctxt, &(&foo, 1)).unwrap(); let f: Foo = from_slice_fds(&encoded, None, ctxt).unwrap(); 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(0); let (encoded, _) = to_bytes_fds(ctxt, &("hello",)).unwrap(); let result: Result<(&str, &str)> = from_slice(&encoded, ctxt); 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(0); let signature = ZVStruct::signature(); let encoded = to_bytes_for_signature(ctxt, &signature, &element).unwrap(); let _: ZVStruct<'_> = from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); } #[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(0); let _: Summary<'_> = from_slice(&encoded, ctxt).unwrap(); // If we're able to deserialize all the data successfully, don't bother checking the summary data. } } zvariant-2.10.0/src/maybe.rs000064400000000000000000000101000072674642500140140ustar 00000000000000use serde::ser::{Serialize, Serializer}; use static_assertions::assert_impl_all; use std::convert::TryFrom; use crate::{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, Clone, PartialEq)] 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(self) -> core::result::Result, Error> where T: TryFrom>, { self.value .map(|v| v.downcast().ok_or(Error::IncorrectType)) .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 to_owned(&self) -> Maybe<'static> { Maybe { value_signature: self.value_signature.to_owned(), value: Box::new(self.value.clone().map(|v| v.to_owned())), signature: self.signature.to_owned(), } } } 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())) } } // This would be great but somehow it conflicts with some blanket generic implementations from // core: // // impl<'a, T> TryFrom> for Option 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-2.10.0/src/object_path.rs000064400000000000000000000242410072674642500152140ustar 00000000000000// FIXME: Drop this when the deprecated `Basic::ALIGNMENT` is dropped in the next API break. #![allow(deprecated)] use core::{convert::TryFrom, fmt::Debug, str}; use serde::{ de::{Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, }; use static_assertions::assert_impl_all; use crate::{Basic, EncodingFormat, 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 core::convert::TryFrom; /// 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)] pub struct ObjectPath<'a>(Str<'a>); assert_impl_all!(ObjectPath<'_>: Send, Sync, Unpin); impl<'a> ObjectPath<'a> { /// A borrowed clone (this never allocates, unlike clone). 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 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"; const ALIGNMENT: usize = <&str>::ALIGNMENT; fn alignment(format: EncodingFormat) -> usize { match format { EncodingFormat::DBus => <&str>::alignment(format), #[cfg(feature = "gvariant")] EncodingFormat::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<'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) } #[inline] fn visit_str(self, value: &str) -> core::result::Result, E> where E: serde::de::Error, { ObjectPath::try_from(String::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, zvariant_derive::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 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<'static> { 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>, { let visitor = ObjectPathVisitor; deserializer .deserialize_string(visitor) .map(|v| OwnedObjectPath(v.to_owned())) } } zvariant-2.10.0/src/optional.rs000064400000000000000000000056650072674642500145700ustar 00000000000000use std::{ convert::TryInto, 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`]. 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][tnv]. 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. /// /// [tnv]: 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, { 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>, { 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 } } zvariant-2.10.0/src/owned_value.rs000064400000000000000000000140200072674642500152340ustar 00000000000000use serde::{Deserialize, Deserializer, Serialize}; use static_assertions::assert_impl_all; use std::{collections::HashMap, convert::TryFrom, hash::BuildHasher}; use crate::{ derive::Type, Array, Dict, Fd, ObjectPath, OwnedObjectPath, OwnedSignature, Signature, Str, Structure, Value, }; #[cfg(feature = "gvariant")] use crate::Maybe; // FIXME: Replace with a generic impl> TryFrom for T? // https://gitlab.freedesktop.org/dbus/zbus/-/issues/138 /// Owned [`Value`](enum.Value.html) #[derive(Debug, Clone, PartialEq, Serialize, Type)] pub struct OwnedValue(Value<'static>); assert_impl_all!(OwnedValue: Send, Sync, Unpin); impl OwnedValue { pub(crate) fn into_inner(self) -> Value<'static> { self.0 } } macro_rules! ov_try_from { ($to:ty) => { impl<'a> 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<'a>); ov_try_from!(OwnedSignature); ov_try_from!(ObjectPath<'a>); ov_try_from!(OwnedObjectPath); ov_try_from!(Array<'a>); ov_try_from!(Dict<'a, 'a>); #[cfg(feature = "gvariant")] ov_try_from!(Maybe<'a>); ov_try_from!(Str<'a>); ov_try_from!(Structure<'a>); ov_try_from!(Fd); 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>); ov_try_from_ref!(Fd); 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::RawBitFlags, F::Type: 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) } } } // tuple conversions in `structure` module for avoiding code-duplication. impl<'a> From> for OwnedValue { fn from(v: Value<'a>) -> Self { // TODO: add into_owned, avoiding copy if already owned.. OwnedValue(v.to_owned()) } } impl<'a> From<&Value<'a>> for OwnedValue { fn from(v: &Value<'a>) -> Self { OwnedValue(v.to_owned()) } } macro_rules! to_value { ($from:ty) => { impl<'a> From<$from> for OwnedValue { fn from(v: $from) -> Self { OwnedValue::from(>::from(v)) } } }; } to_value!(u8); to_value!(bool); to_value!(i16); to_value!(u16); to_value!(i32); to_value!(u32); to_value!(i64); to_value!(u64); to_value!(f64); to_value!(Array<'a>); to_value!(Dict<'a, 'a>); #[cfg(feature = "gvariant")] to_value!(Maybe<'a>); to_value!(Str<'a>); to_value!(Signature<'a>); to_value!(Structure<'a>); to_value!(ObjectPath<'a>); to_value!(Fd); impl From for Value<'static> { fn from(v: OwnedValue) -> Value<'static> { v.into_inner() } } 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>, { Ok(Value::deserialize(deserializer)?.into()) } } #[cfg(test)] mod tests { use byteorder::LE; use std::{convert::TryFrom, error::Error, result::Result}; use crate::{from_slice, to_bytes, EncodingContext, OwnedValue, Value}; #[cfg(feature = "enumflags2")] #[test] fn bitflags() -> Result<(), Box> { #[repr(u32)] #[derive(enumflags2::BitFlags, Copy, Clone, Debug)] pub enum Flaggy { One = 0x1, Two = 0x2, } let v = Value::from(0x2u32); let ov: OwnedValue = v.into(); assert_eq!(>::try_from(ov)?, Flaggy::Two); Ok(()) } #[test] fn from_value() -> Result<(), Box> { let v = Value::from("hi!"); let ov: OwnedValue = v.into(); assert_eq!(<&str>::try_from(&ov)?, "hi!"); Ok(()) } #[test] fn serde() -> Result<(), Box> { let ec = EncodingContext::::new_dbus(0); let ov: OwnedValue = Value::from("hi!").into(); let ser = to_bytes(ec, &ov)?; let de: Value<'_> = from_slice(&ser, ec)?; assert_eq!(<&str>::try_from(&de)?, "hi!"); Ok(()) } } zvariant-2.10.0/src/ser.rs000064400000000000000000000440430072674642500135250ustar 00000000000000use byteorder::WriteBytesExt; use serde::{ser, Serialize}; use static_assertions::assert_impl_all; use std::{ io::{Seek, Write}, marker::PhantomData, os::unix::io::RawFd, str, }; #[cfg(feature = "gvariant")] use crate::gvariant::{self, Serializer as GVSerializer}; use crate::{ dbus::{self, Serializer as DBusSerializer}, signature_parser::SignatureParser, utils::*, Basic, DynamicType, EncodingContext, EncodingFormat, Error, Result, Signature, }; struct NullWriteSeek; impl Write for NullWriteSeek { fn write(&mut self, buf: &[u8]) -> std::io::Result { Ok(buf.len()) } fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } impl Seek for NullWriteSeek { fn seek(&mut self, _pos: std::io::SeekFrom) -> std::io::Result { Ok(std::u64::MAX) // should never read the return value! } } /// Calculate the serialized size of `T`. /// /// # Panics /// /// This function will panic if the value to serialize contains file descriptors. Use /// [`serialized_size_fds`] if `T` (potentially) contains FDs. /// /// # Examples /// /// ``` /// use zvariant::{EncodingContext, serialized_size}; /// /// let ctxt = EncodingContext::::new_dbus(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); /// ``` /// /// [`serialized_size_fds`]: fn.serialized_size_fds.html pub fn serialized_size(ctxt: EncodingContext, value: &T) -> Result where B: byteorder::ByteOrder, T: Serialize + DynamicType, { let mut null = NullWriteSeek; to_writer(&mut null, ctxt, value) } /// Calculate the serialized size of `T` that (potentially) contains FDs. /// /// Returns the serialized size of `T` and the number of FDs. pub fn serialized_size_fds( ctxt: EncodingContext, value: &T, ) -> Result<(usize, usize)> where B: byteorder::ByteOrder, T: Serialize + DynamicType, { let mut null = NullWriteSeek; let (len, fds) = to_writer_fds(&mut null, ctxt, value)?; Ok((len, fds.len())) } /// Serialize `T` to the given `writer`. /// /// This function returns the number of bytes written to the given `writer`. /// /// # Panics /// /// This function will panic if the value to serialize contains file descriptors. Use /// [`to_writer_fds`] if you'd want to potentially pass FDs. /// /// # Examples /// /// ``` /// use zvariant::{EncodingContext, from_slice, to_writer}; /// /// let ctxt = EncodingContext::::new_dbus(0); /// let mut cursor = std::io::Cursor::new(vec![]); /// to_writer(&mut cursor, ctxt, &42u32).unwrap(); /// let value: u32 = from_slice(cursor.get_ref(), ctxt).unwrap(); /// assert_eq!(value, 42); /// ``` /// /// [`to_writer_fds`]: fn.to_writer_fds.html pub fn to_writer( writer: &mut W, ctxt: EncodingContext, value: &T, ) -> Result where B: byteorder::ByteOrder, W: Write + Seek, T: Serialize + DynamicType, { let signature = value.dynamic_signature(); to_writer_for_signature(writer, ctxt, &signature, value) } /// Serialize `T` that (potentially) contains FDs, to the given `writer`. /// /// This function returns the number of bytes written to the given `writer` and the file descriptor /// vector, which needs to be transferred via an out-of-band platform specific mechanism. pub fn to_writer_fds( writer: &mut W, ctxt: EncodingContext, value: &T, ) -> Result<(usize, Vec)> where B: byteorder::ByteOrder, W: Write + Seek, T: Serialize + DynamicType, { let signature = value.dynamic_signature(); to_writer_fds_for_signature(writer, ctxt, &signature, value) } /// Serialize `T` as a byte vector. /// /// See [`from_slice`] documentation for an example of how to use this function. /// /// # Panics /// /// This function will panic if the value to serialize contains file descriptors. Use /// [`to_bytes_fds`] if you'd want to potentially pass FDs. /// /// [`to_bytes_fds`]: fn.to_bytes_fds.html /// [`from_slice`]: fn.from_slice.html#examples pub fn to_bytes(ctxt: EncodingContext, value: &T) -> Result> where B: byteorder::ByteOrder, T: Serialize + DynamicType, { let (bytes, fds) = to_bytes_fds(ctxt, value)?; if !fds.is_empty() { panic!("can't serialize with FDs") } Ok(bytes) } /// Serialize `T` that (potentially) contains FDs, as a byte vector. /// /// The returned file descriptor needs to be transferred via an out-of-band platform specific /// mechanism. pub fn to_bytes_fds( ctxt: EncodingContext, value: &T, ) -> Result<(Vec, Vec)> where B: byteorder::ByteOrder, T: Serialize + DynamicType, { let mut cursor = std::io::Cursor::new(vec![]); let (_, fds) = to_writer_fds(&mut cursor, ctxt, value)?; Ok((cursor.into_inner(), fds)) } /// 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 /// [`Type`]. /// /// This function returns the number of bytes written to the given `writer`. /// /// [`to_writer`]: fn.to_writer.html /// [`Type`]: trait.Type.html pub fn to_writer_for_signature( writer: &mut W, ctxt: EncodingContext, signature: &Signature<'_>, value: &T, ) -> Result where B: byteorder::ByteOrder, W: Write + Seek, T: Serialize, { let (len, fds) = to_writer_fds_for_signature(writer, ctxt, signature, value)?; if !fds.is_empty() { panic!("can't serialize with FDs") } Ok(len) } /// Serialize `T` that (potentially) contains FDs and has the given signature, to the given `writer`. /// /// Use this function instead of [`to_writer_fds`] if the value being serialized does not implement /// [`Type`]. /// /// This function returns the number of bytes written to the given `writer` and the file descriptor /// vector, which needs to be transferred via an out-of-band platform specific mechanism. /// /// [`to_writer_fds`]: fn.to_writer_fds.html /// [`Type`]: trait.Type.html pub fn to_writer_fds_for_signature( writer: &mut W, ctxt: EncodingContext, signature: &Signature<'_>, value: &T, ) -> Result<(usize, Vec)> where B: byteorder::ByteOrder, W: Write + Seek, T: Serialize, { let mut fds = vec![]; match ctxt.format() { EncodingFormat::DBus => { let mut ser = DBusSerializer::::new(signature, writer, &mut fds, ctxt); value.serialize(&mut ser)?; Ok((ser.0.bytes_written, fds)) } #[cfg(feature = "gvariant")] EncodingFormat::GVariant => { let mut ser = GVSerializer::::new(signature, writer, &mut fds, ctxt); value.serialize(&mut ser)?; Ok((ser.0.bytes_written, fds)) } } } /// 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 /// [`Type`]. See [`from_slice_for_signature`] documentation for an example of how to use this /// function. /// /// # Panics /// /// This function will panic if the value to serialize contains file descriptors. Use /// [`to_bytes_fds_for_signature`] if you'd want to potentially pass FDs. /// /// [`to_bytes`]: fn.to_bytes.html /// [`Type`]: trait.Type.html /// [`from_slice_for_signature`]: fn.from_slice_for_signature.html#examples pub fn to_bytes_for_signature( ctxt: EncodingContext, signature: &Signature<'_>, value: &T, ) -> Result> where B: byteorder::ByteOrder, T: Serialize, { let (bytes, fds) = to_bytes_fds_for_signature(ctxt, signature, value)?; if !fds.is_empty() { panic!("can't serialize with FDs") } Ok(bytes) } /// Serialize `T` that (potentially) contains FDs and has the given signature, to a new byte vector. /// /// Use this function instead of [`to_bytes_fds`] if the value being serialized does not implement /// [`Type`]. /// /// Please note that the serialized bytes only contain the indices of the file descriptors from the /// returned file descriptor vector, which needs to be transferred via an out-of-band platform /// specific mechanism. /// /// [`to_bytes_fds`]: fn.to_bytes_fds.html /// [`Type`]: trait.Type.html pub fn to_bytes_fds_for_signature( ctxt: EncodingContext, signature: &Signature<'_>, value: &T, ) -> Result<(Vec, Vec)> where B: byteorder::ByteOrder, T: Serialize, { let mut cursor = std::io::Cursor::new(vec![]); let (_, fds) = to_writer_fds_for_signature(&mut cursor, ctxt, signature, value)?; Ok((cursor.into_inner(), fds)) } /// Context for all our serializers and provides shared functionality. pub(crate) struct SerializerCommon<'ser, 'sig, B, W> { pub(crate) ctxt: EncodingContext, pub(crate) writer: &'ser mut W, pub(crate) bytes_written: usize, pub(crate) fds: &'ser mut Vec, pub(crate) sig_parser: SignatureParser<'sig>, pub(crate) value_sign: Option>, pub(crate) b: PhantomData, } /// Our serialization implementation. /// /// Using this serializer involves an redirection to the actual serializer. It's best to use the /// serialization functions, e.g [`to_bytes`] or specific serializers, [`dbus::Serializer`] or /// [`zvariant::Serializer`]. pub enum Serializer<'ser, 'sig, B, W> { DBus(DBusSerializer<'ser, 'sig, B, W>), #[cfg(feature = "gvariant")] GVariant(GVSerializer<'ser, 'sig, B, W>), } assert_impl_all!(Serializer<'_, '_, i32, i32>: Send, Sync, Unpin); impl<'ser, 'sig, B, W> Serializer<'ser, 'sig, B, W> where B: byteorder::ByteOrder, W: Write + Seek, { /// Create a Serializer struct instance. pub fn new<'w: 'ser, 'f: 'ser>( signature: &Signature<'sig>, writer: &'w mut W, fds: &'f mut Vec, ctxt: EncodingContext, ) -> Self { match ctxt.format() { #[cfg(feature = "gvariant")] EncodingFormat::GVariant => { Self::GVariant(GVSerializer::new(signature, writer, fds, ctxt)) } EncodingFormat::DBus => Self::DBus(DBusSerializer::new(signature, writer, fds, ctxt)), } } /// Unwrap the `Writer` reference from the `Serializer`. #[inline] pub fn into_inner(self) -> &'ser mut W { match self { #[cfg(feature = "gvariant")] Self::GVariant(ser) => ser.0.writer, Self::DBus(ser) => ser.0.writer, } } } impl<'ser, 'sig, B, W> SerializerCommon<'ser, 'sig, B, W> where B: byteorder::ByteOrder, W: Write + Seek, { pub(crate) fn add_fd(&mut self, fd: RawFd) -> u32 { if let Some(idx) = self.fds.iter().position(|&x| x == fd) { return idx as u32; } let idx = self.fds.len(); self.fds.push(fd); idx as u32 } 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(Error::Io)?; } } 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(()) } 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 self.add_padding(u32::alignment(self.ctxt.format()))?; self.write_u32::(variant_index).map_err(Error::Io)?; Ok(()) } fn abs_pos(&self) -> usize { self.ctxt.position() + self.bytes_written } } impl<'ser, 'sig, B, W> Write for SerializerCommon<'ser, 'sig, B, W> where B: byteorder::ByteOrder, 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() } } macro_rules! serialize_method { ($method:ident($($arg:ident: $type:ty),*)) => { serialize_method!(; $method($($arg: $type),*) => () =); }; ($($generic:ident),* ; $method:ident($($arg:ident: $type:ty),*)) => { serialize_method!($($generic),*; $method($($arg: $type),*) => () =); }; ($($generic:ident),* ; $method:ident($($arg:ident: $type:ty),*) => $ret:ty = $($map:ident)*) => { #[inline] fn $method<$($generic),*>(self, $($arg: $type),*) -> Result<$ret> where $($generic: ?Sized + Serialize),* { match self { #[cfg(feature = "gvariant")] Serializer::GVariant(ser) => { ser.$method($($arg),*)$(.map($map::GVariant))* } Serializer::DBus(ser) => { ser.$method($($arg),*)$(.map($map::DBus))* } } } } } impl<'ser, 'sig, 'b, B, W> ser::Serializer for &'b mut Serializer<'ser, 'sig, B, W> where B: byteorder::ByteOrder, W: Write + Seek, { type Ok = (); type Error = Error; type SerializeSeq = SeqSerializer<'ser, 'sig, 'b, B, W>; type SerializeTuple = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeTupleStruct = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeTupleVariant = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeMap = SeqSerializer<'ser, 'sig, 'b, B, W>; type SerializeStruct = StructSerializer<'ser, 'sig, 'b, B, W>; type SerializeStructVariant = StructSerializer<'ser, 'sig, 'b, B, W>; serialize_method!(serialize_bool(b: bool)); serialize_method!(serialize_i8(i: i8)); serialize_method!(serialize_i16(i: i16)); serialize_method!(serialize_i32(i: i32)); serialize_method!(serialize_i64(i: i64)); serialize_method!(serialize_u8(u: u8)); serialize_method!(serialize_u16(u: u16)); serialize_method!(serialize_u32(u: u32)); serialize_method!(serialize_u64(u: u64)); serialize_method!(serialize_f32(f: f32)); serialize_method!(serialize_f64(f: f64)); serialize_method!(serialize_char(c: char)); serialize_method!(serialize_str(s: &str)); serialize_method!(serialize_bytes(b: &[u8])); serialize_method!(T; serialize_some(v: &T)); serialize_method!(serialize_none()); serialize_method!(serialize_unit()); serialize_method!(serialize_unit_struct(s: &'static str)); serialize_method!(serialize_unit_variant( n: &'static str, i: u32, v: &'static str )); serialize_method!(T; serialize_newtype_struct(n: &'static str, v: &T)); serialize_method!(T; serialize_newtype_variant(n: &'static str, i: u32, va: &'static str, v: &T)); serialize_method!(; serialize_seq(l: Option) => Self::SerializeSeq = SeqSerializer); serialize_method!(; serialize_tuple_variant( n: &'static str, i: u32, v: &'static str, l: usize ) => Self::SerializeTupleVariant = StructSerializer); serialize_method!(;serialize_struct_variant( n: &'static str, i: u32, v: &'static str, l: usize ) => Self::SerializeStructVariant = StructSerializer); serialize_method!(; serialize_tuple(l: usize) => Self::SerializeTuple = StructSerializer); serialize_method!(; serialize_tuple_struct( n: &'static str, l: usize ) => Self::SerializeTupleStruct = StructSerializer); serialize_method!(; serialize_map(l: Option) => Self::SerializeMap = SeqSerializer); serialize_method!(; serialize_struct( n: &'static str, l: usize ) => Self::SerializeStruct = StructSerializer); } macro_rules! serialize_impl { ($trait:ident, $impl:ident, $($method:ident($($arg:ident: $type:ty),*))+) => { impl<'ser, 'sig, 'b, B, W> ser::$trait for $impl<'ser, 'sig, 'b, B, W> where B: byteorder::ByteOrder, W: Write + Seek, { type Ok = (); type Error = Error; $( fn $method(&mut self, $($arg: $type),*) -> Result<()> where T: ?Sized + Serialize, { match self { #[cfg(feature = "gvariant")] $impl::GVariant(ser) => ser.$method($($arg),*), $impl::DBus(ser) => ser.$method($($arg),*), } } )* fn end(self) -> Result<()> { match self { #[cfg(feature = "gvariant")] $impl::GVariant(ser) => ser.end(), $impl::DBus(ser) => ser.end(), } } } } } #[doc(hidden)] pub enum SeqSerializer<'ser, 'sig, 'b, B, W> { DBus(dbus::SeqSerializer<'ser, 'sig, 'b, B, W>), #[cfg(feature = "gvariant")] GVariant(gvariant::SeqSerializer<'ser, 'sig, 'b, B, W>), } serialize_impl!(SerializeSeq, SeqSerializer, serialize_element(value: &T)); #[doc(hidden)] pub enum StructSerializer<'ser, 'sig, 'b, B, W> { DBus(dbus::StructSerializer<'ser, 'sig, 'b, B, W>), #[cfg(feature = "gvariant")] GVariant(gvariant::StructSerializer<'ser, 'sig, 'b, B, W>), } serialize_impl!(SerializeTuple, StructSerializer, serialize_element(v: &T)); serialize_impl!( SerializeTupleStruct, StructSerializer, serialize_field(v: &T) ); serialize_impl!( SerializeTupleVariant, StructSerializer, serialize_field(v: &T) ); serialize_impl!( SerializeStruct, StructSerializer, serialize_field(k: &'static str, v: &T) ); serialize_impl!( SerializeStructVariant, StructSerializer, serialize_field(k: &'static str, v: &T) ); serialize_impl!(SerializeMap, SeqSerializer, serialize_key(v: &T) serialize_value(v: &T)); zvariant-2.10.0/src/serialize_value.rs000064400000000000000000000026400072674642500161140ustar 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, EncodingContext, SerializeValue}; /// # /// # let ctxt = EncodingContext::::new_dbus(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-2.10.0/src/signature.rs000064400000000000000000000320120072674642500147260ustar 00000000000000use core::{ convert::TryFrom, fmt::{self, Debug, Display, Formatter}, str, }; use serde::{ de::{Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, }; use static_assertions::assert_impl_all; use std::{ ops::{Bound, RangeBounds}, sync::Arc, }; use crate::{signature_parser::SignatureParser, Basic, EncodingFormat, 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(PartialEq, Eq, Hash, Clone)] enum Bytes<'b> { Borrowed(&'b [u8]), Static(&'static [u8]), Owned(Arc<[u8]>), } impl<'b> Bytes<'b> { fn borrowed<'s: 'b>(bytes: &'s [u8]) -> Self { Self::Borrowed(bytes) } fn owned(bytes: Vec) -> Self { Self::Owned(bytes.into()) } } impl<'b> std::ops::Deref for Bytes<'b> { type Target = [u8]; fn deref(&self) -> &[u8] { match self { Bytes::Borrowed(borrowed) => borrowed, Bytes::Static(borrowed) => borrowed, Bytes::Owned(owned) => owned, } } } /// String that [identifies] the type of an encoded value. /// /// # Examples /// /// ``` /// use core::convert::TryFrom; /// use zvariant::Signature; /// /// // Valid signatures /// let s = Signature::try_from("").unwrap(); /// assert_eq!(s, ""); /// let s = Signature::try_from("y").unwrap(); /// assert_eq!(s, "y"); /// let s = Signature::try_from("xs").unwrap(); /// assert_eq!(s, "xs"); /// let s = Signature::try_from("(ysa{sd})").unwrap(); /// assert_eq!(s, "(ysa{sd})"); /// let s = Signature::try_from("a{sd}").unwrap(); /// assert_eq!(s, "a{sd}"); /// /// // 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(Eq, Hash, Clone)] 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] } /// 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 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 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, } } /// 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. 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 } } impl<'a> Debug for Signature<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { // FIXME: Should we display all the bytes along with self.pos and self.end, instead? f.write_str("Signature: [\n")?; for byte in self.as_bytes() { f.write_fmt(format_args!("\t{} ({}),\n", *byte as char, byte))?; } f.write_str("]") } } impl<'a> Basic for Signature<'a> { const SIGNATURE_CHAR: char = 'g'; const SIGNATURE_STR: &'static str = "g"; const ALIGNMENT: usize = 1; fn alignment(format: EncodingFormat) -> usize { match format { EncodingFormat::DBus => 1, #[cfg(feature = "gvariant")] EncodingFormat::GVariant => 1, } } } impl<'a> Type for Signature<'a> { fn signature() -> Signature<'static> { Signature::from_static_str_unchecked(Self::SIGNATURE_STR) } } impl<'a, 'b> From<&'b Signature<'a>> for Signature<'a> { fn from(signature: &'b Signature<'a>) -> Signature<'a> { signature.clone() } } impl<'a> TryFrom<&'a [u8]> for Signature<'a> { type Error = Error; fn try_from(value: &'a [u8]) -> Result { ensure_correct_signature_str(value)?; // SAFETY: ensure_correct_signature_str 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()) } } impl<'a> TryFrom for Signature<'a> { type Error = Error; fn try_from(value: String) -> Result { ensure_correct_signature_str(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() } } impl<'a, 'b> PartialEq> for Signature<'b> { fn eq(&self, other: &Signature<'_>) -> bool { self.as_bytes() == other.as_bytes() } } 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() } } 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 visitor = SignatureVisitor; deserializer.deserialize_str(visitor) } } struct SignatureVisitor; impl<'de> Visitor<'de> for SignatureVisitor { type Value = Signature<'de>; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("a Signature") } #[inline] fn visit_borrowed_str(self, value: &'de str) -> core::result::Result, E> where E: serde::de::Error, { Signature::try_from(value).map_err(serde::de::Error::custom) } #[inline] fn visit_str(self, value: &str) -> core::result::Result, E> where E: serde::de::Error, { Signature::try_from(String::from(value)).map_err(serde::de::Error::custom) } } fn ensure_correct_signature_str(signature: &[u8]) -> Result<()> { if signature.len() > 255 { return Err(serde::de::Error::invalid_length( signature.len(), &"<= 255 characters", )); } if signature.is_empty() { return Ok(()); } // SAFETY: SignatureParser never calls as_str let signature = unsafe { Signature::from_bytes_unchecked(signature) }; let mut parser = SignatureParser::new(signature); while !parser.done() { let _ = parser.parse_next_signature()?; } Ok(()) } /// Owned [`Signature`](struct.Signature.html) #[derive(Debug, Clone, PartialEq, serde::Serialize, zvariant_derive::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 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<'de> Deserialize<'de> for OwnedSignature { fn deserialize(deserializer: D) -> core::result::Result where D: Deserializer<'de>, { let visitor = SignatureVisitor; deserializer .deserialize_string(visitor) .map(|v| OwnedSignature(v.to_owned())) } } #[cfg(test)] mod tests { use super::Signature; #[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..), ""); } } zvariant-2.10.0/src/signature_parser.rs000064400000000000000000000214100072674642500163020ustar 00000000000000use std::ops::{Bound, RangeBounds}; use crate::{Basic, Fd, ObjectPath, Result, Signature}; #[cfg(feature = "gvariant")] use crate::utils::MAYBE_SIGNATURE_CHAR; use crate::utils::{ ARRAY_SIGNATURE_CHAR, DICT_ENTRY_SIG_START_CHAR, STRUCT_SIG_END_STR, STRUCT_SIG_START_CHAR, STRUCT_SIG_START_STR, 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 fn signature(&self) -> Signature<'_> { self.signature.slice(self.pos..self.end) } pub fn next_char(&self) -> char { // SAFETY: Other methods that increment `self.pos` must ensure we don't go beyond signature // length. // FIXME: Probably best/safer if this method returned Option char::from(self.signature.as_bytes()[self.pos]) } #[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 | Fd::SIGNATURE_CHAR | VARIANT_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() < 2 { return Err(serde::de::Error::invalid_length( signature.len(), &">= 2 characters", )); } // We can't get None here cause we already established there are at least 2 chars above let c = signature .as_bytes() .first() .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, )); } let mut open_braces = 1; let mut i = 1; while i < signature.len() - 1 { if &signature[i..=i] == STRUCT_SIG_END_STR { open_braces -= 1; if open_braces == 0 { break; } } else if &signature[i..=i] == STRUCT_SIG_START_STR { open_braces += 1; } i += 1; } let end = &signature[i..=i]; if end != STRUCT_SIG_END_STR { return Err(serde::de::Error::invalid_value( serde::de::Unexpected::Str(end), &crate::STRUCT_SIG_END_STR, )); } Ok(self.signature_slice(0, i + 1)) } 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 c = signature .as_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, )); } // Key's signature will always be just 1 character so no need to slice for that. // 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 + `}` Ok(self.signature_slice(0, value_len + 3)) } fn signature_slice(&self, idx: usize, end: usize) -> Signature<'_> { self.signature.slice(self.pos + idx..self.pos + end) } } zvariant-2.10.0/src/str.rs000064400000000000000000000113750072674642500135460ustar 00000000000000// FIXME: Drop this when the deprecated `Basic::ALIGNMENT` is dropped in the next API break. #![allow(deprecated)] use serde::{Deserialize, Deserializer, Serialize, Serializer}; use static_assertions::assert_impl_all; use std::hash::{Hash, Hasher}; use crate::{Basic, EncodingFormat, 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(Debug, Default, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)] #[serde(rename(serialize = "zvariant::Str", deserialize = "zvariant::Str"))] pub struct Str<'a>(#[serde(borrow)] Inner<'a>); #[derive(Debug, Eq, Clone)] enum Inner<'a> { Static(&'static str), Borrowed(&'a str), Owned(Box), } 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> 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 fn from_static(s: &'static str) -> Self { Str(Inner::Static(s)) } /// A borrowed clone (this never allocates, unlike clone). 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.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; const ALIGNMENT: usize = <&str>::ALIGNMENT; fn alignment(format: EncodingFormat) -> 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 String { fn from(value: Str<'a>) -> String { match value.0 { Inner::Static(s) => s.into(), Inner::Borrowed(s) => s.into(), Inner::Owned(s) => s.into(), } } } impl<'a> From<&'a Str<'a>> for &'a str { fn from(value: &'a Str<'a>) -> &'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::Display for Str<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.as_str().fmt(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"); } } zvariant-2.10.0/src/structure.rs000064400000000000000000000265760072674642500150070ustar 00000000000000use serde::{ de::{DeserializeSeed, Deserializer, SeqAccess, Visitor}, ser::{Serialize, SerializeTupleStruct, Serializer}, }; use static_assertions::assert_impl_all; use std::convert::TryInto; use crate::{ signature_parser::SignatureParser, value::SignatureSeed, DynamicDeserialize, DynamicType, OwnedValue, Signature, Type, Value, }; /// Use this to efficiently build a [`Structure`]. /// /// [`Structure`]: struct.Structure.html #[derive(Debug, Default, Clone, 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. 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`. 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)] 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. pub fn new_unchecked(signature: Signature<'a>) -> Self { StructureSeed(signature) } } impl<'a> std::convert::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)] 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, Clone, PartialEq)] 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 } /// Create a new `Structure`. /// /// Same as `Structure::default()`. #[deprecated( since = "2.3.0", note = "Please use `StructureBuilder` to create a `Structure` instead." )] 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. #[deprecated( since = "2.3.0", note = "Please use `StructureBuilder` to create a `Structure` instead." )] pub fn add_field(self, field: T) -> Self where T: Type + Into>, { #[allow(deprecated)] 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`. #[deprecated( since = "2.3.0", note = "Please use `StructureBuilder` to create a `Structure` instead." )] pub fn append_field<'e: 'a>(mut self, field: Value<'e>) -> Self { self.fields.push(field); self.signature = create_signature_from_fields(&self.fields); self } /// 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 to_owned(&self) -> Structure<'static> { Structure { fields: self.fields.iter().map(|v| v.to_owned()).collect(), signature: self.signature.to_owned(), } } } 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.clone() } } impl<'a> DynamicType for StructureSeed<'a> { fn dynamic_signature(&self) -> Signature<'_> { self.0.clone() } } 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.clone()); 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),+> std::convert::TryFrom> for ($($name),+,) where $($name: std::convert::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),+> std::convert::TryFrom> for ($($name),+,) where $($name: std::convert::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 std::convert::TryFrom for ($($name),+,) where $($name: std::convert::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) } zvariant-2.10.0/src/type.rs000064400000000000000000000246670072674642500137270ustar 00000000000000use crate::{utils::*, Signature}; use serde::de::{Deserialize, DeserializeSeed}; use std::{convert::TryInto, marker::PhantomData}; /// 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/2.0.0/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.clone(); 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); #[cfg(feature = "arrayvec")] impl Type for arrayvec::ArrayVec where A: arrayvec::Array, T: Type, { #[inline] fn signature() -> Signature<'static> { <[T]>::signature() } } #[cfg(feature = "arrayvec")] impl Type for arrayvec::ArrayString where A: arrayvec::Array + Copy, { #[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("") } } impl Type for &T where T: ?Sized + Type, { #[inline] fn signature() -> Signature<'static> { T::signature() } } #[cfg(feature = "gvariant")] impl Type for Option where T: Type, { #[inline] fn signature() -> Signature<'static> { Signature::from_string_unchecked(format!("m{}", T::signature())) } } //////////////////////////////////////////////////////////////////////////////// macro_rules! tuple_impls { ($($len:expr => ($($n:tt $name:ident)+))+) => { $( impl<$($name),+> Type for ($($name,)+) where $($name: Type,)+ { #[inline] 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. // TODO: Mention this fact in the module docs. macro_rules! array_impls { ($($len:tt)+) => { $( impl Type for [T; $len] where T: Type, { #[inline] #[allow(clippy::reversed_empty_ranges)] fn signature() -> Signature<'static> { let mut sig = String::with_capacity(255); sig.push(STRUCT_SIG_START_CHAR); if $len > 0 { for _ in 0..$len { sig.push_str(T::signature().as_str()); } } sig.push(STRUCT_SIG_END_CHAR); Signature::from_string_unchecked(sig) } } )+ } } array_impls! { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 } //////////////////////////////////////////////////////////////////////////////// use std::{ borrow::Cow, collections::{BTreeMap, HashMap}, hash::{BuildHasher, Hash}, }; macro_rules! map_impl { ($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)* >) => { impl Type for $ty where K: Type $(+ $kbound1 $(+ $kbound2)*)*, V: Type, $($typaram: $bound,)* { #[inline] fn signature() -> Signature<'static> { Signature::from_string_unchecked(format!("a{{{}{}}}", K::signature(), V::signature())) } } } } map_impl!(BTreeMap); map_impl!(HashMap); impl Type for Cow<'_, T> where T: ?Sized + Type + ToOwned, { #[inline] fn signature() -> Signature<'static> { T::signature() } } // BitFlags #[cfg(feature = "enumflags2")] impl Type for enumflags2::BitFlags where F: Type + enumflags2::RawBitFlags, { #[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") } } // TODO: Blanket implementation for more types: https://github.com/serde-rs/serde/blob/master/serde/src/ser/impls.rs zvariant-2.10.0/src/utils.rs000064400000000000000000000247330072674642500141000ustar 00000000000000#[cfg(feature = "gvariant")] use crate::{signature_parser::SignatureParser, Error}; use crate::{Basic, EncodingFormat, Fd, ObjectPath, Signature}; /// 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 <= (std::u32::MAX as usize), "{} too large for `u32`", value, ); value as u32 } pub(crate) fn usize_to_u8(value: usize) -> u8 { assert!( value <= (std::u8::MAX as usize), "{} too large for `u8`", value, ); value as u8 } pub(crate) fn f64_to_f32(value: f64) -> f32 { assert!( value <= (std::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: EncodingFormat) -> usize { match signature .as_bytes() .first() .map(|b| *b as char) .expect("alignment_for_signature expects **one** complete & correct signature") { 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 | 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 { EncodingFormat::DBus => VARIANT_ALIGNMENT_DBUS, #[cfg(feature = "gvariant")] EncodingFormat::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), _ => { println!("WARNING: Unsupported signature: {}", signature); 0 } } } #[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 | 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: EncodingFormat, dbus_align: usize, ) -> usize { match format { EncodingFormat::DBus => dbus_align, #[cfg(feature = "gvariant")] EncodingFormat::GVariant => { let child_signature = Signature::from_str_unchecked(&signature[1..]); alignment_for_signature(&child_signature, format) } } } fn alignment_for_array_signature(signature: &Signature<'_>, format: EncodingFormat) -> usize { alignment_for_single_child_type_signature(signature, format, ARRAY_ALIGNMENT_DBUS) } #[cfg(feature = "gvariant")] fn alignment_for_maybe_signature(signature: &Signature<'_>, format: EncodingFormat) -> usize { alignment_for_single_child_type_signature(signature, format, 1) } fn alignment_for_struct_signature( #[allow(unused)] signature: &Signature<'_>, format: EncodingFormat, ) -> usize { match format { EncodingFormat::DBus => STRUCT_ALIGNMENT_DBUS, #[cfg(feature = "gvariant")] EncodingFormat::GVariant => { 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() .expect("invalid 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; } } } alignment } } } fn alignment_for_dict_entry_signature( #[allow(unused)] signature: &Signature<'_>, format: EncodingFormat, ) -> usize { match format { EncodingFormat::DBus => DICT_ENTRY_ALIGNMENT_DBUS, #[cfg(feature = "gvariant")] EncodingFormat::GVariant => { 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 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 { value_alignment } else { 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() .expect("invalid 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) } zvariant-2.10.0/src/value.rs000064400000000000000000000546240072674642500140560ustar 00000000000000use core::str; use std::{convert::TryFrom, marker::PhantomData}; use serde::{ de::{ Deserialize, DeserializeSeed, Deserializer, Error, MapAccess, SeqAccess, Unexpected, Visitor, }, ser::{Serialize, SerializeSeq, SerializeStruct, SerializeTupleStruct, Serializer}, }; use static_assertions::assert_impl_all; #[cfg(feature = "gvariant")] use crate::Maybe; use crate::{ signature_parser::SignatureParser, utils::*, Array, Basic, Dict, DynamicType, Fd, ObjectPath, OwnedValue, Signature, Str, Structure, StructureBuilder, Type, }; /// 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 std::convert::TryFrom; /// use zvariant::{from_slice, to_bytes, EncodingContext, Value}; /// /// // Create a Value from an i16 /// let v = Value::new(i16::max_value()); /// /// // Encode it /// let ctxt = EncodingContext::::new_dbus(0); /// let encoding = to_bytes(ctxt, &v).unwrap(); /// /// // Decode it back /// let v: Value = from_slice(&encoding, ctxt).unwrap(); /// /// // Check everything is as expected /// assert_eq!(i16::try_from(&v).unwrap(), i16::max_value()); /// ``` /// /// Now let's try a more complicated example: /// /// ``` /// use std::convert::TryFrom; /// use zvariant::{from_slice, to_bytes, EncodingContext}; /// 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 = EncodingContext::::new_dbus(0); /// let encoding = to_bytes(ctxt, &v).unwrap(); /// let v: Value = from_slice(&encoding, ctxt).unwrap(); /// /// // 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, Clone, PartialEq)] 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>), Fd(Fd), } 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), 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() } } pub(crate) fn to_owned(&self) -> Value<'static> { 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::from(&**v); Value::Value(Box::new(o.into_inner())) } Value::Array(v) => Value::Array(v.to_owned()), Value::Dict(v) => Value::Dict(v.to_owned()), Value::Structure(v) => Value::Structure(v.to_owned()), #[cfg(feature = "gvariant")] Value::Maybe(v) => Value::Maybe(v.to_owned()), Value::Fd(v) => Value::Fd(*v), } } /// 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().clone(), Value::Dict(value) => value.full_signature().clone(), Value::Structure(value) => value.full_signature().clone(), #[cfg(feature = "gvariant")] Value::Maybe(value) => value.full_signature().clone(), Value::Fd(_) => Fd::signature(), } } 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) } #[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 std::convert::TryFrom; /// use zvariant::{Result, Value}; /// /// fn value_vec_to_type_vec<'a, T>(values: Vec>) -> Result> /// where /// T: TryFrom>, /// { /// let mut res = vec![]; /// for value in values.into_iter() { /// res.push(value.downcast().unwrap()); /// } /// /// 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) -> Option where T: TryFrom>, { if let Value::Value(v) = self { T::try_from(*v).ok() } else { T::try_from(self).ok() } } /// Try to get a reference to the underlying type `T`. /// /// Same as [`downcast`] except it doesn't consume `self` and get a reference to the underlying /// value. /// /// # Examples /// /// ``` /// use std::convert::TryFrom; /// use zvariant::{Result, Value}; /// /// fn value_vec_to_type_vec<'a, T>(values: &'a Vec>) -> Result> /// where /// &'a T: TryFrom<&'a Value<'a>>, /// { /// let mut res = vec![]; /// for value in values.into_iter() { /// res.push(value.downcast_ref().unwrap()); /// } /// /// 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) -> Option<&'a T> where T: ?Sized, &'a T: TryFrom<&'a Value<'a>>, { if let Value::Value(v) = self { <&T>::try_from(v).ok() } else { <&T>::try_from(self).ok() } } } 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") } #[inline] 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> { #[inline] 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) } #[inline] 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.clone()); 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) => { #[inline] 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); #[inline] 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", ) })? { b'h' => Fd::from(value).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); #[inline] 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", )), } } #[inline] fn visit_map(self, mut visitor: V) -> Result, V::Error> where V: MapAccess<'de>, { 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)) } #[inline] #[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) } }