Skip to main content

tokio_dbus_runtime/
encode.rs

1use std::collections::{BTreeMap, HashMap};
2use std::hash::BuildHasher;
3
4use tokio_dbus::{Alignment, ObjectPath, ObjectPathBuf, Raw, Signature, SignatureBuf};
5
6/// A Rust value which can be written to a D-Bus message body.
7///
8/// This is implemented for the owned types that generated code uses, and for
9/// their borrowed counterparts so that a client does not have to allocate in
10/// order to make a call.
11///
12/// # Examples
13///
14/// ```
15/// use tokio_dbus::Signature;
16/// use tokio_dbus_runtime::Arguments;
17///
18/// let mut arguments = Arguments::new(Signature::new("sas")?)?;
19/// arguments.store("Hello");
20/// arguments.store(&["a", "b"][..]);
21/// # Ok::<_, tokio_dbus_runtime::Error>(())
22/// ```
23pub trait Encode {
24    /// The alignment of the encoded value, which the containers this value is
25    /// nested inside need in order to pad correctly.
26    const ALIGNMENT: Alignment;
27
28    /// Write the value, without writing its signature.
29    fn encode(&self, raw: &mut Raw<'_>);
30}
31
32impl<T> Encode for &T
33where
34    T: ?Sized + Encode,
35{
36    const ALIGNMENT: Alignment = T::ALIGNMENT;
37
38    #[inline]
39    fn encode(&self, raw: &mut Raw<'_>) {
40        (**self).encode(raw);
41    }
42}
43
44macro_rules! encode_frame {
45    ($($ty:ty, $alignment:ident),* $(,)?) => {
46        $(
47            impl Encode for $ty {
48                const ALIGNMENT: Alignment = Alignment::$alignment;
49
50                #[inline]
51                fn encode(&self, raw: &mut Raw<'_>) {
52                    raw.store(*self);
53                }
54            }
55        )*
56    }
57}
58
59encode_frame! {
60    u8, BYTE,
61    bool, U32,
62    i16, U16,
63    u16, U16,
64    i32, U32,
65    u32, U32,
66    i64, U64,
67    u64, U64,
68    f64, U64,
69}
70
71impl Encode for str {
72    const ALIGNMENT: Alignment = Alignment::U32;
73
74    #[inline]
75    fn encode(&self, raw: &mut Raw<'_>) {
76        raw.store(self);
77    }
78}
79
80impl Encode for String {
81    const ALIGNMENT: Alignment = Alignment::U32;
82
83    #[inline]
84    fn encode(&self, raw: &mut Raw<'_>) {
85        raw.store(self.as_str());
86    }
87}
88
89impl Encode for ObjectPath {
90    const ALIGNMENT: Alignment = Alignment::U32;
91
92    #[inline]
93    fn encode(&self, raw: &mut Raw<'_>) {
94        raw.store(self);
95    }
96}
97
98impl Encode for ObjectPathBuf {
99    const ALIGNMENT: Alignment = Alignment::U32;
100
101    #[inline]
102    fn encode(&self, raw: &mut Raw<'_>) {
103        raw.store(&**self);
104    }
105}
106
107impl Encode for Signature {
108    const ALIGNMENT: Alignment = Alignment::BYTE;
109
110    #[inline]
111    fn encode(&self, raw: &mut Raw<'_>) {
112        raw.store(self);
113    }
114}
115
116impl Encode for SignatureBuf {
117    const ALIGNMENT: Alignment = Alignment::BYTE;
118
119    #[inline]
120    fn encode(&self, raw: &mut Raw<'_>) {
121        raw.store(&**self);
122    }
123}
124
125impl<T> Encode for [T]
126where
127    T: Encode,
128{
129    // NB: An array starts with a 32-bit length prefix, regardless of the
130    // alignment of its elements.
131    const ALIGNMENT: Alignment = Alignment::U32;
132
133    #[inline]
134    fn encode(&self, raw: &mut Raw<'_>) {
135        let mut array = raw.store_array(T::ALIGNMENT);
136
137        for value in self {
138            value.encode(&mut array.as_raw());
139        }
140    }
141}
142
143impl<T> Encode for Vec<T>
144where
145    T: Encode,
146{
147    const ALIGNMENT: Alignment = Alignment::U32;
148
149    #[inline]
150    fn encode(&self, raw: &mut Raw<'_>) {
151        <[T] as Encode>::encode(self, raw);
152    }
153}
154
155impl<T, const N: usize> Encode for [T; N]
156where
157    T: Encode,
158{
159    const ALIGNMENT: Alignment = Alignment::U32;
160
161    #[inline]
162    fn encode(&self, raw: &mut Raw<'_>) {
163        <[T] as Encode>::encode(self, raw);
164    }
165}
166
167/// Write a map as an array of dict entries.
168fn encode_entries<'a, K, V, I>(raw: &mut Raw<'_>, entries: I)
169where
170    K: 'a + Encode,
171    V: 'a + Encode,
172    I: IntoIterator<Item = (&'a K, &'a V)>,
173{
174    let mut array = raw.store_array(Alignment::U64);
175
176    for (key, value) in entries {
177        let mut entry = array.as_raw();
178        // NB: Dict entries are aligned just like structs.
179        entry.align(Alignment::U64);
180        key.encode(&mut entry);
181        value.encode(&mut entry);
182    }
183}
184
185impl<K, V, S> Encode for HashMap<K, V, S>
186where
187    K: Encode,
188    V: Encode,
189    S: BuildHasher,
190{
191    const ALIGNMENT: Alignment = Alignment::U32;
192
193    #[inline]
194    fn encode(&self, raw: &mut Raw<'_>) {
195        encode_entries(raw, self);
196    }
197}
198
199impl<K, V> Encode for BTreeMap<K, V>
200where
201    K: Encode,
202    V: Encode,
203{
204    const ALIGNMENT: Alignment = Alignment::U32;
205
206    #[inline]
207    fn encode(&self, raw: &mut Raw<'_>) {
208        encode_entries(raw, self);
209    }
210}
211
212macro_rules! encode_tuple {
213    ($($ty:ident $var:ident),*) => {
214        impl<$($ty,)*> Encode for ($($ty,)*)
215        where
216            $($ty: Encode,)*
217        {
218            // NB: Structs are aligned to 8 bytes.
219            const ALIGNMENT: Alignment = Alignment::U64;
220
221            #[inline]
222            fn encode(&self, raw: &mut Raw<'_>) {
223                let ($($var,)*) = self;
224                raw.align(Alignment::U64);
225                $($var.encode(raw);)*
226            }
227        }
228    }
229}
230
231encode_tuple!(A a);
232encode_tuple!(A a, B b);
233encode_tuple!(A a, B b, C c);
234encode_tuple!(A a, B b, C c, D d);
235encode_tuple!(A a, B b, C c, D d, E e);
236encode_tuple!(A a, B b, C c, D d, E e, F f);
237encode_tuple!(A a, B b, C c, D d, E e, F f, G g);
238encode_tuple!(A a, B b, C c, D d, E e, F f, G g, H h);
239encode_tuple!(A a, B b, C c, D d, E e, F f, G g, H h, I i);
240encode_tuple!(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j);
241encode_tuple!(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k);
242encode_tuple!(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l);