use std::marker::PhantomData;
use typeway_core::effects::{Effect, Requires};
use typeway_core::ApiSpec;
use crate::handler_for::BindableEndpoint;
pub trait Validate<T>: Send + Sync + 'static {
fn validate(body: &T) -> Result<(), String>;
}
pub struct Validated<V, E> {
_marker: PhantomData<(V, E)>,
}
impl<V: Send + Sync + 'static, E: ApiSpec> ApiSpec for Validated<V, E> {}
impl<V: Send + Sync + 'static, E, Provided, Idx> typeway_core::effects::AllProvided<Provided, Idx>
for Validated<V, E>
where
E: typeway_core::effects::AllProvided<Provided, Idx>,
{
}
impl<V: Send + Sync + 'static, E: BindableEndpoint> BindableEndpoint for Validated<V, E> {
fn method() -> http::Method {
E::method()
}
fn pattern() -> String {
E::pattern()
}
fn match_fn() -> crate::router::MatchFn {
E::match_fn()
}
}
pub trait ApiVersion: Send + Sync + 'static {
const PREFIX: &'static str;
}
pub struct Versioned<V, E> {
_marker: PhantomData<(V, E)>,
}
impl<V: ApiVersion, E: ApiSpec> ApiSpec for Versioned<V, E> {}
impl<V: ApiVersion, E: BindableEndpoint> BindableEndpoint for Versioned<V, E> {
fn method() -> http::Method {
E::method()
}
fn pattern() -> String {
format!("/{}{}", V::PREFIX, E::pattern())
}
fn match_fn() -> crate::router::MatchFn {
let prefix = V::PREFIX;
let inner_match = E::match_fn();
Box::new(move |segments: &[&str]| {
if segments.first() == Some(&prefix) {
inner_match(&segments[1..])
} else {
false
}
})
}
}
pub trait ContentTypeMarker: Send + Sync + 'static {
const CONTENT_TYPE: &'static str;
}
pub struct JsonContent;
impl ContentTypeMarker for JsonContent {
const CONTENT_TYPE: &'static str = "application/json";
}
pub struct FormContent;
impl ContentTypeMarker for FormContent {
const CONTENT_TYPE: &'static str = "application/x-www-form-urlencoded";
}
pub struct ContentType<C, E> {
_marker: PhantomData<(C, E)>,
}
impl<C: ContentTypeMarker, E: ApiSpec> ApiSpec for ContentType<C, E> {}
impl<C: ContentTypeMarker, E: BindableEndpoint> BindableEndpoint for ContentType<C, E> {
fn method() -> http::Method {
E::method()
}
fn pattern() -> String {
E::pattern()
}
fn match_fn() -> crate::router::MatchFn {
E::match_fn()
}
}
pub trait RateLimit: Send + Sync + 'static {
const MAX_REQUESTS: u32;
const WINDOW_SECS: u64;
}
pub struct RateLimited<R, E> {
_marker: PhantomData<(R, E)>,
}
impl<R: RateLimit, E: ApiSpec> ApiSpec for RateLimited<R, E> {}
impl<R: RateLimit, E: BindableEndpoint> BindableEndpoint for RateLimited<R, E> {
fn method() -> http::Method {
E::method()
}
fn pattern() -> String {
E::pattern()
}
fn match_fn() -> crate::router::MatchFn {
E::match_fn()
}
}
impl<E: Effect, T: BindableEndpoint> BindableEndpoint for Requires<E, T> {
fn method() -> http::Method {
T::method()
}
fn pattern() -> String {
T::pattern()
}
fn match_fn() -> crate::router::MatchFn {
T::match_fn()
}
}