yew_router_nested_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<MatcherToken> = vec![];
66 let mut run: Vec<RouteParserToken> = vec![];
67
68 fn empty_run(run: &mut Vec<RouteParserToken>) -> Option<MatcherToken> {
69 let segment = run.iter().map(RouteParserToken::as_str).collect::<String>();
70 run.clear();
71
72 if !segment.is_empty() {
73 Some(MatcherToken::Exact(segment))
74 } else {
75 None
76 }
77 }
78
79 fn empty_run_with_query_cap_at_end(
80 run: &mut Vec<RouteParserToken>,
81 query_lhs: &str,
82 ) -> MatcherToken {
83 let segment = run
84 .iter()
85 .map(RouteParserToken::as_str)
86 .chain(Some(query_lhs))
87 .chain(Some("="))
88 .collect::<String>();
89 run.clear();
90
91 MatcherToken::Exact(segment)
92 }
93
94 for token in tokens.iter() {
95 match token {
96 RouteParserToken::QueryBegin
97 | RouteParserToken::FragmentBegin
98 | RouteParserToken::Separator
99 | RouteParserToken::QuerySeparator
100 | RouteParserToken::Exact(_) => run.push(*token),
101 RouteParserToken::Capture(cap) => {
102 if let Some(current_run) = empty_run(&mut run) {
103 new_tokens.push(current_run);
104 }
105 new_tokens.push(MatcherToken::Capture(CaptureVariant::from(*cap)))
106 }
107 RouteParserToken::Query {
108 ident,
109 capture_or_exact,
110 } => match capture_or_exact {
111 CaptureOrExact::Exact(s) => {
112 run.push(RouteParserToken::Exact(ident));
113 run.push(RouteParserToken::Exact("="));
114 run.push(RouteParserToken::Exact(s));
115 }
116 CaptureOrExact::Capture(cap) => {
117 new_tokens.push(empty_run_with_query_cap_at_end(&mut run, *ident));
118 new_tokens.push(MatcherToken::Capture(CaptureVariant::from(*cap)))
119 }
120 },
121 RouteParserToken::End => {
122 if let Some(current_run) = empty_run(&mut run) {
123 new_tokens.push(current_run);
124 }
125 new_tokens.push(MatcherToken::End);
126 }
127 RouteParserToken::Nothing => {}
128 }
129 }
130
131 if !run.is_empty() {
133 if let Some(current_run) = empty_run(&mut run) {
134 new_tokens.push(current_run);
135 }
136 }
137
138 new_tokens
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn empty_creates_empty_token_list() {
147 let tokens = parse_str_and_optimize_tokens("", FieldNamingScheme::Unit).unwrap();
148 assert_eq!(tokens, vec![])
149 }
150}