use crate::std::sync::Arc;
use crate::{
Layer, Service,
extensions::{Extension, ExtensionsRef},
};
use rama_utils::macros::define_inner_service_accessors;
#[derive(Debug)]
pub struct AddInputExtensionLayer<T> {
value: Arc<T>,
}
impl<T> Clone for AddInputExtensionLayer<T> {
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
}
}
}
impl<T> AddInputExtensionLayer<T> {
pub fn new(value: T) -> Self {
Self {
value: Arc::new(value),
}
}
pub fn new_arc(value: Arc<T>) -> Self {
Self { value }
}
}
impl<S, T> Layer<S> for AddInputExtensionLayer<T> {
type Service = AddInputExtension<S, T>;
fn layer(&self, inner: S) -> Self::Service {
AddInputExtension {
inner,
value: self.value.clone(),
}
}
fn into_layer(self, inner: S) -> Self::Service {
AddInputExtension {
inner,
value: self.value,
}
}
}
#[derive(Debug)]
pub struct AddInputExtension<S, T> {
inner: S,
value: Arc<T>,
}
impl<S: Clone, T> Clone for AddInputExtension<S, T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
value: self.value.clone(),
}
}
}
impl<S, T> AddInputExtension<S, T> {
pub fn new(inner: S, value: T) -> Self {
Self {
inner,
value: Arc::new(value),
}
}
pub const fn new_arc(inner: S, value: Arc<T>) -> Self {
Self { inner, value }
}
define_inner_service_accessors!();
}
impl<Input, S, T> Service<Input> for AddInputExtension<S, T>
where
Input: Send + ExtensionsRef + 'static,
S: Service<Input>,
T: Extension,
{
type Output = S::Output;
type Error = S::Error;
async fn serve(&self, input: Input) -> Result<Self::Output, Self::Error> {
input.extensions().insert_arc(self.value.clone());
self.inner.serve(input).await
}
}
#[derive(Debug)]
pub struct AddOutputExtensionLayer<T> {
value: Arc<T>,
}
impl<T> Clone for AddOutputExtensionLayer<T> {
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
}
}
}
impl<T> AddOutputExtensionLayer<T> {
pub fn new(value: T) -> Self {
Self {
value: Arc::new(value),
}
}
pub const fn new_arc(value: Arc<T>) -> Self {
Self { value }
}
}
impl<S, T> Layer<S> for AddOutputExtensionLayer<T> {
type Service = AddOutputExtension<S, T>;
fn layer(&self, inner: S) -> Self::Service {
AddOutputExtension {
inner,
value: self.value.clone(),
}
}
fn into_layer(self, inner: S) -> Self::Service {
AddOutputExtension {
inner,
value: self.value,
}
}
}
#[derive(Debug)]
pub struct AddOutputExtension<S, T> {
inner: S,
value: Arc<T>,
}
impl<S: Clone, T> Clone for AddOutputExtension<S, T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
value: self.value.clone(),
}
}
}
impl<S, T> AddOutputExtension<S, T> {
pub fn new(inner: S, value: T) -> Self {
Self {
inner,
value: Arc::new(value),
}
}
pub const fn new_arc(inner: S, value: Arc<T>) -> Self {
Self { inner, value }
}
define_inner_service_accessors!();
}
impl<Input, S, T> Service<Input> for AddOutputExtension<S, T>
where
Input: Send + 'static,
S: Service<Input, Output: Send + ExtensionsRef + 'static>,
T: Extension,
{
type Output = S::Output;
type Error = S::Error;
async fn serve(&self, input: Input) -> Result<Self::Output, Self::Error> {
let res = self.inner.serve(input).await?;
res.extensions().insert_arc(self.value.clone());
Ok(res)
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
use crate::{ServiceInput, extensions::ExtensionsRef, service::service_fn};
use core::convert::Infallible;
#[derive(Debug, Clone, Copy, Extension)]
struct Counter(i32);
#[tokio::test]
async fn basic_input() {
let svc = AddInputExtensionLayer::new(Counter(42)).into_layer(service_fn(
async |req: ServiceInput<()>| {
let Counter(n) = req.extensions().get_ref().copied().unwrap();
assert_eq!(42, n);
Ok::<_, Infallible>(ServiceInput::new(()))
},
));
let res = svc.serve(ServiceInput::new(())).await.unwrap();
assert!(res.extensions.get_ref::<Counter>().is_none());
}
#[tokio::test]
async fn basic_output() {
let svc = AddOutputExtensionLayer::new(Counter(42)).into_layer(service_fn(
async |req: ServiceInput<()>| {
assert!(req.extensions.get_ref::<Counter>().is_none());
Ok::<_, Infallible>(ServiceInput::new(()))
},
));
let res = svc.serve(ServiceInput::new(())).await.unwrap();
let Counter(n) = res.extensions().get_ref().copied().unwrap();
assert_eq!(42, n);
}
}