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
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
use std::marker::PhantomData;

use crate::{
    DynSvc, InjectError, InjectResult, Injector, Interface, InterfaceFor,
    OwnedDynSvc, RequestInfo, Service, ServiceInfo, Svc,
};

/// Weakly typed service provider.
///
/// Given an injector, this can provide an instance of a service. This is
/// automatically implemented for all types that implement [`TypedProvider`],
/// and [`TypedProvider`] should be preferred if possible for custom service
/// providers to allow for stronger type checking.
pub trait Provider: Service {
    /// The [`ServiceInfo`] which describes the type returned by this provider.
    fn result(&self) -> ServiceInfo;

    /// Provides an instance of the service.
    fn provide(
        &mut self,
        injector: &Injector,
        request_info: &RequestInfo,
    ) -> InjectResult<DynSvc>;

    /// Provides an owned instance of the service.
    fn provide_owned(
        &mut self,
        _injector: &Injector,
        _request_info: &RequestInfo,
    ) -> InjectResult<OwnedDynSvc> {
        Err(InjectError::OwnedNotSupported {
            service_info: self.result(),
        })
    }
}

impl<T> Provider for T
where
    T: TypedProvider,
{
    fn result(&self) -> ServiceInfo {
        ServiceInfo::of::<T::Result>()
    }

    fn provide(
        &mut self,
        injector: &Injector,
        request_info: &RequestInfo,
    ) -> InjectResult<DynSvc> {
        let result = self.provide_typed(injector, request_info)?;
        Ok(result as DynSvc)
    }

    fn provide_owned(
        &mut self,
        injector: &Injector,
        request_info: &RequestInfo,
    ) -> InjectResult<OwnedDynSvc> {
        let result = self.provide_owned_typed(injector, request_info)?;
        Ok(result as OwnedDynSvc)
    }
}

/// A strongly-typed service provider.
///
/// Types which implement this trait can provide strongly-typed instances of a
/// particular service type. Examples of typed providers include providers
/// created from service factories or constant providers. This should be
/// preferred over [`Provider`] for custom service providers if possible due to
/// the strong type guarantees this provides. [`Provider`] is automatically
/// implemented for all types which implement [`TypedProvider`].
///
/// ## Example
///
/// ```
/// use runtime_injector::{
///     InjectResult, Injector, RequestInfo, Svc, TypedProvider,
/// };
///
/// struct Foo;
///
/// struct FooProvider;
/// impl TypedProvider for FooProvider {
///     type Result = Foo;
///
///     fn provide_typed(
///         &mut self,
///         _injector: &Injector,
///         _request_info: &RequestInfo,
///     ) -> InjectResult<Svc<Self::Result>> {
///         Ok(Svc::new(Foo))
///     }
/// }
///
/// let mut builder = Injector::builder();
/// builder.provide(FooProvider);
///
/// let injector = builder.build();
/// let _foo: Svc<Foo> = injector.get().unwrap();
/// ```
pub trait TypedProvider: Sized + Provider {
    /// The type of service this can provide.
    type Result: Interface;

    /// Provides an instance of the service. The [`Injector`] passed in can be
    /// used to retrieve instances of any dependencies this service has.
    fn provide_typed(
        &mut self,
        injector: &Injector,
        request_info: &RequestInfo,
    ) -> InjectResult<Svc<Self::Result>>;

    /// Provides an owned instance of the service. Not all providers can
    /// provide an owned variant of the service.
    fn provide_owned_typed(
        &mut self,
        _injector: &Injector,
        _request_info: &RequestInfo,
    ) -> InjectResult<Box<Self::Result>> {
        Err(InjectError::OwnedNotSupported {
            service_info: ServiceInfo::of::<Self::Result>(),
        })
    }

    /// Provides this service as an implementation of a particular interface.
    /// Rather than requesting this service with its concrete type, it can
    /// instead be requested by its interface type.
    ///
    /// *Note: it cannot be requested with its concrete type once it has been
    /// assigned an interface.*
    ///
    /// ## Example
    ///
    /// ```
    /// use runtime_injector::{
    ///     interface, InjectResult, Injector, IntoSingleton, Service, Svc,
    ///     TypedProvider,
    /// };
    ///
    /// trait Fooable: Service {
    ///     fn bar(&self) {}
    /// }
    ///
    /// interface!(dyn Fooable = [Foo]);
    ///
    /// #[derive(Default)]
    /// struct Foo;
    /// impl Fooable for Foo {}
    ///
    /// let mut builder = Injector::builder();
    /// builder.provide(Foo::default.singleton().with_interface::<dyn Fooable>());
    ///
    /// // Foo can now be requested through its interface of `dyn Fooable`.
    /// let injector = builder.build();
    /// let fooable: Svc<dyn Fooable> = injector.get().unwrap();
    /// fooable.bar();
    ///
    /// // It can't be requested through its original type
    /// assert!(injector.get::<Svc<Foo>>().is_err());
    /// ```
    fn with_interface<I: ?Sized + InterfaceFor<Self::Result>>(
        self,
    ) -> InterfaceProvider<I, Self> {
        InterfaceProvider {
            inner: self,
            marker: PhantomData,
        }
    }
}

/// Provides a service as an implementation of an interface. See
/// [`TypedProvider::with_interface()`] for more information.
pub struct InterfaceProvider<I, P>
where
    P: TypedProvider,
    I: ?Sized + InterfaceFor<P::Result>,
{
    inner: P,
    marker: PhantomData<fn() -> I>,
}

impl<I, P> Provider for InterfaceProvider<I, P>
where
    P: TypedProvider,
    I: ?Sized + InterfaceFor<P::Result>,
{
    fn result(&self) -> ServiceInfo {
        ServiceInfo::of::<I>()
    }

    fn provide(
        &mut self,
        injector: &Injector,
        request_info: &RequestInfo,
    ) -> InjectResult<DynSvc> {
        self.inner.provide(injector, request_info)
    }

    fn provide_owned(
        &mut self,
        injector: &Injector,
        request_info: &RequestInfo,
    ) -> InjectResult<OwnedDynSvc> {
        self.inner.provide_owned(injector, request_info)
    }
}