use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
use std::borrow::Cow;
use crate::request::Request;
use crate::response::{self, Responder, Response};
use crate::http::Status;
#[derive(Debug, Clone, PartialEq)]
pub struct Created<R>(Cow<'static, str>, Option<R>, Option<u64>);
impl<'r, R> Created<R> {
pub fn new<L: Into<Cow<'static, str>>>(location: L) -> Self {
Created(location.into(), None, None)
}
pub fn body(mut self, responder: R) -> Self {
self.1 = Some(responder);
self
}
pub fn tagged_body(mut self, responder: R) -> Self where R: Hash {
let mut hasher = &mut DefaultHasher::default();
responder.hash(&mut hasher);
let hash = hasher.finish();
self.1 = Some(responder);
self.2 = Some(hash);
self
}
}
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Created<R> {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
let mut response = Response::build();
if let Some(responder) = self.1 {
response.merge(responder.respond_to(req)?);
}
if let Some(hash) = self.2 {
response.raw_header("ETag", format!(r#""{}""#, hash));
}
response.status(Status::Created)
.raw_header("Location", self.0)
.ok()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct NoContent;
impl<'r> Responder<'r, 'static> for NoContent {
fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
Response::build().status(Status::NoContent).ok()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Custom<R>(pub Status, pub R);
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Custom<R> {
#[inline]
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
Response::build_from(self.1.respond_to(req)?)
.status(self.0)
.ok()
}
}
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for (Status, R) {
#[inline(always)]
fn respond_to(self, request: &'r Request<'_>) -> response::Result<'o> {
Custom(self.0, self.1).respond_to(request)
}
}
macro_rules! status_response {
($T:ident $kind:expr) => {
#[doc = concat!($kind, concat!(" ([`Status::", stringify!($T), "`])."))]
#[doc = $kind]
#[doc = concat!("fn handler() -> status::", stringify!($T), "<()> {")]
#[doc = concat!(" status::", stringify!($T), "(())")]
#[doc = $kind]
#[doc = concat!("fn handler() -> status::", stringify!($T), "<&'static str> {")]
#[doc = concat!(" status::", stringify!($T), "(\"body\")")]
#[derive(Debug, Clone, PartialEq)]
pub struct $T<R>(pub R);
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for $T<R> {
#[inline(always)]
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
Custom(Status::$T, self.0).respond_to(req)
}
}
}
}
status_response!(Accepted "202 Accepted");
status_response!(BadRequest "400 Bad Request");
status_response!(Unauthorized "401 Unauthorized");
status_response!(Forbidden "403 Forbidden");
status_response!(NotFound "404 NotFound");
status_response!(Conflict "409 Conflict");