#![allow(clippy::tabs_in_doc_comments)]
use std::fmt;
use super::{
header::{HeaderMap, HeaderName, HeaderValue},
status::StatusCode,
version::Version
};
type Result<T> = core::result::Result<T, Box<dyn std::error::Error>>;
pub struct Response {
head: ResponseParts,
body: Vec<u8>
}
#[derive(Clone)]
pub struct ResponseParts {
pub status: StatusCode,
pub version: Version,
pub headers: HeaderMap<HeaderValue>,
pub mimetype: Option<String>
}
#[derive(Debug)]
pub struct Builder {
inner: Result<ResponseParts>
}
impl Response {
#[inline]
pub fn new(body: Vec<u8>) -> Response {
Response { head: ResponseParts::new(), body }
}
#[inline]
#[doc(hidden)]
pub fn into_parts(self) -> (ResponseParts, Vec<u8>) {
(self.head, self.body)
}
#[inline]
pub fn set_status(&mut self, status: StatusCode) {
self.head.status = status;
}
#[inline]
pub fn status(&self) -> StatusCode {
self.head.status
}
#[inline]
pub fn set_mimetype(&mut self, mimetype: Option<String>) {
self.head.mimetype = mimetype;
}
#[inline]
pub fn mimetype(&self) -> Option<&String> {
self.head.mimetype.as_ref()
}
#[inline]
pub fn version(&self) -> Version {
self.head.version
}
#[inline]
pub fn headers_mut(&mut self) -> &mut HeaderMap<HeaderValue> {
&mut self.head.headers
}
#[inline]
pub fn headers(&self) -> &HeaderMap<HeaderValue> {
&self.head.headers
}
#[inline]
pub fn body_mut(&mut self) -> &mut Vec<u8> {
&mut self.body
}
#[inline]
pub fn body(&self) -> &Vec<u8> {
&self.body
}
}
impl Default for Response {
#[inline]
fn default() -> Response {
Response::new(Vec::new())
}
}
impl fmt::Debug for Response {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Response")
.field("status", &self.status())
.field("version", &self.version())
.field("headers", self.headers())
.field("body", self.body())
.finish()
}
}
impl ResponseParts {
fn new() -> ResponseParts {
ResponseParts {
status: StatusCode::default(),
version: Version::default(),
headers: HeaderMap::default(),
mimetype: None
}
}
}
impl fmt::Debug for ResponseParts {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Parts")
.field("status", &self.status)
.field("version", &self.version)
.field("headers", &self.headers)
.finish()
}
}
impl Builder {
#[inline]
pub fn new() -> Builder {
Builder { inner: Ok(ResponseParts::new()) }
}
#[must_use]
pub fn mimetype(self, mimetype: &str) -> Self {
self.and_then(move |mut head| {
head.mimetype = Some(mimetype.to_string());
Ok(head)
})
}
#[must_use]
pub fn status<T>(self, status: T) -> Self
where
StatusCode: TryFrom<T>,
<StatusCode as TryFrom<T>>::Error: Into<crate::Error>
{
self.and_then(move |mut head| {
head.status = TryFrom::try_from(status).map_err(Into::into)?;
Ok(head)
})
}
#[must_use]
pub fn version(self, version: Version) -> Self {
self.and_then(move |mut head| {
head.version = version;
Ok(head)
})
}
#[must_use]
pub fn header<K, V>(self, key: K, value: V) -> Self
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<crate::Error>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<crate::Error>
{
self.and_then(move |mut head| {
let name = <HeaderName as TryFrom<K>>::try_from(key).map_err(Into::into)?;
let value = <HeaderValue as TryFrom<V>>::try_from(value).map_err(Into::into)?;
head.headers.append(name, value);
Ok(head)
})
}
pub fn body(self, body: Vec<u8>) -> Result<Response> {
self.inner.map(move |head| Response { head, body })
}
fn and_then<F>(self, func: F) -> Self
where
F: FnOnce(ResponseParts) -> Result<ResponseParts>
{
Builder { inner: self.inner.and_then(func) }
}
}
impl Default for Builder {
#[inline]
fn default() -> Builder {
Builder { inner: Ok(ResponseParts::new()) }
}
}