Expand description
Lightweight type-keyed dependency injection container.
Container stores services keyed by their Rust type (TypeId). Register
services at startup; resolve them anywhere that has access to the container.
Share across request handlers with App::with_state(container) — see
“Usage with App::with_state” below.
§Concrete services
use rust_web_server::di::Container;
struct EmailService { host: String }
let mut c = Container::new();
c.register(EmailService { host: "smtp.example.com".into() });
let svc = c.get::<EmailService>().unwrap();
assert_eq!(svc.host, "smtp.example.com");§Trait-object services
use std::sync::Arc;
use rust_web_server::di::Container;
pub trait Mailer: Send + Sync {
fn send(&self, to: &str);
}
struct SmtpMailer;
impl Mailer for SmtpMailer {
fn send(&self, _to: &str) {}
}
let mut c = Container::new();
c.provide::<dyn Mailer>(Arc::new(SmtpMailer));
let mailer = c.get::<dyn Mailer>().unwrap();
mailer.send("user@example.com");§Named services
Register multiple instances of the same type under distinct string names:
use rust_web_server::di::Container;
let mut c = Container::new();
c.register_named("primary", 5432u16)
.register_named("replica", 5433u16);
assert_eq!(*c.get_named::<u16>("primary").unwrap(), 5432);
assert_eq!(*c.get_named::<u16>("replica").unwrap(), 5433);§Usage with App::with_state / App::with_async_state
Container needs no special-cased integration — it’s Send + Sync + 'static like any other state type, so it plugs directly into
App::with_state as S. Pass the
container itself, not container.into_arc(): with_state already
wraps S in an Arc internally, so calling into_arc() first just
double-wraps it (Arc<Arc<Container>>) for no benefit — handlers then
receive &Container directly instead of &Arc<Container>. into_arc()
exists for call sites that need to share one container across multiple
Applications built by hand, outside of App::with_state/with_async_state.
use rust_web_server::app::App;
use rust_web_server::di::Container;
use rust_web_server::request::Request;
use rust_web_server::router::PathParams;
use rust_web_server::server::ConnectionInfo;
use rust_web_server::response::{Response, STATUS_CODE_REASON_PHRASE};
use rust_web_server::routes;
struct Config { version: &'static str }
fn get_version(
_req: &Request,
_p: &PathParams,
_c: &ConnectionInfo,
state: &Container,
) -> Response {
let _cfg = state.get::<Config>().unwrap();
Response::get_response(&STATUS_CODE_REASON_PHRASE.n200_ok, None, None)
}
let mut container = Container::new();
container.register(Config { version: "1.0" });
let app = routes! {
App::with_state(container),
GET "/version" => get_version,
};The async counterpart works the same way with App::with_async_state
(requires the http2 feature) — handlers are async fns that receive
&Container and can .await inside the closure while resolving services.
Structs§
- Container
- A type-keyed service container for dependency injection.