use std::{borrow::Borrow, ops::Deref};
use crate::{
Body, Status,
connection::{UpgradeFuture, UpgradeRequest},
header::{HeaderField, HeaderFieldValue},
response::{Response, ResponseBuilder, ResponseHeader},
};
pub struct OutgoingResponseBuilder {
inner: ResponseBuilder,
upgrade: Option<UpgradeRequest>,
}
impl OutgoingResponseBuilder {
#[inline]
const fn new() -> Self {
Self {
inner: Response::builder(),
upgrade: None,
}
}
#[inline]
pub fn set_status(mut self, status: Status) -> Self {
self.inner = self.inner.set_status(status);
self
}
pub fn set_header_field<T>(mut self, field: T) -> Self
where
T: Into<HeaderField>,
{
self.inner = self.inner.set_header_field(field);
self
}
pub fn add_header_field<T>(mut self, field: T) -> Self
where
T: Into<HeaderField>,
{
self.inner = self.inner.add_header_field(field);
self
}
pub fn body<B>(self, body: B) -> OutgoingResponse<B> {
let inner = InnerResponse {
inner: self.inner.body(body),
upgrade: self.upgrade,
};
OutgoingResponse {
inner: Box::new(inner),
}
}
pub fn upgrade<B>(mut self) -> (OutgoingResponse<B>, UpgradeFuture)
where
B: Default,
{
let (rx, tx) = UpgradeFuture::new();
self.upgrade = Some(tx);
let response = self.body(B::default());
(response, rx)
}
}
impl From<ResponseHeader> for OutgoingResponseBuilder {
#[inline]
fn from(header: ResponseHeader) -> Self {
Self {
inner: header.into(),
upgrade: None,
}
}
}
pub struct OutgoingResponse<B = Body> {
inner: Box<InnerResponse<B>>,
}
impl OutgoingResponse<()> {
#[inline]
pub const fn builder() -> OutgoingResponseBuilder {
OutgoingResponseBuilder::new()
}
}
impl<B> OutgoingResponse<B> {
#[inline]
pub fn deconstruct(self) -> (ResponseHeader, B, Option<UpgradeRequest>) {
let (header, body) = self.inner.inner.deconstruct();
(header, body, self.inner.upgrade)
}
pub fn into_builder(self) -> (OutgoingResponseBuilder, B) {
let (header, body) = self.inner.inner.deconstruct();
let builder = OutgoingResponseBuilder {
inner: header.into(),
upgrade: self.inner.upgrade,
};
(builder, body)
}
#[inline]
pub fn take_upgrade_request(&mut self) -> Option<UpgradeRequest> {
self.inner.upgrade.take()
}
}
impl<B> AsRef<Response<B>> for OutgoingResponse<B> {
#[inline]
fn as_ref(&self) -> &Response<B> {
&self.inner.inner
}
}
impl<B> Borrow<Response<B>> for OutgoingResponse<B> {
#[inline]
fn borrow(&self) -> &Response<B> {
&self.inner.inner
}
}
impl<B> Deref for OutgoingResponse<B> {
type Target = Response<B>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner.inner
}
}
struct InnerResponse<B> {
inner: Response<B>,
upgrade: Option<UpgradeRequest>,
}
#[inline(never)]
pub fn empty_response(status: Status) -> OutgoingResponse {
OutgoingResponse::builder()
.set_status(status)
.body(Body::empty())
}
#[inline]
pub fn no_content() -> OutgoingResponse {
empty_response(Status::NO_CONTENT)
}
#[inline]
pub fn bad_request() -> OutgoingResponse {
empty_response(Status::BAD_REQUEST)
}
#[inline]
pub fn not_found() -> OutgoingResponse {
empty_response(Status::NOT_FOUND)
}
#[inline]
pub fn method_not_allowed() -> OutgoingResponse {
empty_response(Status::METHOD_NOT_ALLOWED)
}
#[inline]
pub fn unauthorized() -> OutgoingResponse {
empty_response(Status::UNAUTHORIZED)
}
#[inline]
pub fn expectation_failed() -> OutgoingResponse {
empty_response(Status::EXPECTATION_FAILED)
}
#[inline]
pub fn not_implemented() -> OutgoingResponse {
empty_response(Status::NOT_IMPLEMENTED)
}
#[inline]
pub fn bad_gateway() -> OutgoingResponse {
empty_response(Status::BAD_GATEWAY)
}
#[inline]
pub fn gateway_timeout() -> OutgoingResponse {
empty_response(Status::GATEWAY_TIMEOUT)
}
pub fn moved_permanently<T>(location: T) -> OutgoingResponse
where
T: Into<HeaderFieldValue>,
{
redirect(Status::MOVED_PERMANENTLY, location.into())
}
pub fn see_other<T>(location: T) -> OutgoingResponse
where
T: Into<HeaderFieldValue>,
{
redirect(Status::SEE_OTHER, location.into())
}
#[inline(never)]
fn redirect(status: Status, location: HeaderFieldValue) -> OutgoingResponse {
OutgoingResponse::builder()
.set_status(status)
.set_header_field(("Location", location))
.body(Body::empty())
}