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}