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}