Skip to main content

zvariant_utils/signature/
mod.rs

1mod child;
2pub use child::Child;
3mod fields;
4pub use fields::Fields;
5mod error;
6pub use error::Error;
7
8use serde::{Deserialize, Serialize};
9
10use core::fmt;
11use std::{
12    fmt::{Display, Formatter},
13    hash::Hash,
14    str::FromStr,
15};
16
17use crate::serialized::Format;
18
19/// A D-Bus signature in parsed form.
20///
21/// This is similar to the [`zvariant::Signature`] type, but unlike `zvariant::Signature`, this is a
22/// parsed representation of a signature. Our (de)serialization API primarily uses this type for
23/// efficiency.
24///
25/// # Examples
26///
27/// ## Using the `signature!` macro
28///
29/// The recommended way to create a `Signature` is using the [`signature!`] macro, which provides
30/// compile-time validation and can be used in const contexts:
31///
32/// ```
33/// use zvariant::signature;
34/// use zvariant::Signature;
35///
36/// // Compile-time validated signatures
37/// let sig = signature!("a{sv}");
38/// assert_eq!(sig.to_string(), "a{sv}");
39///
40/// let sig = signature!("(xa{bs}as)");
41/// assert_eq!(sig.to_string(), "(xa{bs}as)");
42///
43/// // Can be used in const contexts
44/// const SIGNATURE: Signature = signature!("a{sv}");
45/// ```
46///
47/// ## Creating from a string at runtime
48///
49/// If you need to create a `Signature` from a runtime string, use `from_str`:
50///
51/// ```
52/// use std::str::FromStr;
53/// use zvariant::Signature;
54///
55/// let sig = Signature::from_str("a{sv}").unwrap();
56/// assert_eq!(sig.to_string(), "a{sv}");
57/// ```
58///
59/// [`signature!`]: https://docs.rs/zvariant/latest/zvariant/macro.signature.html
60/// [`zvariant::Signature`]: https://docs.rs/zvariant/latest/zvariant/struct.Signature.html
61#[derive(Debug, Default, Clone)]
62pub enum Signature {
63    // Basic types
64    /// The signature for the unit type (`()`). This is not a valid D-Bus signature, but is used to
65    /// represnt "no data" (for example, a D-Bus method call without any arguments will have this
66    /// as its body signature).
67    ///
68    /// # Warning
69    ///
70    /// This variant only exists for convenience and must only be used as a top-level signature. If
71    /// used inside container signatures, it will cause errors and in somce cases, panics. It's
72    /// best to not use it directly.
73    #[default]
74    Unit,
75    /// The signature for an 8-bit unsigned integer (AKA a byte).
76    U8,
77    /// The signature for a boolean.
78    Bool,
79    /// The signature for a 16-bit signed integer.
80    I16,
81    /// The signature for a 16-bit unsigned integer.
82    U16,
83    /// The signature for a 32-bit signed integer.
84    I32,
85    /// The signature for a 32-bit unsigned integer.
86    U32,
87    /// The signature for a 64-bit signed integer.
88    I64,
89    /// The signature for a 64-bit unsigned integer.
90    U64,
91    /// The signature for a 64-bit floating point number.
92    F64,
93    /// The signature for a string.
94    Str,
95    /// The signature for a signature.
96    Signature,
97    /// The signature for an object path.
98    ObjectPath,
99    /// The signature for a variant.
100    Variant,
101    /// The signature for a file descriptor.
102    #[cfg(unix)]
103    Fd,
104
105    // Container types
106    /// The signature for an array.
107    Array(Child),
108    /// The signature for a dictionary.
109    Dict {
110        /// The signature for the key.
111        key: Child,
112        /// The signature for the value.
113        value: Child,
114    },
115    /// The signature for a structure.
116    Structure(Fields),
117    /// The signature for a maybe type (gvariant-specific).
118    #[cfg(feature = "gvariant")]
119    Maybe(Child),
120}
121
122impl Signature {
123    /// The size of the string form of `self`.
124    pub const fn string_len(&self) -> usize {
125        match self {
126            Signature::Unit => 0,
127            Signature::U8
128            | Signature::Bool
129            | Signature::I16
130            | Signature::U16
131            | Signature::I32
132            | Signature::U32
133            | Signature::I64
134            | Signature::U64
135            | Signature::F64
136            | Signature::Str
137            | Signature::Signature
138            | Signature::ObjectPath
139            | Signature::Variant => 1,
140            #[cfg(unix)]
141            Signature::Fd => 1,
142            Signature::Array(child) => 1 + child.string_len(),
143            Signature::Dict { key, value } => 3 + key.string_len() + value.string_len(),
144            Signature::Structure(fields) => {
145                let mut len = 2;
146                let mut i = 0;
147                while i < fields.len() {
148                    len += match fields {
149                        Fields::Static { fields } => fields[i].string_len(),
150                        Fields::Dynamic { fields } => fields[i].string_len(),
151                    };
152                    i += 1;
153                }
154                len
155            }
156            #[cfg(feature = "gvariant")]
157            Signature::Maybe(child) => 1 + child.string_len(),
158        }
159    }
160
161    /// Write the string form of `self` to the given formatter.
162    ///
163    /// This produces the same output as the `Display::fmt`, unless `self` is a
164    /// [`Signature::Structure`], in which case the written string will **not** be wrapped in
165    /// parenthesis (`()`).
166    pub fn write_as_string_no_parens(&self, write: &mut impl std::fmt::Write) -> fmt::Result {
167        self.write_as_string(write, false)
168    }
169
170    /// Convert `self` to a string, without any enclosing parenthesis.
171    ///
172    /// This produces the same output as the [`Signature::to_string`], unless `self` is a
173    /// [`Signature::Structure`], in which case the written string will **not** be wrapped in
174    /// parenthesis (`()`).
175    pub fn to_string_no_parens(&self) -> String {
176        let mut s = String::with_capacity(self.string_len());
177        self.write_as_string(&mut s, false).unwrap();
178
179        s
180    }
181
182    /// Convert `self` to a string.
183    ///
184    /// This produces the same output as the `ToString::to_string`, except it preallocates the
185    /// required memory and hence avoids reallocations and moving of data.
186    #[allow(clippy::inherent_to_string_shadow_display)]
187    pub fn to_string(&self) -> String {
188        let mut s = String::with_capacity(self.string_len());
189        self.write_as_string(&mut s, true).unwrap();
190
191        s
192    }
193
194    /// Parse signature from a byte slice.
195    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
196        parse(bytes, false)
197    }
198
199    /// Create a `Signature::Structure` for a given set of field signatures.
200    pub fn structure<F>(fields: F) -> Self
201    where
202        F: Into<Fields>,
203    {
204        Signature::Structure(fields.into())
205    }
206
207    /// Create a `Signature::Structure` for a given set of static field signatures.
208    pub const fn static_structure(fields: &'static [&'static Signature]) -> Self {
209        Signature::Structure(Fields::Static { fields })
210    }
211
212    /// Create a `Signature::Array` for a given child signature.
213    pub fn array<C>(child: C) -> Self
214    where
215        C: Into<Child>,
216    {
217        Signature::Array(child.into())
218    }
219
220    /// Create a `Signature::Array` for a given static child signature.
221    pub const fn static_array(child: &'static Signature) -> Self {
222        Signature::Array(Child::Static { child })
223    }
224
225    /// Create a `Signature::Dict` for a given key and value signatures.
226    pub fn dict<K, V>(key: K, value: V) -> Self
227    where
228        K: Into<Child>,
229        V: Into<Child>,
230    {
231        Signature::Dict {
232            key: key.into(),
233            value: value.into(),
234        }
235    }
236
237    /// Create a `Signature::Dict` for a given static key and value signatures.
238    pub const fn static_dict(key: &'static Signature, value: &'static Signature) -> Self {
239        Signature::Dict {
240            key: Child::Static { child: key },
241            value: Child::Static { child: value },
242        }
243    }
244
245    /// Create a `Signature::Maybe` for a given child signature.
246    #[cfg(feature = "gvariant")]
247    pub fn maybe<C>(child: C) -> Self
248    where
249        C: Into<Child>,
250    {
251        Signature::Maybe(child.into())
252    }
253
254    /// Create a `Signature::Maybe` for a given static child signature.
255    #[cfg(feature = "gvariant")]
256    pub const fn static_maybe(child: &'static Signature) -> Self {
257        Signature::Maybe(Child::Static { child })
258    }
259
260    /// The required padding alignment for the given format.
261    pub fn alignment(&self, format: Format) -> usize {
262        match format {
263            Format::DBus => self.alignment_dbus(),
264            #[cfg(feature = "gvariant")]
265            Format::GVariant => self.alignment_gvariant(),
266        }
267    }
268
269    fn alignment_dbus(&self) -> usize {
270        match self {
271            Signature::U8 | Signature::Variant | Signature::Signature => 1,
272            Signature::I16 | Signature::U16 => 2,
273            Signature::I32
274            | Signature::U32
275            | Signature::Bool
276            | Signature::Str
277            | Signature::ObjectPath
278            | Signature::Array(_)
279            | Signature::Dict { .. } => 4,
280            Signature::I64
281            | Signature::U64
282            | Signature::F64
283            | Signature::Unit
284            | Signature::Structure(_) => 8,
285            #[cfg(unix)]
286            Signature::Fd => 4,
287            #[cfg(feature = "gvariant")]
288            Signature::Maybe(_) => unreachable!("Maybe type is not supported in D-Bus"),
289        }
290    }
291
292    #[cfg(feature = "gvariant")]
293    fn alignment_gvariant(&self) -> usize {
294        use std::cmp::max;
295
296        match self {
297            Signature::Bool => 1,
298            Signature::Unit
299            | Signature::U8
300            | Signature::I16
301            | Signature::U16
302            | Signature::I32
303            | Signature::U32
304            | Signature::F64
305            | Signature::I64
306            | Signature::U64
307            | Signature::Signature => self.alignment_dbus(),
308            #[cfg(unix)]
309            Signature::Fd => self.alignment_dbus(),
310            Signature::Str | Signature::ObjectPath => 1,
311            Signature::Variant => 8,
312            Signature::Array(child) | Signature::Maybe(child) => child.alignment_gvariant(),
313            Signature::Dict { key, value } => {
314                max(key.alignment_gvariant(), value.alignment_gvariant())
315            }
316            Signature::Structure(fields) => fields
317                .iter()
318                .map(Signature::alignment_gvariant)
319                .max()
320                .unwrap_or(1),
321        }
322    }
323
324    /// Check if the signature is of a fixed-sized type.
325    #[cfg(feature = "gvariant")]
326    pub fn is_fixed_sized(&self) -> bool {
327        match self {
328            Signature::Unit
329            | Signature::U8
330            | Signature::Bool
331            | Signature::I16
332            | Signature::U16
333            | Signature::I32
334            | Signature::U32
335            | Signature::I64
336            | Signature::U64
337            | Signature::F64 => true,
338            #[cfg(unix)]
339            Signature::Fd => true,
340            Signature::Str
341            | Signature::Signature
342            | Signature::ObjectPath
343            | Signature::Variant
344            | Signature::Array(_)
345            | Signature::Dict { .. }
346            | Signature::Maybe(_) => false,
347            Signature::Structure(fields) => fields.iter().all(|f| f.is_fixed_sized()),
348        }
349    }
350
351    fn write_as_string(&self, w: &mut impl std::fmt::Write, outer_parens: bool) -> fmt::Result {
352        match self {
353            Signature::Unit => write!(w, ""),
354            Signature::U8 => write!(w, "y"),
355            Signature::Bool => write!(w, "b"),
356            Signature::I16 => write!(w, "n"),
357            Signature::U16 => write!(w, "q"),
358            Signature::I32 => write!(w, "i"),
359            Signature::U32 => write!(w, "u"),
360            Signature::I64 => write!(w, "x"),
361            Signature::U64 => write!(w, "t"),
362            Signature::F64 => write!(w, "d"),
363            Signature::Str => write!(w, "s"),
364            Signature::Signature => write!(w, "g"),
365            Signature::ObjectPath => write!(w, "o"),
366            Signature::Variant => write!(w, "v"),
367            #[cfg(unix)]
368            Signature::Fd => write!(w, "h"),
369            Signature::Array(array) => write!(w, "a{}", **array),
370            Signature::Dict { key, value } => {
371                write!(w, "a{{")?;
372                write!(w, "{}{}", **key, **value)?;
373                write!(w, "}}")
374            }
375            Signature::Structure(fields) => {
376                if outer_parens {
377                    write!(w, "(")?;
378                }
379                for field in fields.iter() {
380                    write!(w, "{field}")?;
381                }
382                if outer_parens {
383                    write!(w, ")")?;
384                }
385
386                Ok(())
387            }
388            #[cfg(feature = "gvariant")]
389            Signature::Maybe(maybe) => write!(w, "m{}", **maybe),
390        }
391    }
392}
393
394impl Display for Signature {
395    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
396        self.write_as_string(f, true)
397    }
398}
399
400impl FromStr for Signature {
401    type Err = Error;
402
403    fn from_str(s: &str) -> Result<Self, Self::Err> {
404        parse(s.as_bytes(), false)
405    }
406}
407
408impl TryFrom<&str> for Signature {
409    type Error = Error;
410
411    fn try_from(value: &str) -> Result<Self, Self::Error> {
412        Signature::from_str(value)
413    }
414}
415
416impl TryFrom<&[u8]> for Signature {
417    type Error = Error;
418
419    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
420        parse(value, false)
421    }
422}
423
424/// Validate the given signature string.
425pub fn validate(bytes: &[u8]) -> Result<(), Error> {
426    parse(bytes, true).map(|_| ())
427}
428
429/// Parse a signature string into a `Signature`.
430///
431/// When `check_only` is true, the function will not allocate memory for the dynamic types.
432/// Instead it will return dummy values in the parsed Signature.
433fn parse(bytes: &[u8], check_only: bool) -> Result<Signature, Error> {
434    use winnow::{
435        Parser,
436        combinator::{alt, delimited, empty, eof, fail, repeat},
437        dispatch,
438        token::any,
439    };
440
441    let unit = eof.map(|_| Signature::Unit);
442
443    // `many1` allocates so we only want to use it when `check_only == false`
444    type ManyError = winnow::error::ErrMode<()>;
445
446    // The maximum struct- and array-nesting depths a signature may use, matching the limits
447    // `zvariant` enforces when (de)serializing (see its `container_depths` module). This also
448    // bounds the recursion below, so a hostile signature string — e.g. tens of thousands of `(`
449    // — cannot exhaust the stack. `maybe` (gvariant) is deliberately not bounded, to stay no
450    // stricter than what the (de)serializer accepts.
451    const MAX_STRUCT_DEPTH: u8 = 32;
452    const MAX_ARRAY_DEPTH: u8 = 32;
453
454    /// The struct- and array-nesting depth at a point in a signature, used to bound the recursion.
455    #[derive(Debug, Default, Clone, Copy)]
456    struct Depth {
457        structure: u8,
458        array: u8,
459    }
460
461    impl Depth {
462        fn inc_structure(mut self) -> Self {
463            self.structure += 1;
464            self
465        }
466
467        fn inc_array(mut self) -> Self {
468            self.array += 1;
469            self
470        }
471
472        /// Whether either nesting limit has been exceeded.
473        fn exceeded(self) -> bool {
474            self.structure > MAX_STRUCT_DEPTH || self.array > MAX_ARRAY_DEPTH
475        }
476    }
477
478    fn many(
479        bytes: &mut &[u8],
480        check_only: bool,
481        top_level: bool,
482        depth: Depth,
483    ) -> Result<Signature, ManyError> {
484        let parser = |s: &mut _| parse_signature(s, check_only, depth);
485        if check_only {
486            return repeat(1.., parser)
487                .map(|_: ()| Signature::Unit)
488                .parse_next(bytes);
489        }
490
491        // Avoid the allocation of `Vec<Signature>` in case of a single signature on the top-level.
492        // This is a a very common case, especially in variants, where the signature needs to be
493        // parsed at runtime.
494        enum SignatureList {
495            Unit,
496            One(Signature),
497            Structure(Vec<Signature>),
498        }
499
500        repeat(1.., parser)
501            .fold(
502                || SignatureList::Unit,
503                |acc, signature| match acc {
504                    // On the top-level, we want to return the signature directly if there is only
505                    // one.
506                    SignatureList::Unit if top_level => SignatureList::One(signature),
507                    SignatureList::Unit => SignatureList::Structure(vec![signature]),
508                    SignatureList::One(one) => SignatureList::Structure(vec![one, signature]),
509                    SignatureList::Structure(mut signatures) => {
510                        signatures.push(signature);
511                        SignatureList::Structure(signatures)
512                    }
513                },
514            )
515            .map(|sig_list| match sig_list {
516                SignatureList::Unit => Signature::Unit,
517                SignatureList::One(sig) => sig,
518                SignatureList::Structure(signatures) => Signature::structure(signatures),
519            })
520            .parse_next(bytes)
521    }
522
523    fn parse_signature(
524        bytes: &mut &[u8],
525        check_only: bool,
526        depth: Depth,
527    ) -> Result<Signature, ManyError> {
528        // Reject types nested past the container-depth limits. Besides matching what `zvariant`
529        // can actually encode, this keeps the recursion below — and hence the stack usage —
530        // bounded on adversarial input.
531        if depth.exceeded() {
532            return fail.parse_next(bytes);
533        }
534        let array_depth = depth.inc_array();
535        let struct_depth = depth.inc_structure();
536
537        let simple_type = dispatch! {any;
538            b'y' => empty.value(Signature::U8),
539            b'b' => empty.value(Signature::Bool),
540            b'n' => empty.value(Signature::I16),
541            b'q' => empty.value(Signature::U16),
542            b'i' => empty.value(Signature::I32),
543            b'u' => empty.value(Signature::U32),
544            b'x' => empty.value(Signature::I64),
545            b't' => empty.value(Signature::U64),
546            b'd' => empty.value(Signature::F64),
547            b's' => empty.value(Signature::Str),
548            b'g' => empty.value(Signature::Signature),
549            b'o' => empty.value(Signature::ObjectPath),
550            b'v' => empty.value(Signature::Variant),
551            _ => fail,
552        };
553
554        let dict = (
555            b'a',
556            delimited(
557                b'{',
558                (
559                    move |s: &mut _| parse_signature(s, check_only, array_depth),
560                    move |s: &mut _| parse_signature(s, check_only, array_depth),
561                ),
562                b'}',
563            ),
564        )
565            .map(|(_, (key, value))| {
566                if check_only {
567                    return Signature::Dict {
568                        key: Signature::Unit.into(),
569                        value: Signature::Unit.into(),
570                    };
571                }
572
573                Signature::Dict {
574                    key: key.into(),
575                    value: value.into(),
576                }
577            });
578
579        let array = (b'a', move |s: &mut _| {
580            parse_signature(s, check_only, array_depth)
581        })
582            .map(|(_, child)| {
583                if check_only {
584                    return Signature::Array(Signature::Unit.into());
585                }
586
587                Signature::Array(child.into())
588            });
589
590        let structure = delimited(
591            b'(',
592            move |s: &mut _| many(s, check_only, false, struct_depth),
593            b')',
594        );
595
596        // `maybe` does not count toward the depth limits (see `Depth`), so its child is parsed
597        // at the same depth.
598        #[cfg(feature = "gvariant")]
599        let maybe =
600            (b'm', move |s: &mut _| parse_signature(s, check_only, depth)).map(|(_, child)| {
601                if check_only {
602                    return Signature::Maybe(Signature::Unit.into());
603                }
604
605                Signature::Maybe(child.into())
606            });
607
608        alt((
609            simple_type,
610            dict,
611            array,
612            structure,
613            #[cfg(feature = "gvariant")]
614            maybe,
615            // FIXME: Should be part of `simple_type` but that's not possible right now:
616            // https://github.com/winnow-rs/winnow/issues/609
617            #[cfg(unix)]
618            b'h'.map(|_| Signature::Fd),
619        ))
620        .parse_next(bytes)
621    }
622
623    let signature = alt((unit, |s: &mut _| {
624        many(s, check_only, true, Depth::default())
625    }))
626    .parse(bytes)
627    .map_err(|_| Error::InvalidSignature)?;
628
629    Ok(signature)
630}
631
632impl PartialEq for Signature {
633    fn eq(&self, other: &Self) -> bool {
634        match (self, other) {
635            (Signature::Unit, Signature::Unit)
636            | (Signature::U8, Signature::U8)
637            | (Signature::Bool, Signature::Bool)
638            | (Signature::I16, Signature::I16)
639            | (Signature::U16, Signature::U16)
640            | (Signature::I32, Signature::I32)
641            | (Signature::U32, Signature::U32)
642            | (Signature::I64, Signature::I64)
643            | (Signature::U64, Signature::U64)
644            | (Signature::F64, Signature::F64)
645            | (Signature::Str, Signature::Str)
646            | (Signature::Signature, Signature::Signature)
647            | (Signature::ObjectPath, Signature::ObjectPath)
648            | (Signature::Variant, Signature::Variant) => true,
649            #[cfg(unix)]
650            (Signature::Fd, Signature::Fd) => true,
651            (Signature::Array(a), Signature::Array(b)) => a.eq(&**b),
652            (
653                Signature::Dict {
654                    key: key_a,
655                    value: value_a,
656                },
657                Signature::Dict {
658                    key: key_b,
659                    value: value_b,
660                },
661            ) => key_a.eq(&**key_b) && value_a.eq(&**value_b),
662            (Signature::Structure(a), Signature::Structure(b)) => a.iter().eq(b.iter()),
663            #[cfg(feature = "gvariant")]
664            (Signature::Maybe(a), Signature::Maybe(b)) => a.eq(&**b),
665            _ => false,
666        }
667    }
668}
669
670impl Eq for Signature {}
671
672impl PartialEq<&str> for Signature {
673    fn eq(&self, other: &&str) -> bool {
674        match self {
675            Signature::Unit => other.is_empty(),
676            Self::Bool => *other == "b",
677            Self::U8 => *other == "y",
678            Self::I16 => *other == "n",
679            Self::U16 => *other == "q",
680            Self::I32 => *other == "i",
681            Self::U32 => *other == "u",
682            Self::I64 => *other == "x",
683            Self::U64 => *other == "t",
684            Self::F64 => *other == "d",
685            Self::Str => *other == "s",
686            Self::Signature => *other == "g",
687            Self::ObjectPath => *other == "o",
688            Self::Variant => *other == "v",
689            #[cfg(unix)]
690            Self::Fd => *other == "h",
691            Self::Array(child) => {
692                if other.len() < 2 || !other.starts_with('a') {
693                    return false;
694                }
695
696                child.eq(&other[1..])
697            }
698            Self::Dict { key, value } => {
699                if other.len() < 4 || !other.starts_with("a{") || !other.ends_with('}') {
700                    return false;
701                }
702
703                let (key_str, value_str) = other[2..other.len() - 1].split_at(1);
704
705                key.eq(key_str) && value.eq(value_str)
706            }
707            Self::Structure(fields) => {
708                let string_len = self.string_len();
709                // self.string_len() will always take `()` into account so it can't be a smaller
710                // number than `other.len()`.
711                if string_len < other.len()
712                    // Their length is either equal (i-e `other` has outer `()`) or `other` has no
713                    // outer `()`.
714                    || (string_len != other.len() && string_len != other.len() + 2)
715                {
716                    return false;
717                }
718
719                let fields_str = if string_len == other.len() {
720                    &other[1..other.len() - 1]
721                } else {
722                    // No outer `()`.
723                    if other.is_empty() {
724                        return false;
725                    }
726
727                    other
728                };
729
730                let mut start = 0;
731                for field in fields.iter() {
732                    let len = field.string_len();
733                    let end = start + len;
734                    if end > fields_str.len() {
735                        return false;
736                    }
737                    if !field.eq(&fields_str[start..end]) {
738                        return false;
739                    }
740
741                    start += len;
742                }
743
744                true
745            }
746            #[cfg(feature = "gvariant")]
747            Self::Maybe(child) => {
748                if other.len() < 2 || !other.starts_with('m') {
749                    return false;
750                }
751
752                child.eq(&other[1..])
753            }
754        }
755    }
756}
757
758impl PartialEq<str> for Signature {
759    fn eq(&self, other: &str) -> bool {
760        self.eq(&other)
761    }
762}
763
764impl PartialOrd for Signature {
765    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
766        Some(self.cmp(other))
767    }
768}
769
770impl Ord for Signature {
771    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
772        match (self, other) {
773            (Signature::Unit, Signature::Unit)
774            | (Signature::U8, Signature::U8)
775            | (Signature::Bool, Signature::Bool)
776            | (Signature::I16, Signature::I16)
777            | (Signature::U16, Signature::U16)
778            | (Signature::I32, Signature::I32)
779            | (Signature::U32, Signature::U32)
780            | (Signature::I64, Signature::I64)
781            | (Signature::U64, Signature::U64)
782            | (Signature::F64, Signature::F64)
783            | (Signature::Str, Signature::Str)
784            | (Signature::Signature, Signature::Signature)
785            | (Signature::ObjectPath, Signature::ObjectPath)
786            | (Signature::Variant, Signature::Variant) => std::cmp::Ordering::Equal,
787            #[cfg(unix)]
788            (Signature::Fd, Signature::Fd) => std::cmp::Ordering::Equal,
789            (Signature::Array(a), Signature::Array(b)) => a.cmp(b),
790            (
791                Signature::Dict {
792                    key: key_a,
793                    value: value_a,
794                },
795                Signature::Dict {
796                    key: key_b,
797                    value: value_b,
798                },
799            ) => match key_a.cmp(key_b) {
800                std::cmp::Ordering::Equal => value_a.cmp(value_b),
801                other => other,
802            },
803            (Signature::Structure(a), Signature::Structure(b)) => a.iter().cmp(b.iter()),
804            #[cfg(feature = "gvariant")]
805            (Signature::Maybe(a), Signature::Maybe(b)) => a.cmp(b),
806            (_, _) => std::cmp::Ordering::Equal,
807        }
808    }
809}
810
811impl Serialize for Signature {
812    fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
813        serializer.serialize_str(&self.to_string())
814    }
815}
816
817impl<'de> Deserialize<'de> for Signature {
818    fn deserialize<D: serde::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
819        <&str>::deserialize(deserializer).and_then(|s| {
820            Signature::from_str(s).map_err(|e| serde::de::Error::custom(e.to_string()))
821        })
822    }
823}
824
825impl Hash for Signature {
826    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
827        match self {
828            Signature::Unit => 0.hash(state),
829            Signature::U8 => 1.hash(state),
830            Signature::Bool => 2.hash(state),
831            Signature::I16 => 3.hash(state),
832            Signature::U16 => 4.hash(state),
833            Signature::I32 => 5.hash(state),
834            Signature::U32 => 6.hash(state),
835            Signature::I64 => 7.hash(state),
836            Signature::U64 => 8.hash(state),
837            Signature::F64 => 9.hash(state),
838            Signature::Str => 10.hash(state),
839            Signature::Signature => 11.hash(state),
840            Signature::ObjectPath => 12.hash(state),
841            Signature::Variant => 13.hash(state),
842            #[cfg(unix)]
843            Signature::Fd => 14.hash(state),
844            Signature::Array(child) => {
845                15.hash(state);
846                child.hash(state);
847            }
848            Signature::Dict { key, value } => {
849                16.hash(state);
850                key.hash(state);
851                value.hash(state);
852            }
853            Signature::Structure(fields) => {
854                17.hash(state);
855                fields.iter().for_each(|f| f.hash(state));
856            }
857            #[cfg(feature = "gvariant")]
858            Signature::Maybe(child) => {
859                18.hash(state);
860                child.hash(state);
861            }
862        }
863    }
864}
865
866impl From<&Signature> for Signature {
867    fn from(value: &Signature) -> Self {
868        value.clone()
869    }
870}
871
872#[cfg(test)]
873mod tests;