1use crate::{utils::*, Signature};
2use serde::de::{Deserialize, DeserializeSeed};
3use 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/
35pub 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.
58pub 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.
70pub 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
81impl<T> DynamicType for T
82where
83 T: Type + ?Sized,
84{
85 fn dynamic_signature(&self) -> Signature<'_> {
86 <T as Type>::signature()
87 }
88}
89
90impl<T> Type for PhantomData<T>
91where
92 T: Type + ?Sized,
93{
94 fn signature() -> Signature<'static> {
95 T::signature()
96 }
97}
98
99impl<'de, T> DynamicDeserialize<'de> for T
100where
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
144macro_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
158array_type!([T]);
159array_type!(Vec<T>);
160
161impl<T, S> Type for std::collections::HashSet<T, S>
162where
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")]
173impl<T, const CAP: usize> Type for arrayvec::ArrayVec<T, CAP>
174where
175 T: Type,
176{
177 #[inline]
178 fn signature() -> Signature<'static> {
179 <[T]>::signature()
180 }
181}
182
183#[cfg(feature = "arrayvec")]
184impl<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
192impl Type for () {
193 #[inline]
194 fn signature() -> Signature<'static> {
195 Signature::from_static_str_unchecked(signature:"")
196 }
197}
198
199macro_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
213deref_impl!(T, <T: ?Sized + Type> Type for &T);
214deref_impl!(T, <T: ?Sized + Type> Type for &mut T);
215deref_impl!(T, <T: ?Sized + Type + ToOwned> Type for Cow<'_, T>);
216deref_impl!(T, <T: ?Sized + Type> Type for Arc<T>);
217deref_impl!(T, <T: ?Sized + Type> Type for Mutex<T>);
218deref_impl!(T, <T: ?Sized + Type> Type for RwLock<T>);
219deref_impl!(T, <T: ?Sized + Type> Type for Box<T>);
220deref_impl!(T, <T: ?Sized + Type> Type for Rc<T>);
221
222#[cfg(feature = "gvariant")]
223impl<T> Type for Option<T>
224where
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
235macro_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
257tuple_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.
281impl<T, const N: usize> Type for [T; N]
282where
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
300use std::{
301 borrow::Cow,
302 collections::{BTreeMap, HashMap},
303 hash::{BuildHasher, Hash},
304 time::SystemTime,
305};
306
307macro_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
323map_impl!(BTreeMap<K: Ord, V>);
324map_impl!(HashMap<K: Eq + Hash, V, H: BuildHasher>);
325
326impl Type for Duration {
327 fn signature() -> Signature<'static> {
328 <(u64, u32)>::signature()
329 }
330}
331
332impl Type for SystemTime {
333 #[inline]
334 fn signature() -> Signature<'static> {
335 <(
336 // seconds
337 u64,
338 // nano
339 u32,
340 )>::signature()
341 }
342}
343
344impl Type for Ipv4Addr {
345 #[inline]
346 fn signature() -> Signature<'static> {
347 <[u8; 4]>::signature()
348 }
349}
350
351impl Type for Ipv6Addr {
352 #[inline]
353 fn signature() -> Signature<'static> {
354 <[u8; 16]>::signature()
355 }
356}
357
358impl Type for IpAddr {
359 #[inline]
360 fn signature() -> Signature<'static> {
361 <(u32, &[u8])>::signature()
362 }
363}
364
365// BitFlags
366#[cfg(feature = "enumflags2")]
367impl<F> Type for enumflags2::BitFlags<F>
368where
369 F: Type + enumflags2::BitFlag,
370{
371 #[inline]
372 fn signature() -> Signature<'static> {
373 F::signature()
374 }
375}
376
377#[cfg(feature = "serde_bytes")]
378impl 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")]
385impl Type for serde_bytes::ByteBuf {
386 fn signature() -> Signature<'static> {
387 Signature::from_static_str_unchecked("ay")
388 }
389}
390
391#[allow(unused)]
392macro_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
402static_str_type!(Path);
403static_str_type!(PathBuf);
404
405#[cfg(feature = "uuid")]
406impl Type for uuid::Uuid {
407 fn signature() -> Signature<'static> {
408 Signature::from_static_str_unchecked("ay")
409 }
410}
411
412#[cfg(feature = "url")]
413static_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")]
418impl 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")]
427impl 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")]
436impl 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")]
464impl 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")]
486impl 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")]
504impl 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")]
513impl 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")]
522impl 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")]
531impl<Tz: chrono::TimeZone> Type for chrono::DateTime<Tz> {
532 fn signature() -> Signature<'static> {
533 <&str>::signature()
534 }
535}
536
537#[cfg(feature = "chrono")]
538static_str_type!(chrono::NaiveDateTime);
539#[cfg(feature = "chrono")]
540static_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