diff --git a/zbus/tests/serde.rs b/zbus/tests/serde.rs new file mode 100644 index 000000000..6f5728d8f --- /dev/null +++ b/zbus/tests/serde.rs @@ -0,0 +1,21 @@ +use byteorder::LE; +use serde::Deserialize; +use std::collections::HashMap; +use zbus::zvariant::{serialized::Context, to_bytes, OwnedValue, Type}; + +#[derive(Deserialize, Type)] +#[zvariant(signature = "a{sv}")] +struct Outer { + foo: OwnedValue, +} + +#[test_log::test] +fn convert() { + let ctxt = Context::::new_dbus(0); + let value = + >::from([("foo".into(), 23.into()), ("bar".into(), 42.into())]); + let data = to_bytes(ctxt, &value).unwrap(); + eprintln!("{data:02x?}"); + let good = data.deserialize::().unwrap().0; + eprintln!("{:?}", good.foo); +} diff --git a/zvariant/src/dbus/de.rs b/zvariant/src/dbus/de.rs index fcffff8f3..1def57d98 100644 --- a/zvariant/src/dbus/de.rs +++ b/zvariant/src/dbus/de.rs @@ -1,4 +1,5 @@ -use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Visitor}; +use core::convert::TryFrom; +use serde::de::{self, Deserialize, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Visitor}; use static_assertions::assert_impl_all; use std::{marker::PhantomData, str}; @@ -49,6 +50,7 @@ where Ok(Self(DeserializerCommon { ctxt, sig_parser, + resolve_variant: false, bytes, #[cfg(unix)] fds, @@ -102,7 +104,11 @@ where { let c = self.0.sig_parser.next_char()?; - crate::de::deserialize_any::(self, c, visitor) + if self.0.resolve_variant { + self.deserialize_str(visitor) + } else { + crate::de::deserialize_any::(self, c, visitor) + } } fn deserialize_bool(self, visitor: V) -> Result @@ -450,6 +456,7 @@ where let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser, + resolve_variant: false, bytes: subslice(self.de.0.bytes, self.de.0.pos..)?, fds: self.de.0.fds, pos: 0, @@ -622,10 +629,19 @@ where T: DeserializeSeed<'de>, { match self.stage { + ValueParseStage::Signature if self.de.0.resolve_variant => { + self.stage = ValueParseStage::Done; + self.de.0.resolve_variant = false; + let signature = Signature::deserialize(&mut *self.de)?; + + seed.deserialize(signature).map(Some) + } ValueParseStage::Signature => { self.stage = ValueParseStage::Value; - - seed.deserialize(&mut *self.de).map(Some) + self.de.0.resolve_variant = true; + let result = seed.deserialize(&mut *self.de).map(Some); + self.de.0.resolve_variant = false; + result } ValueParseStage::Value => { self.stage = ValueParseStage::Done; @@ -645,6 +661,7 @@ where let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser, + resolve_variant: false, bytes: subslice(self.de.0.bytes, value_start..)?, fds: self.de.0.fds, pos: 0, diff --git a/zvariant/src/de.rs b/zvariant/src/de.rs index de234ebde..9c7de11f9 100644 --- a/zvariant/src/de.rs +++ b/zvariant/src/de.rs @@ -31,6 +31,8 @@ pub(crate) struct DeserializerCommon<'de, 'sig, 'f, B, F> { pub(crate) sig_parser: SignatureParser<'sig>, + pub(crate) resolve_variant: bool, + pub(crate) container_depths: ContainerDepths, pub(crate) b: PhantomData, diff --git a/zvariant/src/gvariant/de.rs b/zvariant/src/gvariant/de.rs index 38fecc25d..97427da7c 100644 --- a/zvariant/src/gvariant/de.rs +++ b/zvariant/src/gvariant/de.rs @@ -46,6 +46,7 @@ where Ok(Self(DeserializerCommon { ctxt, sig_parser, + resolve_variant: false, bytes, #[cfg(unix)] fds, @@ -69,6 +70,7 @@ macro_rules! deserialize_basic { let mut dbus_de = crate::dbus::Deserializer::(DeserializerCommon:: { ctxt, sig_parser: self.0.sig_parser.clone(), + resolve_variant: false, bytes: subslice(self.0.bytes, self.0.pos..)?, fds: self.0.fds, pos: 0, @@ -229,6 +231,7 @@ where let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser: self.0.sig_parser.clone(), + resolve_variant: false, bytes: subslice(self.0.bytes, self.0.pos..end)?, fds: self.0.fds, pos: 0, @@ -548,6 +551,7 @@ where let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser: self.de.0.sig_parser.clone(), + resolve_variant: false, bytes: subslice(self.de.0.bytes, self.de.0.pos..end)?, fds: self.de.0.fds, pos: 0, @@ -616,6 +620,7 @@ where let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser: self.de.0.sig_parser.clone(), + resolve_variant: false, bytes: subslice(self.de.0.bytes, self.de.0.pos..key_end)?, fds: self.de.0.fds, pos: 0, @@ -656,6 +661,7 @@ where let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser, + resolve_variant: false, bytes: subslice(self.de.0.bytes, self.de.0.pos..value_end)?, fds: self.de.0.fds, pos: 0, @@ -742,6 +748,7 @@ where let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser, + resolve_variant: false, bytes: subslice(self.de.0.bytes, self.de.0.pos..element_end)?, fds: self.de.0.fds, pos: 0, @@ -844,6 +851,7 @@ where // No padding in signatures so just pass the same context ctxt: self.de.0.ctxt, sig_parser, + resolve_variant: false, bytes: subslice(self.de.0.bytes, self.sig_start..self.sig_end)?, fds: self.de.0.fds, pos: 0, @@ -868,6 +876,7 @@ where let mut de = Deserializer::(DeserializerCommon { ctxt, sig_parser, + resolve_variant: false, bytes: subslice(self.de.0.bytes, self.value_start..self.value_end)?, fds: self.de.0.fds, pos: 0, diff --git a/zvariant/src/signature.rs b/zvariant/src/signature.rs index 8d965536c..30ad081e6 100644 --- a/zvariant/src/signature.rs +++ b/zvariant/src/signature.rs @@ -5,7 +5,7 @@ use core::{ str, }; use serde::{ - de::{Deserialize, Deserializer}, + de::{Deserialize, Deserializer, SeqAccess, Visitor}, ser::{Serialize, Serializer}, }; use static_assertions::assert_impl_all; @@ -338,6 +338,61 @@ impl<'a> Signature<'a> { } } +macro_rules! deserialize_methods { + ($(fn $method:ident($($arg:ident: $type:ty),*);)*) => { + $( + #[inline] + fn $method(self, $($arg: $type,)* visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_str(self.as_str()) + } + )* + } +} + +impl<'de> Deserializer<'de> for Signature<'de> { + type Error = Error; + + deserialize_methods! { + fn deserialize_any(); + fn deserialize_bool(); + fn deserialize_i8(); + fn deserialize_i16(); + fn deserialize_i32(); + fn deserialize_i64(); + fn deserialize_u8(); + fn deserialize_u16(); + fn deserialize_u32(); + fn deserialize_u64(); + fn deserialize_f32(); + fn deserialize_f64(); + fn deserialize_char(); + fn deserialize_str(); + fn deserialize_string(); + fn deserialize_bytes(); + fn deserialize_byte_buf(); + fn deserialize_option(); + fn deserialize_unit(); + fn deserialize_unit_struct(_n: &'static str); + fn deserialize_newtype_struct(_n: &'static str); + fn deserialize_seq(); + fn deserialize_map(); + fn deserialize_tuple(_l: usize); + fn deserialize_tuple_struct(_n: &'static str, _l: usize); + fn deserialize_struct(_n: &'static str, _f: &'static [&'static str]); + fn deserialize_enum(_n: &'static str, _f: &'static [&'static str]); + fn deserialize_identifier(); + fn deserialize_ignored_any(); + } + + #[inline] + fn is_human_readable(&self) -> bool { + false + } +} + impl<'a> Debug for Signature<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("Signature").field(&self.as_str()).finish() @@ -499,9 +554,40 @@ impl<'de: 'a, 'a> Deserialize<'de> for Signature<'a> { where D: Deserializer<'de>, { - let val = >::deserialize(deserializer)?; + let visitor = SignatureVisitor; + + deserializer.deserialize_any(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_seq(self, mut seq: A) -> core::result::Result + where + A: SeqAccess<'de>, + { + let signature = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self)); + let _value = seq.next_element::<()>(); - Self::try_from(val).map_err(serde::de::Error::custom) + signature } }