diff --git a/zbus/src/blocking/proxy/mod.rs b/zbus/src/blocking/proxy/mod.rs index df40e1b97..3d8f67136 100644 --- a/zbus/src/blocking/proxy/mod.rs +++ b/zbus/src/blocking/proxy/mod.rs @@ -227,7 +227,7 @@ impl<'a> Proxy<'a> { M: TryInto>, M::Error: Into, B: serde::ser::Serialize + zvariant::DynamicType, - R: serde::de::DeserializeOwned + zvariant::Type, + R: for<'d> zvariant::DynamicDeserialize<'d>, { block_on(self.inner().call(method_name, body)) } @@ -251,7 +251,7 @@ impl<'a> Proxy<'a> { M: TryInto>, M::Error: Into, B: serde::ser::Serialize + zvariant::DynamicType, - R: serde::de::DeserializeOwned + zvariant::Type, + R: for<'d> zvariant::DynamicDeserialize<'d>, { block_on(self.inner().call_with_flags(method_name, flags, body)) } diff --git a/zbus/src/proxy/mod.rs b/zbus/src/proxy/mod.rs index 3023e9763..310fbcee1 100644 --- a/zbus/src/proxy/mod.rs +++ b/zbus/src/proxy/mod.rs @@ -840,7 +840,7 @@ impl<'a> Proxy<'a> { M: TryInto>, M::Error: Into, B: serde::ser::Serialize + zvariant::DynamicType, - R: serde::de::DeserializeOwned + zvariant::Type, + R: for<'d> zvariant::DynamicDeserialize<'d>, { let reply = self.call_method(method_name, body).await?; @@ -866,7 +866,7 @@ impl<'a> Proxy<'a> { M: TryInto>, M::Error: Into, B: serde::ser::Serialize + zvariant::DynamicType, - R: serde::de::DeserializeOwned + zvariant::Type, + R: for<'d> zvariant::DynamicDeserialize<'d>, { let flags = flags.iter().map(Flags::from).collect::>(); match self diff --git a/zbus_macros/src/proxy.rs b/zbus_macros/src/proxy.rs index e832039cf..81d98449a 100644 --- a/zbus_macros/src/proxy.rs +++ b/zbus_macros/src/proxy.rs @@ -559,7 +559,7 @@ fn gen_proxy_method_call( let object_path: #zbus::zvariant::OwnedObjectPath = self.0.call( #method_name, - &(#(#args),*), + &#zbus::zvariant::DynamicTuple((#(#args,)*)), ) #wait?; #proxy_path::builder(&self.0.connection()) @@ -574,11 +574,11 @@ fn gen_proxy_method_call( // the '()' from the signature that we add and not the actual intended ones. let arg = &args[0]; quote! { - &(#arg,) + &#zbus::zvariant::DynamicTuple((#arg,)) } } else { quote! { - &(#(#args),*) + &#zbus::zvariant::DynamicTuple((#(#args),*)) } }; diff --git a/zbus_macros/tests/tests.rs b/zbus_macros/tests/tests.rs index 7032c70b3..b9b5303ff 100644 --- a/zbus_macros/tests/tests.rs +++ b/zbus_macros/tests/tests.rs @@ -19,7 +19,10 @@ mod param { } mod test { - use zbus::fdo; + use zbus::{ + fdo, + zvariant::{OwnedStructure, Structure}, + }; #[zbus_macros::dbus_proxy( assume_defaults = false, @@ -34,6 +37,12 @@ mod test { /// which is useful to pass in a proxy as a param. It serializes it as an `ObjectPath`. fn some_method(&self, object_path: &T) -> zbus::Result<()>; + /// A call accepting an argument that only implements DynamicType and Serialize. + fn test_dyn_type(&self, arg: Structure<'_>, arg2: u32) -> zbus::Result<()>; + + /// A call returning an type that only implements DynamicDeserialize + fn test_dyn_ret(&self) -> zbus::Result; + #[dbus_proxy(name = "CheckRENAMING")] fn check_renaming(&self) -> zbus::Result>; diff --git a/zvariant/src/lib.rs b/zvariant/src/lib.rs index b97da8dfd..1b093c2bf 100644 --- a/zvariant/src/lib.rs +++ b/zvariant/src/lib.rs @@ -86,6 +86,9 @@ pub use error::*; mod r#type; pub use r#type::*; +mod tuple; +pub use tuple::*; + mod from_value; mod into_value; diff --git a/zvariant/src/structure.rs b/zvariant/src/structure.rs index 148e042e0..b19444aa8 100644 --- a/zvariant/src/structure.rs +++ b/zvariant/src/structure.rs @@ -1,6 +1,6 @@ #![allow(unknown_lints)] use serde::{ - de::{DeserializeSeed, Deserializer, SeqAccess, Visitor}, + de::{DeserializeSeed, Deserializer, Error, SeqAccess, Visitor}, ser::{Serialize, SerializeTupleStruct, Serializer}, }; use static_assertions::assert_impl_all; @@ -405,3 +405,57 @@ fn create_signature_from_fields(fields: &[Value<'_>]) -> Signature<'static> { Signature::from_string_unchecked(signature) } + +/// Owned [`Structure`] +#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct OwnedStructure(pub Structure<'static>); + +/// Use this to deserialize an [`OwnedStructure`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct OwnedStructureSeed(Signature<'static>); + +impl DynamicType for OwnedStructure { + fn dynamic_signature(&self) -> Signature<'_> { + self.0.dynamic_signature() + } +} + +impl DynamicType for OwnedStructureSeed { + fn dynamic_signature(&self) -> Signature<'_> { + self.0.clone() + } +} + +impl<'de> DynamicDeserialize<'de> for OwnedStructure { + type Deserializer = OwnedStructureSeed; + + fn deserializer_for_signature(signature: S) -> zvariant::Result + where + S: TryInto>, + S::Error: Into, + { + Structure::deserializer_for_signature(signature) + .map(|StructureSeed(s)| OwnedStructureSeed(s.to_owned())) + } +} + +impl<'de> DeserializeSeed<'de> for OwnedStructureSeed { + type Value = OwnedStructure; + fn deserialize>(self, deserializer: D) -> Result { + deserializer + .deserialize_seq(StructureVisitor { signature: self.0 }) + .and_then(|s| match s.try_to_owned() { + Ok(s) => Ok(OwnedStructure(s)), + Err(e) => Err(D::Error::custom(e)), + }) + } +} + +impl Serialize for OwnedStructure { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.0.serialize(serializer) + } +} diff --git a/zvariant/src/tuple.rs b/zvariant/src/tuple.rs new file mode 100644 index 000000000..d5208f89f --- /dev/null +++ b/zvariant/src/tuple.rs @@ -0,0 +1,161 @@ +use crate::{ + signature_parser::SignatureParser, utils::*, DynamicDeserialize, DynamicType, Signature, +}; +use serde::{ + de::{Deserialize, DeserializeSeed, Deserializer, Error, Visitor}, + Serialize, Serializer, +}; +use std::marker::PhantomData; + +/// A helper type to serialize or deserialize a tuple whose elements implement [DynamicType] but +/// not [Type]. +/// +/// This is required because tuples already have an implementation of [DynamicType] via the blanket +/// implementation of [DynamicType] where `T: Type`, but that results in a bound of [Type] on each +/// element, which is stronger than needed for serializing. +/// +/// [Type]: trait.Type.html +#[derive(Debug, Copy, Clone)] +pub struct DynamicTuple(pub T); + +impl DynamicType for DynamicTuple<()> { + fn dynamic_signature(&self) -> Signature<'_> { + Signature::from_static_str_unchecked("") + } +} + +impl Serialize for DynamicTuple { + fn serialize(&self, serializer: S) -> Result { + self.0.serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for DynamicTuple<()> { + fn deserialize>(deserializer: D) -> Result { + <()>::deserialize(deserializer).map(DynamicTuple) + } +} + +/// A helper type for [DynamicTuple]'s [DynamicDeserialize] implementation. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TupleSeed<'a, T, S> { + sig: Signature<'a>, + seeds: S, + marker: PhantomData, +} + +impl<'a, T, S> DynamicType for TupleSeed<'a, T, S> { + fn dynamic_signature(&self) -> Signature<'_> { + self.sig.clone() + } +} + +struct TupleVisitor { + seeds: S, + marker: PhantomData, +} + +macro_rules! tuple_impls { + ($($len:expr => ($($n:tt $name:ident)+))+) => { + $( + impl<$($name),+> DynamicType for DynamicTuple<($($name,)+)> + where + $($name: DynamicType,)+ + { + fn dynamic_signature(&self) -> Signature<'_> { + let mut sig = String::with_capacity(255); + sig.push(STRUCT_SIG_START_CHAR); + $( + sig.push_str(DynamicType::dynamic_signature(&self.0.$n).as_str()); + )+ + sig.push(STRUCT_SIG_END_CHAR); + + Signature::from_string_unchecked(sig) + } + } + + impl<'de, $($name),+> DeserializeSeed<'de> for TupleSeed<'de, ($($name,)+), ($(<$name as DynamicDeserialize<'de>>::Deserializer,)+)> + where + $($name: DynamicDeserialize<'de>,)+ + { + type Value = DynamicTuple<($($name,)+)>; + + fn deserialize>(self, deserializer: D) -> Result { + deserializer.deserialize_tuple($len, TupleVisitor { seeds: self.seeds, marker: self.marker }) + } + } + + impl<'de, $($name),+> Visitor<'de> for TupleVisitor<($($name,)+), ($(<$name as DynamicDeserialize<'de>>::Deserializer,)+)> + where + $($name: DynamicDeserialize<'de>,)+ + { + type Value = DynamicTuple<($($name,)+)>; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("a tuple") + } + + fn visit_seq(self, mut visitor: V) -> Result, V::Error> + where + V: serde::de::SeqAccess<'de>, + { + Ok(DynamicTuple(($({ + match visitor.next_element_seed(self.seeds.$n) { + Ok(Some(elt)) => elt, + Ok(None) => return Err(V::Error::invalid_length($len, &"")), + Err(e) => return Err(e), + } + },)+))) + } + } + + impl<'de, $($name),+> DynamicDeserialize<'de> for DynamicTuple<($($name,)+)> + where + $($name: DynamicDeserialize<'de>,)+ + { + type Deserializer = TupleSeed<'de, ($($name,)+), ($(<$name as DynamicDeserialize<'de>>::Deserializer,)+)>; + + fn deserializer_for_signature(signature: S) -> zvariant::Result + where S: TryInto>, S::Error: Into + { + let sig = signature.try_into().map_err(Into::into)?; + if !sig.starts_with(zvariant::STRUCT_SIG_START_CHAR) { + return Err(zvariant::Error::IncorrectType); + } + if !sig.ends_with(zvariant::STRUCT_SIG_END_CHAR) { + return Err(zvariant::Error::IncorrectType); + } + + let end = sig.len() - 1; + let mut sig_parser = SignatureParser::new(sig.slice(1..end)); + + let seeds = ($({ + let elt_sig = sig_parser.parse_next_signature()?; + $name::deserializer_for_signature(elt_sig)? + },)+); + + Ok(TupleSeed { sig, seeds, marker: PhantomData }) + } + } + )+ + } +} + +tuple_impls! { + 1 => (0 T0) + 2 => (0 T0 1 T1) + 3 => (0 T0 1 T1 2 T2) + 4 => (0 T0 1 T1 2 T2 3 T3) + 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) + 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) + 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) + 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) + 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) + 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) + 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) + 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) + 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) + 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) + 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) + 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) +}