Skip to main content

tokio_dbus/body/
load_array.rs

1use core::marker::PhantomData;
2
3use crate::buf::MAX_ARRAY_LENGTH;
4use crate::error::ErrorKind;
5use crate::{Body, ty};
6use crate::{Error, Frame, Read, Result};
7
8/// Read an array from a buffer.
9///
10/// See [`Body::load_array`].
11///
12/// [`Body::load_array`]: crate::Body::load_array
13pub struct LoadArray<'de, T> {
14    buf: Body<'de>,
15    _marker: PhantomData<T>,
16}
17
18impl<'de, T> LoadArray<'de, T>
19where
20    T: ty::Aligned,
21{
22    #[inline]
23    pub(crate) fn from_mut(buf: &mut Body<'de>) -> Result<LoadArray<'de, T>> {
24        let bytes = buf.load::<u32>()?;
25
26        if bytes > MAX_ARRAY_LENGTH {
27            return Err(Error::new(ErrorKind::ArrayTooLong(bytes)));
28        }
29
30        // NB: The length prefix is followed by padding up to the alignment of
31        // the element type, which is present even if the array is empty and is
32        // not counted towards the encoded length.
33        buf.align::<T::Alignment>()?;
34
35        let buf = buf.read_until(bytes as usize);
36        Ok(LoadArray::new(buf))
37    }
38}
39
40impl<'de, T> LoadArray<'de, T> {
41    /// Construct a new array reader around a buffer.
42    pub(crate) fn new(buf: Body<'de>) -> Self {
43        LoadArray {
44            buf,
45            _marker: PhantomData,
46        }
47    }
48
49    /// Test if the array has been fully consumed.
50    ///
51    /// # Examples
52    ///
53    /// ```
54    /// use tokio_dbus::BodyBuf;
55    ///
56    /// let mut buf = BodyBuf::new();
57    /// let mut array = buf.store_array::<u32>()?;
58    /// array.store(10u32);
59    /// array.finish();
60    ///
61    /// let mut buf = buf.as_body();
62    /// let mut array = buf.load_array::<u32>()?;
63    /// assert!(!array.is_empty());
64    /// assert_eq!(array.load()?, Some(10));
65    /// assert!(array.is_empty());
66    /// # Ok::<_, tokio_dbus::Error>(())
67    /// ```
68    #[inline]
69    pub fn is_empty(&self) -> bool {
70        self.buf.is_empty()
71    }
72
73    /// Read the next element of the array with the given closure.
74    ///
75    /// This is an escape hatch for element types which the typed readers cannot
76    /// describe, and hands the closure a [`Body`] positioned at the start of the
77    /// next element.
78    ///
79    /// # Examples
80    ///
81    /// ```
82    /// use tokio_dbus::{ty, BodyBuf, Signature};
83    ///
84    /// let mut buf = BodyBuf::new();
85    ///
86    /// let mut array = buf.store_array::<(u32, ty::Variant)>()?;
87    ///
88    /// array
89    ///     .store_struct()
90    ///     .store(42u32)
91    ///     .store_variant(Signature::new("as")?, |w| {
92    ///         w.store_array::<ty::Str>().store("Hello");
93    ///     })
94    ///     .finish();
95    ///
96    /// array.finish();
97    ///
98    /// let mut buf = buf.as_body();
99    /// let mut array = buf.load_array::<(u32, ty::Variant)>()?;
100    ///
101    /// let element = array.load_with(|b| {
102    ///     b.load_struct_with(|b| {
103    ///         let n = b.load::<u32>()?;
104    ///         b.skip_variant()?;
105    ///         Ok(n)
106    ///     })
107    /// })?;
108    ///
109    /// assert_eq!(element, Some(42));
110    /// assert!(array.is_empty());
111    /// # Ok::<_, tokio_dbus::Error>(())
112    /// ```
113    pub fn load_with<F, O>(&mut self, f: F) -> Result<Option<O>>
114    where
115        F: FnOnce(&mut Body<'de>) -> Result<O>,
116    {
117        if self.buf.is_empty() {
118            return Ok(None);
119        }
120
121        Ok(Some(f(&mut self.buf)?))
122    }
123}
124
125impl<T> LoadArray<'_, T>
126where
127    T: Frame,
128{
129    /// Load the next value from the array.
130    ///
131    /// See [`Body::load_array`].
132    ///
133    /// [`Body::load_array`]: crate::Body::load_array
134    pub fn load(&mut self) -> Result<Option<T>> {
135        if self.buf.is_empty() {
136            return Ok(None);
137        }
138
139        Ok(Some(self.buf.load()?))
140    }
141}
142
143impl<'de, T> LoadArray<'de, T>
144where
145    T: ty::Unsized,
146    T::Target: Read,
147{
148    /// Read the next value from the array.
149    ///
150    /// See [`Body::load_array`].
151    ///
152    /// [`Body::load_array`]: crate::Body::load_array
153    pub fn read(&mut self) -> Result<Option<&'de T::Target>> {
154        if self.buf.is_empty() {
155            return Ok(None);
156        }
157
158        Ok(Some(T::Target::read_from(&mut self.buf)?))
159    }
160}
161
162impl<'de, T> LoadArray<'de, ty::Array<T>>
163where
164    T: ty::Marker,
165{
166    /// Read an array from within the array.
167    ///
168    /// See [`Body::load_struct`].
169    pub fn load_array(&mut self) -> Result<Option<LoadArray<'de, T>>> {
170        if self.buf.is_empty() {
171            return Ok(None);
172        }
173
174        Ok(Some(LoadArray::from_mut(&mut self.buf)?))
175    }
176}
177
178impl<'de, T> LoadArray<'de, T>
179where
180    T: ty::Fields,
181{
182    /// Read a struct from within the array.
183    ///
184    /// See [`Body::load_struct`].
185    pub fn load_struct(&mut self) -> Result<Option<T::Return<'de>>> {
186        if self.buf.is_empty() {
187            return Ok(None);
188        }
189
190        Ok(Some(self.buf.load_struct::<T>()?))
191    }
192}
193
194impl<'de> LoadArray<'de, ty::Variant> {
195    /// Read the next variant from the array.
196    ///
197    /// See [`StoreArray::store_variant`].
198    ///
199    /// [`StoreArray::store_variant`]: crate::StoreArray::store_variant
200    pub fn load_variant(&mut self) -> Result<Option<crate::Variant<'de>>> {
201        if self.buf.is_empty() {
202            return Ok(None);
203        }
204
205        Ok(Some(self.buf.read_variant()?))
206    }
207
208    /// Skip over the next variant in the array, returning the signature of the
209    /// value it contained.
210    ///
211    /// See [`Body::skip_variant`].
212    ///
213    /// [`Body::skip_variant`]: crate::Body::skip_variant
214    pub fn skip_variant(&mut self) -> Result<Option<&'de crate::Signature>> {
215        if self.buf.is_empty() {
216            return Ok(None);
217        }
218
219        Ok(Some(self.buf.skip_variant()?))
220    }
221}
222
223impl<'de, K, V> LoadArray<'de, ty::Dict<K, V>>
224where
225    K: ty::Marker,
226    V: ty::Marker,
227{
228    /// Read a dict entry from within the array.
229    ///
230    /// # Examples
231    ///
232    /// ```
233    /// use tokio_dbus::{ty, BodyBuf};
234    ///
235    /// let mut buf = BodyBuf::new();
236    ///
237    /// let mut dict = buf.store_array::<ty::Dict<ty::Str, u32>>()?;
238    /// dict.store_entry().store("a").store(1u32).finish();
239    /// dict.store_entry().store("b").store(2u32).finish();
240    /// dict.finish();
241    ///
242    /// assert_eq!(buf.signature(), "a{su}");
243    ///
244    /// let mut buf = buf.as_body();
245    /// let mut dict = buf.load_array::<ty::Dict<ty::Str, u32>>()?;
246    ///
247    /// assert_eq!(dict.load_entry()?, Some(("a", 1)));
248    /// assert_eq!(dict.load_entry()?, Some(("b", 2)));
249    /// assert_eq!(dict.load_entry()?, None);
250    /// # Ok::<_, tokio_dbus::Error>(())
251    /// ```
252    pub fn load_entry(&mut self) -> Result<Option<(K::Return<'de>, V::Return<'de>)>> {
253        if self.buf.is_empty() {
254            return Ok(None);
255        }
256
257        // NB: Dict entries are aligned just like structs.
258        self.buf.align::<u64>()?;
259        Ok(Some((
260            K::load_struct(&mut self.buf)?,
261            V::load_struct(&mut self.buf)?,
262        )))
263    }
264}
265
266impl<'de, K> LoadArray<'de, ty::Dict<K, ty::Variant>>
267where
268    K: ty::Marker,
269{
270    /// Read a dict entry whose value is a variant expected to contain a value
271    /// of type `T`.
272    ///
273    /// This is needed for dictionaries like the ones returned by
274    /// `org.freedesktop.DBus.Properties.GetAll`, where the value of an entry is
275    /// a container which [`load_entry()`] cannot represent.
276    ///
277    /// [`load_entry()`]: Self::load_entry
278    ///
279    /// # Examples
280    ///
281    /// ```
282    /// use tokio_dbus::{ty, BodyBuf, Signature};
283    ///
284    /// let mut buf = BodyBuf::new();
285    ///
286    /// let mut dict = buf.store_array::<ty::Dict<ty::Str, ty::Variant>>()?;
287    ///
288    /// dict.store_entry()
289    ///     .store("IconThemePath")
290    ///     .store_variant(Signature::new("as")?, |w| {
291    ///         let mut array = w.store_array::<ty::Str>();
292    ///         array.store("/usr/share/icons");
293    ///     })
294    ///     .finish();
295    ///
296    /// dict.finish();
297    ///
298    /// let mut buf = buf.as_body();
299    /// let mut dict = buf.load_array::<ty::Dict<ty::Str, ty::Variant>>()?;
300    ///
301    /// let Some((key, mut value)) = dict.load_entry_as::<ty::Array<ty::Str>>()? else {
302    ///     panic!("Missing entry");
303    /// };
304    ///
305    /// assert_eq!(key, "IconThemePath");
306    /// assert_eq!(value.read()?, Some("/usr/share/icons"));
307    /// assert_eq!(value.read()?, None);
308    /// # Ok::<_, tokio_dbus::Error>(())
309    /// ```
310    pub fn load_entry_as<T>(&mut self) -> Result<Option<(K::Return<'de>, T::Return<'de>)>>
311    where
312        T: ty::Marker,
313    {
314        if self.buf.is_empty() {
315            return Ok(None);
316        }
317
318        self.buf.align::<u64>()?;
319        let key = K::load_struct(&mut self.buf)?;
320        let value = self.buf.read_variant_as::<T>()?;
321        Ok(Some((key, value)))
322    }
323}