1 | use crate::{utils::*, Signature}; |
2 | use serde::de::{Deserialize, DeserializeSeed}; |
3 | use std::{ |
4 | convert::TryInto, |
5 | marker::PhantomData, |
6 | net::{IpAddr, Ipv4Addr, Ipv6Addr}, |
7 | path::{Path, PathBuf}, |
8 | rc::Rc, |
9 | sync::{Arc, Mutex, RwLock}, |
10 | time::Duration, |
11 | }; |
12 | |
13 | /// Trait implemented by all serializable types. |
14 | /// |
15 | /// This very simple trait provides the signature for the implementing type. Since the [D-Bus type |
16 | /// system] relies on these signatures, our [serialization and deserialization] API requires this |
17 | /// trait in addition to [`Serialize`] and [`Deserialize`], respectively. |
18 | /// |
19 | /// Implementation is provided for all the [basic types] and blanket implementations for common |
20 | /// container types, such as, arrays, slices, tuples, [`Vec`] and [`HashMap`]. For easy |
21 | /// implementation for custom types, use `Type` derive macro from [zvariant_derive] crate. |
22 | /// |
23 | /// If your type's signature cannot be determined statically, you should implement the |
24 | /// [DynamicType] trait instead, which is otherwise automatically implemented if you implement this |
25 | /// trait. |
26 | /// |
27 | /// [D-Bus type system]: https://dbus.freedesktop.org/doc/dbus-specification.html#type-system |
28 | /// [serialization and deserialization]: index.html#functions |
29 | /// [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html |
30 | /// [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html |
31 | /// [basic types]: trait.Basic.html |
32 | /// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html |
33 | /// [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html |
34 | /// [zvariant_derive]: https://docs.rs/zvariant_derive/2.10.0/zvariant_derive/ |
35 | pub trait Type { |
36 | /// Get the signature for the implementing type. |
37 | /// |
38 | /// # Example |
39 | /// |
40 | /// ``` |
41 | /// use std::collections::HashMap; |
42 | /// use zvariant::Type; |
43 | /// |
44 | /// assert_eq!(u32::signature(), "u" ); |
45 | /// assert_eq!(String::signature(), "s" ); |
46 | /// assert_eq!(<(u32, &str, u64)>::signature(), "(ust)" ); |
47 | /// assert_eq!(<(u32, &str, &[u64])>::signature(), "(usat)" ); |
48 | /// assert_eq!(<HashMap<u8, &str>>::signature(), "a{ys}" ); |
49 | /// ``` |
50 | fn signature() -> Signature<'static>; |
51 | } |
52 | |
53 | /// Types with dynamic signatures. |
54 | /// |
55 | /// Prefer implementing [Type] if possible, but if the actual signature of your type cannot be |
56 | /// determined until runtime, you can implement this type to support serialization. You should |
57 | /// also implement [DynamicDeserialize] for deserialization. |
58 | pub trait DynamicType { |
59 | /// Get the signature for the implementing type. |
60 | /// |
61 | /// See [Type::signature] for details. |
62 | fn dynamic_signature(&self) -> Signature<'_>; |
63 | } |
64 | |
65 | /// Types that deserialize based on dynamic signatures. |
66 | /// |
67 | /// Prefer implementing [Type] and [Deserialize] if possible, but if the actual signature of your |
68 | /// type cannot be determined until runtime, you should implement this type to support |
69 | /// deserialization given a signature. |
70 | pub trait DynamicDeserialize<'de>: DynamicType { |
71 | /// A [DeserializeSeed] implementation for this type. |
72 | type Deserializer: DeserializeSeed<'de, Value = Self> + DynamicType; |
73 | |
74 | /// Get a deserializer compatible with this signature. |
75 | fn deserializer_for_signature<S>(signature: S) -> zvariant::Result<Self::Deserializer> |
76 | where |
77 | S: TryInto<Signature<'de>>, |
78 | S::Error: Into<zvariant::Error>; |
79 | } |
80 | |
81 | impl<T> DynamicType for T |
82 | where |
83 | T: Type + ?Sized, |
84 | { |
85 | fn dynamic_signature(&self) -> Signature<'_> { |
86 | <T as Type>::signature() |
87 | } |
88 | } |
89 | |
90 | impl<T> Type for PhantomData<T> |
91 | where |
92 | T: Type + ?Sized, |
93 | { |
94 | fn signature() -> Signature<'static> { |
95 | T::signature() |
96 | } |
97 | } |
98 | |
99 | impl<'de, T> DynamicDeserialize<'de> for T |
100 | where |
101 | T: Type + ?Sized + Deserialize<'de>, |
102 | { |
103 | type Deserializer = PhantomData<T>; |
104 | |
105 | fn deserializer_for_signature<S>(signature: S) -> zvariant::Result<Self::Deserializer> |
106 | where |
107 | S: TryInto<Signature<'de>>, |
108 | S::Error: Into<zvariant::Error>, |
109 | { |
110 | let mut expected = <T as Type>::signature(); |
111 | let original = signature.try_into().map_err(Into::into)?; |
112 | |
113 | if original == expected { |
114 | return Ok(PhantomData); |
115 | } |
116 | |
117 | let mut signature = original.clone(); |
118 | while expected.len() < signature.len() |
119 | && signature.starts_with(STRUCT_SIG_START_CHAR) |
120 | && signature.ends_with(STRUCT_SIG_END_CHAR) |
121 | { |
122 | signature = signature.slice(1..signature.len() - 1); |
123 | } |
124 | |
125 | while signature.len() < expected.len() |
126 | && expected.starts_with(STRUCT_SIG_START_CHAR) |
127 | && expected.ends_with(STRUCT_SIG_END_CHAR) |
128 | { |
129 | expected = expected.slice(1..expected.len() - 1); |
130 | } |
131 | |
132 | if signature == expected { |
133 | Ok(PhantomData) |
134 | } else { |
135 | let expected = <T as Type>::signature(); |
136 | Err(zvariant::Error::SignatureMismatch( |
137 | original.to_owned(), |
138 | format!("` {expected}`" ), |
139 | )) |
140 | } |
141 | } |
142 | } |
143 | |
144 | macro_rules! array_type { |
145 | ($arr:ty) => { |
146 | impl<T> Type for $arr |
147 | where |
148 | T: Type, |
149 | { |
150 | #[inline] |
151 | fn signature() -> Signature<'static> { |
152 | Signature::from_string_unchecked(format!("a{}" , T::signature())) |
153 | } |
154 | } |
155 | }; |
156 | } |
157 | |
158 | array_type!([T]); |
159 | array_type!(Vec<T>); |
160 | |
161 | impl<T, S> Type for std::collections::HashSet<T, S> |
162 | where |
163 | T: Type + Eq + Hash, |
164 | S: BuildHasher, |
165 | { |
166 | #[inline ] |
167 | fn signature() -> Signature<'static> { |
168 | <[T]>::signature() |
169 | } |
170 | } |
171 | |
172 | #[cfg (feature = "arrayvec" )] |
173 | impl<T, const CAP: usize> Type for arrayvec::ArrayVec<T, CAP> |
174 | where |
175 | T: Type, |
176 | { |
177 | #[inline ] |
178 | fn signature() -> Signature<'static> { |
179 | <[T]>::signature() |
180 | } |
181 | } |
182 | |
183 | #[cfg (feature = "arrayvec" )] |
184 | impl<const CAP: usize> Type for arrayvec::ArrayString<CAP> { |
185 | #[inline ] |
186 | fn signature() -> Signature<'static> { |
187 | <&str>::signature() |
188 | } |
189 | } |
190 | |
191 | // Empty type deserves empty signature |
192 | impl Type for () { |
193 | #[inline ] |
194 | fn signature() -> Signature<'static> { |
195 | Signature::from_static_str_unchecked(signature:"" ) |
196 | } |
197 | } |
198 | |
199 | macro_rules! deref_impl { |
200 | ( |
201 | $type:ty, |
202 | <$($desc:tt)+ |
203 | ) => { |
204 | impl <$($desc)+ { |
205 | #[inline] |
206 | fn signature() -> Signature<'static> { |
207 | <$type>::signature() |
208 | } |
209 | } |
210 | }; |
211 | } |
212 | |
213 | deref_impl!(T, <T: ?Sized + Type> Type for &T); |
214 | deref_impl!(T, <T: ?Sized + Type> Type for &mut T); |
215 | deref_impl!(T, <T: ?Sized + Type + ToOwned> Type for Cow<'_, T>); |
216 | deref_impl!(T, <T: ?Sized + Type> Type for Arc<T>); |
217 | deref_impl!(T, <T: ?Sized + Type> Type for Mutex<T>); |
218 | deref_impl!(T, <T: ?Sized + Type> Type for RwLock<T>); |
219 | deref_impl!(T, <T: ?Sized + Type> Type for Box<T>); |
220 | deref_impl!(T, <T: ?Sized + Type> Type for Rc<T>); |
221 | |
222 | #[cfg (feature = "gvariant" )] |
223 | impl<T> Type for Option<T> |
224 | where |
225 | T: Type, |
226 | { |
227 | #[inline ] |
228 | fn signature() -> Signature<'static> { |
229 | Signature::from_string_unchecked(format!("m {}" , T::signature())) |
230 | } |
231 | } |
232 | |
233 | //////////////////////////////////////////////////////////////////////////////// |
234 | |
235 | macro_rules! tuple_impls { |
236 | ($($len:expr => ($($n:tt $name:ident)+))+) => { |
237 | $( |
238 | impl<$($name),+> Type for ($($name,)+) |
239 | where |
240 | $($name: Type,)+ |
241 | { |
242 | fn signature() -> Signature<'static> { |
243 | let mut sig = String::with_capacity(255); |
244 | sig.push(STRUCT_SIG_START_CHAR); |
245 | $( |
246 | sig.push_str($name::signature().as_str()); |
247 | )+ |
248 | sig.push(STRUCT_SIG_END_CHAR); |
249 | |
250 | Signature::from_string_unchecked(sig) |
251 | } |
252 | } |
253 | )+ |
254 | } |
255 | } |
256 | |
257 | tuple_impls! { |
258 | 1 => (0 T0) |
259 | 2 => (0 T0 1 T1) |
260 | 3 => (0 T0 1 T1 2 T2) |
261 | 4 => (0 T0 1 T1 2 T2 3 T3) |
262 | 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) |
263 | 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) |
264 | 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) |
265 | 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) |
266 | 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) |
267 | 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) |
268 | 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) |
269 | 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) |
270 | 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) |
271 | 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) |
272 | 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) |
273 | 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) |
274 | } |
275 | |
276 | //////////////////////////////////////////////////////////////////////////////// |
277 | |
278 | // Arrays are serialized as tuples/structs by Serde so we treat them as such too even though |
279 | // it's very strange. Slices and arrayvec::ArrayVec can be used anyway so I guess it's no big |
280 | // deal. |
281 | impl<T, const N: usize> Type for [T; N] |
282 | where |
283 | T: Type, |
284 | { |
285 | #[allow (clippy::reversed_empty_ranges)] |
286 | fn signature() -> Signature<'static> { |
287 | let mut sig: String = String::with_capacity(255); |
288 | sig.push(STRUCT_SIG_START_CHAR); |
289 | for _ in 0..N { |
290 | sig.push_str(T::signature().as_str()); |
291 | } |
292 | sig.push(STRUCT_SIG_END_CHAR); |
293 | |
294 | Signature::from_string_unchecked(signature:sig) |
295 | } |
296 | } |
297 | |
298 | //////////////////////////////////////////////////////////////////////////////// |
299 | |
300 | use std::{ |
301 | borrow::Cow, |
302 | collections::{BTreeMap, HashMap}, |
303 | hash::{BuildHasher, Hash}, |
304 | time::SystemTime, |
305 | }; |
306 | |
307 | macro_rules! map_impl { |
308 | ($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)* >) => { |
309 | impl<K, V $(, $typaram)*> Type for $ty<K, V $(, $typaram)*> |
310 | where |
311 | K: Type $(+ $kbound1 $(+ $kbound2)*)*, |
312 | V: Type, |
313 | $($typaram: $bound,)* |
314 | { |
315 | #[inline] |
316 | fn signature() -> Signature<'static> { |
317 | Signature::from_string_unchecked(format!("a{{{}{}}}" , K::signature(), V::signature())) |
318 | } |
319 | } |
320 | } |
321 | } |
322 | |
323 | map_impl!(BTreeMap<K: Ord, V>); |
324 | map_impl!(HashMap<K: Eq + Hash, V, H: BuildHasher>); |
325 | |
326 | impl Type for Duration { |
327 | fn signature() -> Signature<'static> { |
328 | <(u64, u32)>::signature() |
329 | } |
330 | } |
331 | |
332 | impl Type for SystemTime { |
333 | #[inline ] |
334 | fn signature() -> Signature<'static> { |
335 | <( |
336 | // seconds |
337 | u64, |
338 | // nano |
339 | u32, |
340 | )>::signature() |
341 | } |
342 | } |
343 | |
344 | impl Type for Ipv4Addr { |
345 | #[inline ] |
346 | fn signature() -> Signature<'static> { |
347 | <[u8; 4]>::signature() |
348 | } |
349 | } |
350 | |
351 | impl Type for Ipv6Addr { |
352 | #[inline ] |
353 | fn signature() -> Signature<'static> { |
354 | <[u8; 16]>::signature() |
355 | } |
356 | } |
357 | |
358 | impl Type for IpAddr { |
359 | #[inline ] |
360 | fn signature() -> Signature<'static> { |
361 | <(u32, &[u8])>::signature() |
362 | } |
363 | } |
364 | |
365 | // BitFlags |
366 | #[cfg (feature = "enumflags2" )] |
367 | impl<F> Type for enumflags2::BitFlags<F> |
368 | where |
369 | F: Type + enumflags2::BitFlag, |
370 | { |
371 | #[inline ] |
372 | fn signature() -> Signature<'static> { |
373 | F::signature() |
374 | } |
375 | } |
376 | |
377 | #[cfg (feature = "serde_bytes" )] |
378 | impl Type for serde_bytes::Bytes { |
379 | fn signature() -> Signature<'static> { |
380 | Signature::from_static_str_unchecked("ay" ) |
381 | } |
382 | } |
383 | |
384 | #[cfg (feature = "serde_bytes" )] |
385 | impl Type for serde_bytes::ByteBuf { |
386 | fn signature() -> Signature<'static> { |
387 | Signature::from_static_str_unchecked("ay" ) |
388 | } |
389 | } |
390 | |
391 | #[allow (unused)] |
392 | macro_rules! static_str_type { |
393 | ($ty:ty) => { |
394 | impl Type for $ty { |
395 | fn signature() -> Signature<'static> { |
396 | <&str>::signature() |
397 | } |
398 | } |
399 | }; |
400 | } |
401 | |
402 | static_str_type!(Path); |
403 | static_str_type!(PathBuf); |
404 | |
405 | #[cfg (feature = "uuid" )] |
406 | impl Type for uuid::Uuid { |
407 | fn signature() -> Signature<'static> { |
408 | Signature::from_static_str_unchecked("ay" ) |
409 | } |
410 | } |
411 | |
412 | #[cfg (feature = "url" )] |
413 | static_str_type!(url::Url); |
414 | |
415 | // FIXME: Ignoring the `serde-human-readable` feature of `time` crate in these impls: |
416 | // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L110 |
417 | #[cfg (feature = "time" )] |
418 | impl Type for time::Date { |
419 | fn signature() -> Signature<'static> { |
420 | // Serialized as a (year, ordinal) tuple: |
421 | // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L92 |
422 | <(i32, u16)>::signature() |
423 | } |
424 | } |
425 | |
426 | #[cfg (feature = "time" )] |
427 | impl Type for time::Duration { |
428 | fn signature() -> Signature<'static> { |
429 | // Serialized as a (whole seconds, nanoseconds) tuple: |
430 | // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L119 |
431 | <(i64, i32)>::signature() |
432 | } |
433 | } |
434 | |
435 | #[cfg (feature = "time" )] |
436 | impl Type for time::OffsetDateTime { |
437 | fn signature() -> Signature<'static> { |
438 | // Serialized as a tuple: |
439 | // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L155 |
440 | <( |
441 | // year |
442 | i32, |
443 | // ordinal |
444 | u16, |
445 | // hour |
446 | u8, |
447 | // minute |
448 | u8, |
449 | // second |
450 | u8, |
451 | // nanosecond |
452 | u32, |
453 | // offset.whole_hours |
454 | i8, |
455 | // offset.minutes_past_hour |
456 | i8, |
457 | // offset.seconds_past_minute |
458 | i8, |
459 | )>::signature() |
460 | } |
461 | } |
462 | |
463 | #[cfg (feature = "time" )] |
464 | impl Type for time::PrimitiveDateTime { |
465 | fn signature() -> Signature<'static> { |
466 | // Serialized as a tuple: |
467 | // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L200 |
468 | <( |
469 | // year |
470 | i32, |
471 | // ordinal |
472 | u16, |
473 | // hour |
474 | u8, |
475 | // minute |
476 | u8, |
477 | // second |
478 | u8, |
479 | // nanosecond |
480 | u32, |
481 | )>::signature() |
482 | } |
483 | } |
484 | |
485 | #[cfg (feature = "time" )] |
486 | impl Type for time::Time { |
487 | fn signature() -> Signature<'static> { |
488 | // Serialized as a tuple: |
489 | // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L246 |
490 | <( |
491 | // hour |
492 | u8, |
493 | // minute |
494 | u8, |
495 | // second |
496 | u8, |
497 | // nanosecond |
498 | u32, |
499 | )>::signature() |
500 | } |
501 | } |
502 | |
503 | #[cfg (feature = "time" )] |
504 | impl Type for time::UtcOffset { |
505 | fn signature() -> Signature<'static> { |
506 | // Serialized as a (whole hours, minutes past hour, seconds past minute) tuple: |
507 | // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L282 |
508 | <(i8, i8, i8)>::signature() |
509 | } |
510 | } |
511 | |
512 | #[cfg (feature = "time" )] |
513 | impl Type for time::Weekday { |
514 | fn signature() -> Signature<'static> { |
515 | // Serialized as number from Monday: |
516 | // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L312 |
517 | u8::signature() |
518 | } |
519 | } |
520 | |
521 | #[cfg (feature = "time" )] |
522 | impl Type for time::Month { |
523 | fn signature() -> Signature<'static> { |
524 | // Serialized as month number: |
525 | // https://github.com/time-rs/time/blob/f9398b9598757508ca3815694f23203843e0011b/src/serde/mod.rs#L337 |
526 | u8::signature() |
527 | } |
528 | } |
529 | |
530 | #[cfg (feature = "chrono" )] |
531 | impl<Tz: chrono::TimeZone> Type for chrono::DateTime<Tz> { |
532 | fn signature() -> Signature<'static> { |
533 | <&str>::signature() |
534 | } |
535 | } |
536 | |
537 | #[cfg (feature = "chrono" )] |
538 | static_str_type!(chrono::NaiveDateTime); |
539 | #[cfg (feature = "chrono" )] |
540 | static_str_type!(chrono::NaiveTime); |
541 | |
542 | // TODO: Blanket implementation for more types: https://github.com/serde-rs/serde/blob/master/serde/src/ser/impls.rs |
543 | |