Repository navigation
Expand file tree
/
Copy pathmodule.rs
More file actions
111 lines (101 loc) · 2.78 KB
/
Copy pathmodule.rs
File metadata and controls
111 lines (101 loc) · 2.78 KB
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
use crate::error::Result;
use crate::app::BuildState;
use crate::option::ModOption;
use crate::wiring::{impl_group_wiring_methods, impl_private_wiring_methods, impl_wiring_methods};
use std::fmt;
/// A named domain module.
///
/// ```
/// # use modrun::{Modrun, Module};
/// #[derive(Clone)]
/// struct Config;
/// #[derive(Clone)]
/// struct Repo;
/// #[derive(Clone)]
/// struct Greeter;
///
/// fn new_repo(_cfg: Config) -> Repo { Repo }
/// fn new_greeter(_repo: Repo) -> Greeter { Greeter }
/// fn register(_greeter: Greeter) {}
///
/// fn greeter_domain() -> Module {
/// Module::builder("greeter")
/// .provide_private(new_repo)
/// .provide(new_greeter)
/// .invoke(register)
/// }
///
/// # #[tokio::main]
/// # async fn main() -> modrun::Result<()> {
/// Modrun::builder()
/// .supply(Config)
/// .module(greeter_domain())
/// .start()
/// .await?
/// .stop()
/// .await
/// # }
/// ```
pub struct Module {
name: &'static str,
options: Vec<Box<dyn ModOption>>,
}
impl fmt::Debug for Module {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Module")
.field("name", &self.name)
.field("options", &self.options.len())
.finish()
}
}
impl Module {
/// Start wiring a named domain module. `name` should be unique; it is used only
/// in diagnostics and dependency graphs.
///
/// Symmetric with [`Modrun::builder`](crate::Modrun::builder) at the composition root.
#[must_use]
pub fn builder(name: &'static str) -> Self {
Self {
name,
options: Vec::new(),
}
}
fn push_option(&mut self, option: Box<dyn ModOption>) {
self.options.push(option);
}
/// Nest another domain module.
#[must_use]
pub fn module(mut self, child: Module) -> Self {
self.push_option(child.into_option());
self
}
pub(crate) fn into_option(self) -> Box<dyn ModOption> {
Box::new(ModuleOption {
name: self.name,
options: self.options,
})
}
}
impl_wiring_methods!(Module);
impl_private_wiring_methods!(Module);
impl_group_wiring_methods!(Module);
struct ModuleOption {
name: &'static str,
options: Vec<Box<dyn ModOption>>,
}
impl ModOption for ModuleOption {
fn apply(self: Box<Self>, app: &mut BuildState) -> Result<()> {
let parent = app.current_scope;
let child = app.container.scopes_mut().child(parent, self.name);
app.current_scope = child;
// On `Err` we restore; on panic the whole `BuildState` is discarded.
let result = (|| {
for opt in self.options {
opt.apply(app)?;
}
Ok(())
})();
app.current_scope = parent;
result
}
}