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
//! # Getting started with submodules //! This guide assumes you have already read the general [getting started guide]. //! //! [`Module`]s can contain other modules, called submodules. For example, a //! top-level `RootModule` may use an `AuthModule` to provide authentication //! services. The submodule's implementation may be known, or the submodule may //! be hidden behind a trait (aka module interface). //! //! ## Why use submodules? //! Unlike components or providers, the implementation of a submodule does not need to be known to //! the module. You can easily swap out, say, an OAuth authenticaion implementation for a fake //! during development. This is more powerful than overriding components/providers because with //! overriding you cannot remove services from the dependency graph. For example, the OAuth //! `AuthManager` implementation may use an `OAuthKeyStore` internally. When you swap the module out //! for a fake, the `OAuthKeyStore` is no longer part of the dependency graph. If the `AuthManager` //! was instead overridden, the keystore would still be created or would need to be overridden as //! well, despite being internal or private to the OAuth `AuthManager`. //! //! ## The example //! ```rust //! use shaku::{module, Component, HasComponent, Interface}; //! use std::sync::Arc; //! //! trait MyComponent: Interface {} //! trait AuthManager: Interface {} //! trait AuthModule: HasComponent<dyn AuthManager> {} //! //! #[derive(Component)] //! #[shaku(interface = MyComponent)] //! struct MyComponentImpl { //! #[shaku(inject)] //! auth_manager: Arc<dyn AuthManager> //! } //! impl MyComponent for MyComponentImpl {} //! //! module! { //! RootModule { //! components = [MyComponentImpl], //! providers = [], //! //! use AuthModule { //! components = [AuthManager], //! providers = [] //! } //! } //! } //! # fn main() {} //! ``` //! //! In this example, `RootModule` knows the implementation of its `MyComponent` component, but it //! does not know the implementation of `AuthManager` or the `AuthModule` that it gets it from. The //! `AuthModule` implementation is passed in when `RootModule` is built. //! //! ## Providing submodule implementations //! To build a module, you need to give it a reference to each submodule implementation. The //! [`module`][module macro] macro will generate a `builder` function which takes in the submodules //! and outputs a [`ModuleBuilder`] //! //! ```rust //! # use shaku::{module, Component, HasComponent, Interface}; //! # use std::sync::Arc; //! # //! # trait MyComponent: Interface {} //! # trait AuthManager: Interface {} //! # trait AuthModule: HasComponent<dyn AuthManager> {} //! # //! # #[derive(Component)] //! # #[shaku(interface = MyComponent)] //! # struct MyComponentImpl { #[shaku(inject)] auth_manager: Arc<dyn AuthManager> } //! # impl MyComponent for MyComponentImpl {} //! # //! # module! { //! # RootModule { //! # components = [MyComponentImpl], providers = [], //! # use AuthModule { components = [AuthManager], providers = [] } //! # } //! # } //! # //! #[derive(Component)] //! #[shaku(interface = AuthManager)] //! struct AuthManagerImpl; //! impl AuthManager for AuthManagerImpl {} //! //! module! { //! AuthModuleImpl: AuthModule { //! components = [AuthManagerImpl], //! providers = [] //! } //! } //! //! # fn main() { //! let auth_module = Arc::new(AuthModuleImpl::builder().build()); //! let root_module = RootModule::builder(auth_module).build(); //! //! let my_component: &dyn MyComponent = root_module.resolve_ref(); //! # } //! ``` //! //! `AuthModuleImpl` has no submodules, thus its `builder` function has no arguments. //! `RootModule` has one submodule, thus its `builder` function takes in an //! `Arc<dyn AuthModule>`. //! //! Note: `AuthModuleImpl` uses a feature of the [`module`][module macro] macro to automatically //! implement `AuthModule`. It does this by adding `: AuthModule` after the name of the module. //! This is shorthand for the statement `impl AuthModule for AuthModuleImpl {}`. //! //! [getting started guide]: ../index.html //! [`Module`]: ../../trait.Module.html //! [module macro]: ../../macro.module.html //! [`ModuleBuilder`]: ../../struct.ModuleBuilder.html