use http::Method;
use crate::{action::RawResponse, type_cache::TypeCacheKey, PathIter, RequestState};
pub trait Resolve<'a>: Sized {
type Output: 'a;
fn resolve(ctx: &'a RequestState, path_iter: &mut PathIter) -> ResolveGuard<Self::Output>;
}
pub enum ResolveGuard<T> {
Value(T),
Respond(RawResponse),
None,
}
impl<T> From<Option<T>> for ResolveGuard<T> {
fn from(value: Option<T>) -> Self {
match value {
Some(v) => ResolveGuard::Value(v),
None => ResolveGuard::None,
}
}
}
impl<T> ResolveGuard<T> {
pub fn map<N>(self, f: fn(T) -> N) -> ResolveGuard<N> {
match self {
ResolveGuard::Value(v) => ResolveGuard::Value(f(v)),
ResolveGuard::Respond(v) => ResolveGuard::Respond(v),
ResolveGuard::None => ResolveGuard::None,
}
}
}
pub struct Get;
impl<'a> Resolve<'a> for Get {
type Output = Self;
fn resolve(ctx: &'a RequestState, _path_iter: &mut PathIter) -> ResolveGuard<Self> {
if ctx.request.method() == Method::GET {
ResolveGuard::Value(Get)
} else {
ResolveGuard::None
}
}
}
pub struct Post;
impl<'a> Resolve<'a> for Post {
type Output = Self;
fn resolve(ctx: &'a RequestState, _path_iter: &mut PathIter) -> ResolveGuard<Self> {
if ctx.request.method() == Method::POST {
ResolveGuard::Value(Post)
} else {
ResolveGuard::None
}
}
}
pub struct Query<K>(pub K::Value)
where
K: TypeCacheKey;
impl<'a, K> Resolve<'a> for Query<K>
where
K: TypeCacheKey,
K::Value: Clone,
{
type Output = Self;
fn resolve(ctx: &'a RequestState, _path_iter: &mut PathIter) -> ResolveGuard<Self> {
ctx.global_cache.get::<K>().map(|v| Query(v.clone())).into()
}
}
pub struct Endpoint;
impl<'a> Resolve<'a> for Endpoint {
type Output = Self;
fn resolve(_ctx: &RequestState, path_iter: &mut PathIter) -> ResolveGuard<Self> {
match path_iter.peek() {
Some(v) if !v.is_empty() => ResolveGuard::None,
_ => ResolveGuard::Value(Endpoint),
}
}
}
pub struct Url(pub Vec<String>);
impl<'a> Resolve<'a> for Url {
type Output = Self;
fn resolve(_ctx: &'a RequestState, path_iter: &mut PathIter) -> ResolveGuard<Self::Output> {
ResolveGuard::Value(Url(path_iter.clone().map(|s| s.to_owned()).collect()))
}
}
pub struct UrlPart(pub String);
impl<'a> Resolve<'a> for UrlPart {
type Output = Self;
fn resolve(_ctx: &'a RequestState, path_iter: &mut PathIter) -> ResolveGuard<Self> {
path_iter.next().map(|i| UrlPart(i.to_string())).into()
}
}
pub struct UrlCollect(pub Vec<String>);
impl<'a> Resolve<'a> for UrlCollect {
type Output = Self;
fn resolve(_ctx: &'a RequestState, path_iter: &mut PathIter) -> ResolveGuard<Self> {
let mut collect = Vec::new();
for part in path_iter.by_ref().map(|i| i.to_string()) {
collect.push(part.to_string())
}
ResolveGuard::Value(UrlCollect(collect))
}
}
impl<'a, 'b> Resolve<'a> for &'b [u8] {
type Output = &'a [u8];
fn resolve(ctx: &'a RequestState, _path_iter: &mut PathIter) -> ResolveGuard<Self::Output> {
ResolveGuard::Value(ctx.request.body().get_as_slice())
}
}
impl<'a, 'b> Resolve<'a> for &'b str {
type Output = &'a str;
fn resolve(ctx: &'a RequestState, _path_iter: &mut PathIter) -> ResolveGuard<Self::Output> {
std::str::from_utf8(ctx.request.body().get_as_slice())
.ok()
.into()
}
}