use super::Layer;
use std::fmt;
pub fn layer_fn<T>(f: T) -> LayerFn<T> {
LayerFn { f }
}
pub struct LayerFn<F> {
f: F,
}
impl<F, S, Out> Layer<S> for LayerFn<F>
where
F: FnOnce(S) -> Out + Clone,
{
type Service = Out;
fn layer(&self, inner: S) -> Self::Service {
(self.f.clone())(inner)
}
fn into_layer(self, inner: S) -> Self::Service {
(self.f)(inner)
}
}
impl<F> Clone for LayerFn<F>
where
F: Clone,
{
fn clone(&self) -> Self {
Self { f: self.f.clone() }
}
}
impl<F> fmt::Debug for LayerFn<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LayerFn")
.field("f", &format_args!("<{}>", std::any::type_name::<F>()))
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_layer_fn() {
use crate::{Context, Service, service::service_fn};
use std::convert::Infallible;
struct ToUpper<S>(S);
impl<S> fmt::Debug for ToUpper<S>
where
S: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("ToUpper").field(&self.0).finish()
}
}
impl<S> Clone for ToUpper<S>
where
S: Clone,
{
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<S, State, Request> Service<State, Request> for ToUpper<S>
where
Request: Send + 'static,
S: Service<State, Request, Response = &'static str>,
State: Clone + Send + Sync + 'static,
{
type Response = String;
type Error = S::Error;
async fn serve(
&self,
ctx: Context<State>,
req: Request,
) -> Result<Self::Response, Self::Error> {
let res = self.0.serve(ctx, req).await;
res.map(|msg| msg.to_uppercase())
}
}
let layer = layer_fn(ToUpper);
let f = async |_, req| Ok::<_, Infallible>(req);
let res = layer
.layer(service_fn(f))
.serve(Context::default(), "hello")
.await;
assert_eq!(res, Ok("HELLO".to_owned()));
let svc = layer.layer(service_fn(f));
let res = svc.serve(Context::default(), "hello").await;
assert_eq!(res, Ok("HELLO".to_owned()));
let res = svc.clone().serve(Context::default(), "hello").await;
assert_eq!(res, Ok("HELLO".to_owned()));
}
#[allow(dead_code)]
#[test]
fn layer_fn_has_useful_debug_impl() {
struct WrappedService<S> {
inner: S,
}
let layer = layer_fn(|svc| WrappedService { inner: svc });
let _svc = layer.layer("foo");
assert_eq!(
"LayerFn { f: <rama_core::layer::layer_fn::tests::layer_fn_has_useful_debug_impl::{{closure}}> }".to_owned(),
format!("{:?}", layer),
);
}
}