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}