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}