use std::borrow::Cow;
use nyquest_interface::Body as BodyImpl;
#[cfg(feature = "multipart")]
use nyquest_interface::{Part as PartImpl, PartBody as PartBodyImpl};
pub struct Body<S> {
pub(crate) inner: BodyImpl<S>,
}
#[cfg(feature = "multipart")]
pub struct Part<S> {
inner: PartImpl<S>,
}
#[cfg(feature = "multipart")]
pub struct PartBody<S> {
inner: PartBodyImpl<S>,
}
impl<S> Body<S> {
pub fn plain_text(text: impl Into<Cow<'static, str>>) -> Self {
Self::text(text, "text/plain")
}
pub fn text(
text: impl Into<Cow<'static, str>>,
content_type: impl Into<Cow<'static, str>>,
) -> Self {
Self {
inner: BodyImpl::Bytes {
content: match text.into() {
Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
Cow::Owned(s) => Cow::Owned(s.into_bytes()),
},
content_type: content_type.into(),
},
}
}
pub fn binary_bytes(bytes: impl Into<Cow<'static, [u8]>>) -> Self {
Self::bytes(bytes, "application/octet-stream")
}
pub fn bytes(
bytes: impl Into<Cow<'static, [u8]>>,
content_type: impl Into<Cow<'static, str>>,
) -> Self {
Self {
inner: BodyImpl::Bytes {
content: bytes.into(),
content_type: content_type.into(),
},
}
}
pub fn json_bytes(bytes: impl Into<Cow<'static, [u8]>>) -> Self {
Self::bytes(bytes, "application/json")
}
#[cfg(feature = "json")]
pub fn json<T: serde::Serialize>(value: &T) -> serde_json::Result<Self> {
let bytes = serde_json::to_vec(value)?;
Ok(Self::json_bytes(bytes))
}
pub fn form(fields: impl IntoIterator<Item = (Cow<'static, str>, Cow<'static, str>)>) -> Self {
Self {
inner: BodyImpl::Form {
fields: fields.into_iter().collect(),
},
}
}
#[cfg(feature = "multipart")]
pub fn multipart(parts: impl IntoIterator<Item = Part<S>>) -> Self {
Self {
inner: BodyImpl::Multipart {
parts: parts.into_iter().map(|part| part.inner).collect(),
},
}
}
#[cfg(any(feature = "blocking-stream", feature = "async-stream"))]
#[cfg_attr(
docsrs,
doc(cfg(any(feature = "blocking-stream", feature = "async-stream")))
)]
pub fn stream(
stream: impl private::IntoSizedStream<S>,
content_type: impl Into<Cow<'static, str>>,
content_length: u64,
) -> Self {
Self {
inner: BodyImpl::Stream {
stream: stream.into_stream(content_length),
content_type: content_type.into(),
},
}
}
#[cfg(any(feature = "blocking-stream", feature = "async-stream"))]
#[cfg_attr(
docsrs,
doc(cfg(any(feature = "blocking-stream", feature = "async-stream")))
)]
pub fn stream_unsized(
stream: impl private::IntoUnsizedStream<S>,
content_type: impl Into<Cow<'static, str>>,
) -> Self {
Self {
inner: BodyImpl::Stream {
stream: stream.into_stream(),
content_type: content_type.into(),
},
}
}
}
#[macro_export]
macro_rules! body_form {
($($key:expr => $value:expr),* $(,)?) => {
::nyquest::Body::form(vec![
$(
(
::std::convert::Into::<::std::borrow::Cow::<'static, str>>::into($key),
::std::convert::Into::<::std::borrow::Cow::<'static, str>>::into($value)
),
)*
])
};
}
#[cfg(feature = "multipart")]
impl<S> Part<S> {
pub fn new_with_content_type(
name: impl Into<Cow<'static, str>>,
content_type: impl Into<Cow<'static, str>>,
body: PartBody<S>,
) -> Self {
Self {
inner: PartImpl {
headers: vec![],
name: name.into(),
filename: None,
content_type: content_type.into(),
body: body.inner,
},
}
}
pub fn with_header(
mut self,
name: impl Into<Cow<'static, str>>,
value: impl Into<Cow<'static, str>>,
) -> Self {
self.inner.headers.push((name.into(), value.into()));
self
}
pub fn with_filename(mut self, filename: impl Into<Cow<'static, str>>) -> Self {
self.inner.filename = Some(filename.into());
self
}
}
pub(crate) mod private {
pub trait IntoSizedStream<B> {
fn into_stream(self, size: u64) -> B;
}
pub trait IntoUnsizedStream<B> {
fn into_stream(self) -> B;
}
}
#[cfg(feature = "multipart")]
impl<S> PartBody<S> {
pub fn text(text: impl Into<Cow<'static, str>>) -> Self {
Self {
inner: PartBodyImpl::Bytes {
content: match text.into() {
Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
Cow::Owned(s) => Cow::Owned(s.into_bytes()),
},
},
}
}
pub fn bytes(bytes: impl Into<Cow<'static, [u8]>>) -> Self {
Self {
inner: PartBodyImpl::Bytes {
content: bytes.into(),
},
}
}
#[cfg(any(feature = "blocking", feature = "async"))]
pub fn stream(stream: impl private::IntoSizedStream<S>, content_length: u64) -> Self {
Self {
inner: PartBodyImpl::Stream(stream.into_stream(content_length)),
}
}
#[cfg(any(feature = "blocking", feature = "async"))]
pub fn stream_unsized(stream: impl private::IntoUnsizedStream<S>) -> Self {
Self {
inner: PartBodyImpl::Stream(stream.into_stream()),
}
}
}