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