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}