zvariant/
signature.rs

1use core::{
2    cmp::Ordering,
3    fmt::{self, Debug, Display, Formatter},
4    hash::{Hash, Hasher},
5    str,
6};
7use serde::{
8    de::{Deserialize, Deserializer},
9    ser::{Serialize, Serializer},
10};
11use static_assertions::assert_impl_all;
12use std::{
13    borrow::Cow,
14    ops::{Bound, RangeBounds},
15    sync::Arc,
16};
17
18use crate::{serialized::Format, signature_parser::SignatureParser, Basic, Error, Result, Type};
19
20// A data type similar to Cow and [`bytes::Bytes`] but unlike the former won't allow us to only keep
21// the owned bytes in Arc and latter doesn't have a notion of borrowed data and would require API
22// breakage.
23//
24// [`bytes::Bytes`]: https://docs.rs/bytes/0.5.6/bytes/struct.Bytes.html
25#[derive(Debug, Clone)]
26enum Bytes<'b> {
27    Borrowed(&'b [u8]),
28    Static(&'static [u8]),
29    Owned(Arc<[u8]>),
30}
31
32impl<'b> Bytes<'b> {
33    const fn borrowed<'s: 'b>(bytes: &'s [u8]) -> Self {
34        Self::Borrowed(bytes)
35    }
36
37    fn owned(bytes: Vec<u8>) -> Self {
38        Self::Owned(bytes.into())
39    }
40
41    /// This is faster than `Clone::clone` when `self` contains owned data.
42    fn as_ref(&self) -> Bytes<'_> {
43        match &self {
44            Bytes::Static(s) => Bytes::Static(s),
45            Bytes::Borrowed(s) => Bytes::Borrowed(s),
46            Bytes::Owned(s) => Bytes::Borrowed(s),
47        }
48    }
49}
50
51impl std::ops::Deref for Bytes<'_> {
52    type Target = [u8];
53
54    fn deref(&self) -> &[u8] {
55        match self {
56            Bytes::Borrowed(borrowed) => borrowed,
57            Bytes::Static(borrowed) => borrowed,
58            Bytes::Owned(owned) => owned,
59        }
60    }
61}
62
63impl Eq for Bytes<'_> {}
64
65impl PartialEq for Bytes<'_> {
66    fn eq(&self, other: &Self) -> bool {
67        **self == **other
68    }
69}
70
71impl Ord for Bytes<'_> {
72    fn cmp(&self, other: &Self) -> Ordering {
73        (**self).cmp(&**other)
74    }
75}
76
77impl PartialOrd for Bytes<'_> {
78    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
79        Some(self.cmp(other))
80    }
81}
82
83impl Hash for Bytes<'_> {
84    fn hash<H: Hasher>(&self, state: &mut H) {
85        (**self).hash(state)
86    }
87}
88
89/// String that [identifies] the type of an encoded value.
90///
91/// # Examples
92///
93/// ```
94/// use zvariant::Signature;
95///
96/// // Valid signatures
97/// let s = Signature::try_from("").unwrap();
98/// assert_eq!(s, "");
99/// # assert_eq!(s.n_complete_types(), Ok(0));
100/// let s = Signature::try_from("y").unwrap();
101/// assert_eq!(s, "y");
102/// # assert_eq!(s.n_complete_types(), Ok(1));
103/// let s = Signature::try_from("xs").unwrap();
104/// assert_eq!(s, "xs");
105/// # assert_eq!(s.n_complete_types(), Ok(2));
106/// let s = Signature::try_from("(ysa{sd})").unwrap();
107/// assert_eq!(s, "(ysa{sd})");
108/// # assert_eq!(s.n_complete_types(), Ok(1));
109/// let s = Signature::try_from("a{sd}").unwrap();
110/// assert_eq!(s, "a{sd}");
111/// # assert_eq!(s.n_complete_types(), Ok(1));
112///
113/// // Invalid signatures
114/// Signature::try_from("z").unwrap_err();
115/// Signature::try_from("(xs").unwrap_err();
116/// Signature::try_from("xs)").unwrap_err();
117/// Signature::try_from("s/").unwrap_err();
118/// Signature::try_from("a").unwrap_err();
119/// Signature::try_from("a{yz}").unwrap_err();
120/// ```
121///
122/// This is implemented so that multiple instances can share the same underlying signature string.
123/// Use [`slice`] method to create new signature that represents a portion of a signature
124///
125/// [identifies]: https://dbus.freedesktop.org/doc/dbus-specification.html#type-system
126/// [`slice`]: #method.slice
127#[derive(Hash, Clone, PartialOrd, Ord)]
128pub struct Signature<'a> {
129    bytes: Bytes<'a>,
130    pos: usize,
131    end: usize,
132}
133
134assert_impl_all!(Signature<'_>: Send, Sync, Unpin);
135
136impl<'a> Signature<'a> {
137    /// The signature as a string.
138    pub fn as_str(&self) -> &str {
139        // SAFETY: non-UTF8 characters in Signature are rejected by safe constructors
140        unsafe { str::from_utf8_unchecked(self.as_bytes()) }
141    }
142
143    /// The signature bytes.
144    pub fn as_bytes(&self) -> &[u8] {
145        &self.bytes[self.pos..self.end]
146    }
147
148    /// This is faster than `Clone::clone` when `self` contains owned data.
149    pub fn as_ref(&self) -> Signature<'_> {
150        Signature {
151            bytes: self.bytes.as_ref(),
152            pos: self.pos,
153            end: self.end,
154        }
155    }
156
157    /// Create a new Signature from given bytes.
158    ///
159    /// Since the passed bytes are not checked for correctness, it's provided for ease of
160    /// `Type` implementations.
161    ///
162    /// # Safety
163    ///
164    /// This method is unsafe as it allows creating a `str` that is not valid UTF-8.
165    pub unsafe fn from_bytes_unchecked<'s: 'a>(bytes: &'s [u8]) -> Self {
166        Self {
167            bytes: Bytes::borrowed(bytes),
168            pos: 0,
169            end: bytes.len(),
170        }
171    }
172
173    /// Same as `from_bytes_unchecked`, except it takes a static reference.
174    ///
175    /// # Safety
176    ///
177    /// This method is unsafe as it allows creating a `str` that is not valid UTF-8.
178    pub unsafe fn from_static_bytes_unchecked(bytes: &'static [u8]) -> Self {
179        Self {
180            bytes: Bytes::Static(bytes),
181            pos: 0,
182            end: bytes.len(),
183        }
184    }
185
186    /// Same as `from_bytes_unchecked`, except it takes a string reference.
187    pub const fn from_str_unchecked<'s: 'a>(signature: &'s str) -> Self {
188        Self {
189            bytes: Bytes::borrowed(signature.as_bytes()),
190            pos: 0,
191            end: signature.len(),
192        }
193    }
194
195    /// Same as `from_str_unchecked`, except it takes a static string reference.
196    pub const fn from_static_str_unchecked(signature: &'static str) -> Self {
197        Self {
198            bytes: Bytes::Static(signature.as_bytes()),
199            pos: 0,
200            end: signature.len(),
201        }
202    }
203
204    /// Same as `from_str_unchecked`, except it takes an owned `String`.
205    pub fn from_string_unchecked(signature: String) -> Self {
206        let bytes = signature.into_bytes();
207        let end = bytes.len();
208
209        Self {
210            bytes: Bytes::owned(bytes),
211            pos: 0,
212            end,
213        }
214    }
215
216    /// Same as `from_static_str_unchecked`, except it checks validity of the signature.
217    ///
218    /// It's recommended to use this method instead of `TryFrom<&str>` implementation for
219    /// `&'static str`. The former will ensure that [`Signature::to_owned`] and
220    /// [`Signature::into_owned`] do not clone the underlying bytes.
221    pub fn from_static_str(signature: &'static str) -> Result<Self> {
222        let bytes = signature.as_bytes();
223        SignatureParser::validate(bytes)?;
224
225        Ok(Self {
226            bytes: Bytes::Static(bytes),
227            pos: 0,
228            end: signature.len(),
229        })
230    }
231
232    /// Same as `from_static_bytes_unchecked`, except it checks validity of the signature.
233    ///
234    /// It's recommended to use this method instead of the `TryFrom<&[u8]>` implementation for
235    /// `&'static [u8]`. The former will ensure that [`Signature::to_owned`] and
236    /// [`Signature::into_owned`] do not clone the underlying bytes.
237    pub fn from_static_bytes(bytes: &'static [u8]) -> Result<Self> {
238        SignatureParser::validate(bytes)?;
239
240        Ok(Self {
241            bytes: Bytes::Static(bytes),
242            pos: 0,
243            end: bytes.len(),
244        })
245    }
246
247    /// the signature's length.
248    pub fn len(&self) -> usize {
249        self.end - self.pos
250    }
251
252    /// if the signature is empty.
253    pub fn is_empty(&self) -> bool {
254        self.as_bytes().is_empty()
255    }
256
257    /// Creates an owned clone of `self`.
258    pub fn to_owned(&self) -> Signature<'static> {
259        match &self.bytes {
260            Bytes::Borrowed(_) => {
261                let bytes = Bytes::owned(self.as_bytes().to_vec());
262                let pos = 0;
263                let end = bytes.len();
264
265                Signature { bytes, pos, end }
266            }
267            Bytes::Static(b) => Signature {
268                bytes: Bytes::Static(b),
269                pos: self.pos,
270                end: self.end,
271            },
272            Bytes::Owned(owned) => Signature {
273                bytes: Bytes::Owned(owned.clone()),
274                pos: self.pos,
275                end: self.end,
276            },
277        }
278    }
279
280    /// Creates an owned clone of `self`.
281    pub fn into_owned(self) -> Signature<'static> {
282        self.to_owned()
283    }
284
285    /// Returns a slice of `self` for the provided range.
286    ///
287    /// # Panics
288    ///
289    /// Requires that begin <= end and end <= self.len(), otherwise slicing will panic.
290    #[must_use]
291    pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
292        let len = self.len();
293
294        let pos = match range.start_bound() {
295            Bound::Included(&n) => n,
296            Bound::Excluded(&n) => n + 1,
297            Bound::Unbounded => 0,
298        };
299
300        let end = match range.end_bound() {
301            Bound::Included(&n) => n + 1,
302            Bound::Excluded(&n) => n,
303            Bound::Unbounded => len,
304        };
305
306        assert!(
307            pos <= end,
308            "range start must not be greater than end: {:?} > {:?}",
309            pos,
310            end,
311        );
312        assert!(end <= len, "range end out of bounds: {:?} > {:?}", end, len,);
313
314        if end == pos {
315            return Self::from_str_unchecked("");
316        }
317
318        let mut clone = self.clone();
319        clone.pos += pos;
320        clone.end = self.pos + end;
321
322        clone
323    }
324
325    /// The number of complete types for the signature.
326    ///
327    /// # Errors
328    ///
329    /// If the signature is invalid, returns the first error.
330    pub fn n_complete_types(&self) -> Result<usize> {
331        let mut count = 0;
332        // SAFETY: the parser is only used to do counting
333        for s in unsafe { SignatureParser::from_bytes_unchecked(self.as_bytes())? } {
334            s?;
335            count += 1;
336        }
337        Ok(count)
338    }
339}
340
341impl<'a> Debug for Signature<'a> {
342    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
343        f.debug_tuple("Signature").field(&self.as_str()).finish()
344    }
345}
346
347impl<'a> Basic for Signature<'a> {
348    const SIGNATURE_CHAR: char = 'g';
349    const SIGNATURE_STR: &'static str = "g";
350
351    fn alignment(format: Format) -> usize {
352        match format {
353            Format::DBus => 1,
354            #[cfg(feature = "gvariant")]
355            Format::GVariant => 1,
356        }
357    }
358}
359
360impl<'a> Type for Signature<'a> {
361    fn signature() -> Signature<'static> {
362        Signature::from_static_str_unchecked(Self::SIGNATURE_STR)
363    }
364}
365
366impl<'a> From<&Signature<'a>> for Signature<'a> {
367    fn from(signature: &Signature<'a>) -> Signature<'a> {
368        signature.clone()
369    }
370}
371
372impl<'a> TryFrom<&'a [u8]> for Signature<'a> {
373    type Error = Error;
374
375    fn try_from(value: &'a [u8]) -> Result<Self> {
376        SignatureParser::validate(value)?;
377
378        // SAFETY: validate checks UTF8
379        unsafe { Ok(Self::from_bytes_unchecked(value)) }
380    }
381}
382
383/// Try to create a Signature from a string.
384impl<'a> TryFrom<&'a str> for Signature<'a> {
385    type Error = Error;
386
387    fn try_from(value: &'a str) -> Result<Self> {
388        Self::try_from(value.as_bytes())
389    }
390}
391
392/// Try to create a Signature from a `Cow<str>.`
393impl<'a> TryFrom<Cow<'a, str>> for Signature<'a> {
394    type Error = Error;
395
396    fn try_from(value: Cow<'a, str>) -> Result<Self> {
397        match value {
398            Cow::Borrowed(v) => Self::try_from(v),
399            Cow::Owned(v) => Self::try_from(v),
400        }
401    }
402}
403
404impl<'a> TryFrom<String> for Signature<'a> {
405    type Error = Error;
406
407    fn try_from(value: String) -> Result<Self> {
408        SignatureParser::validate(value.as_bytes())?;
409
410        Ok(Self::from_string_unchecked(value))
411    }
412}
413
414impl<'a> From<Signature<'a>> for String {
415    fn from(value: Signature<'a>) -> String {
416        String::from(value.as_str())
417    }
418}
419
420impl<'a> From<&Signature<'a>> for String {
421    fn from(value: &Signature<'a>) -> String {
422        String::from(value.as_str())
423    }
424}
425
426impl<'a> std::ops::Deref for Signature<'a> {
427    type Target = str;
428
429    fn deref(&self) -> &Self::Target {
430        self.as_str()
431    }
432}
433
434/// Checks whether the string slice has balanced parentheses.
435fn has_balanced_parentheses(signature_str: &str) -> bool {
436    signature_str.chars().fold(0, |count, ch| match ch {
437        '(' => count + 1,
438        ')' if count != 0 => count - 1,
439        _ => count,
440    }) == 0
441}
442
443/// Determines whether the signature has outer parentheses and if so, return the
444/// string slice without those parentheses.
445fn without_outer_parentheses<'a, 'b>(sig: &'a Signature<'b>) -> &'a str
446where
447    'b: 'a,
448{
449    let sig_str = sig.as_str();
450
451    if let Some(subslice) = sig_str.strip_prefix('(').and_then(|s| s.strip_suffix(')')) {
452        if has_balanced_parentheses(subslice) {
453            return subslice;
454        }
455    }
456    sig_str
457}
458
459/// Evaluate equality of two signatures, ignoring outer parentheses if needed.
460impl<'a, 'b> PartialEq<Signature<'a>> for Signature<'b> {
461    fn eq(&self, other: &Signature<'_>) -> bool {
462        without_outer_parentheses(self) == without_outer_parentheses(other)
463    }
464}
465
466impl<'a> PartialEq<str> for Signature<'a> {
467    fn eq(&self, other: &str) -> bool {
468        self.as_bytes() == other.as_bytes()
469    }
470}
471
472impl<'a> PartialEq<&str> for Signature<'a> {
473    fn eq(&self, other: &&str) -> bool {
474        self.as_bytes() == other.as_bytes()
475    }
476}
477
478// According to the docs, `Eq` derive should only be used on structs if all its fields are
479// are `Eq`. Hence the manual implementation.
480impl Eq for Signature<'_> {}
481
482impl<'a> Display for Signature<'a> {
483    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
484        std::fmt::Display::fmt(&self.as_str(), f)
485    }
486}
487
488impl<'a> Serialize for Signature<'a> {
489    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
490    where
491        S: Serializer,
492    {
493        serializer.serialize_str(self.as_str())
494    }
495}
496
497impl<'de: 'a, 'a> Deserialize<'de> for Signature<'a> {
498    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
499    where
500        D: Deserializer<'de>,
501    {
502        let val = <std::borrow::Cow<'a, str>>::deserialize(deserializer)?;
503
504        Self::try_from(val).map_err(serde::de::Error::custom)
505    }
506}
507
508/// Owned [`Signature`](struct.Signature.html)
509#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, Type)]
510pub struct OwnedSignature(Signature<'static>);
511
512assert_impl_all!(OwnedSignature: Send, Sync, Unpin);
513
514impl OwnedSignature {
515    pub fn into_inner(self) -> Signature<'static> {
516        self.0
517    }
518}
519
520impl Basic for OwnedSignature {
521    const SIGNATURE_CHAR: char = Signature::SIGNATURE_CHAR;
522    const SIGNATURE_STR: &'static str = Signature::SIGNATURE_STR;
523
524    fn alignment(format: Format) -> usize {
525        Signature::alignment(format)
526    }
527}
528
529impl std::ops::Deref for OwnedSignature {
530    type Target = Signature<'static>;
531
532    fn deref(&self) -> &Self::Target {
533        &self.0
534    }
535}
536
537impl std::convert::From<OwnedSignature> for Signature<'static> {
538    fn from(o: OwnedSignature) -> Self {
539        o.into_inner()
540    }
541}
542
543impl<'a> std::convert::From<Signature<'a>> for OwnedSignature {
544    fn from(o: Signature<'a>) -> Self {
545        OwnedSignature(o.into_owned())
546    }
547}
548
549impl std::convert::From<OwnedSignature> for crate::Value<'static> {
550    fn from(o: OwnedSignature) -> Self {
551        o.into_inner().into()
552    }
553}
554
555impl TryFrom<String> for OwnedSignature {
556    type Error = Error;
557
558    fn try_from(value: String) -> Result<Self> {
559        Ok(Self(Signature::try_from(value)?))
560    }
561}
562
563impl<'de> Deserialize<'de> for OwnedSignature {
564    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
565    where
566        D: Deserializer<'de>,
567    {
568        let val = String::deserialize(deserializer)?;
569
570        OwnedSignature::try_from(val).map_err(serde::de::Error::custom)
571    }
572}
573
574impl std::fmt::Display for OwnedSignature {
575    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
576        std::fmt::Display::fmt(&self.as_str(), f)
577    }
578}
579
580#[cfg(test)]
581mod tests {
582    use super::{Bytes, Signature};
583    use std::sync::Arc;
584
585    #[test]
586    fn bytes_equality() {
587        let borrowed1 = Bytes::Borrowed(b"foo");
588        let borrowed2 = Bytes::Borrowed(b"foo");
589        let static1 = Bytes::Static(b"foo");
590        let static2 = Bytes::Static(b"foo");
591        let owned1 = Bytes::Owned(Arc::new(*b"foo"));
592        let owned2 = Bytes::Owned(Arc::new(*b"foo"));
593
594        assert_eq!(borrowed1, borrowed2);
595        assert_eq!(static1, static2);
596        assert_eq!(owned1, owned2);
597
598        assert_eq!(borrowed1, static1);
599        assert_eq!(static1, borrowed1);
600
601        assert_eq!(static1, owned1);
602        assert_eq!(owned1, static1);
603
604        assert_eq!(borrowed1, owned1);
605        assert_eq!(owned1, borrowed1);
606    }
607
608    #[test]
609    fn signature_slicing() {
610        let sig = Signature::from_str_unchecked("(asta{sv})");
611        assert_eq!(sig, "(asta{sv})");
612
613        let slice = sig.slice(1..);
614        assert_eq!(slice.len(), sig.len() - 1);
615        assert_eq!(slice, &sig[1..]);
616        assert_eq!(slice.as_bytes()[1], b's');
617        assert_eq!(slice.as_bytes()[2], b't');
618
619        let slice = slice.slice(2..3);
620        assert_eq!(slice.len(), 1);
621        assert_eq!(slice, "t");
622        assert_eq!(slice.slice(1..), "");
623    }
624
625    #[test]
626    fn signature_equality() {
627        let sig_a = Signature::from_str_unchecked("(asta{sv})");
628        let sig_b = Signature::from_str_unchecked("asta{sv}");
629        assert_eq!(sig_a, sig_b);
630
631        let sig_a = Signature::from_str_unchecked("((so)ii(uu))");
632        let sig_b = Signature::from_str_unchecked("(so)ii(uu)");
633        assert_eq!(sig_a, sig_b);
634
635        let sig_a = Signature::from_str_unchecked("(so)i");
636        let sig_b = Signature::from_str_unchecked("(so)u");
637        assert_ne!(sig_a, sig_b);
638    }
639}