ntex_service/
map_config.rs

1use std::{fmt, marker::PhantomData};
2
3use super::{IntoServiceFactory, ServiceFactory};
4
5/// Adapt external config argument to a config for provided service factory
6///
7/// Note that this function consumes the receiving service factory and returns
8/// a wrapped version of it.
9pub fn map_config<T, R, U, F, C, C2>(factory: U, f: F) -> MapConfig<T, F, C, C2>
10where
11    T: ServiceFactory<R, C2>,
12    U: IntoServiceFactory<T, R, C2>,
13    F: Fn(C) -> C2,
14{
15    MapConfig::new(factory.into_factory(), f)
16}
17
18/// Replace config with unit
19pub fn unit_config<T, R, U>(factory: U) -> UnitConfig<T>
20where
21    T: ServiceFactory<R>,
22    U: IntoServiceFactory<T, R>,
23{
24    UnitConfig::new(factory.into_factory())
25}
26
27/// `map_config()` adapter service factory
28pub struct MapConfig<A, F, C, C2> {
29    a: A,
30    f: F,
31    e: PhantomData<(C, C2)>,
32}
33
34impl<A, F, C, C2> MapConfig<A, F, C, C2> {
35    /// Create new `MapConfig` combinator
36    pub(crate) fn new(a: A, f: F) -> Self {
37        Self {
38            a,
39            f,
40            e: PhantomData,
41        }
42    }
43}
44
45impl<A, F, C, C2> Clone for MapConfig<A, F, C, C2>
46where
47    A: Clone,
48    F: Clone,
49{
50    fn clone(&self) -> Self {
51        Self {
52            a: self.a.clone(),
53            f: self.f.clone(),
54            e: PhantomData,
55        }
56    }
57}
58
59impl<A, F, C, C2> fmt::Debug for MapConfig<A, F, C, C2>
60where
61    A: fmt::Debug,
62{
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        f.debug_struct("MapConfig")
65            .field("factory", &self.a)
66            .field("map", &std::any::type_name::<F>())
67            .finish()
68    }
69}
70
71impl<A, F, R, C, C2> ServiceFactory<R, C> for MapConfig<A, F, C, C2>
72where
73    A: ServiceFactory<R, C2>,
74    F: Fn(C) -> C2,
75{
76    type Response = A::Response;
77    type Error = A::Error;
78
79    type Service = A::Service;
80    type InitError = A::InitError;
81
82    async fn create(&self, cfg: C) -> Result<Self::Service, Self::InitError> {
83        self.a.create((self.f)(cfg)).await
84    }
85}
86
87#[derive(Clone, Debug)]
88/// `unit_config()` config combinator
89pub struct UnitConfig<A> {
90    factory: A,
91}
92
93impl<A> UnitConfig<A> {
94    /// Create new `UnitConfig` combinator
95    pub(crate) fn new(factory: A) -> Self {
96        Self { factory }
97    }
98}
99
100impl<A, R, C> ServiceFactory<R, C> for UnitConfig<A>
101where
102    A: ServiceFactory<R>,
103{
104    type Response = A::Response;
105    type Error = A::Error;
106
107    type Service = A::Service;
108    type InitError = A::InitError;
109
110    async fn create(&self, _: C) -> Result<Self::Service, Self::InitError> {
111        self.factory.create(()).await
112    }
113}
114
115#[cfg(test)]
116#[allow(clippy::redundant_closure)]
117mod tests {
118    use std::{cell::Cell, rc::Rc};
119
120    use super::*;
121    use crate::fn_service;
122
123    #[ntex::test]
124    async fn test_map_config() {
125        let item = Rc::new(Cell::new(1usize));
126
127        let factory = map_config(
128            fn_service(|item: usize| async move { Ok::<_, ()>(item) }),
129            |t: &usize| {
130                item.set(item.get() + *t);
131            },
132        )
133        .clone();
134
135        let _ = factory.create(&10).await;
136        assert_eq!(item.get(), 11);
137        let _ = format!("{:?}", factory);
138    }
139
140    #[ntex::test]
141    async fn test_unit_config() {
142        let _ = unit_config(fn_service(|item: usize| async move { Ok::<_, ()>(item) }))
143            .clone()
144            .create(&10)
145            .await;
146    }
147}