1use alloc::{string::ToString, vec::Vec};
2use core::{iter::Peekable, str::CharIndices};
3
4#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
5pub enum Kind {
6 Normal,
9 Optional,
12 OptionalSegment,
14 OneOrMore,
17 ZeroOrMore,
20 ZeroOrMoreSegment,
22 }
24
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub enum Piece {
27 String(Vec<u8>),
28 Parameter(Position, Kind),
29}
30
31#[derive(Clone, Debug, PartialEq, Eq)]
32pub enum Position {
33 Index(usize, Vec<u8>),
34 Named(Vec<u8>),
35}
36
37pub struct Parser<'a> {
38 pos: usize,
39 count: usize,
40 input: &'a str,
41 cursor: Peekable<CharIndices<'a>>,
42}
43
44impl<'a> Parser<'a> {
45 #[must_use]
46 pub fn new(input: &'a str) -> Self {
47 Self {
48 input,
49 pos: 0,
50 count: 0,
51 cursor: input.char_indices().peekable(),
52 }
53 }
54
55 fn string(&mut self) -> &'a [u8] {
56 let mut start = self.pos;
57 while let Some(&(i, c)) = self.cursor.peek() {
58 match c {
59 '\\' => {
60 if start < i {
61 self.pos = i;
62 return self.input[start..i].as_bytes();
63 }
64
65 self.cursor.next();
66 if let Some(&(j, c)) = self.cursor.peek() {
67 if c == '\\' {
69 start = j;
70 } else {
71 self.cursor.next();
72 self.pos = j + c.len_utf8();
73 return self.input[j..self.pos].as_bytes();
74 }
75 }
76 }
77 ':' | '+' | '*' => {
78 self.pos = i + 1;
79 return self.input[start..i].as_bytes();
80 }
81 _ => {
82 self.cursor.next();
83 }
84 }
85 }
86
87 self.input[start..].as_bytes()
88 }
89
90 fn parameter(&mut self) -> (Position, Kind) {
91 let start = self.pos;
92 while let Some(&(i, c)) = self.cursor.peek() {
93 match c {
94 '-' | '.' | '~' | '/' | '\\' | ':' => {
95 self.pos = i;
96 return (
97 Position::Named(self.input[start..i].as_bytes().to_vec()),
98 Kind::Normal,
99 );
100 }
101 '?' | '+' | '*' => {
102 self.cursor.next();
103 self.pos = i + 1;
104 return (
105 Position::Named(self.input[start..i].as_bytes().to_vec()),
106 if c == '+' {
107 Kind::OneOrMore
108 } else {
109 let f = {
110 let prefix = start >= 2
111 && (self.input.get(start - 2..start - 1) == Some("/"));
112 let suffix = self.cursor.peek().is_none_or(|(_, c)| *c == '/');
113 prefix && suffix
114 };
115 if c == '?' {
116 if f {
117 Kind::OptionalSegment
118 } else {
119 Kind::Optional
120 }
121 } else if f {
122 Kind::ZeroOrMoreSegment
123 } else {
124 Kind::ZeroOrMore
125 }
126 },
127 );
128 }
129 _ => {
130 self.cursor.next();
131 }
132 }
133 }
134
135 (
136 Position::Named(self.input[start..].as_bytes().to_vec()),
137 Kind::Normal,
138 )
139 }
140}
141
142impl Iterator for Parser<'_> {
143 type Item = Piece;
144
145 fn next(&mut self) -> Option<Self::Item> {
146 match self.cursor.peek() {
147 Some(&(i, c)) => match c {
148 ':' => {
149 self.cursor.next();
150 self.pos = i + 1;
151 let (position, kind) = self.parameter();
152 Some(Piece::Parameter(position, kind))
153 }
154 '+' | '*' => {
155 self.cursor.next();
156 self.count += 1;
157 self.pos = i + 1;
158 Some(Piece::Parameter(
159 Position::Index(self.count, {
160 let mut s = Vec::new();
161 s.push(c as u8);
162 s.extend_from_slice(self.count.to_string().as_bytes());
163 s
164 }),
165 if c == '+' {
166 Kind::OneOrMore
167 } else {
168 let f = {
169 let prefix = i >= 1 && (self.input.get(i - 1..i) == Some("/"));
170 let suffix = self.cursor.peek().is_none_or(|(_, c)| *c == '/');
171 prefix && suffix
172 };
173 if f {
174 Kind::ZeroOrMoreSegment
175 } else {
176 Kind::ZeroOrMore
177 }
178 },
179 ))
180 }
181 _ => Some(Piece::String(self.string().to_vec())),
182 },
183 None => None,
184 }
185 }
186}