use std::sync::Arc;
use async_trait::async_trait;
use http::header::HeaderName;
use crate::error::Result;
use crate::runtime::MaybeSendSync;
#[cfg(feature = "transport-reqwest")]
mod reqwest;
#[cfg(feature = "transport-reqwest")]
pub use reqwest::ReqwestTransport;
#[cfg(feature = "transport-reqwest-middleware")]
pub use reqwest::ReqwestMiddlewareTransport;
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
pub trait Transport: Clone + MaybeSendSync + 'static {
async fn send(&self, request: TransportRequest) -> Result<TransportResponse>;
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl<T> Transport for Arc<T>
where
T: Transport,
{
async fn send(&self, request: TransportRequest) -> Result<TransportResponse> {
(**self).send(request).await
}
}
#[derive(Clone)]
pub struct BoxTransport {
inner: Arc<dyn ErasedTransport>,
}
impl BoxTransport {
#[must_use]
pub fn new<T>(transport: T) -> Self
where
T: Transport,
{
Self {
inner: Arc::new(transport),
}
}
}
impl std::fmt::Debug for BoxTransport {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BoxTransport").finish_non_exhaustive()
}
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl Transport for BoxTransport {
async fn send(&self, request: TransportRequest) -> Result<TransportResponse> {
self.inner.send_erased(request).await
}
}
pub type TransportRequest = http::Request<TransportBody>;
pub type TransportResponse = http::Response<Vec<u8>>;
#[derive(Clone)]
#[non_exhaustive]
pub enum TransportBody {
Empty,
Bytes(Vec<u8>),
#[non_exhaustive]
BytesWithTrailer {
body: Vec<u8>,
trailer_name: HeaderName,
trailer_value: String,
},
}
impl std::fmt::Debug for TransportBody {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TransportBody::Empty => f.write_str("Empty"),
TransportBody::Bytes(body) => {
f.debug_struct("Bytes").field("len", &body.len()).finish()
}
TransportBody::BytesWithTrailer {
body,
trailer_name,
trailer_value,
} => f
.debug_struct("BytesWithTrailer")
.field("len", &body.len())
.field("trailer_name", trailer_name)
.field("trailer_value", trailer_value)
.finish(),
}
}
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
trait ErasedTransport: MaybeSendSync {
async fn send_erased(&self, request: TransportRequest) -> Result<TransportResponse>;
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl<T> ErasedTransport for T
where
T: Transport,
{
async fn send_erased(&self, request: TransportRequest) -> Result<TransportResponse> {
Transport::send(self, request).await
}
}