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
8pub trait Decode: Sized {
27 const ALIGNMENT: Alignment;
29
30 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
114fn 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 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 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);