use std::{any::type_name, slice::Iter};
use mincat_core::request::{FromRequestParts, Parts};
use serde::{
de::{DeserializeOwned, DeserializeSeed, MapAccess, SeqAccess, Visitor},
forward_to_deserialize_any, Deserializer,
};
use crate::app::MincatRoutePath;
use super::ExtractError;
fn get_path_args(path: &str) -> Vec<String> {
let mut res = vec![];
path.split('/').for_each(|item| {
if let Some(key) = item.strip_prefix(':') {
res.push(key.into());
}
});
res
}
fn get_path_args_tuple(
define_path: &str,
real_path: &str,
) -> Result<Vec<(String, String)>, ExtractError> {
let mut res = vec![];
let mut router = matchit::Router::new();
router
.insert(define_path, true)
.map_err(ExtractError::from)?;
let matched = router.at(real_path).map_err(ExtractError::from)?;
let path_args = get_path_args(define_path);
for arg in path_args {
let value = matched.params.get(&arg).unwrap_or("");
res.push((arg, value.to_string()));
}
Ok(res)
}
pub struct Path<T>(pub T);
#[async_trait::async_trait]
impl<T> FromRequestParts for Path<T>
where
T: DeserializeOwned + Clone + Send + 'static,
{
type Error = ExtractError;
async fn from_request_parts(parts: &mut Parts) -> Result<Self, Self::Error> {
let MincatRoutePath(path) = parts
.extensions
.get::<MincatRoutePath>()
.ok_or(ExtractError("missing path".to_string()))?;
let path_args = get_path_args_tuple(path, parts.uri.path())?;
Ok(Path(T::deserialize(PathDeserializer(path_args.iter()))?))
}
}
macro_rules! unsupport_type {
($trait_fn:ident) => {
fn $trait_fn<V>(self, _: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(ExtractError(format!(
"unsupport_type: {}",
type_name::<V::Value>()
)))
}
};
($trait_fn:ident, name) => {
fn $trait_fn<V>(self, _: &'static str, _: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(ExtractError(format!(
"unsupport_type: {}",
type_name::<V::Value>()
)))
}
};
($trait_fn:ident, len) => {
fn $trait_fn<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(ExtractError(format!(
"unsupport_type: {}",
type_name::<V::Value>()
)))
}
};
($trait_fn:ident, name_len) => {
fn $trait_fn<V>(self, _: &'static str, _: usize, _: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(ExtractError(format!(
"unsupport_type: {}",
type_name::<V::Value>()
)))
}
};
($trait_fn:ident, name_arr) => {
fn $trait_fn<V>(
self,
_: &'static str,
_: &'static [&'static str],
_: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(ExtractError(format!(
"unsupport_type: {}",
type_name::<V::Value>()
)))
}
};
}
#[derive(Debug)]
struct PathDeserializer<'de>(Iter<'de, (String, String)>);
impl<'de> Deserializer<'de> for PathDeserializer<'de> {
type Error = ExtractError;
unsupport_type!(deserialize_bytes);
unsupport_type!(deserialize_option);
unsupport_type!(deserialize_identifier);
unsupport_type!(deserialize_ignored_any);
unsupport_type!(deserialize_any);
unsupport_type!(deserialize_bool);
unsupport_type!(deserialize_i8);
unsupport_type!(deserialize_i16);
unsupport_type!(deserialize_i32);
unsupport_type!(deserialize_i64);
unsupport_type!(deserialize_u8);
unsupport_type!(deserialize_u16);
unsupport_type!(deserialize_u32);
unsupport_type!(deserialize_u64);
unsupport_type!(deserialize_f32);
unsupport_type!(deserialize_f64);
unsupport_type!(deserialize_char);
unsupport_type!(deserialize_str);
unsupport_type!(deserialize_string);
unsupport_type!(deserialize_byte_buf);
unsupport_type!(deserialize_unit);
unsupport_type!(deserialize_unit_struct, name);
unsupport_type!(deserialize_newtype_struct, name);
unsupport_type!(deserialize_seq);
unsupport_type!(deserialize_tuple_struct, name_len);
unsupport_type!(deserialize_enum, name_arr);
fn deserialize_tuple<V>(self, _: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_seq(SeqDeserializer(self.0))
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_map(MapDeserializer(self.0, None))
}
fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
self.deserialize_map(visitor)
}
}
struct SeqDeserializer<'de>(Iter<'de, (String, String)>);
impl<'de> SeqAccess<'de> for SeqDeserializer<'de> {
type Error = ExtractError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: serde::de::DeserializeSeed<'de>,
{
match self.0.next() {
Some(param) => Ok(Some(
seed.deserialize(ValueDeserializer(¶m.1))
.map_err(ExtractError::from)?,
)),
None => Ok(None),
}
}
}
macro_rules! parse_value {
($trait_fn:ident, $visit_fn:ident) => {
fn $trait_fn<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let v = self.0.parse().map_err(ExtractError::from)?;
visitor.$visit_fn(v)
}
};
}
struct ValueDeserializer<'de>(&'de str);
impl<'de> Deserializer<'de> for ValueDeserializer<'de> {
type Error = ExtractError;
unsupport_type!(deserialize_bytes);
unsupport_type!(deserialize_option);
unsupport_type!(deserialize_identifier);
unsupport_type!(deserialize_ignored_any);
unsupport_type!(deserialize_any);
unsupport_type!(deserialize_unit);
unsupport_type!(deserialize_unit_struct, name);
unsupport_type!(deserialize_newtype_struct, name);
unsupport_type!(deserialize_seq);
unsupport_type!(deserialize_tuple_struct, name_len);
unsupport_type!(deserialize_enum, name_arr);
unsupport_type!(deserialize_tuple, len);
unsupport_type!(deserialize_map);
unsupport_type!(deserialize_struct, name_arr);
unsupport_type!(deserialize_str);
parse_value!(deserialize_bool, visit_bool);
parse_value!(deserialize_i8, visit_i8);
parse_value!(deserialize_i16, visit_i16);
parse_value!(deserialize_i32, visit_i32);
parse_value!(deserialize_i64, visit_i64);
parse_value!(deserialize_i128, visit_i128);
parse_value!(deserialize_u8, visit_u8);
parse_value!(deserialize_u16, visit_u16);
parse_value!(deserialize_u32, visit_u32);
parse_value!(deserialize_u64, visit_u64);
parse_value!(deserialize_u128, visit_u128);
parse_value!(deserialize_f32, visit_f32);
parse_value!(deserialize_f64, visit_f64);
parse_value!(deserialize_string, visit_string);
parse_value!(deserialize_byte_buf, visit_string);
parse_value!(deserialize_char, visit_char);
}
struct MapDeserializer<'de>(Iter<'de, (String, String)>, Option<&'de (String, String)>);
impl<'de> MapAccess<'de> for MapDeserializer<'de> {
type Error = ExtractError;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
where
K: DeserializeSeed<'de>,
{
match self.0.next() {
Some(param) => {
self.1 = Some(param);
seed.deserialize(KeyDeserializer(¶m.0)).map(Some)
}
None => Ok(None),
}
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: DeserializeSeed<'de>,
{
match self.1.take() {
Some((_, ref value)) => seed.deserialize(ValueDeserializer(value)),
None => Err(ExtractError("value is missing".to_string())),
}
}
}
struct KeyDeserializer<'de>(&'de str);
macro_rules! parse_key {
($trait_fn:ident) => {
fn $trait_fn<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_str(&self.0)
}
};
}
impl<'de> Deserializer<'de> for KeyDeserializer<'de> {
type Error = ExtractError;
unsupport_type!(deserialize_any);
parse_key!(deserialize_identifier);
parse_key!(deserialize_str);
parse_key!(deserialize_string);
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char bytes
byte_buf option unit unit_struct seq tuple
tuple_struct map newtype_struct struct enum ignored_any
}
}