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}