mod req_builder;
mod res_builder;
use crate::{
codec::u32_string,
collection::Vector,
http::{Header, KnownHeaderName, Mime, MsgDataMut},
misc::{Either, LeaseMut},
};
use core::fmt::Arguments;
pub use req_builder::ReqBuilder;
pub use res_builder::ResBuilder;
#[derive(Debug)]
pub struct MsgBuilderInput<'left, 'right>(Either<&'left [&'left str], Arguments<'right>>);
impl From<()> for MsgBuilderInput<'_, '_> {
#[inline]
fn from(_: ()) -> Self {
Self(Either::Left(&[]))
}
}
impl<'left, const N: usize> From<&'left [&'left str; N]> for MsgBuilderInput<'left, '_> {
#[inline]
fn from(value: &'left [&'left str; N]) -> Self {
Self(Either::Left(value))
}
}
impl<'left> From<&'left [&'left str]> for MsgBuilderInput<'left, '_> {
#[inline]
fn from(value: &'left [&'left str]) -> Self {
Self(Either::Left(value))
}
}
impl<'right> From<Arguments<'right>> for MsgBuilderInput<'_, 'right> {
#[inline]
fn from(value: Arguments<'right>) -> Self {
Self(Either::Right(value))
}
}
#[derive(Debug)]
pub struct MsgBuilder<MD> {
msg_data: MD,
}
impl<MD> MsgBuilder<MD> {
#[inline]
pub const fn new(msg_data: MD) -> Self {
Self { msg_data }
}
#[inline]
pub fn into_msg_data(self) -> MD {
self.msg_data
}
#[inline]
pub const fn msg_data(&self) -> &MD {
&self.msg_data
}
#[inline]
pub const fn msg_data_mut(&mut self) -> &mut MD {
&mut self.msg_data
}
}
impl<MD> MsgBuilder<MD>
where
MD: MsgDataMut,
{
#[inline]
pub fn accept<'left, 'right, I>(&mut self, value: I) -> crate::Result<&mut Self>
where
I: Into<MsgBuilderInput<'left, 'right>>,
{
self.push_header(KnownHeaderName::Accept.into(), value)?;
Ok(self)
}
#[inline]
pub fn auth_bearer<'left, 'right, I>(&mut self, value: I) -> crate::Result<&mut Self>
where
I: Into<MsgBuilderInput<'left, 'right>>,
{
let headers = self.msg_data.headers_mut();
let name = KnownHeaderName::Authorization.into();
match value.into().0 {
Either::Left(el) => {
headers.push_from_iter(Header::from_name_and_value(
name,
["Bearer "].into_iter().chain(el.iter().copied()),
))?;
}
Either::Right(el) => {
headers.push_from_fmt(Header::from_name_and_value(name, format_args!("Bearer {el}")))?;
}
}
Ok(self)
}
#[inline]
pub fn content_length(&mut self, value: u32) -> crate::Result<&mut Self> {
self.msg_data.headers_mut().push_from_iter(Header::from_name_and_value(
KnownHeaderName::ContentLength.into(),
[u32_string(value).as_str()],
))?;
Ok(self)
}
#[inline]
pub fn content_type(&mut self, value: Mime) -> crate::Result<&mut Self> {
self.msg_data.headers_mut().push_from_iter(Header::from_name_and_value(
KnownHeaderName::ContentType.into(),
[value.as_str()],
))?;
Ok(self)
}
#[inline]
pub fn header_iter<'kv, I>(&mut self, name: &'kv str, value: I) -> crate::Result<&mut Self>
where
I: IntoIterator<Item = &'kv str>,
I::IntoIter: Clone,
{
self.msg_data.headers_mut().push_from_iter(Header::from_name_and_value(name, value))?;
Ok(self)
}
#[inline]
pub fn header_fmt(&mut self, name: &str, value: Arguments<'_>) -> crate::Result<&mut Self> {
self.msg_data.headers_mut().push_from_fmt(Header::from_name_and_value(name, value))?;
Ok(self)
}
#[inline]
pub fn host<'left, 'right, I>(&mut self, value: Option<I>) -> crate::Result<&mut Self>
where
I: Into<MsgBuilderInput<'left, 'right>>,
{
let (_, headers, uri) = self.msg_data.parts_mut();
let name = KnownHeaderName::Host;
if let Some(elem) = value {
self.push_header(name.into(), elem)?;
} else {
headers.push_from_iter(Header::from_name_and_value(name.into(), [uri.host()]))?;
}
Ok(self)
}
#[inline]
pub fn user_agent<'left, 'right, I>(&mut self, value: I) -> crate::Result<&mut Self>
where
I: Into<MsgBuilderInput<'left, 'right>>,
{
self.push_header(KnownHeaderName::UserAgent.into(), value)?;
Ok(self)
}
fn push_header<'left, 'right, I>(&mut self, name: &str, value: I) -> crate::Result<()>
where
I: Into<MsgBuilderInput<'left, 'right>>,
{
let headers = self.msg_data.headers_mut();
match value.into().0 {
Either::Left(el) => {
headers.push_from_iter(Header::from_name_and_value(name, el.iter().copied()))?;
}
Either::Right(el) => {
headers.push_from_fmt(Header::from_name_and_value(name, el))?;
}
}
Ok(())
}
}
impl<MD> MsgBuilder<MD>
where
MD: MsgDataMut,
MD::Body: LeaseMut<Vector<u8>>,
{
#[inline]
pub fn bytes(&mut self, data: &[u8]) -> crate::Result<&mut Self> {
let before = self.msg_data.body_mut().lease_mut().len();
self.msg_data.body_mut().lease_mut().extend_from_copyable_slice(data)?;
let length = self.msg_data.body_mut().lease_mut().len().wrapping_sub(before);
self.content_length(length.try_into()?)
}
#[inline]
pub fn html(&mut self, data: &[u8]) -> crate::Result<&mut Self> {
let before = self.msg_data.body_mut().lease_mut().len();
self.msg_data.body_mut().lease_mut().extend_from_copyable_slice(data)?;
let length = self.msg_data.body_mut().lease_mut().len().wrapping_sub(before);
self.content_type(Mime::TextHtml)?.content_length(length.try_into()?)
}
#[cfg(feature = "serde_json")]
#[inline]
pub fn serde_json<T>(&mut self, data: &T) -> crate::Result<&mut Self>
where
T: serde::Serialize,
{
let before = self.msg_data.body_mut().lease_mut().len();
serde_json::to_writer(self.msg_data.body_mut().lease_mut(), data)?;
let length = self.msg_data.body_mut().lease_mut().len().wrapping_sub(before);
self.content_type(Mime::ApplicationJson)?.content_length(length.try_into()?)
}
#[inline]
pub fn text(&mut self, data: &[u8]) -> crate::Result<&mut Self> {
let before = self.msg_data.body_mut().lease_mut().len();
self.msg_data.body_mut().lease_mut().extend_from_copyable_slice(data)?;
let length = self.msg_data.body_mut().lease_mut().len().wrapping_sub(before);
self.content_type(Mime::TextPlain)?.content_length(length.try_into()?)
}
}