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}