1 | #[cfg (unix)] |
2 | use crate::{Fd, OwnedFd}; |
3 | use std::{ |
4 | borrow::Cow, |
5 | ops::{Bound, Deref, Range, RangeBounds}, |
6 | sync::Arc, |
7 | }; |
8 | |
9 | use serde::{de::DeserializeSeed, Deserialize}; |
10 | |
11 | use 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)] |
23 | pub struct Data<'bytes, 'fds> { |
24 | inner: Arc<Inner<'bytes, 'fds>>, |
25 | context: Context, |
26 | range: Range<usize>, |
27 | } |
28 | |
29 | #[derive (Debug)] |
30 | pub 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 | |
38 | impl<'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 | |
332 | impl<'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 | |
384 | impl Deref for Data<'_, '_> { |
385 | type Target = [u8]; |
386 | |
387 | fn deref(&self) -> &Self::Target { |
388 | self.bytes() |
389 | } |
390 | } |
391 | |
392 | impl<T> AsRef<T> for Data<'_, '_> |
393 | where |
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 | } |
401 | |