yew_router_min_route_parser/
optimizer.rs1use crate::{
2 error::PrettyParseError,
3 parser::{parse, CaptureOrExact, RefCaptureVariant, RouteParserToken},
4};
5
6use crate::{core::FieldNamingScheme, CaptureVariant, MatcherToken};
7
8impl<'a> From<RefCaptureVariant<'a>> for CaptureVariant {
9 fn from(v: RefCaptureVariant<'a>) -> Self {
10 match v {
11 RefCaptureVariant::Named(s) => CaptureVariant::Named(s.to_string()),
12 RefCaptureVariant::ManyNamed(s) => CaptureVariant::ManyNamed(s.to_string()),
13 RefCaptureVariant::NumberedNamed { sections, name } => CaptureVariant::NumberedNamed {
14 sections,
15 name: name.to_string(),
16 },
17 RefCaptureVariant::Unnamed => CaptureVariant::Unnamed,
18 RefCaptureVariant::ManyUnnamed => CaptureVariant::ManyUnnamed,
19 RefCaptureVariant::NumberedUnnamed { sections } => {
20 CaptureVariant::NumberedUnnamed { sections }
21 }
22 }
23 }
24}
25
26impl<'a> From<CaptureOrExact<'a>> for MatcherToken {
27 fn from(value: CaptureOrExact<'a>) -> Self {
28 match value {
29 CaptureOrExact::Exact(m) => MatcherToken::Exact(m.to_string()),
30 CaptureOrExact::Capture(v) => MatcherToken::Capture(v.into()),
31 }
32 }
33}
34
35impl<'a> RouteParserToken<'a> {
36 fn as_str(&self) -> &str {
37 match self {
38 RouteParserToken::Separator => "/",
39 RouteParserToken::Exact(literal) => &literal,
40 RouteParserToken::QueryBegin => "?",
41 RouteParserToken::QuerySeparator => "&",
42 RouteParserToken::FragmentBegin => "#",
43 RouteParserToken::Nothing
44 | RouteParserToken::Capture { .. }
45 | RouteParserToken::Query { .. }
46 | RouteParserToken::End => unreachable!(),
47 }
48 }
49}
50
51pub fn parse_str_and_optimize_tokens(
53 i: &str,
54 field_naming_scheme: FieldNamingScheme,
55) -> Result<Vec<MatcherToken>, PrettyParseError> {
56 let tokens = parse(i, field_naming_scheme)?;
57 Ok(convert_tokens(&tokens))
58}
59
60pub fn convert_tokens(tokens: &[RouteParserToken]) -> Vec<MatcherToken> {
65 let mut new_tokens = vec![];
66 let mut run: Vec<RouteParserToken> = vec![];
67
68 fn empty_run(run: &mut Vec<RouteParserToken>) -> MatcherToken {
69 let segment = run.iter().map(RouteParserToken::as_str).collect::<String>();
70 run.clear();
71
72 MatcherToken::Exact(segment)
73 }
74
75 fn empty_run_with_query_cap_at_end(
76 run: &mut Vec<RouteParserToken>,
77 query_lhs: &str,
78 ) -> MatcherToken {
79 let segment = run
80 .iter()
81 .map(RouteParserToken::as_str)
82 .chain(Some(query_lhs))
83 .chain(Some("="))
84 .collect::<String>();
85 run.clear();
86
87 MatcherToken::Exact(segment)
88 }
89
90 for token in tokens.iter() {
91 match token {
92 RouteParserToken::QueryBegin
93 | RouteParserToken::FragmentBegin
94 | RouteParserToken::Separator
95 | RouteParserToken::QuerySeparator
96 | RouteParserToken::Exact(_) => run.push(*token),
97 RouteParserToken::Capture(cap) => {
98 new_tokens.push(empty_run(&mut run));
99 new_tokens.push(MatcherToken::Capture(CaptureVariant::from(*cap)))
100 }
101 RouteParserToken::Query {
102 ident,
103 capture_or_exact,
104 } => match capture_or_exact {
105 CaptureOrExact::Exact(s) => {
106 run.push(RouteParserToken::Exact(ident));
107 run.push(RouteParserToken::Exact("="));
108 run.push(RouteParserToken::Exact(s));
109 }
110 CaptureOrExact::Capture(cap) => {
111 new_tokens.push(empty_run_with_query_cap_at_end(&mut run, *ident));
112 new_tokens.push(MatcherToken::Capture(CaptureVariant::from(*cap)))
113 }
114 },
115 RouteParserToken::End => {
116 new_tokens.push(empty_run(&mut run));
117 new_tokens.push(MatcherToken::End);
118 }
119 RouteParserToken::Nothing => {}
120 }
121 }
122
123 if !run.is_empty() {
125 new_tokens.push(empty_run(&mut run));
126 }
127
128 new_tokens
129}
130
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn empty_creates_empty_token_list() {
138 let tokens = parse_str_and_optimize_tokens("", FieldNamingScheme::Unit).unwrap();
139 assert_eq!(tokens, vec![])
140 }
141}