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
//! This module contains trait definitions for components and interfaces

use crate::module::ModuleInterface;
use crate::Module;
use crate::ModuleBuildContext;
use std::any::Any;
use std::sync::Arc;

/// Components provide a service by implementing an interface. They may use
/// other components as dependencies.
///
/// This trait is normally derived, but if the `derive` feature is turned off
/// then it will need to be implemented manually.
pub trait Component<M: Module>: Interface {
    /// The trait/interface which this component implements
    type Interface: Interface + ?Sized;

    /// The parameters this component requires. If none are required, use `()`.
    #[cfg(feature = "thread_safe")]
    type Parameters: Default + Send;

    /// The parameters this component requires. If none are required, use `()`.
    #[cfg(not(feature = "thread_safe"))]
    type Parameters: Default;

    /// Use the build context and parameters to create the component. Other
    /// components can be resolved by adding a [`HasComponent`] bound to the
    /// `M` generic, then calling [`M::build_component`].
    ///
    /// [`HasComponent`]: trait.HasComponent.html
    /// [`M::build_component`]: trait.HasComponent.html#tymethod.build_component
    fn build(context: &mut ModuleBuildContext<M>, params: Self::Parameters)
        -> Box<Self::Interface>;
}

#[cfg(not(feature = "thread_safe"))]
trait_alias!(
    /// Interfaces must be `'static` in order to be stored in a module
    /// (hence the `Any` requirement).
    ///
    /// The `thread_safe` feature is turned off, so interfaces do not need to
    /// implement `Send` or `Sync`.
    pub Interface = Any
);
#[cfg(feature = "thread_safe")]
trait_alias!(
    /// Interfaces must be `'static` in order to be stored in a module
    /// (hence the `Any` requirement).
    ///
    /// The `thread_safe` feature is turned on, which requires interfaces to
    /// also implement `Send` and `Sync`.
    pub Interface = Any + Send + Sync
);

/// The type signature of [`Component::build`] without the parameters. This is
/// used when overriding a component via [`ModuleBuilder::with_component_override_fn`]
///
/// [`Component::build`]: trait.Component.html#tymethod.build
/// [`ModuleBuilder::with_component_override_fn`]: struct.ModuleBuilder.html#method.with_component_override_fn
#[cfg(not(feature = "thread_safe"))]
pub type ComponentFn<M, I> = Box<dyn FnOnce(&mut ModuleBuildContext<M>) -> Box<I>>;
/// The type signature of [`Component::build`] without the parameters. This is
/// used when overriding a component via [`ModuleBuilder::with_component_override_fn`]
///
/// [`Component::build`]: trait.Component.html#tymethod.build
/// [`ModuleBuilder::with_component_override_fn`]: struct.ModuleBuilder.html#method.with_component_override_fn
#[cfg(feature = "thread_safe")]
pub type ComponentFn<M, I> = Box<dyn (FnOnce(&mut ModuleBuildContext<M>) -> Box<I>) + Send + Sync>;

/// Indicates that a module contains a component which implements the interface.
pub trait HasComponent<I: Interface + ?Sized>: ModuleInterface {
    /// Build the component during module build. Usually this involves calling
    /// [`ModuleBuildContext::build_component`] with the implementation.
    ///
    /// [`ModuleBuildContext::build_component`]: struct.ModuleBuildContext.html#method.build_component
    fn build_component(context: &mut ModuleBuildContext<Self>) -> Arc<I>
    where
        Self: Module + Sized;

    /// Get a reference to the component. The ownership of the component is
    /// shared via `Arc`.
    ///
    /// # Example
    /// ```
    /// # use shaku::{module, Component, Interface, HasComponent};
    /// # use std::sync::Arc;
    /// #
    /// # trait Foo: Interface {}
    /// #
    /// # #[derive(Component)]
    /// # #[shaku(interface = Foo)]
    /// # struct FooImpl;
    /// # impl Foo for FooImpl {}
    /// #
    /// # module! {
    /// #     TestModule {
    /// #         components = [FooImpl],
    /// #         providers = []
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// # let module = TestModule::builder().build();
    /// #
    /// let foo: Arc<dyn Foo> = module.resolve();
    /// # }
    /// ```
    fn resolve(&self) -> Arc<I>;

    /// Get a reference to the component.
    ///
    /// # Example
    /// ```
    /// # use shaku::{module, Component, Interface, HasComponent};
    /// # use std::sync::Arc;
    /// #
    /// # trait Foo: Interface {}
    /// #
    /// # #[derive(Component)]
    /// # #[shaku(interface = Foo)]
    /// # struct FooImpl;
    /// # impl Foo for FooImpl {}
    /// #
    /// # module! {
    /// #     TestModule {
    /// #         components = [FooImpl],
    /// #         providers = []
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// # let module = TestModule::builder().build();
    /// #
    /// let foo: &dyn Foo = module.resolve_ref();
    /// # }
    /// ```
    fn resolve_ref(&self) -> &I;
}