use std::{
borrow::Cow,
fmt::{self, Debug, Formatter},
marker::PhantomData,
};
use prost::Message as PbMsg;
use crate::{
body::Body, common::extensions::Extensions, decode::*, encode::encode_protobuf_message,
};
#[non_exhaustive]
#[derive(Debug)]
pub struct Parts {
pub body: Body,
pub extensions: Extensions,
pub endpoint: Cow<'static, str>,
}
impl<T> From<Request<T>> for Parts {
fn from(req: Request<T>) -> Self {
req.parts
}
}
impl<T> From<Parts> for Request<T> {
fn from(parts: Parts) -> Self {
Self {
parts,
message: PhantomData,
}
}
}
pub struct Request<T> {
parts: Parts,
message: PhantomData<T>,
}
impl<T> Debug for Request<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Request")
.field("body", &self.parts.body)
.field("extensions", &self.parts.extensions)
.field("endpoint", &self.parts.endpoint)
.finish()
}
}
impl Request<()> {
pub fn empty() -> Request<()> {
Self::new_with_body(Body::empty())
}
}
impl<T> Request<T> {
pub fn new_with_body(body: Body) -> Self {
Self {
parts: Parts {
body,
extensions: Extensions::new(),
endpoint: Cow::Borrowed(""),
},
message: PhantomData,
}
}
#[inline]
pub fn extensions_mut(&mut self) -> &mut Extensions {
&mut self.parts.extensions
}
#[inline]
pub fn extensions(&self) -> &Extensions {
&self.parts.extensions
}
#[inline]
pub fn endpoint_mut(&mut self) -> &mut Cow<'static, str> {
&mut self.parts.endpoint
}
#[inline]
pub fn endpoint(&self) -> &str {
self.parts.endpoint.as_ref()
}
#[allow(dead_code)]
pub(crate) fn map<M>(self) -> Request<M> {
Request {
parts: self.parts,
message: PhantomData,
}
}
}
impl<T: PbMsg> Request<T> {
pub fn new(msg: &T) -> Self {
let encoded = encode_protobuf_message(msg).freeze();
Self::new_with_body(Body::full(encoded))
}
}
impl<T: PbMsg + Default> Request<T> {
#[inline]
pub async fn into_message(self) -> Result<T, DecodeBodyError> {
decode_body(self.parts.body).await
}
}
pub trait IntoRequest<T> {
fn into_request(self) -> Request<T>;
}
impl<T: PbMsg> IntoRequest<T> for T {
fn into_request(self) -> Request<Self> {
Request::new(&self)
}
}
impl<T> IntoRequest<T> for Request<T> {
fn into_request(self) -> Request<T> {
self
}
}
pub type BoxRequest = Request<()>;