1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use std::{rc::Rc, sync::Arc};

use crate::{Context, Provider, Service};

/// Allow `Fn` functions to act as providers.
impl<'cx, F, S> Provider<'cx, S> for F
where
    F: Fn(&'cx Context) -> S::Output<'cx> + 'cx,
    S: Service,
{
    fn provide(&'cx self, cx: &'cx Context) -> S::Output<'cx> {
        (self)(cx)
    }
}

impl<'cx, S, P> Provider<'cx, Option<S>> for Option<P>
where
    S: Service,
    P: Provider<'cx, S>,
{
    fn provide(&'cx self, cx: &'cx Context) -> Option<S::Output<'cx>> {
        self.as_ref().map(|p| p.provide(cx))
    }
}

// Generic common types

impl<const N: usize, S: Service> Service for [S; N] {
    type Output<'cx> = [S::Output<'cx>; N];
}

macro_rules! service_impl_generic {
    ($($ty:ty => $out:ty,)*) => {
        $( impl <S: Service> Service for $ty { type Output<'cx> = $out; } )*
    };
}

service_impl_generic! {
    &'static S => &'cx S::Output<'cx>,
    &'static mut S => &'cx mut S::Output<'cx>,
    Option<S> => Option<S::Output<'cx>>,
    Box<S> => Box<S::Output<'cx>>,
    Rc<S> => Rc<S::Output<'cx>>,
    Arc<S> => Arc<S::Output<'cx>>,
}

macro_rules! service_impl_tuples {
    ($( ( $($param:ident),* ), )*) => {
        $(
            impl<$($param),*> Service for ($($param,)*)
            where
                $($param: Service,)*
            {
                type Output<'cx> = ($($param::Output<'cx>,)*);
            }
        )*
    };
}

service_impl_tuples! {
    (S1),
    (S1, S2),
    (S1, S2, S3),
    (S1, S2, S3, S4),
    (S1, S2, S3, S4, S5),
    (S1, S2, S3, S4, S5, S6),
    (S1, S2, S3, S4, S5, S6, S7),
    (S1, S2, S3, S4, S5, S6, S7, S8),
    (S1, S2, S3, S4, S5, S6, S7, S8, S9),
}