rust_web_server/url/path/
mod.rs1use std::collections::HashMap;
2use std::fmt::{Display, Formatter};
3use crate::symbol::SYMBOL;
4
5#[cfg(test)]
6mod tests;
7
8pub struct UrlPath;
9
10#[derive(Clone, Debug)]
11pub struct Part {
12 pub is_static: bool,
13 pub name: Option<String>,
14 pub value: Option<String>,
15 pub static_pattern: Option<String>
16}
17
18impl Display for Part {
19 fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
20 println!("{:?} {:?} {:?} {:?}", &self.is_static, &self.name, &self.value, &self.static_pattern);
21 Ok(())
22 }
23}
24
25impl UrlPath {
26 pub fn extract_parts_from_pattern(_pattern: &str) -> Result<Vec<Part>, String>{
27 let mut part_list: Vec<Part> = vec![];
28 let mut _buffer: Vec<char> = vec![];
29 let mut previous_char: Option<char> = None;
30 let mut is_opened_token = false;
31
32 for _char in _pattern.chars() {
33 if _char.is_whitespace() || _char.is_control() {
34 return Err("path contains control character or whitespace".to_string())
35 }
36
37 _buffer.push(_char);
38
39 if _char == '[' && previous_char.is_some() && previous_char.unwrap() == '[' {
40 if is_opened_token {
41 return Err("at least one extra [ char".to_string());
42 }
43 is_opened_token = true;
44 if _buffer.len() != 0 && _buffer.len() >= 2 {
45 let without_square_brackets = _buffer.len() - 2;
46 let pattern : String = _buffer[0..without_square_brackets].into_iter().collect();
47 if pattern.len() > 0 {
48 let part = Part {
49 is_static: true,
50 name: None,
51 value: None,
52 static_pattern: Some(pattern),
53 };
54 part_list.push(part);
55 }
56 }
57 _buffer = vec![];
58
59 let previous_part_is_token = part_list.last().is_some() && part_list.last().unwrap().is_static == false;
60 if previous_part_is_token {
61 return Err("two consecutive tokens one after another".to_string())
62 }
63 }
64
65 if _char == ']' && previous_char.is_some() && previous_char.unwrap() == ']' {
66 is_opened_token = false;
67 let without_square_brackets = _buffer.len() - 2;
68 let key : String = _buffer[0..without_square_brackets].into_iter().collect();
69 let part = Part {
70 is_static: false,
71 name: Some(key),
72 value: None,
73 static_pattern: None,
74 };
75 part_list.push(part);
76
77 _buffer = vec![];
78
79 }
80
81 previous_char = Some(_char.clone());
82 }
83
84 if _buffer.len() != 0 {
85 let static_ending : String = _buffer.into_iter().collect();
86
87 let part = Part {
88 is_static: true,
89 name: None,
90 value: None,
91 static_pattern: Some(static_ending),
92 };
93 part_list.push(part);
94 _buffer = vec![];
95 }
96
97 Ok(part_list)
98 }
99
100 pub fn is_matching(_path: &str, _pattern: &str) -> Result<bool, String> {
101 let is_matching = true;
102 let is_not_matching = false;
103
104 for char in _path.chars() {
105 if char.is_whitespace() || char.is_control() {
106 return Err("path contains control character or whitespace".to_string());
107 }
108 }
109
110 let boxed_parts = UrlPath::extract_parts_from_pattern(_pattern);
111 if boxed_parts.is_err() {
112 return Err(boxed_parts.err().unwrap());
113 }
114
115 let parts : Vec<Part> = boxed_parts.unwrap();
116 let mut populated_parts : Vec<Part> = vec![];
117
118 let mut url_path = _path.to_string();
119 let number_of_parts = parts.len();
120 println!("number_of_parts, {}", number_of_parts);
121
122 for (index, part) in parts.iter().enumerate() {
123 let part = part;
124 println!("1, {}", part);
125 let is_there_next_part = index < number_of_parts - 1;
126 if part.is_static {
127 let static_pattern = part.static_pattern.clone().unwrap();
128 if !url_path.starts_with(&static_pattern) {
129 return Ok(is_not_matching)
130 }
131
132 let _part = part.clone();
133 populated_parts.push(_part);
134
135 url_path = url_path.replacen(static_pattern.as_str(), SYMBOL.empty_string, 1);
136 } else {
137 if !is_there_next_part {
138 let _part = Part {
139 is_static: false,
140 name: part.name.clone(),
141 value: Some(url_path.clone()),
142 static_pattern: None,
143 };
144 let _part = part.clone();
145 populated_parts.push(_part);
146
147 println!("2, {}", part);
148
149 } else {
150 let next_part = parts.get(index + 1).unwrap();
151 println!("3, {}", part);
152 let delimiter = next_part.static_pattern.clone().unwrap().chars().next().unwrap();
153 let occurence = url_path.find(delimiter);
154 if occurence.is_none() {
155 return Ok(is_not_matching)
156 }
157 let occurence_place = occurence.unwrap();
158 let token = url_path[..occurence_place].to_string();
159 let _part = Part {
160 is_static: false,
161 name: part.name.clone(),
162 value: Some(token.clone()),
163 static_pattern: None,
164 };
165 println!("4, {}", part);
166
167 populated_parts.push(_part.clone());
168
169 url_path = url_path.chars().skip(occurence_place).collect();
170
171 println!("123")
172 }
173 }
174 }
175
176 Ok(is_matching)
177 }
178
179 pub fn extract(_path: &str, _pattern: &str) -> Result<HashMap<String, String>, String> {
180 let boxed_parts = UrlPath::extract_parts_from_pattern(_pattern);
183 if boxed_parts.is_err() {
184 return Err(boxed_parts.err().unwrap());
185 }
186
187 let parts : Vec<Part> = boxed_parts.unwrap();
188 let mut resulting_parts : Vec<Part> = vec![];
189
190 let mut path = _path.to_string();
191 let mut previous_part: Option<Part> = None;
192 let number_of_parts = parts.len();
193 for (index, part) in parts.iter().enumerate() {
194 println!("path: {:?}", path);
195 println!("part: {:?} {:?} {:?}", part.name, part.value, part.static_pattern);
196
197 if part.is_static {
198 if previous_part.is_some() {
199 let unboxed_previous_part = previous_part.clone().unwrap();
200 println!("previous_part: {:?} {:?} {:?}", unboxed_previous_part.name, unboxed_previous_part.value, unboxed_previous_part.static_pattern);
201
202 let static_pattern = part.static_pattern.clone().unwrap();
205 let first_char_to_stop = static_pattern.chars().next().unwrap();
206 let mut buffer = vec![];
207
208 for char in path.clone().chars() {
209 if char == first_char_to_stop {
210 println!("found {:?}", char);
211 break;
213 } else {
214 let removed_char = path.remove(0);
215 buffer.push(removed_char);
216 println!("removed char: {:?}", removed_char);
217 }
218 }
219 let token : String = buffer.iter().collect();
220 println!("dynamic part {:?}", token);
221 let mut processed_part = previous_part.clone().unwrap();
222 processed_part.value = Some(token);
223 resulting_parts.push(processed_part.clone());
224 println!("{:?}", processed_part)
225 } else {
226 }
228
229 let static_pattern = part.static_pattern.clone().unwrap();
230 path = path.strip_prefix(static_pattern.as_str()).unwrap().to_string();
233 } else {
234 if number_of_parts == index + 1 {
237 let mut processed_part = part.clone();
241 processed_part.value = Some(path.clone());
242 resulting_parts.push(processed_part.clone());
243 println!("{:?}", processed_part)
244 }
245
246 }
247
248 previous_part = Some(part.clone());
249 }
250
251 let mut map = HashMap::new();
252 for part in resulting_parts {
253 let key = part.name.unwrap();
254 let value = part.value.unwrap();
255
256 map.insert(key, value);
257 }
258
259 Ok(map)
260 }
261
262 pub fn build(_params: HashMap<String, String>, _pattern: &str) -> Result<String, String> {
263 let boxed_parts = UrlPath::extract_parts_from_pattern(_pattern);
264 if boxed_parts.is_err() {
265 return Err(boxed_parts.err().unwrap());
266 }
267
268 let parts : Vec<Part> = boxed_parts.unwrap();
269
270
271 let mut strings_array = vec![];
272 for part in parts {
273 if part.is_static {
274 strings_array.push(part.static_pattern.unwrap())
275 } else {
276 let key = part.name.unwrap().to_string();
277 let boxed_value = _params.get(key.as_str());
278 if boxed_value.is_none() {
279 return Err(format!("specified parameter {} is not found", key))
280 }
281 let value = boxed_value.unwrap();
282 strings_array.push(value.clone());
283 }
284 }
285 let populated_pattern : String = strings_array.join(SYMBOL.empty_string);
286
287 Ok(populated_pattern)
288
289 }
290}