Skip to main content

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::{Deserialize, de::DeserializeSeed};
10
11use crate::{
12    DynamicDeserialize, DynamicType, Error, Result, Signature, Type,
13    de::Deserializer,
14    serialized::{Context, Format},
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            #[allow(deprecated)]
237            Format::GVariant => {
238                #[cfg(unix)]
239                {
240                    crate::gvariant::Deserializer::new(
241                        self.bytes(),
242                        Some(fds),
243                        &signature,
244                        self.context,
245                    )
246                }
247                #[cfg(not(unix))]
248                {
249                    crate::gvariant::Deserializer::<()>::new(self.bytes(), &signature, self.context)
250                }
251            }
252            .map(Deserializer::GVariant)?,
253            Format::DBus => {
254                #[cfg(unix)]
255                {
256                    crate::dbus::Deserializer::new(
257                        self.bytes(),
258                        Some(fds),
259                        &signature,
260                        self.context,
261                    )
262                }
263                #[cfg(not(unix))]
264                {
265                    crate::dbus::Deserializer::<()>::new(self.bytes(), &signature, self.context)
266                }
267            }
268            .map(Deserializer::DBus)?,
269            // `Format` can still have a `GVariant` variant here even with `zvariant`'s own
270            // `gvariant` feature disabled: if some other crate in the dependency graph (e.g.
271            // `zgvariant`) enables `zvariant_utils/gvariant`, Cargo feature unification adds
272            // the variant to this build regardless. `zvariant`'s own `#[cfg(feature = ...)]`
273            // can't detect that (Cargo features don't propagate that way), so the variant
274            // can't be named explicitly here without breaking the common case where it
275            // doesn't exist at all. Fall back to a wildcard instead: it's unreachable
276            // whenever `gvariant` is enabled (the two arms above are then exhaustive) or the
277            // variant doesn't exist.
278            #[cfg(not(feature = "gvariant"))]
279            #[allow(unreachable_patterns)]
280            _ => {
281                return Err(Error::Message(
282                    "GVariant support has moved to the `zgvariant` crate; enable `zvariant`'s \
283                     deprecated `gvariant` feature only for legacy compatibility"
284                        .to_owned(),
285                ));
286            }
287        };
288
289        T::deserialize(&mut de).map(|t| match de {
290            #[cfg(feature = "gvariant")]
291            #[allow(deprecated)]
292            Deserializer::GVariant(de) => (t, de.0.pos),
293            Deserializer::DBus(de) => (t, de.0.pos),
294        })
295    }
296
297    /// Deserialize `T` from `self`, with the given dynamic signature.
298    ///
299    /// # Return value
300    ///
301    /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`.
302    pub fn deserialize_for_dynamic_signature<'d, S, T>(&'d self, signature: S) -> Result<(T, usize)>
303    where
304        T: DynamicDeserialize<'d>,
305        S: TryInto<Signature>,
306        S::Error: Into<Error>,
307    {
308        let signature = signature.try_into().map_err(Into::into)?;
309        let seed = T::deserializer_for_signature(&signature)?;
310
311        self.deserialize_with_seed(seed)
312    }
313
314    /// Deserialize `T` from `self`, using the given seed.
315    ///
316    /// # Return value
317    ///
318    /// A tuple containing the deserialized value and the number of bytes parsed from `bytes`.
319    pub fn deserialize_with_seed<'d, S>(&'d self, seed: S) -> Result<(S::Value, usize)>
320    where
321        S: DeserializeSeed<'d> + DynamicType,
322    {
323        let signature = S::signature(&seed);
324
325        #[cfg(unix)]
326        let fds = &self.inner.fds;
327        let mut de = match self.context.format() {
328            #[cfg(feature = "gvariant")]
329            #[allow(deprecated)]
330            Format::GVariant => {
331                #[cfg(unix)]
332                {
333                    crate::gvariant::Deserializer::new(
334                        self.bytes(),
335                        Some(fds),
336                        &signature,
337                        self.context,
338                    )
339                }
340                #[cfg(not(unix))]
341                {
342                    crate::gvariant::Deserializer::new(self.bytes(), &signature, self.context)
343                }
344            }
345            .map(Deserializer::GVariant)?,
346            Format::DBus => {
347                #[cfg(unix)]
348                {
349                    crate::dbus::Deserializer::new(
350                        self.bytes(),
351                        Some(fds),
352                        &signature,
353                        self.context,
354                    )
355                }
356                #[cfg(not(unix))]
357                {
358                    crate::dbus::Deserializer::<()>::new(self.bytes(), &signature, self.context)
359                }
360            }
361            .map(Deserializer::DBus)?,
362            // See the comment on the equivalent arm in `deserialize_for_signature` above.
363            #[cfg(not(feature = "gvariant"))]
364            #[allow(unreachable_patterns)]
365            _ => {
366                return Err(Error::Message(
367                    "GVariant support has moved to the `zgvariant` crate; enable `zvariant`'s \
368                     deprecated `gvariant` feature only for legacy compatibility"
369                        .to_owned(),
370                ));
371            }
372        };
373
374        seed.deserialize(&mut de).map(|t| match de {
375            #[cfg(feature = "gvariant")]
376            #[allow(deprecated)]
377            Deserializer::GVariant(de) => (t, de.0.pos),
378            Deserializer::DBus(de) => (t, de.0.pos),
379        })
380    }
381}
382
383impl<'bytes> Data<'bytes, 'static> {
384    /// Create a new `Data` instance.
385    pub fn new<T>(bytes: T, context: Context) -> Self
386    where
387        T: Into<Cow<'bytes, [u8]>>,
388    {
389        let bytes = bytes.into();
390        let range = Range {
391            start: 0,
392            end: bytes.len(),
393        };
394        Data {
395            inner: Arc::new(Inner {
396                bytes,
397                #[cfg(unix)]
398                fds: vec![],
399                #[cfg(not(unix))]
400                _fds: std::marker::PhantomData,
401            }),
402            context,
403            range,
404        }
405    }
406
407    /// Create a new `Data` instance containing owned file descriptors.
408    ///
409    /// This method is only available on Unix platforms.
410    #[cfg(unix)]
411    pub fn new_fds<T>(
412        bytes: T,
413        context: Context,
414        fds: impl IntoIterator<Item = impl Into<OwnedFd>>,
415    ) -> Self
416    where
417        T: Into<Cow<'bytes, [u8]>>,
418    {
419        let bytes = bytes.into();
420        let range = Range {
421            start: 0,
422            end: bytes.len(),
423        };
424        Data {
425            inner: Arc::new(Inner {
426                bytes,
427                fds: fds.into_iter().map(Into::into).map(Fd::from).collect(),
428            }),
429            context,
430            range,
431        }
432    }
433}
434
435impl Deref for Data<'_, '_> {
436    type Target = [u8];
437
438    fn deref(&self) -> &Self::Target {
439        self.bytes()
440    }
441}
442
443impl<T> AsRef<T> for Data<'_, '_>
444where
445    T: ?Sized,
446    for<'bytes, 'fds> <Data<'bytes, 'fds> as Deref>::Target: AsRef<T>,
447{
448    fn as_ref(&self) -> &T {
449        self.deref().as_ref()
450    }
451}