web_route/parameterized_route/
route.rs1use std::{fmt, ops};
2
3use crate::{
4 WebRoute, error::WebRouteError, parameterized_route::segment::ParameterizedSegment,
5 to_segments::ToParameterizedSegments, utils::struct_to_map,
6};
7
8#[derive(Clone, PartialEq)]
14pub struct ParameterizedRoute(String);
15
16impl ParameterizedRoute {
17 pub fn new<R: ToParameterizedSegments>(route: R) -> Self {
27 let segments = route.to_segments();
28
29 Self(evaluate_segments(segments))
30 }
31
32 pub fn join<R: ToParameterizedSegments>(&self, route: R) -> Self {
47 let joined_segments = [self.to_segments(), route.to_segments()].concat();
48
49 Self(evaluate_segments(joined_segments))
50 }
51
52 pub fn to_web_route<V: serde::Serialize>(&self, values: &V) -> Result<WebRoute, WebRouteError> {
88 let values = struct_to_map(values).ok_or(WebRouteError::InvalidValue)?;
89
90 let populated_segments = self
91 .to_segments()
92 .iter()
93 .map(|segment| segment.to_populated(&values))
94 .collect::<Result<Vec<_>, _>>()?;
95
96 let web_route = WebRoute::new(format!("/{}", populated_segments.join("/")));
97
98 Ok(web_route)
99 }
100
101 pub(crate) fn to_segments(&self) -> Vec<ParameterizedSegment> {
102 ToParameterizedSegments::to_segments(&self.0)
103 }
104}
105
106impl fmt::Display for ParameterizedRoute {
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 write!(f, "{}", self.0)
109 }
110}
111
112impl fmt::Debug for ParameterizedRoute {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 f.debug_tuple("ParameterizedRoute")
115 .field(&self.to_string())
116 .finish()
117 }
118}
119
120impl ops::Deref for ParameterizedRoute {
122 type Target = str;
123
124 fn deref(&self) -> &Self::Target {
125 &self.0
126 }
127}
128
129impl AsRef<str> for ParameterizedRoute {
130 fn as_ref(&self) -> &str {
131 &self.0
132 }
133}
134
135#[cfg(feature = "fake")]
136impl fake::Dummy<fake::Faker> for ParameterizedRoute {
137 fn dummy_with_rng<R: fake::Rng + ?Sized>(config: &fake::Faker, rng: &mut R) -> Self {
138 use fake::Fake;
139
140 let segments: Vec<ParameterizedSegment> = config.fake_with_rng(rng);
141 Self::new(segments)
142 }
143}
144
145fn evaluate_segments(segments: Vec<ParameterizedSegment>) -> String {
147 let evaluated_segments = segments
148 .iter()
149 .map(ParameterizedSegment::to_template)
150 .collect::<Vec<_>>();
151
152 format!("/{}", evaluated_segments.join("/"))
153}
154
155#[cfg(test)]
156mod parameterized_route_tests {
157 use super::*;
158
159 mod to_web_route {
160 use std::ops::Deref;
161
162 use super::*;
163
164 #[test]
165 fn should_normalize_double_forward_slashes() {
166 #[derive(serde::Serialize)]
168 struct RouteParams {
169 param: String,
170 }
171
172 let parameterized_route = ParameterizedRoute::new("/some/route/{param}");
173
174 let web_route = parameterized_route
176 .to_web_route(&RouteParams {
177 param: "/value".to_owned(),
178 })
179 .unwrap();
180
181 assert_eq!(web_route.deref(), "/some/route/value")
183 }
184 }
185}