Skip to main content

tokio_dbus_runtime/
decode.rs

1use std::collections::{BTreeMap, HashMap};
2use std::hash::{BuildHasher, Hash};
3
4use tokio_dbus::{Alignment, Body, ObjectPath, ObjectPathBuf, Signature, SignatureBuf};
5
6use crate::Result;
7
8/// A Rust value which can be read from a D-Bus message body.
9///
10/// # Examples
11///
12/// ```
13/// use tokio_dbus::{BodyBuf, Signature};
14/// use tokio_dbus_runtime::Decode;
15///
16/// let mut buf = BodyBuf::new();
17/// buf.extend_signature(Signature::new("su")?)?;
18/// buf.raw().store("Hello");
19/// buf.raw().store(42u32);
20///
21/// let mut body = buf.as_body();
22/// assert_eq!(String::decode(&mut body)?, "Hello");
23/// assert_eq!(u32::decode(&mut body)?, 42);
24/// # Ok::<_, tokio_dbus_runtime::Error>(())
25/// ```
26pub trait Decode: Sized {
27    /// The alignment of the encoded value.
28    const ALIGNMENT: Alignment;
29
30    /// Read one value from the body.
31    fn decode(body: &mut Body<'_>) -> Result<Self>;
32}
33
34macro_rules! decode_frame {
35    ($($ty:ty, $alignment:ident),* $(,)?) => {
36        $(
37            impl Decode for $ty {
38                const ALIGNMENT: Alignment = Alignment::$alignment;
39
40                #[inline]
41                fn decode(body: &mut Body<'_>) -> Result<Self> {
42                    Ok(body.load::<$ty>()?)
43                }
44            }
45        )*
46    }
47}
48
49decode_frame! {
50    u8, BYTE,
51    i16, U16,
52    u16, U16,
53    i32, U32,
54    u32, U32,
55    i64, U64,
56    u64, U64,
57    f64, U64,
58}
59
60impl Decode for bool {
61    const ALIGNMENT: Alignment = Alignment::U32;
62
63    #[inline]
64    fn decode(body: &mut Body<'_>) -> Result<Self> {
65        Ok(body.load_bool()?)
66    }
67}
68
69impl Decode for String {
70    const ALIGNMENT: Alignment = Alignment::U32;
71
72    #[inline]
73    fn decode(body: &mut Body<'_>) -> Result<Self> {
74        Ok(body.read::<str>()?.to_owned())
75    }
76}
77
78impl Decode for ObjectPathBuf {
79    const ALIGNMENT: Alignment = Alignment::U32;
80
81    #[inline]
82    fn decode(body: &mut Body<'_>) -> Result<Self> {
83        Ok(body.read::<ObjectPath>()?.to_owned())
84    }
85}
86
87impl Decode for SignatureBuf {
88    const ALIGNMENT: Alignment = Alignment::BYTE;
89
90    #[inline]
91    fn decode(body: &mut Body<'_>) -> Result<Self> {
92        Ok(body.read::<Signature>()?.to_owned())
93    }
94}
95
96impl<T> Decode for Vec<T>
97where
98    T: Decode,
99{
100    const ALIGNMENT: Alignment = Alignment::U32;
101
102    fn decode(body: &mut Body<'_>) -> Result<Self> {
103        let mut array = body.load_raw_array(T::ALIGNMENT)?;
104        let mut out = Vec::new();
105
106        while !array.is_empty() {
107            out.push(T::decode(&mut array)?);
108        }
109
110        Ok(out)
111    }
112}
113
114/// Read an array of dict entries.
115fn decode_entries<K, V, O>(body: &mut Body<'_>, mut insert: impl FnMut(&mut O, K, V)) -> Result<O>
116where
117    K: Decode,
118    V: Decode,
119    O: Default,
120{
121    // NB: Dict entries are aligned just like structs.
122    let mut array = body.load_raw_array(Alignment::U64)?;
123    let mut out = O::default();
124
125    while !array.is_empty() {
126        array.align_to(Alignment::U64)?;
127        let key = K::decode(&mut array)?;
128        let value = V::decode(&mut array)?;
129        insert(&mut out, key, value);
130    }
131
132    Ok(out)
133}
134
135impl<K, V, S> Decode for HashMap<K, V, S>
136where
137    K: Decode + Eq + Hash,
138    V: Decode,
139    S: Default + BuildHasher,
140{
141    const ALIGNMENT: Alignment = Alignment::U32;
142
143    fn decode(body: &mut Body<'_>) -> Result<Self> {
144        decode_entries(body, |out: &mut Self, key, value| {
145            out.insert(key, value);
146        })
147    }
148}
149
150impl<K, V> Decode for BTreeMap<K, V>
151where
152    K: Decode + Ord,
153    V: Decode,
154{
155    const ALIGNMENT: Alignment = Alignment::U32;
156
157    fn decode(body: &mut Body<'_>) -> Result<Self> {
158        decode_entries(body, |out: &mut Self, key, value| {
159            out.insert(key, value);
160        })
161    }
162}
163
164macro_rules! decode_tuple {
165    ($($ty:ident),*) => {
166        impl<$($ty,)*> Decode for ($($ty,)*)
167        where
168            $($ty: Decode,)*
169        {
170            // NB: Structs are aligned to 8 bytes.
171            const ALIGNMENT: Alignment = Alignment::U64;
172
173            #[inline]
174            fn decode(body: &mut Body<'_>) -> Result<Self> {
175                body.align_to(Alignment::U64)?;
176                Ok(($($ty::decode(body)?,)*))
177            }
178        }
179    }
180}
181
182decode_tuple!(A);
183decode_tuple!(A, B);
184decode_tuple!(A, B, C);
185decode_tuple!(A, B, C, D);
186decode_tuple!(A, B, C, D, E);
187decode_tuple!(A, B, C, D, E, F);
188decode_tuple!(A, B, C, D, E, F, G);
189decode_tuple!(A, B, C, D, E, F, G, H);
190decode_tuple!(A, B, C, D, E, F, G, H, I);
191decode_tuple!(A, B, C, D, E, F, G, H, I, J);
192decode_tuple!(A, B, C, D, E, F, G, H, I, J, K);
193decode_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);