zvariant/serialized/data.rs
1#[cfg(unix)]
2use crate::{Fd, OwnedFd};
3use std::{
4 borrow::Cow,
5 ops::{Bound, Deref, Range, RangeBounds},
6 sync::Arc,
7};
8
9use serde::{de::DeserializeSeed, Deserialize};
10
11use crate::{
12 de::Deserializer,
13 serialized::{Context, Format},
14 DynamicDeserialize, DynamicType, Error, Result, Signature, Type,
15};
16
17/// Represents serialized bytes in a specific format.
18///
19/// On Unix platforms, it also contains a list of file descriptors, whose indexes are included in
20/// the serialized bytes. By packing them together, we ensure that the file descriptors are never
21/// closed before the serialized bytes are dropped.
22#[derive(Clone, Debug)]
23pub struct Data<'bytes, 'fds> {
24 inner: Arc<Inner<'bytes, 'fds>>,
25 context: Context,
26 range: Range<usize>,
27}
28
29#[derive(Debug)]
30pub struct Inner<'bytes, 'fds> {
31 bytes: Cow<'bytes, [u8]>,
32 #[cfg(unix)]
33 fds: Vec<Fd<'fds>>,
34 #[cfg(not(unix))]
35 _fds: std::marker::PhantomData<&'fds ()>,
36}
37
38impl<'bytes, 'fds> Data<'bytes, 'fds> {
39 /// Create a new `Data` instance containing borrowed file descriptors.
40 ///
41 /// This method is only available on Unix platforms.
42 #[cfg(unix)]
43 pub fn new_borrowed_fds<T>(
44 bytes: T,
45 context: Context,
46 fds: impl IntoIterator<Item = impl Into<Fd<'fds>>>,
47 ) -> Self
48 where
49 T: Into<Cow<'bytes, [u8]>>,
50 {
51 let bytes = bytes.into();
52 let range = Range {
53 start: 0,
54 end: bytes.len(),
55 };
56 Data {
57 inner: Arc::new(Inner {
58 bytes,
59 fds: fds.into_iter().map(Into::into).collect(),
60 }),
61 range,
62 context,
63 }
64 }
65
66 /// The serialized bytes.
67 pub fn bytes(&self) -> &[u8] {
68 &self.inner.bytes[self.range.start..self.range.end]
69 }
70
71 /// The encoding context.
72 pub fn context(&self) -> Context {
73 self.context
74 }
75
76 /// The file descriptors that are references by the serialized bytes.
77 ///
78 /// This method is only available on Unix platforms.
79 #[cfg(unix)]
80 pub fn fds(&self) -> &[Fd<'fds>] {
81 &self.inner.fds
82 }
83
84 /// Returns a slice of `self` for the provided range.
85 ///
86 /// # Panics
87 ///
88 /// Requires that begin <= end and end <= self.len(), otherwise slicing will panic.
89 pub fn slice(&self, range: impl RangeBounds<usize>) -> Data<'bytes, 'fds> {
90 let len = self.range.end - self.range.start;
91 let start = match range.start_bound() {
92 Bound::Included(&n) => n,
93 Bound::Excluded(&n) => n + 1,
94 Bound::Unbounded => 0,
95 };
96 let end = match range.end_bound() {
97 Bound::Included(&n) => n + 1,
98 Bound::Excluded(&n) => n,
99 Bound::Unbounded => len,
100 };
101 assert!(
102 start <= end,
103 "range start must not be greater than end: {start:?} > {end:?}",
104 );
105 assert!(end <= len, "range end out of bounds: {end:?} > {len:?}");
106
107 let context = Context::new(
108 self.context.format(),
109 self.context.endian(),
110 self.context.position() + start,
111 );
112 let range = Range {
113 start: self.range.start + start,
114 end: self.range.start + end,
115 };
116
117 Data {
118 inner: self.inner.clone(),
119 context,
120 range,
121 }
122 }
123
124 /// Deserialize `T` from `self`.
125 ///
126 /// # Examples
127 ///
128 /// ```
129 /// use zvariant::LE;
130 /// use zvariant::to_bytes;
131 /// use zvariant::serialized::Context;
132 ///
133 /// let ctxt = Context::new_dbus(LE, 0);
134 /// let encoded = to_bytes(ctxt, "hello world").unwrap();
135 /// let decoded: &str = encoded.deserialize().unwrap().0;
136 /// assert_eq!(decoded, "hello world");
137 /// ```
138 ///
139 /// # Return value
140 ///
141 /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`.
142 pub fn deserialize<'d, T>(&'d self) -> Result<(T, usize)>
143 where
144 T: ?Sized + Deserialize<'d> + Type,
145 {
146 let signature = T::signature();
147 self.deserialize_for_signature(&signature)
148 }
149
150 /// Deserialize `T` from `self` with the given signature.
151 ///
152 /// Use this method instead of [`Data::deserialize`] if the value being deserialized does not
153 /// implement [`Type`].
154 ///
155 /// # Examples
156 ///
157 /// While `Type` derive supports enums, for this example, let's supposed it doesn't and we don't
158 /// want to manually implement `Type` trait either:
159 ///
160 /// ```
161 /// use serde::{Deserialize, Serialize};
162 /// use zvariant::LE;
163 ///
164 /// use zvariant::to_bytes_for_signature;
165 /// use zvariant::serialized::Context;
166 ///
167 /// let ctxt = Context::new_dbus(LE, 0);
168 /// #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
169 /// enum Unit {
170 /// Variant1,
171 /// Variant2,
172 /// Variant3,
173 /// }
174 ///
175 /// let encoded = to_bytes_for_signature(ctxt, "u", &Unit::Variant2).unwrap();
176 /// assert_eq!(encoded.len(), 4);
177 /// let decoded: Unit = encoded.deserialize_for_signature("u").unwrap().0;
178 /// assert_eq!(decoded, Unit::Variant2);
179 ///
180 /// #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
181 /// enum NewType<'s> {
182 /// Variant1(&'s str),
183 /// Variant2(&'s str),
184 /// Variant3(&'s str),
185 /// }
186 ///
187 /// let signature = "(us)";
188 /// let encoded =
189 /// to_bytes_for_signature(ctxt, signature, &NewType::Variant2("hello")).unwrap();
190 /// assert_eq!(encoded.len(), 14);
191 /// let decoded: NewType<'_> = encoded.deserialize_for_signature(signature).unwrap().0;
192 /// assert_eq!(decoded, NewType::Variant2("hello"));
193 ///
194 /// #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
195 /// enum Structs {
196 /// Tuple(u8, u64),
197 /// Struct { y: u8, t: u64 },
198 /// }
199 ///
200 /// let signature = "(u(yt))";
201 /// let encoded = to_bytes_for_signature(ctxt, signature, &Structs::Tuple(42, 42)).unwrap();
202 /// assert_eq!(encoded.len(), 24);
203 /// let decoded: Structs = encoded.deserialize_for_signature(signature).unwrap().0;
204 /// assert_eq!(decoded, Structs::Tuple(42, 42));
205 ///
206 /// let s = Structs::Struct { y: 42, t: 42 };
207 /// let encoded = to_bytes_for_signature(ctxt, signature, &s).unwrap();
208 /// assert_eq!(encoded.len(), 24);
209 /// let decoded: Structs = encoded.deserialize_for_signature(signature).unwrap().0;
210 /// assert_eq!(decoded, Structs::Struct { y: 42, t: 42 });
211 /// ```
212 ///
213 /// # Return value
214 ///
215 /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`.
216 pub fn deserialize_for_signature<'d, S, T>(&'d self, signature: S) -> Result<(T, usize)>
217 where
218 T: ?Sized + Deserialize<'d>,
219 S: TryInto<Signature<'d>>,
220 S::Error: Into<Error>,
221 {
222 let signature = signature.try_into().map_err(Into::into)?;
223
224 #[cfg(unix)]
225 let fds = &self.inner.fds;
226 let mut de = match self.context.format() {
227 #[cfg(feature = "gvariant")]
228 Format::GVariant => {
229 #[cfg(unix)]
230 {
231 crate::gvariant::Deserializer::new(
232 self.bytes(),
233 Some(fds),
234 signature,
235 self.context,
236 )
237 }
238 #[cfg(not(unix))]
239 {
240 crate::gvariant::Deserializer::<()>::new(self.bytes(), signature, self.context)
241 }
242 }
243 .map(Deserializer::GVariant)?,
244 Format::DBus => {
245 #[cfg(unix)]
246 {
247 crate::dbus::Deserializer::new(self.bytes(), Some(fds), signature, self.context)
248 }
249 #[cfg(not(unix))]
250 {
251 crate::dbus::Deserializer::<()>::new(self.bytes(), signature, self.context)
252 }
253 }
254 .map(Deserializer::DBus)?,
255 };
256
257 T::deserialize(&mut de).map(|t| match de {
258 #[cfg(feature = "gvariant")]
259 Deserializer::GVariant(de) => (t, de.0.pos),
260 Deserializer::DBus(de) => (t, de.0.pos),
261 })
262 }
263
264 /// Deserialize `T` from `self`, with the given dynamic signature.
265 ///
266 /// # Return value
267 ///
268 /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`.
269 pub fn deserialize_for_dynamic_signature<'d, S, T>(&'d self, signature: S) -> Result<(T, usize)>
270 where
271 T: DynamicDeserialize<'d>,
272 S: TryInto<Signature<'d>>,
273 S::Error: Into<Error>,
274 {
275 let seed = T::deserializer_for_signature(signature)?;
276
277 self.deserialize_with_seed(seed)
278 }
279
280 /// Deserialize `T` from `self`, using the given seed.
281 ///
282 /// # Return value
283 ///
284 /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`.
285 pub fn deserialize_with_seed<'d, S>(&'d self, seed: S) -> Result<(S::Value, usize)>
286 where
287 S: DeserializeSeed<'d> + DynamicType,
288 {
289 let signature = S::dynamic_signature(&seed).to_owned();
290
291 #[cfg(unix)]
292 let fds = &self.inner.fds;
293 let mut de = match self.context.format() {
294 #[cfg(feature = "gvariant")]
295 Format::GVariant => {
296 #[cfg(unix)]
297 {
298 crate::gvariant::Deserializer::new(
299 self.bytes(),
300 Some(fds),
301 signature,
302 self.context,
303 )
304 }
305 #[cfg(not(unix))]
306 {
307 crate::gvariant::Deserializer::new(self.bytes(), signature, self.context)
308 }
309 }
310 .map(Deserializer::GVariant)?,
311 Format::DBus => {
312 #[cfg(unix)]
313 {
314 crate::dbus::Deserializer::new(self.bytes(), Some(fds), signature, self.context)
315 }
316 #[cfg(not(unix))]
317 {
318 crate::dbus::Deserializer::<()>::new(self.bytes(), signature, self.context)
319 }
320 }
321 .map(Deserializer::DBus)?,
322 };
323
324 seed.deserialize(&mut de).map(|t| match de {
325 #[cfg(feature = "gvariant")]
326 Deserializer::GVariant(de) => (t, de.0.pos),
327 Deserializer::DBus(de) => (t, de.0.pos),
328 })
329 }
330}
331
332impl<'bytes> Data<'bytes, 'static> {
333 /// Create a new `Data` instance.
334 pub fn new<T>(bytes: T, context: Context) -> Self
335 where
336 T: Into<Cow<'bytes, [u8]>>,
337 {
338 let bytes = bytes.into();
339 let range = Range {
340 start: 0,
341 end: bytes.len(),
342 };
343 Data {
344 inner: Arc::new(Inner {
345 bytes,
346 #[cfg(unix)]
347 fds: vec![],
348 #[cfg(not(unix))]
349 _fds: std::marker::PhantomData,
350 }),
351 context,
352 range,
353 }
354 }
355
356 /// Create a new `Data` instance containing owned file descriptors.
357 ///
358 /// This method is only available on Unix platforms.
359 #[cfg(unix)]
360 pub fn new_fds<T>(
361 bytes: T,
362 context: Context,
363 fds: impl IntoIterator<Item = impl Into<OwnedFd>>,
364 ) -> Self
365 where
366 T: Into<Cow<'bytes, [u8]>>,
367 {
368 let bytes = bytes.into();
369 let range = Range {
370 start: 0,
371 end: bytes.len(),
372 };
373 Data {
374 inner: Arc::new(Inner {
375 bytes,
376 fds: fds.into_iter().map(Into::into).map(Fd::from).collect(),
377 }),
378 context,
379 range,
380 }
381 }
382}
383
384impl Deref for Data<'_, '_> {
385 type Target = [u8];
386
387 fn deref(&self) -> &Self::Target {
388 self.bytes()
389 }
390}
391
392impl<T> AsRef<T> for Data<'_, '_>
393where
394 T: ?Sized,
395 for<'bytes, 'fds> <Data<'bytes, 'fds> as Deref>::Target: AsRef<T>,
396{
397 fn as_ref(&self) -> &T {
398 self.deref().as_ref()
399 }
400}