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