fire_http/routes/
path_params.rs1use std::{
2 collections::{HashMap, HashSet},
3 str::FromStr,
4};
5
6use byte_parser::{ParseIterator, StrParser};
7use matchit::Params;
8
9#[derive(Debug, Clone)]
10pub struct PathParams {
11 inner: HashMap<String, String>,
12}
13
14impl PathParams {
15 pub(crate) fn new(params: Params) -> Self {
16 let mut inner = HashMap::new();
17
18 for (key, value) in params.iter() {
19 inner.insert(key.to_string(), value.to_string());
20 }
21
22 Self { inner }
23 }
24
25 pub fn exists(&self, key: impl AsRef<str>) -> bool {
26 self.inner.get(key.as_ref()).is_some()
27 }
28
29 pub fn parse<T>(&self, key: impl AsRef<str>) -> Result<T, T::Err>
30 where
31 T: FromStr,
32 {
33 self.inner.get(key.as_ref()).unwrap().parse()
34 }
35
36 pub fn get(&self, key: impl AsRef<str>) -> Option<&str> {
37 self.inner.get(key.as_ref()).map(|s| s.as_str())
38 }
39}
40
41#[derive(Debug, Clone)]
49pub struct ParamsNames<'a> {
50 list: HashSet<&'a str>,
51}
52
53impl<'a> ParamsNames<'a> {
54 pub fn parse(s: &'a str) -> Self {
55 let mut parser = StrParser::new(s);
56
57 let mut list = HashSet::new();
58
59 'template_loop: loop {
60 parser.consume_while_byte_fn(|&b| b != b'{');
61 let Some(b) = parser.next() else {
64 return Self { list };
65 };
66 debug_assert_eq!(b, b'{');
67
68 if parser.next_if(|&b| b == b'{').is_some() {
70 continue 'template_loop;
71 }
72
73 let mut parser = parser.record();
74
75 loop {
76 parser.consume_while_byte_fn(|&b| b != b'}' && b != b'{');
77 match parser.peek() {
78 Some(b) if b == b'{' => {
79 panic!("unexpected {{");
80 }
81 Some(b) if b == b'}' => {
82 assert!(
83 !matches!(parser.peek_at(2), Some(b) if b == b'}'),
84 "escapping does not work in template string"
85 );
86
87 let s = parser.to_str();
88 let s = s.trim_start_matches('*');
89 list.insert(s);
90
91 parser.next().unwrap();
92
93 continue 'template_loop;
94 }
95 Some(b) => unreachable!("reached byte {b}"),
96 None => {
97 panic!("unexpected end of string");
98 }
99 }
100 }
101 }
102 }
103
104 pub fn exists(&self, key: impl AsRef<str>) -> bool {
105 self.list.contains(key.as_ref())
106 }
107
108 pub fn is_empty(&self) -> bool {
109 self.list.is_empty()
110 }
111}