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
13pub trait Type {
36 fn signature() -> Signature<'static>;
51}
52
53pub trait DynamicType {
59 fn dynamic_signature(&self) -> Signature<'_>;
63}
64
65pub trait DynamicDeserialize<'de>: DynamicType {
71 type Deserializer: DeserializeSeed<'de, Value = Self> + DynamicType;
73
74 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
191impl Type for () {
193 #[inline]
194 fn signature() -> Signature<'static> {
195 Signature::from_static_str_unchecked("")
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
233macro_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
276impl<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::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(sig)
295 }
296}
297
298use 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 u64,
338 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#[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#[cfg(feature = "time")]
418impl Type for time::Date {
419 fn signature() -> Signature<'static> {
420 <(i32, u16)>::signature()
423 }
424}
425
426#[cfg(feature = "time")]
427impl Type for time::Duration {
428 fn signature() -> Signature<'static> {
429 <(i64, i32)>::signature()
432 }
433}
434
435#[cfg(feature = "time")]
436impl Type for time::OffsetDateTime {
437 fn signature() -> Signature<'static> {
438 <(
441 i32,
443 u16,
445 u8,
447 u8,
449 u8,
451 u32,
453 i8,
455 i8,
457 i8,
459 )>::signature()
460 }
461}
462
463#[cfg(feature = "time")]
464impl Type for time::PrimitiveDateTime {
465 fn signature() -> Signature<'static> {
466 <(
469 i32,
471 u16,
473 u8,
475 u8,
477 u8,
479 u32,
481 )>::signature()
482 }
483}
484
485#[cfg(feature = "time")]
486impl Type for time::Time {
487 fn signature() -> Signature<'static> {
488 <(
491 u8,
493 u8,
495 u8,
497 u32,
499 )>::signature()
500 }
501}
502
503#[cfg(feature = "time")]
504impl Type for time::UtcOffset {
505 fn signature() -> Signature<'static> {
506 <(i8, i8, i8)>::signature()
509 }
510}
511
512#[cfg(feature = "time")]
513impl Type for time::Weekday {
514 fn signature() -> Signature<'static> {
515 u8::signature()
518 }
519}
520
521#[cfg(feature = "time")]
522impl Type for time::Month {
523 fn signature() -> Signature<'static> {
524 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