use std::{error, iter::FromIterator, marker::PhantomData};
use bytes::Bytes;
use conjure_error::{Error, InvalidArgument};
use conjure_object::FromPlain;
use futures_core::Stream;
use http::{header::CONTENT_TYPE, HeaderMap, HeaderValue, Response};
use serde::{de::DeserializeOwned, Serialize};
use crate::private::APPLICATION_OCTET_STREAM;
use super::{
AsyncDeserializeRequest, AsyncResponseBody, AsyncSerializeResponse, AsyncWriteBody,
ConjureRuntime, DecodeHeader, DecodeParam, DeserializeRequest, EmptyResponseSerializer,
ResponseBody, SerializeResponse, StdRequestDeserializer, StdResponseSerializer, WriteBody,
};
pub enum OptionalRequestDeserializer {}
impl<T, R> DeserializeRequest<Option<T>, R> for OptionalRequestDeserializer
where
T: DeserializeOwned,
R: Iterator<Item = Result<Bytes, Error>>,
{
fn deserialize(
runtime: &ConjureRuntime,
headers: &HeaderMap,
body: R,
) -> Result<Option<T>, Error> {
if !headers.contains_key(CONTENT_TYPE) {
return Ok(None);
}
<StdRequestDeserializer as DeserializeRequest<_, _>>::deserialize(runtime, headers, body)
}
}
impl<T, R> AsyncDeserializeRequest<Option<T>, R> for OptionalRequestDeserializer
where
T: DeserializeOwned,
R: Stream<Item = Result<Bytes, Error>> + Send,
{
async fn deserialize(
runtime: &ConjureRuntime,
headers: &HeaderMap,
body: R,
) -> Result<Option<T>, Error> {
if !headers.contains_key(CONTENT_TYPE) {
return Ok(None);
}
<StdRequestDeserializer as AsyncDeserializeRequest<_, _>>::deserialize(
runtime, headers, body,
)
.await
}
}
pub enum BinaryRequestDeserializer {}
impl BinaryRequestDeserializer {
fn deserialize_inner<R>(headers: &HeaderMap, body: R) -> Result<R, Error> {
if headers.get(CONTENT_TYPE) != Some(&APPLICATION_OCTET_STREAM) {
return Err(Error::service_safe(
"unexpected Content-Type",
InvalidArgument::new(),
));
}
Ok(body)
}
}
impl<R> DeserializeRequest<R, R> for BinaryRequestDeserializer {
fn deserialize(_runtime: &ConjureRuntime, headers: &HeaderMap, body: R) -> Result<R, Error> {
Self::deserialize_inner(headers, body)
}
}
impl<R> AsyncDeserializeRequest<R, R> for BinaryRequestDeserializer
where
R: Send,
{
async fn deserialize(
_runtime: &ConjureRuntime,
headers: &HeaderMap,
body: R,
) -> Result<R, Error> {
Self::deserialize_inner(headers, body)
}
}
pub enum CollectionResponseSerializer {}
impl<T, W> SerializeResponse<T, W> for CollectionResponseSerializer
where
T: Serialize + PartialEq + Default,
{
fn serialize(
runtime: &ConjureRuntime,
request_headers: &HeaderMap,
value: T,
) -> Result<Response<ResponseBody<W>>, Error> {
if value == T::default() {
<EmptyResponseSerializer as SerializeResponse<_, _>>::serialize(
runtime,
request_headers,
(),
)
} else {
<StdResponseSerializer as SerializeResponse<_, _>>::serialize(
runtime,
request_headers,
value,
)
}
}
}
impl<T, W> AsyncSerializeResponse<T, W> for CollectionResponseSerializer
where
T: Serialize + PartialEq + Default,
{
fn serialize(
runtime: &ConjureRuntime,
request_headers: &HeaderMap,
value: T,
) -> Result<Response<AsyncResponseBody<W>>, Error> {
if value == T::default() {
<EmptyResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
runtime,
request_headers,
(),
)
} else {
<StdResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
runtime,
request_headers,
value,
)
}
}
}
pub enum BinaryResponseSerializer {}
impl BinaryResponseSerializer {
fn serialize_inner<B>(body: B) -> Result<Response<B>, Error> {
let mut response = Response::new(body);
response
.headers_mut()
.insert(CONTENT_TYPE, APPLICATION_OCTET_STREAM);
Ok(response)
}
}
impl<T, W> SerializeResponse<T, W> for BinaryResponseSerializer
where
T: WriteBody<W> + 'static,
{
fn serialize(
_runtime: &ConjureRuntime,
_request_headers: &HeaderMap,
value: T,
) -> Result<Response<ResponseBody<W>>, Error> {
Self::serialize_inner(ResponseBody::Streaming(Box::new(value)))
}
}
impl<T, W> AsyncSerializeResponse<T, W> for BinaryResponseSerializer
where
T: AsyncWriteBody<W> + 'static + Send,
{
fn serialize(
_runtime: &ConjureRuntime,
_request_headers: &HeaderMap,
value: T,
) -> Result<Response<AsyncResponseBody<W>>, Error> {
Self::serialize_inner(AsyncResponseBody::Streaming(super::BoxAsyncWriteBody::new(
value,
)))
}
}
pub enum OptionalBinaryResponseSerializer {}
impl<T, W> SerializeResponse<Option<T>, W> for OptionalBinaryResponseSerializer
where
T: WriteBody<W> + 'static,
{
fn serialize(
runtime: &ConjureRuntime,
request_headers: &HeaderMap,
value: Option<T>,
) -> Result<Response<ResponseBody<W>>, Error> {
match value {
Some(value) => <BinaryResponseSerializer as SerializeResponse<_, _>>::serialize(
runtime,
request_headers,
value,
),
None => <EmptyResponseSerializer as SerializeResponse<_, _>>::serialize(
runtime,
request_headers,
(),
),
}
}
}
impl<T, W> AsyncSerializeResponse<Option<T>, W> for OptionalBinaryResponseSerializer
where
T: AsyncWriteBody<W> + 'static + Send,
{
fn serialize(
runtime: &ConjureRuntime,
request_headers: &HeaderMap,
value: Option<T>,
) -> Result<Response<AsyncResponseBody<W>>, Error> {
match value {
Some(value) => <BinaryResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
runtime,
request_headers,
value,
),
None => <EmptyResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
runtime,
request_headers,
(),
),
}
}
}
pub enum FromPlainDecoder {}
impl<T> DecodeHeader<T> for FromPlainDecoder
where
T: FromPlain,
T::Err: Into<Box<dyn error::Error + Sync + Send>>,
{
fn decode<'a, I>(_: &ConjureRuntime, headers: I) -> Result<T, Error>
where
I: IntoIterator<Item = &'a HeaderValue>,
{
T::from_plain(
super::only_item(headers)?
.to_str()
.map_err(|e| Error::service(e, InvalidArgument::new()))?,
)
.map_err(|e| Error::service(e, InvalidArgument::new()))
}
}
impl<T> DecodeParam<T> for FromPlainDecoder
where
T: FromPlain,
T::Err: Into<Box<dyn error::Error + Sync + Send>>,
{
fn decode<I>(_: &ConjureRuntime, params: I) -> Result<T, Error>
where
I: IntoIterator,
I::Item: AsRef<str>,
{
T::from_plain(super::only_item(params)?.as_ref())
.map_err(|e| Error::service(e, InvalidArgument::new()))
}
}
pub enum FromPlainOptionDecoder {}
impl<T> DecodeHeader<Option<T>> for FromPlainOptionDecoder
where
T: FromPlain,
T::Err: Into<Box<dyn error::Error + Sync + Send>>,
{
fn decode<'a, I>(_: &ConjureRuntime, headers: I) -> Result<Option<T>, Error>
where
I: IntoIterator<Item = &'a HeaderValue>,
{
let Some(header) = super::optional_item(headers)? else {
return Ok(None);
};
let value = T::from_plain(
header
.to_str()
.map_err(|e| Error::service(e, InvalidArgument::new()))?,
)
.map_err(|e| Error::service(e, InvalidArgument::new()))?;
Ok(Some(value))
}
}
impl<T> DecodeParam<Option<T>> for FromPlainOptionDecoder
where
T: FromPlain,
T::Err: Into<Box<dyn error::Error + Sync + Send>>,
{
fn decode<I>(_: &ConjureRuntime, params: I) -> Result<Option<T>, Error>
where
I: IntoIterator,
I::Item: AsRef<str>,
{
let Some(param) = super::optional_item(params)? else {
return Ok(None);
};
let value =
T::from_plain(param.as_ref()).map_err(|e| Error::service(e, InvalidArgument::new()))?;
Ok(Some(value))
}
}
pub struct FromPlainSeqDecoder<U> {
_p: PhantomData<U>,
}
impl<T, U> DecodeParam<T> for FromPlainSeqDecoder<U>
where
T: FromIterator<U>,
U: FromPlain,
U::Err: Into<Box<dyn error::Error + Sync + Send>>,
{
fn decode<I>(_: &ConjureRuntime, params: I) -> Result<T, Error>
where
I: IntoIterator,
I::Item: AsRef<str>,
{
params
.into_iter()
.map(|s| {
U::from_plain(s.as_ref()).map_err(|e| Error::service(e, InvalidArgument::new()))
})
.collect()
}
}