use std::{future::ready, future::Future, future::Ready, marker::PhantomData};
use crate::{IntoService, IntoServiceFactory, Service, ServiceFactory};
#[inline]
pub fn fn_service<F, Fut, Req, Res, Err, Cfg>(
f: F,
) -> FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
where
F: Fn(Req) -> Fut + Clone,
Fut: Future<Output = Result<Res, Err>>,
{
FnServiceFactory::new(f)
}
#[inline]
pub fn fn_factory<F, Srv, Fut, Req, Err>(f: F) -> FnServiceNoConfig<F, Srv, Fut, Req, Err>
where
F: Fn() -> Fut,
Srv: Service<Req>,
Fut: Future<Output = Result<Srv, Err>>,
{
FnServiceNoConfig::new(f)
}
#[inline]
pub fn fn_factory_with_config<F, Fut, Cfg, Srv, Req, Err>(
f: F,
) -> FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
where
F: Fn(Cfg) -> Fut,
Fut: Future<Output = Result<Srv, Err>>,
Srv: Service<Req>,
{
FnServiceConfig { f, _t: PhantomData }
}
pub struct FnService<F, Req> {
f: F,
_t: PhantomData<Req>,
}
impl<F, Req> Clone for FnService<F, Req>
where
F: Clone,
{
fn clone(&self) -> Self {
Self {
f: self.f.clone(),
_t: PhantomData,
}
}
}
impl<F, Fut, Req, Res, Err> Service<Req> for FnService<F, Req>
where
F: Fn(Req) -> Fut,
Fut: Future<Output = Result<Res, Err>>,
{
type Response = Res;
type Error = Err;
type Future<'f> = Fut where Self: 'f, Req: 'f;
#[inline]
fn call(&self, req: Req) -> Self::Future<'_> {
(self.f)(req)
}
}
impl<F, Fut, Req, Res, Err> IntoService<FnService<F, Req>, Req> for F
where
F: Fn(Req) -> Fut,
Fut: Future<Output = Result<Res, Err>>,
{
#[inline]
fn into_service(self) -> FnService<F, Req> {
FnService {
f: self,
_t: PhantomData,
}
}
}
pub struct FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
where
F: Fn(Req) -> Fut,
Fut: Future<Output = Result<Res, Err>>,
{
f: F,
_t: PhantomData<(Req, Cfg)>,
}
impl<F, Fut, Req, Res, Err, Cfg> FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
where
F: Fn(Req) -> Fut + Clone,
Fut: Future<Output = Result<Res, Err>>,
{
fn new(f: F) -> Self {
FnServiceFactory { f, _t: PhantomData }
}
}
impl<F, Fut, Req, Res, Err, Cfg> Clone for FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
where
F: Fn(Req) -> Fut + Clone,
Fut: Future<Output = Result<Res, Err>>,
{
#[inline]
fn clone(&self) -> Self {
Self {
f: self.f.clone(),
_t: PhantomData,
}
}
}
impl<F, Fut, Req, Res, Err> Service<Req> for FnServiceFactory<F, Fut, Req, Res, Err, ()>
where
F: Fn(Req) -> Fut,
Fut: Future<Output = Result<Res, Err>>,
{
type Response = Res;
type Error = Err;
type Future<'f> = Fut where Self: 'f;
#[inline]
fn call(&self, req: Req) -> Self::Future<'_> {
(self.f)(req)
}
}
impl<F, Fut, Req, Res, Err, Cfg> ServiceFactory<Req, Cfg>
for FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
where
F: Fn(Req) -> Fut + Clone,
Fut: Future<Output = Result<Res, Err>>,
{
type Response = Res;
type Error = Err;
type Service = FnService<F, Req>;
type InitError = ();
type Future<'f> = Ready<Result<Self::Service, Self::InitError>> where Self: 'f;
#[inline]
fn create(&self, _: Cfg) -> Self::Future<'_> {
ready(Ok(FnService {
f: self.f.clone(),
_t: PhantomData,
}))
}
}
impl<F, Fut, Req, Res, Err, Cfg>
IntoServiceFactory<FnServiceFactory<F, Fut, Req, Res, Err, Cfg>, Req, Cfg> for F
where
F: Fn(Req) -> Fut + Clone,
Fut: Future<Output = Result<Res, Err>>,
{
#[inline]
fn into_factory(self) -> FnServiceFactory<F, Fut, Req, Res, Err, Cfg> {
FnServiceFactory::new(self)
}
}
pub struct FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
where
F: Fn(Cfg) -> Fut,
Fut: Future<Output = Result<Srv, Err>>,
Srv: Service<Req>,
{
f: F,
_t: PhantomData<(Fut, Cfg, Srv, Req, Err)>,
}
impl<F, Fut, Cfg, Srv, Req, Err> Clone for FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
where
F: Fn(Cfg) -> Fut + Clone,
Fut: Future<Output = Result<Srv, Err>>,
Srv: Service<Req>,
{
#[inline]
fn clone(&self) -> Self {
FnServiceConfig {
f: self.f.clone(),
_t: PhantomData,
}
}
}
impl<F, Fut, Cfg, Srv, Req, Err> ServiceFactory<Req, Cfg>
for FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
where
F: Fn(Cfg) -> Fut,
Fut: Future<Output = Result<Srv, Err>>,
Srv: Service<Req>,
{
type Response = Srv::Response;
type Error = Srv::Error;
type Service = Srv;
type InitError = Err;
type Future<'f> = Fut where Self: 'f, Fut: 'f;
#[inline]
fn create(&self, cfg: Cfg) -> Self::Future<'_> {
(self.f)(cfg)
}
}
pub struct FnServiceNoConfig<F, S, R, Req, E>
where
F: Fn() -> R,
S: Service<Req>,
R: Future<Output = Result<S, E>>,
{
f: F,
_t: PhantomData<Req>,
}
impl<F, S, R, Req, E> FnServiceNoConfig<F, S, R, Req, E>
where
F: Fn() -> R,
R: Future<Output = Result<S, E>>,
S: Service<Req>,
{
fn new(f: F) -> Self {
Self { f, _t: PhantomData }
}
}
impl<F, S, R, Req, E, C> ServiceFactory<Req, C> for FnServiceNoConfig<F, S, R, Req, E>
where
F: Fn() -> R,
R: Future<Output = Result<S, E>>,
S: Service<Req>,
C: 'static,
{
type Response = S::Response;
type Error = S::Error;
type Service = S;
type InitError = E;
type Future<'f> = R where Self: 'f, R: 'f;
#[inline]
fn create(&self, _: C) -> Self::Future<'_> {
(self.f)()
}
}
impl<F, S, R, Req, E> Clone for FnServiceNoConfig<F, S, R, Req, E>
where
F: Fn() -> R + Clone,
R: Future<Output = Result<S, E>>,
S: Service<Req>,
{
#[inline]
fn clone(&self) -> Self {
Self::new(self.f.clone())
}
}
impl<F, S, R, Req, E, C> IntoServiceFactory<FnServiceNoConfig<F, S, R, Req, E>, Req, C>
for F
where
F: Fn() -> R,
R: Future<Output = Result<S, E>>,
S: Service<Req>,
C: 'static,
{
#[inline]
fn into_factory(self) -> FnServiceNoConfig<F, S, R, Req, E> {
FnServiceNoConfig::new(self)
}
}
#[cfg(test)]
mod tests {
use ntex_util::future::lazy;
use std::task::Poll;
use super::*;
use crate::{Service, ServiceFactory};
#[ntex::test]
async fn test_fn_service() {
let new_srv = fn_service(|()| async { Ok::<_, ()>("srv") }).clone();
let srv = new_srv.create(()).await.unwrap();
let res = srv.call(()).await;
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
assert!(res.is_ok());
assert_eq!(res.unwrap(), "srv");
let srv2 = new_srv.clone();
let res = srv2.call(()).await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), "srv");
assert_eq!(lazy(|cx| srv2.poll_shutdown(cx)).await, Poll::Ready(()));
}
#[ntex::test]
async fn test_fn_service_service() {
let srv = fn_service(|()| async { Ok::<_, ()>("srv") })
.clone()
.create(&())
.await
.unwrap()
.clone();
let res = srv.call(()).await;
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
assert!(res.is_ok());
assert_eq!(res.unwrap(), "srv");
assert_eq!(lazy(|cx| srv.poll_shutdown(cx)).await, Poll::Ready(()));
}
#[ntex::test]
async fn test_fn_service_with_config() {
let new_srv = fn_factory_with_config(|cfg: &usize| {
let cfg = *cfg;
async move {
Ok::<_, ()>(fn_service(
move |()| async move { Ok::<_, ()>(("srv", cfg)) },
))
}
})
.clone();
let srv = new_srv.create(&1).await.unwrap();
let res = srv.call(()).await;
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
assert!(res.is_ok());
assert_eq!(res.unwrap(), ("srv", 1));
}
}