zvariant/type/dynamic.rs
1use crate::{Signature, Type};
2use serde::de::{Deserialize, DeserializeSeed};
3use std::marker::PhantomData;
4
5/// Types with dynamic signatures.
6///
7/// Prefer implementing [Type] if possible, but if the actual signature of your type cannot be
8/// determined until runtime, you can implement this type to support serialization. You should
9/// also implement [DynamicDeserialize] for deserialization.
10pub trait DynamicType {
11 /// The type signature for `self`.
12 ///
13 /// See [`Type::SIGNATURE`] for details.
14 fn signature(&self) -> Signature;
15}
16
17/// Types that deserialize based on dynamic signatures.
18///
19/// Prefer implementing [Type] and [Deserialize] if possible, but if the actual signature of your
20/// type cannot be determined until runtime, you should implement this type to support
21/// deserialization given a signature.
22pub trait DynamicDeserialize<'de>: DynamicType {
23 /// A [DeserializeSeed] implementation for this type.
24 type Deserializer: DeserializeSeed<'de, Value = Self> + DynamicType;
25
26 /// Get a deserializer compatible with this parsed signature.
27 fn deserializer_for_signature(signature: &Signature) -> zvariant::Result<Self::Deserializer>;
28}
29
30impl<T> DynamicType for T
31where
32 T: Type + ?Sized,
33{
34 fn signature(&self) -> Signature {
35 <T as Type>::SIGNATURE.clone()
36 }
37}
38
39impl<'de, T> DynamicDeserialize<'de> for T
40where
41 T: Type + Deserialize<'de>,
42{
43 type Deserializer = PhantomData<T>;
44
45 fn deserializer_for_signature(signature: &Signature) -> zvariant::Result<Self::Deserializer> {
46 let expected = <T as Type>::SIGNATURE;
47
48 if expected != signature {
49 match expected {
50 Signature::Structure(fields)
51 if fields.len() == 1 && fields.iter().next().unwrap() == signature =>
52 {
53 // This is likely a D-Bus message body containing a single type being
54 // deserialized as a single-field struct. No need to be super strict here.
55 }
56 _ => {
57 return Err(zvariant::Error::SignatureMismatch(
58 signature.clone(),
59 format!("`{expected}`"),
60 ))
61 }
62 }
63 }
64
65 Ok(PhantomData)
66 }
67}