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}