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: Deserialize<'d> + Type,
145 {
146 self.deserialize_for_signature(T::SIGNATURE)
147 }
148
149 /// Deserialize `T` from `self` with the given signature.
150 ///
151 /// Use this method instead of [`Data::deserialize`] if the value being deserialized does not
152 /// implement [`Type`].
153 ///
154 /// # Examples
155 ///
156 /// While `Type` derive supports enums, for this example, let's supposed it doesn't and we don't
157 /// want to manually implement `Type` trait either:
158 ///
159 /// ```rust
160 /// use serde::{Deserialize, Serialize};
161 /// use zvariant::{
162 /// LE, to_bytes_for_signature, serialized::Context,
163 /// signature::{Signature, Fields},
164 /// };
165 ///
166 /// let ctxt = Context::new_dbus(LE, 0);
167 /// #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
168 /// enum Unit {
169 /// Variant1,
170 /// Variant2,
171 /// Variant3,
172 /// }
173 ///
174 /// let encoded = to_bytes_for_signature(ctxt, &Signature::U32, &Unit::Variant2).unwrap();
175 /// assert_eq!(encoded.len(), 4);
176 /// let decoded: Unit = encoded.deserialize_for_signature(&Signature::U32).unwrap().0;
177 /// assert_eq!(decoded, Unit::Variant2);
178 ///
179 /// #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
180 /// enum NewType<'s> {
181 /// Variant1(&'s str),
182 /// Variant2(&'s str),
183 /// Variant3(&'s str),
184 /// }
185 ///
186 /// let signature = Signature::Structure(Fields::Static {
187 /// fields: &[&Signature::U32, &Signature::Str],
188 /// });
189 /// let encoded =
190 /// to_bytes_for_signature(ctxt, &signature, &NewType::Variant2("hello")).unwrap();
191 /// assert_eq!(encoded.len(), 14);
192 /// let decoded: NewType<'_> = encoded.deserialize_for_signature(&signature).unwrap().0;
193 /// assert_eq!(decoded, NewType::Variant2("hello"));
194 ///
195 /// #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
196 /// enum Structs {
197 /// Tuple(u8, u64),
198 /// Struct { y: u8, t: u64 },
199 /// }
200 ///
201 /// let signature = Signature::Structure(Fields::Static {
202 /// fields: &[
203 /// &Signature::U32,
204 /// &Signature::Structure(Fields::Static {
205 /// fields: &[&Signature::U8, &Signature::U64],
206 /// }),
207 /// ],
208 /// });
209 /// let encoded = to_bytes_for_signature(ctxt, &signature, &Structs::Tuple(42, 42)).unwrap();
210 /// assert_eq!(encoded.len(), 24);
211 /// let decoded: Structs = encoded.deserialize_for_signature(&signature).unwrap().0;
212 /// assert_eq!(decoded, Structs::Tuple(42, 42));
213 ///
214 /// let s = Structs::Struct { y: 42, t: 42 };
215 /// let encoded = to_bytes_for_signature(ctxt, &signature, &s).unwrap();
216 /// assert_eq!(encoded.len(), 24);
217 /// let decoded: Structs = encoded.deserialize_for_signature(&signature).unwrap().0;
218 /// assert_eq!(decoded, Structs::Struct { y: 42, t: 42 });
219 /// ```
220 ///
221 /// # Return value
222 ///
223 /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`.
224 pub fn deserialize_for_signature<'d, S, T>(&'d self, signature: S) -> Result<(T, usize)>
225 where
226 T: Deserialize<'d>,
227 S: TryInto<Signature>,
228 S::Error: Into<Error>,
229 {
230 let signature = signature.try_into().map_err(Into::into)?;
231
232 #[cfg(unix)]
233 let fds = &self.inner.fds;
234 let mut de = match self.context.format() {
235 #[cfg(feature = "gvariant")]
236 Format::GVariant => {
237 #[cfg(unix)]
238 {
239 crate::gvariant::Deserializer::new(
240 self.bytes(),
241 Some(fds),
242 &signature,
243 self.context,
244 )
245 }
246 #[cfg(not(unix))]
247 {
248 crate::gvariant::Deserializer::<()>::new(self.bytes(), &signature, self.context)
249 }
250 }
251 .map(Deserializer::GVariant)?,
252 Format::DBus => {
253 #[cfg(unix)]
254 {
255 crate::dbus::Deserializer::new(
256 self.bytes(),
257 Some(fds),
258 &signature,
259 self.context,
260 )
261 }
262 #[cfg(not(unix))]
263 {
264 crate::dbus::Deserializer::<()>::new(self.bytes(), &signature, self.context)
265 }
266 }
267 .map(Deserializer::DBus)?,
268 };
269
270 T::deserialize(&mut de).map(|t| match de {
271 #[cfg(feature = "gvariant")]
272 Deserializer::GVariant(de) => (t, de.0.pos),
273 Deserializer::DBus(de) => (t, de.0.pos),
274 })
275 }
276
277 /// Deserialize `T` from `self`, with the given dynamic signature.
278 ///
279 /// # Return value
280 ///
281 /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`.
282 pub fn deserialize_for_dynamic_signature<'d, S, T>(&'d self, signature: S) -> Result<(T, usize)>
283 where
284 T: DynamicDeserialize<'d>,
285 S: TryInto<Signature>,
286 S::Error: Into<Error>,
287 {
288 let signature = signature.try_into().map_err(Into::into)?;
289 let seed = T::deserializer_for_signature(&signature)?;
290
291 self.deserialize_with_seed(seed)
292 }
293
294 /// Deserialize `T` from `self`, using the given seed.
295 ///
296 /// # Return value
297 ///
298 /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`.
299 pub fn deserialize_with_seed<'d, S>(&'d self, seed: S) -> Result<(S::Value, usize)>
300 where
301 S: DeserializeSeed<'d> + DynamicType,
302 {
303 let signature = S::signature(&seed);
304
305 #[cfg(unix)]
306 let fds = &self.inner.fds;
307 let mut de = match self.context.format() {
308 #[cfg(feature = "gvariant")]
309 Format::GVariant => {
310 #[cfg(unix)]
311 {
312 crate::gvariant::Deserializer::new(
313 self.bytes(),
314 Some(fds),
315 &signature,
316 self.context,
317 )
318 }
319 #[cfg(not(unix))]
320 {
321 crate::gvariant::Deserializer::new(self.bytes(), &signature, self.context)
322 }
323 }
324 .map(Deserializer::GVariant)?,
325 Format::DBus => {
326 #[cfg(unix)]
327 {
328 crate::dbus::Deserializer::new(
329 self.bytes(),
330 Some(fds),
331 &signature,
332 self.context,
333 )
334 }
335 #[cfg(not(unix))]
336 {
337 crate::dbus::Deserializer::<()>::new(self.bytes(), &signature, self.context)
338 }
339 }
340 .map(Deserializer::DBus)?,
341 };
342
343 seed.deserialize(&mut de).map(|t| match de {
344 #[cfg(feature = "gvariant")]
345 Deserializer::GVariant(de) => (t, de.0.pos),
346 Deserializer::DBus(de) => (t, de.0.pos),
347 })
348 }
349}
350
351impl<'bytes> Data<'bytes, 'static> {
352 /// Create a new `Data` instance.
353 pub fn new<T>(bytes: T, context: Context) -> Self
354 where
355 T: Into<Cow<'bytes, [u8]>>,
356 {
357 let bytes = bytes.into();
358 let range = Range {
359 start: 0,
360 end: bytes.len(),
361 };
362 Data {
363 inner: Arc::new(Inner {
364 bytes,
365 #[cfg(unix)]
366 fds: vec![],
367 #[cfg(not(unix))]
368 _fds: std::marker::PhantomData,
369 }),
370 context,
371 range,
372 }
373 }
374
375 /// Create a new `Data` instance containing owned file descriptors.
376 ///
377 /// This method is only available on Unix platforms.
378 #[cfg(unix)]
379 pub fn new_fds<T>(
380 bytes: T,
381 context: Context,
382 fds: impl IntoIterator<Item = impl Into<OwnedFd>>,
383 ) -> Self
384 where
385 T: Into<Cow<'bytes, [u8]>>,
386 {
387 let bytes = bytes.into();
388 let range = Range {
389 start: 0,
390 end: bytes.len(),
391 };
392 Data {
393 inner: Arc::new(Inner {
394 bytes,
395 fds: fds.into_iter().map(Into::into).map(Fd::from).collect(),
396 }),
397 context,
398 range,
399 }
400 }
401}
402
403impl Deref for Data<'_, '_> {
404 type Target = [u8];
405
406 fn deref(&self) -> &Self::Target {
407 self.bytes()
408 }
409}
410
411impl<T> AsRef<T> for Data<'_, '_>
412where
413 T: ?Sized,
414 for<'bytes, 'fds> <Data<'bytes, 'fds> as Deref>::Target: AsRef<T>,
415{
416 fn as_ref(&self) -> &T {
417 self.deref().as_ref()
418 }
419}