viz_core/types/
params.rs

1//! Represents a Params extractor for the path of a URL.
2
3mod de;
4
5use std::{
6    fmt::Display,
7    ops::{Deref, DerefMut},
8    str::FromStr,
9};
10
11use serde::de::DeserializeOwned;
12
13use crate::{
14    Error, FromRequest, IntoResponse, Request, RequestExt, Response, StatusCode, ThisError,
15};
16
17#[allow(clippy::redundant_pub_crate)]
18pub(crate) use de::PathDeserializer;
19
20/// Extracts params from the path of a URL.
21#[derive(Debug, Clone)]
22pub struct Params<T = Vec<(String, String)>>(pub T);
23
24impl<T> AsRef<T> for Params<T> {
25    fn as_ref(&self) -> &T {
26        &self.0
27    }
28}
29
30impl<T> Deref for Params<T> {
31    type Target = T;
32
33    fn deref(&self) -> &T {
34        &self.0
35    }
36}
37
38impl<T> DerefMut for Params<T> {
39    fn deref_mut(&mut self) -> &mut T {
40        &mut self.0
41    }
42}
43
44impl From<Vec<(&str, &str)>> for Params {
45    fn from(v: Vec<(&str, &str)>) -> Self {
46        Self(
47            v.into_iter()
48                .map(|(k, v)| (k.to_string(), v.to_string()))
49                .collect(),
50        )
51    }
52}
53
54impl Params {
55    /// Gets single parameter by name.
56    ///
57    /// # Errors
58    ///
59    /// Throws a `ParamsError`
60    pub fn find<T>(&self, name: &str) -> Result<T, ParamsError>
61    where
62        T: FromStr,
63        T::Err: Display,
64    {
65        self.iter()
66            .find(|p| p.0 == name)
67            .ok_or_else(|| {
68                let mut s = String::new();
69                s.push_str("missing ");
70                s.push_str(name);
71                s.push_str(" param");
72                ParamsError::SingleParse(s)
73            })?
74            .1
75            .parse()
76            .map_err(|e: T::Err| ParamsError::SingleParse(e.to_string()))
77    }
78}
79
80impl<T> FromRequest for Params<T>
81where
82    T: DeserializeOwned,
83{
84    type Error = ParamsError;
85
86    async fn extract(req: &mut Request) -> Result<Self, Self::Error> {
87        req.params().map(Params)
88    }
89}
90
91/// Rejects a parsing error.
92#[derive(ThisError, Debug)]
93pub enum ParamsError {
94    /// Represents pasing single param was failed.
95    #[error("{}", .0)]
96    SingleParse(String),
97    /// Represents pasing multi param was failed.
98    #[error(transparent)]
99    Parse(#[from] serde::de::value::Error),
100    /// Represents params is empty.
101    #[error("params is empty")]
102    Empty,
103}
104
105impl IntoResponse for ParamsError {
106    fn into_response(self) -> Response {
107        (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()).into_response()
108    }
109}
110
111impl From<ParamsError> for Error {
112    fn from(e: ParamsError) -> Self {
113        e.into_error()
114    }
115}