1use std::{fmt, ops};
3
4use serde::de;
5
6use crate::web::error::PathError;
7use crate::web::{FromRequest, HttpRequest, State};
8use crate::{http::Payload, router::PathDeserializer};
9
10#[derive(PartialEq, Eq, PartialOrd, Ord)]
11pub struct Path<T> {
68 inner: T,
69}
70
71impl<T> Path<T> {
72 pub fn into_inner(self) -> T {
74 self.inner
75 }
76}
77
78impl<T> AsRef<T> for Path<T> {
79 fn as_ref(&self) -> &T {
80 &self.inner
81 }
82}
83
84impl<T> ops::Deref for Path<T> {
85 type Target = T;
86
87 fn deref(&self) -> &T {
88 &self.inner
89 }
90}
91
92impl<T> ops::DerefMut for Path<T> {
93 fn deref_mut(&mut self) -> &mut T {
94 &mut self.inner
95 }
96}
97
98impl<T> From<T> for Path<T> {
99 fn from(inner: T) -> Path<T> {
100 Path { inner }
101 }
102}
103
104impl<T: fmt::Debug> fmt::Debug for Path<T> {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 self.inner.fmt(f)
107 }
108}
109
110impl<T: fmt::Display> fmt::Display for Path<T> {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 self.inner.fmt(f)
113 }
114}
115
116impl<T, St: State> FromRequest<St> for Path<T>
163where
164 T: de::DeserializeOwned,
165{
166 type Error = PathError;
167
168 async fn from_request(_: &St, req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
169 de::Deserialize::deserialize(PathDeserializer::new(req.match_info()))
170 .map(|inner| Path { inner })
171 .map_err(move |e| {
172 log::debug!(
173 "Failed during Path extractor deserialization. \
174 Request path: {:?}",
175 req.path()
176 );
177 PathError::from(e)
178 })
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185 use crate::router::Router;
186 use crate::web::test::{TestRequest, from_request};
187
188 #[derive(thiserror::Error, serde::Deserialize, Debug)]
189 #[error("MyStruct({key}, {value})")]
190 struct MyStruct {
191 key: String,
192 value: String,
193 }
194
195 #[derive(serde::Deserialize)]
196 struct Test2 {
197 key: String,
198 value: u32,
199 }
200
201 #[crate::rt_test]
202 async fn test_extract_path_single() {
203 let mut router = Router::<usize>::builder();
204 router.path("/{value}/", 10).set_id(0);
205 let router = router.build();
206
207 let mut req = TestRequest::with_uri("/32/").to_srv_request();
208 router.recognize(req.match_info_mut());
209
210 let (req, mut pl, ()) = req.into_parts();
211 assert_eq!(
212 *from_request::<_, Path<i8>>(&(), &req, &mut pl)
213 .await
214 .unwrap(),
215 32
216 );
217 assert!(
218 from_request::<_, Path<MyStruct>>(&(), &req, &mut pl)
219 .await
220 .is_err()
221 );
222 }
223
224 #[crate::rt_test]
225 async fn test_tuple_extract() {
226 let mut router = Router::<usize>::builder();
227 router.path("/{key}/{value}/", 10).set_id(0);
228 let router = router.build();
229
230 let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();
231 router.recognize(req.match_info_mut());
232
233 let (req, mut pl, ()) = req.into_parts();
234 let res = from_request::<_, (Path<(String, String)>,)>(&(), &req, &mut pl)
235 .await
236 .unwrap();
237 assert_eq!((res.0).0, "name");
238 assert_eq!((res.0).1, "user1");
239
240 let res =
241 from_request::<_, (Path<(String, String)>, Path<(String, String)>)>(&(), &req, &mut pl)
242 .await
243 .unwrap();
244 assert_eq!((res.0).0, "name");
245 assert_eq!((res.0).1, "user1");
246 assert_eq!((res.1).0, "name");
247 assert_eq!((res.1).1, "user1");
248
249 from_request::<_, ()>(&(), &req, &mut pl).await.unwrap();
250 }
251
252 #[crate::rt_test]
253 async fn test_request_extract() {
254 let mut router = Router::<usize>::builder();
255 router.path("/{key}/{value}/", 10).set_id(0);
256 let router = router.build();
257
258 let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();
259 router.recognize(req.match_info_mut());
260
261 let (req, mut pl, ()) = req.into_parts();
262 let mut s = from_request::<_, Path<MyStruct>>(&(), &req, &mut pl)
263 .await
264 .unwrap();
265 assert_eq!(s.key, "name");
266 assert_eq!(s.value, "user1");
267 s.value = "user2".to_string();
268 assert_eq!(s.value, "user2");
269 assert_eq!(
270 format!("{s}, {s:?}"),
271 "MyStruct(name, user2), MyStruct { key: \"name\", value: \"user2\" }"
272 );
273 let s = s.into_inner();
274 assert_eq!(s.value, "user2");
275
276 let s = from_request::<_, Path<(String, String)>>(&(), &req, &mut pl)
277 .await
278 .unwrap();
279 assert_eq!(s.0, "name");
280 assert_eq!(s.1, "user1");
281
282 let mut req = TestRequest::with_uri("/name/32/").to_srv_request();
283 router.recognize(req.match_info_mut());
284
285 let (req, mut pl, ()) = req.into_parts();
286 let s = from_request::<_, Path<Test2>>(&(), &req, &mut pl)
287 .await
288 .unwrap();
289 assert_eq!(s.as_ref().key, "name");
290 assert_eq!(s.value, 32);
291
292 let s = from_request::<_, Path<(String, u8)>>(&(), &req, &mut pl)
293 .await
294 .unwrap();
295 assert_eq!(s.0, "name");
296 assert_eq!(s.1, 32);
297
298 let res = from_request::<_, Path<Vec<String>>>(&(), &req, &mut pl)
299 .await
300 .unwrap();
301 assert_eq!(res[0], "name".to_owned());
302 assert_eq!(res[1], "32".to_owned());
303 }
304
305 #[test]
306 fn test_path_from() {
307 let path = Path::from(10u32);
308 assert_eq!(*path, 10);
309 assert_eq!(path.into_inner(), 10);
310 }
311}