Skip to main content

tokio_dbus/body_buf/
raw.rs

1use crate::buf::Alloc;
2use crate::{Alignment, BodyBuf, Signature, Storable};
3
4/// A writer for values whose shape is only known at runtime.
5///
6/// The typed writers in this crate derive alignment and signatures from a
7/// [`ty::Marker`], which requires the shape of a value to be known when the code
8/// is written. A [`Raw`] writer instead takes the alignment of each container it
9/// opens as an argument, which is what makes it usable from code that is generic
10/// over, or generated for, arbitrary D-Bus types.
11///
12/// Nothing written through a [`Raw`] writer is reflected in the signature of the
13/// underlying buffer. The signature is instead declared up front, when the
14/// writer is constructed with [`BodyBuf::store_raw`].
15///
16/// [`ty::Marker`]: crate::ty::Marker
17///
18/// # Examples
19///
20/// ```
21/// use tokio_dbus::{Alignment, BodyBuf, Signature};
22///
23/// let mut buf = BodyBuf::new();
24///
25/// let mut raw = buf.store_raw(Signature::new("a(us)")?)?;
26/// let mut array = raw.store_array(Alignment::U64);
27///
28/// for (n, name) in [(1u32, "one"), (2u32, "two")] {
29///     let mut entry = array.as_raw();
30///     entry.align(Alignment::U64);
31///     entry.store(n);
32///     entry.store(name);
33/// }
34///
35/// array.finish();
36///
37/// assert_eq!(buf.signature(), "a(us)");
38/// # Ok::<_, tokio_dbus::Error>(())
39/// ```
40pub struct Raw<'a> {
41    buf: &'a mut BodyBuf,
42}
43
44impl<'a> Raw<'a> {
45    #[inline]
46    pub(crate) fn new(buf: &'a mut BodyBuf) -> Self {
47        Self { buf }
48    }
49
50    /// Reborrow this writer.
51    ///
52    /// This is needed to hand the writer to a function which takes it by value
53    /// without giving up ownership of it.
54    #[inline]
55    pub fn as_raw(&mut self) -> Raw<'_> {
56        Raw::new(self.buf)
57    }
58
59    /// Align the buffer to the given alignment.
60    ///
61    /// This must be called before the fields of a struct or a dict entry, both
62    /// of which are aligned to [`Alignment::U64`].
63    #[inline]
64    pub fn align(&mut self, alignment: Alignment) {
65        self.buf.align_mut_to(alignment.in_bytes());
66    }
67
68    /// Store a value, without recording anything in the signature of the
69    /// buffer.
70    #[inline]
71    pub fn store<T>(&mut self, value: T)
72    where
73        T: Storable,
74    {
75        value.store_to(self.buf);
76    }
77
78    /// Write a signature inline, as the `g` type.
79    ///
80    /// A variant is a signature written this way followed by a value matching
81    /// it.
82    ///
83    /// # Examples
84    ///
85    /// ```
86    /// use tokio_dbus::{BodyBuf, Signature, Variant};
87    ///
88    /// let mut buf = BodyBuf::new();
89    ///
90    /// let mut raw = buf.store_raw(Signature::VARIANT)?;
91    /// raw.store_signature(Signature::UINT32);
92    /// raw.store(42u32);
93    ///
94    /// let mut buf = buf.as_body();
95    /// assert_eq!(buf.read_variant()?, Variant::U32(42));
96    /// # Ok::<_, tokio_dbus::Error>(())
97    /// ```
98    #[inline]
99    pub fn store_signature(&mut self, signature: &Signature) {
100        self.buf.write_only(signature);
101    }
102
103    /// Extend the buffer with raw bytes, which is how the elements of a `ay` are
104    /// written.
105    #[inline]
106    pub fn write_slice(&mut self, bytes: &[u8]) {
107        self.buf.extend_from_slice(bytes);
108    }
109
110    /// Open an array whose elements have the given alignment.
111    ///
112    /// The length of the array is written when the returned writer is finished
113    /// or dropped.
114    #[inline]
115    pub fn store_array(&mut self, alignment: Alignment) -> RawArray<'_> {
116        RawArray::new(self.buf, alignment)
117    }
118
119    /// Open an array, consuming this writer so that the array inherits its
120    /// lifetime.
121    ///
122    /// This is what to use when the array has to outlive the writer it was
123    /// opened from, such as when it is returned from a function.
124    #[inline]
125    pub fn into_array(self, alignment: Alignment) -> RawArray<'a> {
126        RawArray::new(self.buf, alignment)
127    }
128}
129
130/// A writer for the elements of an array whose shape is only known at runtime.
131///
132/// See [`Raw::store_array`].
133pub struct RawArray<'a> {
134    buf: &'a mut BodyBuf,
135    len: Alloc<u32>,
136    start: usize,
137}
138
139impl<'a> RawArray<'a> {
140    #[inline]
141    fn new(buf: &'a mut BodyBuf, alignment: Alignment) -> Self {
142        let len = buf.alloc();
143        // NB: The length prefix is followed by padding up to the alignment of
144        // the element type, which is present even when the array is empty and is
145        // not counted towards the length.
146        buf.align_mut_to(alignment.in_bytes());
147        let start = buf.len();
148        Self { buf, len, start }
149    }
150
151    /// Write the next element of the array.
152    #[inline]
153    pub fn as_raw(&mut self) -> Raw<'_> {
154        Raw::new(self.buf)
155    }
156
157    /// Finish writing the array.
158    ///
159    /// This also happens implicitly when the writer is dropped.
160    #[inline]
161    pub fn finish(self) {}
162}
163
164impl Drop for RawArray<'_> {
165    #[inline]
166    fn drop(&mut self) {
167        let len = (self.buf.len() - self.start) as u32;
168        self.buf.store_at(self.len, len);
169    }
170}