use futures::future;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use crate::{configuration::Store, Extract, IntoResponse, Request, Response, RouteMatch};
#[derive(Clone)]
pub struct Head {
inner: Arc<http::request::Parts>,
}
impl From<http::request::Parts> for Head {
fn from(parts: http::request::Parts) -> Self {
Self {
inner: Arc::new(parts),
}
}
}
impl Head {
pub fn uri(&self) -> &http::Uri {
&self.inner.uri
}
pub fn path(&self) -> &str {
self.uri().path()
}
pub fn query(&self) -> Option<&str> {
self.uri().query()
}
pub fn method(&self) -> &http::Method {
&self.inner.method
}
pub fn headers(&self) -> &http::header::HeaderMap<http::header::HeaderValue> {
&self.inner.headers
}
}
pub struct Path<T>(pub T);
impl<T> Deref for Path<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> DerefMut for Path<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
struct PathIdx(usize);
impl<T: Send + 'static + std::str::FromStr, S: 'static> Extract<S> for Path<T> {
type Fut = future::Ready<Result<Self, Response>>;
fn extract(
data: &mut S,
req: &mut Request,
params: &Option<RouteMatch<'_>>,
store: &Store,
) -> Self::Fut {
let &PathIdx(i) = req.extensions().get::<PathIdx>().unwrap_or(&PathIdx(0));
req.extensions_mut().insert(PathIdx(i + 1));
match params {
Some(params) => match params.vec[i].parse() {
Ok(t) => future::ok(Path(t)),
Err(_) => future::err(http::status::StatusCode::BAD_REQUEST.into_response()),
},
None => future::err(http::status::StatusCode::INTERNAL_SERVER_ERROR.into_response()),
}
}
}
pub trait NamedSegment: Send + 'static + std::str::FromStr {
const NAME: &'static str;
}
pub struct Named<T: NamedSegment>(pub T);
impl<T: NamedSegment> Deref for Named<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T: NamedSegment> DerefMut for Named<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T: NamedSegment, S: 'static> Extract<S> for Named<T> {
type Fut = future::Ready<Result<Self, Response>>;
fn extract(
data: &mut S,
req: &mut Request,
params: &Option<RouteMatch<'_>>,
store: &Store,
) -> Self::Fut {
match params {
Some(params) => params
.map
.get(T::NAME)
.and_then(|segment| segment.parse().ok())
.map_or(
future::err(http::status::StatusCode::BAD_REQUEST.into_response()),
|t| future::ok(Named(t)),
),
None => future::err(http::status::StatusCode::BAD_REQUEST.into_response()),
}
}
}
pub struct UrlQuery<T>(pub T);
impl<S, T> Extract<S> for UrlQuery<T>
where
T: Send + std::str::FromStr + 'static,
S: 'static,
{
type Fut = future::Ready<Result<Self, Response>>;
fn extract(
data: &mut S,
req: &mut Request,
params: &Option<RouteMatch<'_>>,
store: &Store,
) -> Self::Fut {
req.uri().query().and_then(|q| q.parse().ok()).map_or(
future::err(http::status::StatusCode::BAD_REQUEST.into_response()),
|q| future::ok(UrlQuery(q)),
)
}
}