use std::{future::Future, marker::PhantomData, pin::Pin, task::Context, task::Poll};
use super::{IntoServiceFactory, ServiceFactory};
pub fn map_config<T, R, U, F, C, C2>(factory: U, f: F) -> MapConfig<T, F, C, C2>
where
T: ServiceFactory<R, C2>,
U: IntoServiceFactory<T, R, C2>,
F: Fn(C) -> C2,
{
MapConfig::new(factory.into_factory(), f)
}
pub fn unit_config<T, R, U>(factory: U) -> UnitConfig<T>
where
T: ServiceFactory<R>,
U: IntoServiceFactory<T, R>,
{
UnitConfig::new(factory.into_factory())
}
pub struct MapConfig<A, F, C, C2> {
a: A,
f: F,
e: PhantomData<(C, C2)>,
}
impl<A, F, C, C2> MapConfig<A, F, C, C2> {
pub(crate) fn new(a: A, f: F) -> Self {
Self {
a,
f,
e: PhantomData,
}
}
}
impl<A, F, C, C2> Clone for MapConfig<A, F, C, C2>
where
A: Clone,
F: Clone,
{
fn clone(&self) -> Self {
Self {
a: self.a.clone(),
f: self.f.clone(),
e: PhantomData,
}
}
}
impl<A, F, R, C, C2> ServiceFactory<R, C> for MapConfig<A, F, C, C2>
where
A: ServiceFactory<R, C2>,
F: Fn(C) -> C2,
{
type Response = A::Response;
type Error = A::Error;
type Service = A::Service;
type InitError = A::InitError;
type Future<'f> = A::Future<'f> where Self: 'f;
fn create(&self, cfg: C) -> Self::Future<'_> {
let cfg = (self.f)(cfg);
self.a.create(cfg)
}
}
pub struct UnitConfig<A> {
a: A,
}
impl<A> UnitConfig<A> {
pub(crate) fn new(a: A) -> Self {
Self { a }
}
}
impl<A> Clone for UnitConfig<A>
where
A: Clone,
{
fn clone(&self) -> Self {
Self { a: self.a.clone() }
}
}
impl<A, R, C> ServiceFactory<R, C> for UnitConfig<A>
where
A: ServiceFactory<R>,
{
type Response = A::Response;
type Error = A::Error;
type Service = A::Service;
type InitError = A::InitError;
type Future<'f> = UnitConfigFuture<'f, A, R, C> where Self: 'f, C: 'f;
fn create(&self, _: C) -> Self::Future<'_> {
UnitConfigFuture {
fut: self.a.create(()),
_t: PhantomData,
}
}
}
pin_project_lite::pin_project! {
pub struct UnitConfigFuture<'f, A, R, C>
where A: ServiceFactory<R>,
A: 'f,
C: 'f,
{
#[pin]
fut: A::Future<'f>,
_t: PhantomData<C>,
}
}
impl<'f, A, R, C> Future for UnitConfigFuture<'f, A, R, C>
where
A: ServiceFactory<R>,
{
type Output = Result<A::Service, A::InitError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.project().fut.poll(cx)
}
}
#[cfg(test)]
#[allow(clippy::redundant_closure)]
mod tests {
use ntex_util::future::Ready;
use std::{cell::Cell, rc::Rc};
use super::*;
use crate::{fn_service, ServiceFactory};
#[ntex::test]
async fn test_map_config() {
let item = Rc::new(Cell::new(1usize));
let factory = map_config(
fn_service(|item: usize| Ready::<_, ()>::Ok(item)),
|t: &usize| {
item.set(item.get() + *t);
},
)
.clone();
let _ = factory.create(&10).await;
assert_eq!(item.get(), 11);
}
#[ntex::test]
async fn test_unit_config() {
let _ = unit_config(fn_service(|item: usize| Ready::<_, ()>::Ok(item)))
.clone()
.create(&10)
.await;
}
}