Skip to main content

tokio_dbus/body_buf/
store_array.rs

1use std::marker::PhantomData;
2use std::mem::ManuallyDrop;
3
4use crate::buf::Alloc;
5use crate::ty;
6use crate::{BodyBuf, Signature, Storable};
7
8use super::{StoreStruct, StoreVariant};
9
10/// Write a typed array.
11///
12/// See [`BodyBuf::store_array`].
13///
14/// [`BodyBuf::store_array`]: crate::BodyBuf::store_array
15pub struct StoreArray<'a, T>
16where
17    T: ty::Aligned,
18{
19    buf: &'a mut BodyBuf,
20    len: Alloc<u32>,
21    start: usize,
22    _marker: PhantomData<T>,
23}
24
25impl<'a, T> StoreArray<'a, T>
26where
27    T: ty::Aligned,
28{
29    pub(crate) fn new(buf: &'a mut BodyBuf) -> Self {
30        let len = buf.alloc();
31        // NB: The length prefix is followed by padding up to the alignment of
32        // the element type. This padding is present even if the array is empty,
33        // and is *not* included in the encoded length.
34        buf.align_mut::<T::Alignment>();
35        let start = buf.len();
36
37        Self {
38            buf,
39            start,
40            len,
41            _marker: PhantomData,
42        }
43    }
44
45    /// Finish writing the array.
46    ///
47    /// This will also be done implicitly once this is dropped.
48    ///
49    /// See [`BodyBuf::store_array`].
50    ///
51    /// [`BodyBuf::store_array`]: crate::BodyBuf::store_array
52    #[inline]
53    pub fn finish(self) {
54        ManuallyDrop::new(self).finalize();
55    }
56
57    #[inline(always)]
58    fn finalize(&mut self) {
59        let end = self.buf.len();
60        let len = (end - self.start) as u32;
61        self.buf.store_at(self.len, len);
62    }
63}
64
65impl<T> Drop for StoreArray<'_, T>
66where
67    T: ty::Aligned,
68{
69    #[inline]
70    fn drop(&mut self) {
71        self.finalize();
72    }
73}
74
75impl<T> StoreArray<'_, T>
76where
77    T: ty::Aligned,
78{
79    /// Store a value and return the builder for the next value to store.
80    ///
81    /// See [`BodyBuf::store_array`].
82    ///
83    /// [`BodyBuf::store_array`]: crate::BodyBuf::store_array
84    pub fn store(&mut self, value: T::Return<'_>)
85    where
86        T: ty::Marker,
87        for<'b> T::Return<'b>: Storable,
88    {
89        value.store_to(self.buf);
90    }
91
92    /// Write a struct inside of the array.
93    ///
94    /// See [`BodyBuf::store_array`].
95    ///
96    /// [`BodyBuf::store_array`]: crate::BodyBuf::store_array
97    #[inline]
98    pub fn store_struct(&mut self) -> StoreStruct<'_, T>
99    where
100        T: ty::Fields,
101    {
102        StoreStruct::new(self.buf)
103    }
104}
105
106impl StoreArray<'_, ty::Variant> {
107    /// Write a variant inside of the array.
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use tokio_dbus::{ty, BodyBuf, Signature, Variant};
113    ///
114    /// let mut buf = BodyBuf::new();
115    ///
116    /// let mut array = buf.store_array::<ty::Variant>()?;
117    /// array.store_variant(Signature::STRING).store("Hello World!");
118    /// array.store_variant(Signature::UINT32).store(42u32);
119    /// array.finish();
120    ///
121    /// assert_eq!(buf.signature(), "av");
122    ///
123    /// let mut buf = buf.as_body();
124    /// let mut array = buf.load_array::<ty::Variant>()?;
125    /// assert_eq!(array.load_variant()?, Some(Variant::String("Hello World!")));
126    /// assert_eq!(array.load_variant()?, Some(Variant::U32(42)));
127    /// assert_eq!(array.load_variant()?, None);
128    /// # Ok::<_, tokio_dbus::Error>(())
129    /// ```
130    #[inline]
131    pub fn store_variant(&mut self, signature: &Signature) -> StoreVariant<'_> {
132        StoreVariant::new(self.buf, signature)
133    }
134}
135
136impl<K, V> StoreArray<'_, ty::Dict<K, V>>
137where
138    K: ty::Marker,
139    V: ty::Marker,
140{
141    /// Write a dict entry inside of the array.
142    ///
143    /// # Examples
144    ///
145    /// ```
146    /// use tokio_dbus::{ty, BodyBuf, Signature, Variant};
147    ///
148    /// let mut buf = BodyBuf::new();
149    ///
150    /// let mut dict = buf.store_array::<ty::Dict<ty::Str, ty::Variant>>()?;
151    /// dict.store_entry().store("Id").store(Variant::String("example")).finish();
152    /// dict.store_entry().store("ItemIsMenu").store(Variant::Bool(false)).finish();
153    /// dict.finish();
154    ///
155    /// assert_eq!(buf.signature(), "a{sv}");
156    ///
157    /// let mut buf = buf.as_body();
158    /// let mut dict = buf.load_array::<ty::Dict<ty::Str, ty::Variant>>()?;
159    ///
160    /// assert_eq!(dict.load_entry()?, Some(("Id", Variant::String("example"))));
161    /// assert_eq!(dict.load_entry()?, Some(("ItemIsMenu", Variant::Bool(false))));
162    /// assert_eq!(dict.load_entry()?, None);
163    /// # Ok::<_, tokio_dbus::Error>(())
164    /// ```
165    #[inline]
166    pub fn store_entry(&mut self) -> StoreStruct<'_, (K, V)> {
167        // NB: Dict entries are laid out exactly like a two-field struct.
168        StoreStruct::new(self.buf)
169    }
170}
171
172impl<T> StoreArray<'_, ty::Array<T>>
173where
174    T: ty::Aligned,
175{
176    /// Write an array inside of the array.
177    ///
178    /// See [`BodyBuf::store_array`].
179    ///
180    /// [`BodyBuf::store_array`]: crate::BodyBuf::store_array
181    #[inline]
182    pub fn store_array(&mut self) -> StoreArray<'_, T> {
183        StoreArray::new(self.buf)
184    }
185}
186
187impl StoreArray<'_, u8> {
188    /// Extend a byte array with the given slice.
189    ///
190    /// See [`BodyBuf::store_array`].
191    ///
192    /// [`BodyBuf::store_array`]: crate::BodyBuf::store_array
193    #[inline]
194    pub fn write_slice(&mut self, bytes: &[u8]) {
195        self.buf.extend_from_slice(bytes);
196    }
197}