use std::sync::Arc;
use crate::route::scan::HandlerCache;
#[derive(Clone)]
pub struct DispatchRuntime {
provider: Arc<rust_dix::ServiceProvider>,
handler_cache: Arc<HandlerCache>,
}
impl DispatchRuntime {
pub fn new(provider: Arc<rust_dix::ServiceProvider>, handler_cache: Arc<HandlerCache>) -> Self {
Self {
provider,
handler_cache,
}
}
pub fn provider(&self) -> &Arc<rust_dix::ServiceProvider> {
&self.provider
}
pub fn handler_cache(&self) -> &Arc<HandlerCache> {
&self.handler_cache
}
pub fn scope(&self) -> rust_dix::Scope {
self.provider.scope()
}
}
#[cfg(test)]
mod tests {
use super::*;
use rust_dix::ServiceCollection;
use std::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug)]
struct ScopedThing(usize);
fn runtime_with_scoped_counter() -> (Arc<DispatchRuntime>, Arc<AtomicUsize>) {
let created = Arc::new(AtomicUsize::new(0));
let counter = Arc::clone(&created);
let provider = ServiceCollection::new()
.scoped::<ScopedThing>(move |_| {
let n = counter.fetch_add(1, Ordering::SeqCst);
Arc::new(ScopedThing(n))
})
.build()
.expect("provider");
(
Arc::new(DispatchRuntime::new(
provider,
Arc::new(HandlerCache::build()),
)),
created,
)
}
#[tokio::test]
async fn runtime_scope_is_the_explicit_di_entry_point() {
let (runtime, created) = runtime_with_scoped_counter();
let scope = runtime.scope();
let first = scope.get::<ScopedThing>().expect("scoped in scope");
let second = scope.get::<ScopedThing>().expect("scoped in scope");
assert!(
Arc::ptr_eq(&first, &second),
"Scoped services are cached per scope"
);
assert_eq!(first.0, 0, "the scope created the service once");
assert_eq!(created.load(Ordering::SeqCst), 1);
let error = runtime
.provider()
.get::<ScopedThing>()
.expect_err("strict scope validation rejects Scoped services from the root");
assert!(error.to_string().contains("root provider"), "{error}");
}
}