shaku/
component.rs

1//! This module contains trait definitions for components and interfaces
2
3use crate::module::ModuleInterface;
4use crate::Module;
5use crate::ModuleBuildContext;
6use std::any::Any;
7use std::sync::Arc;
8
9/// Components provide a service by implementing an interface. They may use
10/// other components as dependencies.
11///
12/// This trait is normally derived, but if the `derive` feature is turned off
13/// then it will need to be implemented manually.
14pub trait Component<M: Module>: Interface {
15    /// The trait/interface which this component implements
16    type Interface: Interface + ?Sized;
17
18    /// The parameters this component requires. If none are required, use `()`.
19    #[cfg(feature = "thread_safe")]
20    type Parameters: Default + Send;
21
22    /// The parameters this component requires. If none are required, use `()`.
23    #[cfg(not(feature = "thread_safe"))]
24    type Parameters: Default;
25
26    /// Use the build context and parameters to create the component. Other
27    /// components can be resolved by adding a [`HasComponent`] bound to the
28    /// `M` generic, then calling [`M::build_component`].
29    ///
30    /// [`HasComponent`]: trait.HasComponent.html
31    /// [`M::build_component`]: trait.HasComponent.html#tymethod.build_component
32    fn build(context: &mut ModuleBuildContext<M>, params: Self::Parameters)
33        -> Box<Self::Interface>;
34}
35
36#[cfg(not(feature = "thread_safe"))]
37trait_alias!(
38    /// Interfaces must be `'static` in order to be stored in a module
39    /// (hence the `Any` requirement).
40    ///
41    /// The `thread_safe` feature is turned off, so interfaces do not need to
42    /// implement `Send` or `Sync`.
43    pub Interface = Any
44);
45#[cfg(feature = "thread_safe")]
46trait_alias!(
47    /// Interfaces must be `'static` in order to be stored in a module
48    /// (hence the `Any` requirement).
49    ///
50    /// The `thread_safe` feature is turned on, which requires interfaces to
51    /// also implement `Send` and `Sync`.
52    pub Interface = Any + Send + Sync
53);
54
55/// The type signature of [`Component::build`] without the parameters. This is
56/// used when overriding a component via [`ModuleBuilder::with_component_override_fn`]
57///
58/// [`Component::build`]: trait.Component.html#tymethod.build
59/// [`ModuleBuilder::with_component_override_fn`]: struct.ModuleBuilder.html#method.with_component_override_fn
60#[cfg(not(feature = "thread_safe"))]
61pub type ComponentFn<M, I> = Box<dyn FnOnce(&mut ModuleBuildContext<M>) -> Box<I>>;
62/// The type signature of [`Component::build`] without the parameters. This is
63/// used when overriding a component via [`ModuleBuilder::with_component_override_fn`]
64///
65/// [`Component::build`]: trait.Component.html#tymethod.build
66/// [`ModuleBuilder::with_component_override_fn`]: struct.ModuleBuilder.html#method.with_component_override_fn
67#[cfg(feature = "thread_safe")]
68pub type ComponentFn<M, I> = Box<dyn (FnOnce(&mut ModuleBuildContext<M>) -> Box<I>) + Send + Sync>;
69
70/// Indicates that a module contains a component which implements the interface.
71pub trait HasComponent<I: Interface + ?Sized>: ModuleInterface {
72    /// Build the component during module build. Usually this involves calling
73    /// [`ModuleBuildContext::build_component`] with the implementation.
74    ///
75    /// [`ModuleBuildContext::build_component`]: struct.ModuleBuildContext.html#method.build_component
76    fn build_component(context: &mut ModuleBuildContext<Self>) -> Arc<I>
77    where
78        Self: Module + Sized;
79
80    /// Get a reference to the component. The ownership of the component is
81    /// shared via `Arc`.
82    ///
83    /// # Example
84    /// ```
85    /// # use shaku::{module, Component, Interface, HasComponent};
86    /// # use std::sync::Arc;
87    /// #
88    /// # trait Foo: Interface {}
89    /// #
90    /// # #[derive(Component)]
91    /// # #[shaku(interface = Foo)]
92    /// # struct FooImpl;
93    /// # impl Foo for FooImpl {}
94    /// #
95    /// # module! {
96    /// #     TestModule {
97    /// #         components = [FooImpl],
98    /// #         providers = []
99    /// #     }
100    /// # }
101    /// #
102    /// # fn main() {
103    /// # let module = TestModule::builder().build();
104    /// #
105    /// let foo: Arc<dyn Foo> = module.resolve();
106    /// # }
107    /// ```
108    fn resolve(&self) -> Arc<I>;
109
110    /// Get a reference to the component.
111    ///
112    /// # Example
113    /// ```
114    /// # use shaku::{module, Component, Interface, HasComponent};
115    /// # use std::sync::Arc;
116    /// #
117    /// # trait Foo: Interface {}
118    /// #
119    /// # #[derive(Component)]
120    /// # #[shaku(interface = Foo)]
121    /// # struct FooImpl;
122    /// # impl Foo for FooImpl {}
123    /// #
124    /// # module! {
125    /// #     TestModule {
126    /// #         components = [FooImpl],
127    /// #         providers = []
128    /// #     }
129    /// # }
130    /// #
131    /// # fn main() {
132    /// # let module = TestModule::builder().build();
133    /// #
134    /// let foo: &dyn Foo = module.resolve_ref();
135    /// # }
136    /// ```
137    fn resolve_ref(&self) -> &I;
138}