use std::{any::Any, convert::Infallible};
use http::Error as HttpError;
use thiserror::Error;
use crate::{header::HeaderMap, method::MethodParseError, Body, Extensions, Method, Uri, Version};
#[derive(Debug, Default)]
pub struct Request {
pub method: Method,
pub uri: Uri,
pub version: Version,
pub headers: HeaderMap,
pub extensions: Extensions,
pub body: Body,
}
#[derive(Debug, Default)]
pub struct RequestParts {
pub method: Method,
pub uri: Uri,
pub version: Version,
pub headers: HeaderMap,
pub extensions: Extensions,
}
impl RequestParts {
pub fn as_ref(&self) -> RequestPartsRef<'_> {
RequestPartsRef {
method: self.method,
uri: &self.uri,
version: self.version,
headers: &self.headers,
extensions: &self.extensions,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct RequestPartsRef<'a> {
pub method: Method,
pub uri: &'a Uri,
pub version: Version,
pub headers: &'a HeaderMap,
pub extensions: &'a Extensions,
}
impl<'a> RequestPartsRef<'a> {
pub fn into_owned(&self) -> RequestParts {
RequestParts {
method: self.method,
uri: self.uri.clone(),
version: self.version,
headers: self.headers.clone(),
extensions: self.extensions.clone(),
}
}
}
impl Request {
pub fn parts(&self) -> RequestPartsRef<'_> {
RequestPartsRef {
method: self.method,
uri: &self.uri,
version: self.version,
headers: &self.headers,
extensions: &self.extensions,
}
}
pub fn builder() -> Builder {
Builder::new()
}
pub fn get<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<HttpError>,
{
Builder::new().method(Method::Get).uri(uri)
}
pub fn put<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<HttpError>,
{
Builder::new().method(Method::Put).uri(uri)
}
pub fn post<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<HttpError>,
{
Builder::new().method(Method::Post).uri(uri)
}
pub fn delete<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<HttpError>,
{
Builder::new().method(Method::Delete).uri(uri)
}
pub fn options<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<HttpError>,
{
Builder::new().method(Method::Options).uri(uri)
}
pub fn head<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<HttpError>,
{
Builder::new().method(Method::Head).uri(uri)
}
pub fn connect<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<HttpError>,
{
Builder::new().method(Method::Connect).uri(uri)
}
pub fn patch<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<HttpError>,
{
Builder::new().method(Method::Patch).uri(uri)
}
pub fn trace<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<HttpError>,
{
Builder::new().method(Method::Trace).uri(uri)
}
pub fn new(body: impl Into<Body>) -> Request {
Self::from_parts(Default::default(), body)
}
pub fn from_parts(parts: RequestParts, body: impl Into<Body>) -> Request {
Request {
method: parts.method,
uri: parts.uri,
version: parts.version,
headers: parts.headers,
extensions: parts.extensions,
body: body.into(),
}
}
pub fn into_parts(self) -> (RequestParts, Body) {
(
RequestParts {
method: self.method,
uri: self.uri,
version: self.version,
headers: self.headers,
extensions: self.extensions,
},
self.body,
)
}
}
#[derive(Error, Debug)]
pub enum RequestBuilderError {
#[error("")]
Infallible(#[from] Infallible),
#[error("method parse error: {0}")]
MethodParse(#[from] MethodParseError),
#[error("http error: {0}")]
Http(#[from] HttpError),
}
#[derive(Debug)]
pub struct Builder {
inner: Result<Request, RequestBuilderError>,
}
impl Builder {
pub fn new() -> Builder {
Builder::default()
}
pub fn method(self, method: Method) -> Builder {
self.and_then(move |mut head| {
head.method = method;
Ok(head)
})
}
pub fn method_ref(&self) -> Option<Method> {
self.inner.as_ref().ok().map(|h| h.method)
}
pub fn uri<T>(self, uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<HttpError>,
{
self.and_then(move |mut head| {
head.uri = TryFrom::try_from(uri).map_err(Into::into)?;
Ok(head)
})
}
pub fn uri_ref(&self) -> Option<&Uri> {
self.inner.as_ref().ok().map(|h| &h.uri)
}
pub fn version(self, version: Version) -> Builder {
self.and_then(move |mut head| {
head.version = version;
Ok(head)
})
}
pub fn version_ref(&self) -> Option<&Version> {
self.inner.as_ref().ok().map(|h| &h.version)
}
pub fn header(self, name: impl AsRef<str>, value: impl Into<String>) -> Builder {
self.and_then(move |mut head| {
head.headers.insert(name, value);
Ok(head)
})
}
pub fn headers_ref(&self) -> Option<&HeaderMap> {
self.inner.as_ref().ok().map(|h| &h.headers)
}
pub fn headers_mut(&mut self) -> Option<&mut HeaderMap> {
self.inner.as_mut().ok().map(|h| &mut h.headers)
}
pub fn extension<T>(self, extension: T) -> Builder
where
T: Any + Send + Sync + 'static,
{
self.and_then(move |head| {
head.extensions.insert(extension);
Ok(head)
})
}
pub fn extensions(&self) -> Option<&Extensions> {
self.inner.as_ref().ok().map(|h| &h.extensions)
}
pub fn extensions_mut(&mut self) -> Option<&mut Extensions> {
self.inner.as_mut().ok().map(|h| &mut h.extensions)
}
pub fn body(self, body: impl Into<Body>) -> Result<Request, RequestBuilderError> {
self.inner.map(move |mut head| {
head.body = body.into();
head
})
}
fn and_then<F>(self, func: F) -> Self
where
F: FnOnce(Request) -> Result<Request, RequestBuilderError>,
{
Builder {
inner: self.inner.and_then(func),
}
}
}
impl Default for Builder {
fn default() -> Builder {
Builder {
inner: Ok(Request::default()),
}
}
}