1use core::mem;
4
5use crate::parser::str::find_split_hole;
6use crate::template::error::Error;
7use crate::template::parser::validate as validate_parser;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub(super) struct ExprBody<'a>(&'a str);
14
15impl<'a> ExprBody<'a> {
16    #[inline]
22    #[must_use]
23    pub(super) fn new(s: &'a str) -> Self {
24        debug_assert!(
25            !s.is_empty(),
26            "[precondition] valid expression body is not empty"
27        );
28
29        Self(s)
30    }
31
32    #[must_use]
38    pub(super) fn decompose(&self) -> (Operator, VarListStr<'a>) {
39        debug_assert!(
40            !self.0.is_empty(),
41            "[precondition] valid expression body is not empty"
42        );
43        let first = self.0.as_bytes()[0];
44        if first.is_ascii_alphanumeric() || (first == b'_') || (first == b'%') {
45            (Operator::String, VarListStr::new(self.0))
47        } else {
48            let op = Operator::from_byte(first).unwrap_or_else(|| {
49                unreachable!(
50                    "[precondition] valid expression has (optional) \
51                     valid operator, but got a byte {first:#02x?}"
52                )
53            });
54            (op, VarListStr::new(&self.0[1..]))
55        }
56    }
57
58    #[inline]
60    #[must_use]
61    pub(super) fn as_str(&self) -> &'a str {
62        self.0
63    }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
69pub struct VarName<'a>(&'a str);
70
71impl<'a> VarName<'a> {
72    #[inline]
78    #[must_use]
79    pub(super) fn from_trusted(s: &'a str) -> Self {
80        Self(s)
81    }
82
83    #[inline]
99    pub fn new(s: &'a str) -> Result<Self, Error> {
100        match validate_parser::validate_varname(s, 0) {
101            Ok(_) => Ok(Self::from_trusted(s)),
102            Err(e) => Err(e),
103        }
104    }
105
106    #[inline]
108    #[must_use]
109    pub fn as_str(&self) -> &'a str {
110        self.0
111    }
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
116pub struct VarSpec<'a> {
117    name: VarName<'a>,
119    modifier: Modifier,
121}
122
123impl<'a> VarSpec<'a> {
124    #[inline]
126    #[must_use]
127    pub(super) fn name(&self) -> VarName<'a> {
128        self.name
129    }
130
131    #[inline]
133    #[must_use]
134    pub(super) fn modifier(&self) -> Modifier {
135        self.modifier
136    }
137
138    #[must_use]
144    pub(super) fn parse_trusted(s: &'a str) -> Self {
145        if let Some(varname) = s.strip_suffix('*') {
146            return Self {
148                name: VarName::from_trusted(varname),
149                modifier: Modifier::Explode,
150            };
151        }
152        match find_split_hole(s, b':') {
154            Some((varname, max_len)) => {
155                let max_len: u16 = max_len
156                    .parse()
157                    .expect("[precondition] the input should be valid `varspec`");
158                Self {
159                    name: VarName::from_trusted(varname),
160                    modifier: Modifier::MaxLen(max_len),
161                }
162            }
163            None => Self {
164                name: VarName(s),
165                modifier: Modifier::None,
166            },
167        }
168    }
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub(super) struct VarListStr<'a>(&'a str);
174
175impl<'a> VarListStr<'a> {
176    #[inline]
182    #[must_use]
183    pub(super) fn new(s: &'a str) -> Self {
184        Self(s)
185    }
186}
187
188impl<'a> IntoIterator for VarListStr<'a> {
189    type IntoIter = VarListIter<'a>;
190    type Item = (usize, VarSpec<'a>);
191
192    #[inline]
193    fn into_iter(self) -> Self::IntoIter {
194        VarListIter { rest: self.0 }
195    }
196}
197
198#[derive(Debug, Clone)]
200pub(super) struct VarListIter<'a> {
201    rest: &'a str,
203}
204
205impl<'a> Iterator for VarListIter<'a> {
206    type Item = (usize, VarSpec<'a>);
208
209    fn next(&mut self) -> Option<Self::Item> {
210        match find_split_hole(self.rest, b',') {
211            Some((prefix, new_rest)) => {
212                self.rest = new_rest;
213                Some((prefix.len(), VarSpec::parse_trusted(prefix)))
214            }
215            None => {
216                if self.rest.is_empty() {
217                    None
218                } else {
219                    Some((
220                        self.rest.len(),
221                        VarSpec::parse_trusted(mem::take(&mut self.rest)),
222                    ))
223                }
224            }
225        }
226    }
227}
228
229#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
231pub(super) enum Modifier {
232    None,
234    MaxLen(u16),
236    Explode,
238}
239
240#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
242pub(super) enum MaybeOperator {
243    Operator(Operator),
245    Reserved(OperatorReservedForFuture),
247}
248
249impl MaybeOperator {
250    pub(super) fn from_byte(b: u8) -> Option<Self> {
252        match b {
253            b'+' => Some(Self::Operator(Operator::Reserved)),
254            b'#' => Some(Self::Operator(Operator::Fragment)),
255            b'.' => Some(Self::Operator(Operator::Label)),
256            b'/' => Some(Self::Operator(Operator::PathSegments)),
257            b';' => Some(Self::Operator(Operator::PathParams)),
258            b'?' => Some(Self::Operator(Operator::FormQuery)),
259            b'&' => Some(Self::Operator(Operator::FormQueryCont)),
260            b'=' => Some(Self::Reserved(OperatorReservedForFuture::Equals)),
261            b',' => Some(Self::Reserved(OperatorReservedForFuture::Comma)),
262            b'!' => Some(Self::Reserved(OperatorReservedForFuture::Exclamation)),
263            b'@' => Some(Self::Reserved(OperatorReservedForFuture::AtSign)),
264            b'|' => Some(Self::Reserved(OperatorReservedForFuture::Pipe)),
265            _ => None,
266        }
267    }
268}
269
270#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
272pub(super) enum Operator {
273    String,
275    Reserved,
277    Fragment,
279    Label,
281    PathSegments,
283    PathParams,
285    FormQuery,
287    FormQueryCont,
289}
290
291impl Operator {
292    #[must_use]
294    pub(super) fn from_byte(b: u8) -> Option<Self> {
295        match b {
296            b'+' => Some(Self::Reserved),
297            b'#' => Some(Self::Fragment),
298            b'.' => Some(Self::Label),
299            b'/' => Some(Self::PathSegments),
300            b';' => Some(Self::PathParams),
301            b'?' => Some(Self::FormQuery),
302            b'&' => Some(Self::FormQueryCont),
303            _ => None,
304        }
305    }
306
307    #[inline]
309    #[must_use]
310    pub(super) const fn len(self) -> usize {
311        if matches!(self, Self::String) {
312            0
313        } else {
314            1
315        }
316    }
317}
318
319#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
321pub(super) enum OperatorReservedForFuture {
322    Equals,
324    Comma,
326    Exclamation,
328    AtSign,
330    Pipe,
332}