zvariant/
signature_parser.rs

1use std::ops::{Bound, RangeBounds};
2
3use crate::{subslice, Basic, ObjectPath, Result, Signature, STRUCT_SIG_END_CHAR};
4
5#[cfg(unix)]
6use crate::Fd;
7
8#[cfg(feature = "gvariant")]
9use crate::utils::MAYBE_SIGNATURE_CHAR;
10use crate::utils::{
11    ARRAY_SIGNATURE_CHAR, DICT_ENTRY_SIG_END_CHAR, DICT_ENTRY_SIG_START_CHAR,
12    STRUCT_SIG_START_CHAR, VARIANT_SIGNATURE_CHAR,
13};
14
15#[derive(Debug, Clone)]
16pub(crate) struct SignatureParser<'s> {
17    signature: Signature<'s>,
18    pos: usize,
19    end: usize,
20}
21
22impl<'s> SignatureParser<'s> {
23    pub fn new(signature: Signature<'s>) -> Self {
24        let end = signature.len();
25
26        Self {
27            signature,
28            pos: 0,
29            end,
30        }
31    }
32
33    pub fn signature(&self) -> Signature<'_> {
34        self.signature.slice(self.pos..self.end)
35    }
36
37    pub fn next_char(&self) -> Result<char> {
38        subslice(self.signature.as_bytes(), self.pos).map(|b| *b as char)
39    }
40
41    #[inline]
42    pub fn skip_char(&mut self) -> Result<()> {
43        self.skip_chars(1)
44    }
45
46    pub fn skip_chars(&mut self, num_chars: usize) -> Result<()> {
47        self.pos += num_chars;
48
49        // We'll be going one char beyond at the end of parsing but not beyond that.
50        if self.pos > self.end {
51            return Err(serde::de::Error::invalid_length(
52                self.signature.len(),
53                &format!(">= {} characters", self.pos).as_str(),
54            ));
55        }
56
57        Ok(())
58    }
59
60    #[inline]
61    pub fn len(&self) -> usize {
62        self.end - self.pos
63    }
64
65    #[inline]
66    pub fn done(&self) -> bool {
67        self.pos == self.end
68    }
69
70    /// Returns a slice of `self` for the provided range.
71    ///
72    /// # Panics
73    ///
74    /// Requires that begin <= end and end <= self.len(), otherwise slicing will panic.
75    pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
76        let len = self.len();
77
78        let pos = match range.start_bound() {
79            Bound::Included(&n) => n,
80            Bound::Excluded(&n) => n + 1,
81            Bound::Unbounded => 0,
82        };
83
84        let end = match range.end_bound() {
85            Bound::Included(&n) => n + 1,
86            Bound::Excluded(&n) => n,
87            Bound::Unbounded => len,
88        };
89
90        assert!(
91            pos <= end,
92            "range start must not be greater than end: {:?} > {:?}",
93            pos,
94            end,
95        );
96        assert!(end <= len, "range end out of bounds: {:?} > {:?}", end, len,);
97
98        let mut clone = self.clone();
99        clone.pos += pos;
100        clone.end = self.pos + end;
101
102        clone
103    }
104
105    /// Get the next signature and increment the position.
106    pub fn parse_next_signature(&mut self) -> Result<Signature<'s>> {
107        let len = &self.next_signature()?.len();
108        let pos = self.pos;
109        self.pos += len;
110
111        // We'll be going one char beyond at the end of parsing but not beyond that.
112        if self.pos > self.end {
113            return Err(serde::de::Error::invalid_length(
114                self.signature.len(),
115                &format!(">= {} characters", self.pos).as_str(),
116            ));
117        }
118
119        Ok(self.signature.slice(pos..self.pos))
120    }
121
122    /// Get the next signature but don't increment the position.
123    pub fn next_signature(&self) -> Result<Signature<'_>> {
124        match self
125            .signature()
126            .as_bytes()
127            .first()
128            .map(|b| *b as char)
129            .ok_or_else(|| -> crate::Error {
130                serde::de::Error::invalid_length(0, &">= 1 character")
131            })? {
132            u8::SIGNATURE_CHAR
133            | bool::SIGNATURE_CHAR
134            | i16::SIGNATURE_CHAR
135            | u16::SIGNATURE_CHAR
136            | i32::SIGNATURE_CHAR
137            | u32::SIGNATURE_CHAR
138            | i64::SIGNATURE_CHAR
139            | u64::SIGNATURE_CHAR
140            | f64::SIGNATURE_CHAR
141            | <&str>::SIGNATURE_CHAR
142            | ObjectPath::SIGNATURE_CHAR
143            | Signature::SIGNATURE_CHAR
144            | VARIANT_SIGNATURE_CHAR => Ok(self.signature_slice(0, 1)),
145            #[cfg(unix)]
146            Fd::SIGNATURE_CHAR => Ok(self.signature_slice(0, 1)),
147            ARRAY_SIGNATURE_CHAR => self.next_array_signature(),
148            STRUCT_SIG_START_CHAR => self.next_structure_signature(),
149            DICT_ENTRY_SIG_START_CHAR => self.next_dict_entry_signature(),
150            #[cfg(feature = "gvariant")]
151            MAYBE_SIGNATURE_CHAR => self.next_maybe_signature(),
152            c => Err(serde::de::Error::invalid_value(
153                serde::de::Unexpected::Char(c),
154                &"a valid signature character",
155            )),
156        }
157    }
158
159    fn next_single_child_type_container_signature(
160        &self,
161        expected_sig_prefix: char,
162    ) -> Result<Signature<'_>> {
163        let signature = self.signature();
164
165        if signature.len() < 2 {
166            return Err(serde::de::Error::invalid_length(
167                signature.len(),
168                &">= 2 characters",
169            ));
170        }
171
172        // We can't get None here cause we already established there is are least 2 chars above
173        let c = signature
174            .as_bytes()
175            .first()
176            .map(|b| *b as char)
177            .expect("empty signature");
178        if c != expected_sig_prefix {
179            return Err(serde::de::Error::invalid_value(
180                serde::de::Unexpected::Char(c),
181                &expected_sig_prefix.to_string().as_str(),
182            ));
183        }
184
185        // There should be a valid complete signature after 'a' but not more than 1
186        let child_parser = self.slice(1..);
187        let child_len = child_parser.next_signature()?.len();
188
189        Ok(self.signature_slice(0, child_len + 1))
190    }
191
192    fn next_array_signature(&self) -> Result<Signature<'_>> {
193        self.next_single_child_type_container_signature(ARRAY_SIGNATURE_CHAR)
194    }
195
196    #[cfg(feature = "gvariant")]
197    fn next_maybe_signature(&self) -> Result<Signature<'_>> {
198        self.next_single_child_type_container_signature(MAYBE_SIGNATURE_CHAR)
199    }
200
201    fn next_structure_signature(&self) -> Result<Signature<'_>> {
202        let signature = self.signature();
203
204        if signature.len() < 3 {
205            return Err(serde::de::Error::invalid_length(
206                signature.len(),
207                &">= 2 characters",
208            ));
209        }
210
211        let mut bytes = signature.as_bytes().iter();
212        // We can't get None here cause we already established there are at least 2 chars above
213        let c = bytes.next().map(|b| *b as char).expect("empty signature");
214        if c != STRUCT_SIG_START_CHAR {
215            return Err(serde::de::Error::invalid_value(
216                serde::de::Unexpected::Char(c),
217                &crate::STRUCT_SIG_START_STR,
218            ));
219        }
220        if bytes.next().map(|b| *b as char).expect("empty signature") == STRUCT_SIG_END_CHAR {
221            return Err(serde::de::Error::invalid_value(
222                serde::de::Unexpected::Str("()"),
223                &"at least one field signature between `(` and `)`",
224            ));
225        }
226
227        let mut fields_sig_len = 0;
228        let mut fields_parser = self.slice(1..);
229        while !fields_parser.done() && fields_parser.next_char()? != STRUCT_SIG_END_CHAR {
230            fields_sig_len += fields_parser.parse_next_signature()?.len();
231        }
232        let c = fields_parser.next_char()?;
233        if c != STRUCT_SIG_END_CHAR {
234            return Err(serde::de::Error::invalid_value(
235                serde::de::Unexpected::Char(c),
236                &crate::STRUCT_SIG_END_STR,
237            ));
238        }
239
240        // The `(`, fields signatures and `)`.
241        Ok(self.signature_slice(0, fields_sig_len + 2))
242    }
243
244    fn next_dict_entry_signature(&self) -> Result<Signature<'_>> {
245        let signature = self.signature();
246
247        if signature.len() < 4 {
248            return Err(serde::de::Error::invalid_length(
249                signature.len(),
250                &">= 4 characters",
251            ));
252        }
253
254        // We can't get None here cause we already established there are at least 4 chars above
255        let bytes = signature.as_bytes();
256        let c = bytes.first().map(|b| *b as char).expect("empty signature");
257        if c != DICT_ENTRY_SIG_START_CHAR {
258            return Err(serde::de::Error::invalid_value(
259                serde::de::Unexpected::Char(c),
260                &crate::DICT_ENTRY_SIG_START_STR,
261            ));
262        }
263
264        let key_parser = self.slice(1..);
265        let key_signature = key_parser.next_signature()?;
266        // Key's signature will always be just 1 character.
267        if key_signature.len() != 1 {
268            return Err(serde::de::Error::invalid_length(
269                key_signature.len(),
270                &"dict-entry key's signature can only be a single character",
271            ));
272        }
273
274        // There should be one valid complete signature for value.
275        let value_parser = self.slice(2..);
276        let value_len = value_parser.next_signature()?.len();
277        // signature of value + `{` + 1 char of the key signature + `}`
278        let end = value_len + 3;
279
280        if signature.len() < end {
281            return Err(serde::de::Error::invalid_length(
282                signature.len(),
283                &format!(">= {end} characters").as_str(),
284            ));
285        }
286        if bytes[end - 1] as char != DICT_ENTRY_SIG_END_CHAR {
287            return Err(serde::de::Error::invalid_value(
288                serde::de::Unexpected::Char(c),
289                &crate::DICT_ENTRY_SIG_END_STR,
290            ));
291        }
292
293        Ok(self.signature_slice(0, end))
294    }
295
296    fn signature_slice(&self, idx: usize, end: usize) -> Signature<'_> {
297        self.signature.slice(self.pos + idx..self.pos + end)
298    }
299}