use bytes::Bytes;
use conjure_error::{Error, InvalidArgument};
use futures_core::Stream;
use http::header::CONTENT_TYPE;
use http::{
request, Extensions, HeaderMap, HeaderValue, Method, Request, Response, StatusCode, Uri,
};
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::borrow::Cow;
use std::error;
use std::future::Future;
use std::io::Write;
use std::iter::FromIterator;
use std::marker::PhantomData;
use std::ops::Deref;
use std::pin::Pin;
use std::str;
use std::str::FromStr;
use std::sync::Arc;
use crate::private::{self, SERIALIZABLE_REQUEST_SIZE_LIMIT};
pub use crate::server::encoding::*;
#[doc(inline)]
pub use crate::server::runtime::ConjureRuntime;
pub mod conjure;
mod encoding;
pub mod runtime;
pub trait EndpointMetadata {
fn method(&self) -> Method;
fn path(&self) -> &[PathSegment];
fn template(&self) -> &str;
fn service_name(&self) -> &str;
fn name(&self) -> &str;
fn deprecated(&self) -> Option<&str>;
}
impl<T> EndpointMetadata for Box<T>
where
T: ?Sized + EndpointMetadata,
{
fn method(&self) -> Method {
(**self).method()
}
fn path(&self) -> &[PathSegment] {
(**self).path()
}
fn template(&self) -> &str {
(**self).template()
}
fn service_name(&self) -> &str {
(**self).service_name()
}
fn name(&self) -> &str {
(**self).name()
}
fn deprecated(&self) -> Option<&str> {
(**self).deprecated()
}
}
pub trait Endpoint<I, O>: EndpointMetadata {
fn handle(
&self,
req: Request<I>,
response_extensions: &mut Extensions,
) -> Result<Response<ResponseBody<O>>, Error>;
}
impl<T, I, O> Endpoint<I, O> for Box<T>
where
T: ?Sized + Endpoint<I, O>,
{
fn handle(
&self,
req: Request<I>,
response_extensions: &mut Extensions,
) -> Result<Response<ResponseBody<O>>, Error> {
(**self).handle(req, response_extensions)
}
}
pub trait AsyncEndpoint<I, O>: EndpointMetadata {
fn handle(
&self,
req: Request<I>,
response_extensions: &mut Extensions,
) -> impl Future<Output = Result<Response<AsyncResponseBody<O>>, Error>> + Send;
}
impl<T, I, O> AsyncEndpoint<I, O> for Box<T>
where
T: ?Sized + AsyncEndpoint<I, O>,
{
fn handle(
&self,
req: Request<I>,
response_extensions: &mut Extensions,
) -> impl Future<Output = Result<Response<AsyncResponseBody<O>>, Error>> + Send {
(**self).handle(req, response_extensions)
}
}
trait AsyncEndpointEraser<I, O>: EndpointMetadata {
#[allow(clippy::type_complexity)]
fn handle<'a>(
&'a self,
req: Request<I>,
response_extensions: &'a mut Extensions,
) -> Pin<Box<dyn Future<Output = Result<Response<AsyncResponseBody<O>>, Error>> + Send + 'a>>
where
I: 'a,
O: 'a;
}
impl<T, I, O> AsyncEndpointEraser<I, O> for T
where
T: AsyncEndpoint<I, O>,
{
fn handle<'a>(
&'a self,
req: Request<I>,
response_extensions: &'a mut Extensions,
) -> Pin<Box<dyn Future<Output = Result<Response<AsyncResponseBody<O>>, Error>> + Send + 'a>>
where
I: 'a,
O: 'a,
{
Box::pin(self.handle(req, response_extensions))
}
}
pub struct BoxAsyncEndpoint<'a, I, O> {
inner: Box<dyn AsyncEndpointEraser<I, O> + 'a + Sync + Send>,
}
impl<'a, I, O> BoxAsyncEndpoint<'a, I, O> {
pub fn new<T>(v: T) -> Self
where
T: AsyncEndpoint<I, O> + Sync + Send + 'a,
{
BoxAsyncEndpoint { inner: Box::new(v) }
}
}
impl<I, O> EndpointMetadata for BoxAsyncEndpoint<'_, I, O> {
fn method(&self) -> Method {
self.inner.method()
}
fn path(&self) -> &[PathSegment] {
self.inner.path()
}
fn template(&self) -> &str {
self.inner.template()
}
fn service_name(&self) -> &str {
self.inner.service_name()
}
fn name(&self) -> &str {
self.inner.name()
}
fn deprecated(&self) -> Option<&str> {
self.inner.deprecated()
}
}
impl<'a, I, O> AsyncEndpoint<I, O> for BoxAsyncEndpoint<'a, I, O>
where
I: Send,
{
async fn handle(
&self,
req: Request<I>,
response_extensions: &mut Extensions,
) -> Result<Response<AsyncResponseBody<O>>, Error> {
self.inner.handle(req, response_extensions).await
}
}
#[derive(Debug, Clone)]
pub enum PathSegment {
Literal(Cow<'static, str>),
Parameter {
name: Cow<'static, str>,
regex: Option<Cow<'static, str>>,
},
}
pub enum ResponseBody<O> {
Empty,
Fixed(Bytes),
Streaming(Box<dyn WriteBody<O>>),
}
pub enum AsyncResponseBody<O> {
Empty,
Fixed(Bytes),
Streaming(BoxAsyncWriteBody<'static, O>),
}
pub trait Service<I, O> {
fn endpoints(
&self,
runtime: &Arc<ConjureRuntime>,
) -> Vec<Box<dyn Endpoint<I, O> + Sync + Send>>;
}
pub trait AsyncService<I, O> {
fn endpoints(&self, runtime: &Arc<ConjureRuntime>) -> Vec<BoxAsyncEndpoint<'static, I, O>>;
}
pub trait WriteBody<W> {
fn write_body(self: Box<Self>, w: &mut W) -> Result<(), Error>;
}
impl<W> WriteBody<W> for Vec<u8>
where
W: Write,
{
fn write_body(self: Box<Self>, w: &mut W) -> Result<(), Error> {
w.write_all(&self).map_err(Error::internal_safe)
}
}
pub trait AsyncWriteBody<W> {
fn write_body(self, w: Pin<&mut W>) -> impl Future<Output = Result<(), Error>> + Send;
}
trait AsyncWriteBodyEraser<W> {
fn write_body<'a>(
self: Box<Self>,
w: Pin<&'a mut W>,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>>
where
Self: 'a;
}
impl<T, W> AsyncWriteBodyEraser<W> for T
where
T: AsyncWriteBody<W>,
{
fn write_body<'a>(
self: Box<Self>,
w: Pin<&'a mut W>,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>>
where
Self: 'a,
{
Box::pin((*self).write_body(w))
}
}
pub struct BoxAsyncWriteBody<'a, W> {
inner: Box<dyn AsyncWriteBodyEraser<W> + Send + 'a>,
}
impl<'a, W> BoxAsyncWriteBody<'a, W> {
pub fn new<T>(v: T) -> Self
where
T: AsyncWriteBody<W> + Send + 'a,
{
BoxAsyncWriteBody { inner: Box::new(v) }
}
}
impl<'a, W> AsyncWriteBody<W> for BoxAsyncWriteBody<'a, W>
where
W: Send,
{
async fn write_body(self, w: Pin<&mut W>) -> Result<(), Error>
where
W: Send,
{
self.inner.write_body(w).await
}
}
pub struct RequestContext<'a> {
request_parts: MaybeBorrowed<'a, request::Parts>,
response_extensions: &'a mut Extensions,
}
impl<'a> RequestContext<'a> {
#[doc(hidden)]
#[inline]
pub fn new(request_parts: request::Parts, response_extensions: &'a mut Extensions) -> Self {
RequestContext {
request_parts: MaybeBorrowed::Owned(request_parts),
response_extensions,
}
}
#[doc(hidden)]
#[inline]
pub fn new2(
request_parts: &'a request::Parts,
response_extensions: &'a mut Extensions,
) -> Self {
RequestContext {
request_parts: MaybeBorrowed::Borrowed(request_parts),
response_extensions,
}
}
#[inline]
pub fn request_uri(&self) -> &Uri {
&self.request_parts.uri
}
#[inline]
pub fn request_headers(&self) -> &HeaderMap {
&self.request_parts.headers
}
#[inline]
pub fn request_extensions(&self) -> &Extensions {
&self.request_parts.extensions
}
#[inline]
pub fn response_extensions(&self) -> &Extensions {
self.response_extensions
}
#[inline]
pub fn response_extensions_mut(&mut self) -> &mut Extensions {
self.response_extensions
}
}
enum MaybeBorrowed<'a, T> {
Borrowed(&'a T),
Owned(T),
}
impl<T> Deref for MaybeBorrowed<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
match self {
MaybeBorrowed::Borrowed(v) => v,
MaybeBorrowed::Owned(v) => v,
}
}
}
pub trait DeserializeRequest<T, R> {
fn deserialize(runtime: &ConjureRuntime, headers: &HeaderMap, body: R) -> Result<T, Error>;
}
pub trait AsyncDeserializeRequest<T, R> {
fn deserialize(
runtime: &ConjureRuntime,
headers: &HeaderMap,
body: R,
) -> impl Future<Output = Result<T, Error>> + Send;
}
pub enum StdRequestDeserializer<const N: usize = { SERIALIZABLE_REQUEST_SIZE_LIMIT }> {}
impl<const N: usize, T, R> DeserializeRequest<T, R> for StdRequestDeserializer<N>
where
T: DeserializeOwned,
R: Iterator<Item = Result<Bytes, Error>>,
{
fn deserialize(runtime: &ConjureRuntime, headers: &HeaderMap, body: R) -> Result<T, Error> {
let encoding = runtime.request_body_encoding(headers)?;
let buf = private::read_body(body, Some(N))?;
let v = T::deserialize(encoding.deserializer(&buf).deserializer())
.map_err(|e| Error::service(e, InvalidArgument::new()))?;
Ok(v)
}
}
impl<const N: usize, T, R> AsyncDeserializeRequest<T, R> for StdRequestDeserializer<N>
where
T: DeserializeOwned,
R: Stream<Item = Result<Bytes, Error>> + Send,
{
async fn deserialize(
runtime: &ConjureRuntime,
headers: &HeaderMap,
body: R,
) -> Result<T, Error> {
let encoding = runtime.request_body_encoding(headers)?;
let buf = private::async_read_body(body, Some(N)).await?;
let v = T::deserialize(encoding.deserializer(&buf).deserializer())
.map_err(|e| Error::service(e, InvalidArgument::new()))?;
Ok(v)
}
}
pub struct FromRequestDeserializer<D, U> {
_p: PhantomData<(D, U)>,
}
impl<T, R, D, U> DeserializeRequest<T, R> for FromRequestDeserializer<D, U>
where
T: From<U>,
D: DeserializeRequest<U, R>,
{
fn deserialize(runtime: &ConjureRuntime, headers: &HeaderMap, body: R) -> Result<T, Error> {
D::deserialize(runtime, headers, body).map(From::from)
}
}
impl<T, R, D, U> AsyncDeserializeRequest<T, R> for FromRequestDeserializer<D, U>
where
T: From<U>,
D: AsyncDeserializeRequest<U, R>,
R: Send,
{
async fn deserialize(
runtime: &ConjureRuntime,
headers: &HeaderMap,
body: R,
) -> Result<T, Error> {
D::deserialize(runtime, headers, body).await.map(From::from)
}
}
pub trait SerializeResponse<T, W> {
fn serialize(
runtime: &ConjureRuntime,
request_headers: &HeaderMap,
value: T,
) -> Result<Response<ResponseBody<W>>, Error>;
}
pub trait AsyncSerializeResponse<T, W> {
fn serialize(
runtime: &ConjureRuntime,
request_headers: &HeaderMap,
value: T,
) -> Result<Response<AsyncResponseBody<W>>, Error>;
}
pub enum EmptyResponseSerializer {}
impl EmptyResponseSerializer {
fn serialize_inner<T>(body: T) -> Result<Response<T>, Error> {
let mut response = Response::new(body);
*response.status_mut() = StatusCode::NO_CONTENT;
Ok(response)
}
}
impl<W> SerializeResponse<(), W> for EmptyResponseSerializer {
fn serialize(
_: &ConjureRuntime,
_: &HeaderMap,
_: (),
) -> Result<Response<ResponseBody<W>>, Error> {
Self::serialize_inner(ResponseBody::Empty)
}
}
impl<W> AsyncSerializeResponse<(), W> for EmptyResponseSerializer {
fn serialize(
_: &ConjureRuntime,
_: &HeaderMap,
_: (),
) -> Result<Response<AsyncResponseBody<W>>, Error> {
Self::serialize_inner(AsyncResponseBody::Empty)
}
}
pub enum StdResponseSerializer {}
impl StdResponseSerializer {
fn serialize_inner<B>(
runtime: &ConjureRuntime,
request_headers: &HeaderMap,
value: &dyn erased_serde::Serialize,
make_body: impl FnOnce(Bytes) -> B,
) -> Result<Response<B>, Error> {
let encoding = runtime.response_body_encoding(request_headers)?;
let mut body = vec![];
value
.erased_serialize(&mut *encoding.serializer(&mut body).serializer())
.map_err(Error::internal)?;
let mut response = Response::new(make_body(body.into()));
response
.headers_mut()
.insert(CONTENT_TYPE, encoding.content_type());
Ok(response)
}
}
impl<T, W> SerializeResponse<T, W> for StdResponseSerializer
where
T: Serialize,
{
fn serialize(
runtime: &ConjureRuntime,
request_headers: &HeaderMap,
value: T,
) -> Result<Response<ResponseBody<W>>, Error> {
Self::serialize_inner(runtime, request_headers, &value, ResponseBody::Fixed)
}
}
impl<T, W> AsyncSerializeResponse<T, W> for StdResponseSerializer
where
T: Serialize,
{
fn serialize(
runtime: &ConjureRuntime,
request_headers: &HeaderMap,
value: T,
) -> Result<Response<AsyncResponseBody<W>>, Error> {
Self::serialize_inner(runtime, request_headers, &value, AsyncResponseBody::Fixed)
}
}
pub trait DecodeHeader<T> {
fn decode<'a, I>(runtime: &ConjureRuntime, headers: I) -> Result<T, Error>
where
I: IntoIterator<Item = &'a HeaderValue>;
}
pub trait DecodeParam<T> {
fn decode<I>(runtime: &ConjureRuntime, params: I) -> Result<T, Error>
where
I: IntoIterator,
I::Item: AsRef<str>;
}
pub enum FromStrDecoder {}
impl<T> DecodeHeader<T> for FromStrDecoder
where
T: FromStr,
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>,
{
only_item(headers)?
.to_str()
.map_err(|e| Error::service(e, InvalidArgument::new()))?
.parse()
.map_err(|e| Error::service(e, InvalidArgument::new()))
}
}
impl<T> DecodeParam<T> for FromStrDecoder
where
T: FromStr,
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>,
{
only_item(params)?
.as_ref()
.parse()
.map_err(|e| Error::service(e, InvalidArgument::new()))
}
}
pub enum FromStrOptionDecoder {}
impl<T> DecodeHeader<Option<T>> for FromStrOptionDecoder
where
T: FromStr,
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) = optional_item(headers)? else {
return Ok(None);
};
let value = header
.to_str()
.map_err(|e| Error::service(e, InvalidArgument::new()))?
.parse()
.map_err(|e| Error::service(e, InvalidArgument::new()))?;
Ok(Some(value))
}
}
impl<T> DecodeParam<Option<T>> for FromStrOptionDecoder
where
T: FromStr,
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) = optional_item(params)? else {
return Ok(None);
};
let value = param
.as_ref()
.parse()
.map_err(|e| Error::service(e, InvalidArgument::new()))?;
Ok(Some(value))
}
}
fn optional_item<I>(it: I) -> Result<Option<I::Item>, Error>
where
I: IntoIterator,
{
let mut it = it.into_iter();
let Some(item) = it.next() else {
return Ok(None);
};
let remaining = it.count();
if remaining > 0 {
return Err(
Error::service_safe("expected at most 1 parameter", InvalidArgument::new())
.with_safe_param("actual", remaining + 1),
);
}
Ok(Some(item))
}
pub struct FromStrSeqDecoder<U> {
_p: PhantomData<U>,
}
impl<T, U> DecodeParam<T> for FromStrSeqDecoder<U>
where
T: FromIterator<U>,
U: FromStr,
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| {
s.as_ref()
.parse()
.map_err(|e| Error::service(e, InvalidArgument::new()))
})
.collect()
}
}
fn only_item<I>(it: I) -> Result<I::Item, Error>
where
I: IntoIterator,
{
let mut it = it.into_iter();
let Some(item) = it.next() else {
return Err(
Error::service_safe("expected exactly 1 parameter", InvalidArgument::new())
.with_safe_param("actual", 0),
);
};
let remaining = it.count();
if remaining > 0 {
return Err(
Error::service_safe("expected exactly 1 parameter", InvalidArgument::new())
.with_safe_param("actual", remaining + 1),
);
}
Ok(item)
}
pub struct FromDecoder<D, U> {
_p: PhantomData<(D, U)>,
}
impl<T, D, U> DecodeParam<T> for FromDecoder<D, U>
where
T: From<U>,
D: DecodeParam<U>,
{
fn decode<I>(runtime: &ConjureRuntime, params: I) -> Result<T, Error>
where
I: IntoIterator,
I::Item: AsRef<str>,
{
D::decode(runtime, params).map(T::from)
}
}
impl<T, D, U> DecodeHeader<T> for FromDecoder<D, U>
where
T: From<U>,
D: DecodeHeader<U>,
{
fn decode<'a, I>(runtime: &ConjureRuntime, headers: I) -> Result<T, Error>
where
I: IntoIterator<Item = &'a HeaderValue>,
{
D::decode(runtime, headers).map(T::from)
}
}