1use hyper::Request;
2use serde::de::value::{Error as ValueError, MapDeserializer};
3use serde::de::{self, DeserializeOwned, Deserializer, IntoDeserializer, Visitor};
4
5use crate::error::ServeError;
6use crate::router::{PathParams, QueryParams};
7
8static EMPTY_PATH_PARAMS: std::sync::OnceLock<PathParams> = std::sync::OnceLock::new();
16static EMPTY_QUERY_PARAMS: std::sync::OnceLock<QueryParams> = std::sync::OnceLock::new();
17
18pub fn query_params<B>(req: &Request<B>) -> &QueryParams {
32 req.extensions()
33 .get::<QueryParams>()
34 .unwrap_or_else(|| EMPTY_QUERY_PARAMS.get_or_init(QueryParams::default))
35}
36
37pub fn path_params<T: DeserializeOwned, B>(req: &Request<B>) -> Result<T, ServeError> {
60 let params = req
61 .extensions()
62 .get::<PathParams>()
63 .unwrap_or_else(|| EMPTY_PATH_PARAMS.get_or_init(PathParams::default));
64
65 let pairs = params.0.iter().map(|(k, v)| (k.clone(), ParamValue(v.clone())));
66 let deserializer = MapDeserializer::<_, ValueError>::new(pairs);
67 T::deserialize(deserializer)
68 .map_err(|_| ServeError::new(400, "invalid path parameters"))
69}
70
71struct ParamValue(String);
75
76macro_rules! deserialize_parsed {
77 ($($method:ident => $visit:ident : $ty:ty),* $(,)?) => {
78 $(
79 fn $method<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
80 match self.0.parse::<$ty>() {
81 Ok(v) => visitor.$visit(v),
82 Err(_) => Err(de::Error::invalid_value(
83 de::Unexpected::Str(&self.0),
84 &stringify!($ty),
85 )),
86 }
87 }
88 )*
89 };
90}
91
92impl<'de> Deserializer<'de> for ParamValue {
93 type Error = ValueError;
94
95 fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
96 visitor.visit_string(self.0)
97 }
98
99 fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
100 visitor.visit_some(self)
101 }
102
103 deserialize_parsed! {
104 deserialize_bool => visit_bool: bool,
105 deserialize_i8 => visit_i8: i8,
106 deserialize_i16 => visit_i16: i16,
107 deserialize_i32 => visit_i32: i32,
108 deserialize_i64 => visit_i64: i64,
109 deserialize_i128 => visit_i128: i128,
110 deserialize_u8 => visit_u8: u8,
111 deserialize_u16 => visit_u16: u16,
112 deserialize_u32 => visit_u32: u32,
113 deserialize_u64 => visit_u64: u64,
114 deserialize_u128 => visit_u128: u128,
115 deserialize_f32 => visit_f32: f32,
116 deserialize_f64 => visit_f64: f64,
117 deserialize_char => visit_char: char,
118 }
119
120 serde::forward_to_deserialize_any! {
121 str string bytes byte_buf unit unit_struct newtype_struct seq tuple
122 tuple_struct map struct enum identifier ignored_any
123 }
124}
125
126impl<'de> IntoDeserializer<'de, ValueError> for ParamValue {
127 type Deserializer = Self;
128
129 fn into_deserializer(self) -> Self {
130 self
131 }
132}
133
134#[cfg(test)]
135#[path = "../tests/unit/extract.rs"]
136mod tests;