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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
//! modrun — a modular application composer for Rust.
//!
//! Build large Tokio services as domain-oriented [`Module`]s with constructor
//! injection, explicit module boundaries, and coordinated lifecycle — wired once
//! at the composition root.
//!
//! Register constructors, pull the graph with invokers, and manage start/stop
//! via [`Lifecycle`].
//!
//! # Quick start
//!
//! ```no_run
//! use modrun::{Hook, Lifecycle, Modrun};
//!
//! #[derive(Clone)]
//! struct Config { port: u16 }
//!
//! #[derive(Clone)]
//! struct Server { cfg: Config }
//!
//! impl Hook for Server {
//! async fn on_start(&mut self) -> modrun::Result<()> {
//! println!("listening on {}", self.cfg.port);
//! Ok(())
//! }
//!
//! async fn on_stop(&mut self) -> modrun::Result<()> {
//! Ok(())
//! }
//! }
//!
//! fn new_config() -> Config { Config { port: 8080 } }
//! fn new_server(cfg: Config) -> Server { Server { cfg } }
//!
//! fn boot(lc: Lifecycle, server: Server) -> modrun::Result<()> {
//! lc.append(server)
//! }
//!
//! #[tokio::main]
//! async fn main() -> modrun::Result<()> {
//! Modrun::builder()
//! .provide(new_config)
//! .provide(new_server)
//! .invoke(boot)
//! .run()
//! .await
//! }
//! ```
//!
//! Dependencies must be `Clone` to inject by value. Singletons are cached by
//! type and cloned on inject. Prefer `Arc<T>` when a type is large, shared across
//! many constructors, or injected more than once — `Arc<T>` is also stored, so you
//! can inject `Arc<T>` even when `T` itself is not `Clone`. Put shared mutable
//! state behind `Arc` inside your type, e.g. `#[derive(Clone)] struct Db(Arc<DbInner>)`.
//!
//! Because the cache key is the type, a type can only be provided once. To wire
//! two of the same thing — a primary and a replica pool, say — give each its own
//! newtype wrapper.
//!
//! # Async constructors
//!
//! Anything that needs to `await` before it exists (connection pools, clients
//! that handshake) can be provided directly:
//!
//! ```
//! use modrun::Modrun;
//!
//! #[derive(Clone)]
//! struct Pool;
//!
//! async fn connect() -> Result<Pool, std::io::Error> {
//! Ok(Pool)
//! }
//!
//! #[tokio::main]
//! async fn main() -> modrun::Result<()> {
//! Modrun::builder()
//! .provide_result_async(connect)
//! .invoke(|_pool: Pool| {})
//! .start()
//! .await?
//! .stop()
//! .await
//! }
//! ```
//!
//! # Domain modules
//!
//! A [`Module`] groups related wiring under a name and gives it a private scope.
//! `provide_private` keeps a type invisible outside the module, so two modules
//! can each hold their own `Repo` without colliding.
//!
//! ```
//! use modrun::{Modrun, Module};
//!
//! #[derive(Clone)]
//! struct UserRepo;
//! #[derive(Clone)]
//! struct UserService;
//!
//! fn new_user_repo() -> UserRepo { UserRepo }
//! fn new_user_service(_repo: UserRepo) -> UserService { UserService }
//! fn boot_user(_svc: UserService) {}
//!
//! fn user_domain() -> Module {
//! Module::builder("user")
//! .provide_private(new_user_repo)
//! .provide(new_user_service)
//! .invoke(boot_user)
//! }
//!
//! #[tokio::main]
//! async fn main() -> modrun::Result<()> {
//! Modrun::builder()
//! .module(user_domain())
//! .start()
//! .await?
//! .stop()
//! .await
//! }
//! ```
//!
//! # Groups
//!
//! Several modules can each contribute one `T`; consumers inject [`Group<T>`]
//! (not `Vec<T>`). Register members with [`ModrunBuilder::provide_group`]. An
//! empty group needs [`ModrunBuilder::init_group`] (or
//! [`ModrunBuilder::require_group`], which also registers the group and then
//! rejects emptiness). Members do not occupy the singleton slot for `T`. Group
//! members and injected groups require `T: Clone`; prefer `Arc<Group<T>>` or
//! `Group<Arc<T>>` when many consumers or heavy values would otherwise clone.
//!
//! # Dependency graph
//!
//! Export the wiring graph with [`ModrunBuilder::render_dot`] or
//! [`.dot_graph(path)`](ModrunBuilder::dot_graph) (DOT is written after validation,
//! before constructors run). Built-in `Lifecycle` and `Shutdowner` are omitted from
//! the exported graph.
//!
//! # Startup banner
//!
//! [`ModrunBuilder::run`] and [`ModrunBuilder::start`] print a modrun ASCII banner
//! to stderr before wiring begins (Spring Boot style), and only when stderr is a
//! TTY. Override with [`.banner(text)`](ModrunBuilder::banner) (always printed to
//! stderr) or disable with [`.no_banner()`](ModrunBuilder::no_banner). Tests that
//! run in a terminal should call `.no_banner()` so captured stderr stays quiet.
//!
//! # Logging
//!
//! Framework events (provide / supply / invoke / construct / lifecycle) are
//! emitted through [`tracing`] with target `modrun`, using [uber/fx](https://github.com/uber-go/fx)-style
//! console lines such as `[modrun] PROVIDE ...`. Events also carry structured
//! fields (`constructor`, `module`, `elapsed`, …) for JSON subscribers.
//! Call `modrun::logging::init()` from examples and local binaries
//! (requires the `logging` feature); it is a no-op if a subscriber is already
//! installed, writes to stderr, and enables ANSI only when stderr is a terminal. Production
//! processes should install their own subscriber and
//! filter with `RUST_LOG=modrun=info`. Without a subscriber the events are
//! cheap no-ops. Debug builds also print to stderr if a `RunningApp` is dropped
//! without [`RunningApp::stop`].
//!
//! ```no_run
//! # #[cfg(feature = "logging")]
//! modrun::logging::init();
//! ```
//!
//! # Stability
//!
//! The public model is type-keyed singletons, [`Group<T>`] value groups, lazy
//! `provide`, `invoke` as the graph root, and start/stop via [`Lifecycle`].
//! Domain wiring uses [`Module::builder`] (symmetric with [`Modrun::builder`]).
//! There are no string qualifiers and no service locator after build. [`Hook`]
//! methods will only grow with defaults. Constructors and invokers accept at most
//! eight parameters; pack extra deps in a struct. MSRV is **1.85** (edition 2024).
//! **Application-facing API is stable since 1.0.0**; see CONTRIBUTING.md.
//! Startup overhead is mostly your constructors; the container is dropped after build.
//! Prefer `Arc<T>` and `Arc<Group<T>>` for heavy deps — see README「Performance」.
//! Examples may need a newer compiler via their own dependencies (the MSRV job
//! does not compile `--all-targets`).
//!
//! Application code should use [`ModrunBuilder::provide`] /
//! [`ModrunBuilder::invoke`]. Wrapper libraries use the hidden [`__wiring`] module
//! and `ModrunBuilder::provide_dyn` / `invoke_dyn` (also `#[doc(hidden)]`).
//!
//! # Crate features
//!
//! * **`signal`** *(enabled by default)* — OS signal listeners in
//! [`ModrunBuilder::run`] on **Unix** (Ctrl-C / SIGTERM) and **Windows**
//! (Ctrl-C / Ctrl-Break / Ctrl-Close / Ctrl-Shutdown). On other targets the
//! feature is a no-op for OS signals; use [`Shutdowner`]. Disable with
//! `default-features = false` when you only call [`ModrunBuilder::start`] or
//! wait on [`Shutdowner`] yourself.
//! * **`logging`** — `modrun::logging::init` / `try_init` for fx-style console
//! output (`fmt`-only, no regex crates). Skip it in production and install
//! your own subscriber.
//! * **`env-filter`** — adds `RUST_LOG` / per-target filtering to
//! `modrun::logging` (pulls `regex-automata`, `matchers`). Implies
//! `logging`; on by default. Use `default-features = false` +
//! `features = ["logging"]` for console output without the regex deps.
pub use ;
pub use DEFAULT_BANNER;
pub use ;
pub use Group;
pub use ;
pub use Module;
pub use Shutdowner;
pub use ;
pub use DEFAULT_TIMEOUT;
/// Type-erased wiring traits and erased provider/invoker types.
///
/// For **wrapper libraries** that re-export modrun's builder API. Not part of the
/// application-facing model and omitted from docs.rs navigation (`#[doc(hidden)]`).
/// Semver: treat as unstable relative to the typed `provide` / `invoke` surface.
;