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}