zvariant/type/mod.rs
1mod dynamic;
2pub use dynamic::{DynamicDeserialize, DynamicType};
3#[cfg(feature = "serde_bytes")]
4mod bytes;
5#[cfg(feature = "enumflags2")]
6mod enumflags2;
7mod libstd;
8mod net;
9mod paths;
10mod time;
11#[cfg(feature = "uuid")]
12mod uuid;
13
14use crate::Signature;
15
16/// Trait implemented by all serializable types.
17///
18/// This very simple trait provides the signature for the implementing type. Since the [D-Bus type
19/// system] relies on these signatures, our [serialization and deserialization] API requires this
20/// trait in addition to [`Serialize`] and [`Deserialize`], respectively.
21///
22/// Implementation is provided for all the [basic types] and blanket implementations for common
23/// container types, such as, arrays, slices, tuples, [`Vec`] and [`HashMap`]. For easy
24/// implementation for custom types, use `Type` derive macro from [zvariant_derive] crate.
25///
26/// If your type's signature cannot be determined statically, you should implement the
27/// [DynamicType] trait instead, which is otherwise automatically implemented if you implement this
28/// trait.
29///
30/// [D-Bus type system]: https://dbus.freedesktop.org/doc/dbus-specification.html#type-system
31/// [serialization and deserialization]: index.html#functions
32/// [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html
33/// [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
34/// [basic types]: trait.Basic.html
35/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
36/// [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html
37/// [zvariant_derive]: https://docs.rs/zvariant_derive/latest/zvariant_derive/
38pub trait Type {
39 /// The signature for the implementing type, in parsed format.
40 ///
41 /// # Example
42 ///
43 /// ```
44 /// use std::collections::HashMap;
45 /// use zvariant::{Type, signature::{Child, Signature}};
46 ///
47 /// assert_eq!(u32::SIGNATURE, &Signature::U32);
48 /// assert_eq!(String::SIGNATURE, &Signature::Str);
49 /// assert_eq!(
50 /// <(u32, &str, u64)>::SIGNATURE,
51 /// &Signature::static_structure(&[&Signature::U32, &Signature::Str, &Signature::U64]),
52 /// );
53 /// assert_eq!(
54 /// <(u32, &str, &[u64])>::SIGNATURE,
55 /// &Signature::static_structure(&[
56 /// &Signature::U32,
57 /// &Signature::Str,
58 /// &Signature::Array(Child::Static { child: &Signature::U64 }),
59 /// ]),
60 /// );
61 /// assert_eq!(
62 /// <HashMap<u8, &str>>::SIGNATURE,
63 /// &Signature::static_dict(&Signature::U8, &Signature::Str),
64 /// );
65 /// ```
66 const SIGNATURE: &'static Signature;
67}
68
69/// Implements the [`Type`] trait by delegating the signature to a simpler type (usually a tuple).
70/// Tests that ensure that the two types are serialize-compatible are auto-generated.
71///
72/// Example:
73/// ```no_compile
74/// impl_type_with_repr! {
75/// // Duration is serialized as a (u64, u32) pair.
76/// Duration => (u64, u32) {
77/// // The macro auto-generates tests for us,
78/// // so we need to provide a test name.
79/// duration {
80/// // Sample values used to test serialize compatibility.
81/// samples = [Duration::ZERO, Duration::MAX],
82/// // Converts our type into the simpler "repr" type.
83/// repr(d) = (d.as_secs(), d.subsec_nanos()),
84/// }
85/// }
86/// }
87/// ```
88#[macro_export]
89macro_rules! impl_type_with_repr {
90 ($($ty:ident)::+ $(<$typaram:ident $(: $($tbound:ident)::+)?>)? => $repr:ty {
91 $test_mod:ident $(<$($typaram_sample:ident = $typaram_sample_value:ty),*>)? {
92 $(signature = $signature:literal,)?
93 samples = $samples:expr,
94 repr($sample_ident:ident) = $into_repr:expr,
95 }
96 }) => {
97 impl $(<$typaram $(: $($tbound)::+)?>)? $crate::Type for $($ty)::+ $(<$typaram>)? {
98 const SIGNATURE: &'static $crate::Signature = <$repr>::SIGNATURE;
99 }
100
101 #[cfg(test)]
102 #[allow(unused_imports)]
103 mod $test_mod {
104 use super::*;
105 use $crate::{serialized::Context, to_bytes, LE};
106
107 $($(type $typaram_sample = $typaram_sample_value;)*)?
108 type Ty = $($ty)::+$(<$typaram>)?;
109
110 const _: fn() = || {
111 fn assert_impl_all<'de, T: ?Sized + serde::Serialize + serde::Deserialize<'de>>() {}
112 assert_impl_all::<Ty>();
113 };
114
115 #[test]
116 fn type_can_be_deserialized_from_encoded_type() {
117 let ctx = Context::new_dbus(LE, 0);
118 let samples = $samples;
119 let _: &[Ty] = &samples;
120
121 for $sample_ident in samples {
122 let encoded = to_bytes(ctx, &$sample_ident).unwrap();
123 let (decoded, _): (Ty, _) = encoded.deserialize().unwrap();
124 assert_eq!($sample_ident, decoded);
125 }
126 }
127
128 #[test]
129 fn repr_can_be_deserialized_from_encoded_type() {
130 let ctx = Context::new_dbus(LE, 0);
131 let samples = $samples;
132 let _: &[Ty] = &samples;
133
134 for $sample_ident in samples {
135 let repr: $repr = $into_repr;
136 let encoded = to_bytes(ctx, &$sample_ident).unwrap();
137 let (decoded, _): ($repr, _) = encoded.deserialize().unwrap();
138 assert_eq!(repr, decoded);
139 }
140 }
141
142 #[test]
143 fn type_can_be_deserialized_from_encoded_repr() {
144 let ctx = Context::new_dbus(LE, 0);
145 let samples = $samples;
146 let _: &[Ty] = &samples;
147
148 for $sample_ident in samples {
149 let repr: $repr = $into_repr;
150 let encoded = to_bytes(ctx, &repr).unwrap();
151 let (decoded, _): (Ty, _) = encoded.deserialize().unwrap();
152 assert_eq!($sample_ident, decoded);
153 }
154 }
155
156 #[test]
157 fn encoding_of_type_and_repr_match() {
158 let ctx = Context::new_dbus(LE, 0);
159 let samples = $samples;
160 let _: &[Ty] = &samples;
161
162 for $sample_ident in samples {
163 let repr: $repr = $into_repr;
164 let encoded = to_bytes(ctx, &$sample_ident).unwrap();
165 let encoded_repr = to_bytes(ctx, &repr).unwrap();
166 assert_eq!(encoded.bytes(), encoded_repr.bytes());
167 }
168 }
169
170 $(
171 #[test]
172 fn signature_equals() {
173 assert_eq!(<Ty as $crate::Type>::SIGNATURE, $signature);
174 }
175 )?
176 }
177 };
178}
179
180#[macro_export]
181#[allow(unused)]
182macro_rules! static_str_type {
183 ($ty:ty) => {
184 impl Type for $ty {
185 const SIGNATURE: &'static Signature = &Signature::Str;
186 }
187 };
188}