Skip to main content

rust_dix/
provider.rs

1use crate::cache::{AnyService, LazyCache};
2use crate::entry::{
3    AsyncServiceFactory, IServiceResolver, ServiceEntry, ServiceFactory, ServiceLifetime,
4    ServiceStore,
5};
6use crate::error::RdiError;
7use crate::scope::ScopeFactory;
8use crate::validation::ValidationResolver;
9use std::any::{Any, TypeId};
10use std::cell::{Cell, RefCell};
11use std::collections::HashMap;
12use std::panic::AssertUnwindSafe;
13use std::sync::atomic::{AtomicBool, Ordering};
14use std::sync::{Arc, Mutex, OnceLock, RwLock, Weak};
15
16thread_local! {
17    /// Runtime resolution stack for Scoped/Transient cycle detection.
18    static RESOLVING: RefCell<Vec<(usize, &'static str)>> = const { RefCell::new(Vec::new()) };
19    /// Non-zero while a build-time singleton factory is executing.
20    ///
21    /// Resolving services through an injected provider inside a constructor
22    /// would bypass build-time cycle/captive validation *and* make the outcome
23    /// depend on store iteration order, so it is rejected deterministically.
24    static BUILD_FACTORY_DEPTH: Cell<usize> = const { Cell::new(0) };
25}
26
27pub(crate) struct ResolveGuard;
28
29impl Drop for ResolveGuard {
30    fn drop(&mut self) {
31        RESOLVING.with(|stack| {
32            stack.borrow_mut().pop();
33        });
34    }
35}
36
37/// RAII marker for “a build-time singleton factory is currently executing”.
38pub(crate) struct BuildFactoryGuard;
39
40impl BuildFactoryGuard {
41    pub(crate) fn enter() -> Self {
42        BUILD_FACTORY_DEPTH.with(|depth| depth.set(depth.get() + 1));
43        Self
44    }
45}
46
47impl Drop for BuildFactoryGuard {
48    fn drop(&mut self) {
49        BUILD_FACTORY_DEPTH.with(|depth| depth.set(depth.get().saturating_sub(1)));
50    }
51}
52
53/// Reject provider-mediated resolution while a constructor is running.
54///
55/// Construction should declare dependencies as fields; dynamic resolution must
56/// happen later in methods, where no build-time validation constraint applies.
57fn reject_build_time_provider_resolution(type_name: &'static str) {
58    if BUILD_FACTORY_DEPTH.with(|depth| depth.get()) > 0 {
59        std::panic::panic_any(RdiError::FactoryPanic {
60            service: type_name.to_string(),
61            payload: format!(
62                "resolving services through the injected provider from a build-time constructor \
63                 is not supported: store the provider/ScopeFactory and resolve lazily in methods \
64                 (attempted to resolve {type_name})"
65            ),
66        });
67    }
68}
69
70pub(crate) fn enter_resolve(
71    cache_key: usize,
72    type_name: &'static str,
73) -> Result<ResolveGuard, RdiError> {
74    RESOLVING.with(|stack| {
75        let mut s = stack.borrow_mut();
76        if s.iter().any(|(k, _)| *k == cache_key) {
77            let mut chain: Vec<&str> = s.iter().map(|(_, n)| *n).collect();
78            chain.push(type_name);
79            return Err(RdiError::CircularDependency(chain.join(" -> ")));
80        }
81        s.push((cache_key, type_name));
82        Ok(ResolveGuard)
83    })
84}
85
86/// Check the current (synchronous) resolution chain without pushing a frame.
87///
88/// Used by async factories: a nested `await` of a service that is already being
89/// resolved would dead-lock on its own per-key async lock, so it is reported as
90/// [`RdiError::CircularDependency`] instead.
91fn check_not_resolving(cache_key: usize, type_name: &'static str) -> Result<(), RdiError> {
92    RESOLVING.with(|stack| {
93        let s = stack.borrow();
94        if s.iter().any(|(k, _)| *k == cache_key) {
95            let mut chain: Vec<&str> = s.iter().map(|(_, n)| *n).collect();
96            chain.push(type_name);
97            return Err(RdiError::CircularDependency(chain.join(" -> ")));
98        }
99        Ok(())
100    })
101}
102
103struct AsyncPollGuard {
104    cache_key: usize,
105    type_name: &'static str,
106}
107
108impl Drop for AsyncPollGuard {
109    fn drop(&mut self) {
110        let _ = self.cache_key;
111        let _ = self.type_name;
112        RESOLVING.with(|stack| {
113            stack.borrow_mut().pop();
114        });
115    }
116}
117
118/// Future wrapper that marks a resolution as "in chain" **for the duration of a
119/// single poll**.
120///
121/// This is what makes async re-entrancy detection precise: the marker is only
122/// visible to nested resolutions started synchronously inside the same poll
123/// chain (which is where the self-await dead-lock would occur). Concurrent
124/// tasks polled on the same thread interleave between polls, so they never see
125/// each other's markers and cannot produce false `CircularDependency` errors.
126struct AsyncPollGuardFuture<F> {
127    inner: std::pin::Pin<Box<F>>,
128    cache_key: usize,
129    type_name: &'static str,
130}
131
132impl<F: std::future::Future> std::future::Future for AsyncPollGuardFuture<F> {
133    type Output = F::Output;
134
135    fn poll(
136        self: std::pin::Pin<&mut Self>,
137        cx: &mut std::task::Context<'_>,
138    ) -> std::task::Poll<Self::Output> {
139        // `Self` is `Unpin` (it only holds a `Pin<Box<F>>` and `Copy` fields).
140        let this = self.get_mut();
141        RESOLVING.with(|stack| stack.borrow_mut().push((this.cache_key, this.type_name)));
142        let _guard = AsyncPollGuard {
143            cache_key: this.cache_key,
144            type_name: this.type_name,
145        };
146        this.inner.as_mut().poll(cx)
147    }
148}
149
150fn poll_guard<F: std::future::Future>(
151    cache_key: usize,
152    type_name: &'static str,
153    future: F,
154) -> AsyncPollGuardFuture<F> {
155    AsyncPollGuardFuture {
156        inner: Box::pin(future),
157        cache_key,
158        type_name,
159    }
160}
161
162/// Drop cached instances, collecting (instead of propagating) `Drop` panics.
163///
164/// Disposal must finish releasing the remaining instances even when a user
165/// `Drop` impl panics; the first panic is re-raised by the caller after all
166/// cleanup work completed (and swallowed during unwinding).
167fn drop_instances_safely(instances: Vec<AnyService>) -> Option<Box<dyn Any + Send>> {
168    let mut first_panic: Option<Box<dyn Any + Send>> = None;
169    for instance in instances {
170        if let Err(payload) = std::panic::catch_unwind(AssertUnwindSafe(|| drop(instance))) {
171            if first_panic.is_none() {
172                first_panic = Some(payload);
173            }
174        }
175    }
176    first_panic
177}
178
179/// Options for building a [`ServiceProvider`].
180///
181/// `#[non_exhaustive]`: construct via [`ServiceProviderOptions::new`] and the
182/// `with_*` builder methods (`Default` equals `new()`), so future options stay
183/// additive.
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185#[non_exhaustive]
186pub struct ServiceProviderOptions {
187    /// Reject resolving `Scoped` services from the root provider.
188    ///
189    /// Mirrors MEDI `ValidateScopes` as enabled by the .NET (ASP.NET Core) host
190    /// in the Development environment: resolving a scoped service outside a
191    /// scope is a misconfiguration, because the root caches it for the container
192    /// lifetime (the "scoped becomes singleton" anti-pattern).
193    ///
194    /// - `true` (default): `get`/`get_async` (and constructor dependencies)
195    ///   return [`RdiError::ScopedFromRootProvider`] when they would resolve a
196    ///   `Scoped` service from the root provider. Infallible lookups
197    ///   (`get_optional`, `get_all`, `get_all_keyed`, `try_*`) treat such a
198    ///   service as not resolvable at the root. `get_owned` is exempt for the
199    ///   owned instance itself (it is caller-owned and never enters a scope
200    ///   cache); its transitive dependencies are still validated.
201    /// - `false`: restores rust-dix ≤ 0.7 root-scope behavior (the root provider
202    ///   caches scoped instances and acts as the root scope).
203    pub validate_scopes: bool,
204}
205
206impl ServiceProviderOptions {
207    /// Strict defaults: `validate_scopes = true`.
208    pub fn new() -> Self {
209        Self {
210            validate_scopes: true,
211        }
212    }
213
214    /// Set scope validation explicitly.
215    pub fn with_validate_scopes(mut self, validate_scopes: bool) -> Self {
216        self.validate_scopes = validate_scopes;
217        self
218    }
219
220    /// Convenience preset matching MEDI's bare `BuildServiceProvider()`:
221    /// scope validation disabled (root-scope resolution allowed).
222    pub fn lenient() -> Self {
223        Self {
224            validate_scopes: false,
225        }
226    }
227}
228
229impl Default for ServiceProviderOptions {
230    fn default() -> Self {
231        Self::new()
232    }
233}
234
235/// State shared between the root provider and every scope created from it.
236///
237/// Disposing the root marks the whole tree disposed; scopes created earlier can
238/// no longer resolve services.
239pub(crate) struct SharedProviderState {
240    disposed: AtomicBool,
241}
242
243impl SharedProviderState {
244    fn new() -> Self {
245        Self {
246            disposed: AtomicBool::new(false),
247        }
248    }
249}
250
251pub struct ServiceProvider {
252    /// Service registry. Shared across root + scope-derived providers via `Arc`.
253    store: Arc<ServiceStore>,
254    /// String → TypeId lookup for IServiceResolver string-based resolution.
255    /// Shared across root + scope-derived providers via `Arc`.
256    type_map: Arc<HashMap<&'static str, TypeId>>,
257    /// Singleton 实例缓存(per-key `OnceLock`,多线程下工厂只执行一次)。
258    /// build 阶段 validation + eager init 预热,运行时 lazy fallback。
259    /// Shared across root + scope-derived providers via `Arc`(全局单例语义)。
260    /// 记录首次创建顺序,供 [`Self::dispose`] 逆序释放。
261    singleton_cache: Arc<LazyCache>,
262    /// 当前 provider 的 Scoped 实例缓存。
263    ///
264    /// Root provider 即 root scope:`validate_scopes = true`(默认)时 root 不允许
265    /// 解析 Scoped 服务;`validate_scopes = false` 时实例在此缓存中复用,语义等同
266    /// 于在根 scope 内单例化。子 Scope(通过 [`ServiceProvider::scope`] 创建)拥有
267    /// 独立的 scoped 缓存,不回退到根。per-key `OnceLock` 保证多线程下工厂只执行
268    /// 一次,无 TOCTOU 竞态。**每个 provider 独立**。
269    root_scoped_cache: LazyCache,
270    /// String-keyed registry for cross-DLL (cdylib) service access.
271    /// Rust's `TypeId` differs across compilation units, so named
272    /// lookup is the only reliable mechanism for plugin services.
273    /// Shared across root + scope-derived providers via `Arc`.
274    pub(crate) named: Arc<RwLock<HashMap<String, Arc<dyn Any + Send + Sync>>>>,
275    /// Self-referential weak pointer, initialized by [`Self::new`] or
276    /// [`Self::new_scope`]. Enables [`IServiceResolver::provider_arc`] to hand
277    /// out `Arc<ServiceProvider>` to services using `#[inject(provider)]`.
278    /// **每个 provider 独立**:scope-derived provider 的 self_weak 指向自身。
279    self_weak: OnceLock<Weak<ServiceProvider>>,
280    /// Built-in `dyn ScopeFactory` singleton, created lazily on first resolution.
281    /// It holds a `Weak` provider reference, so caching it cannot create an
282    /// `Arc` cycle (MEDI parity: the scope factory is itself a singleton).
283    scope_factory_cache: OnceLock<Arc<dyn ScopeFactory>>,
284    /// Cleanup closures for scoped services registered via [`Self::register_disposable`].
285    /// Populated during factory execution, drained (reverse registration order) by
286    /// `Self::dispose`.
287    /// **每个 provider 独立**:scope-derived provider 的 disposables 绑定到当前 scope。
288    disposables: Mutex<Vec<Box<dyn FnOnce() + Send>>>,
289    /// Root/scope shared state (`disposed` flag). Root dispose marks the tree dead.
290    shared: Arc<SharedProviderState>,
291    /// This provider disposed flag (root dispose or scope dispose/Drop).
292    disposed: AtomicBool,
293    /// Root provider (not a scope): only the root applies scope validation.
294    is_root: bool,
295    /// Whether Scoped services may be resolved from this root provider.
296    validate_scopes: bool,
297}
298
299impl ServiceProvider {
300    pub(crate) fn new_with(
301        store: ServiceStore,
302        options: ServiceProviderOptions,
303    ) -> Result<Arc<Self>, RdiError> {
304        // Reject async registrations on the sync build path.
305        if let Some(entry) = store
306            .values()
307            .flat_map(|entries| entries.iter())
308            .find(|e| e.async_factory.is_some())
309        {
310            return Err(RdiError::AsyncServiceRequiresBuildAsync {
311                service: entry.type_name.to_string(),
312            });
313        }
314
315        // Build type_name → TypeId lookup table for string-based resolution
316        let mut type_map = HashMap::new();
317        for (&tid, entries) in &store {
318            if let Some(e) = entries.first() {
319                type_map.entry(e.type_name).or_insert(tid);
320            }
321        }
322
323        let singleton_cache = Arc::new(LazyCache::new());
324
325        // Phase 1: create the provider in an `Arc` **before** dependency
326        // validation. Singleton factories may legitimately depend on the
327        // container itself (`#[inject(provider)]`, `#[inject] Arc<dyn
328        // ScopeFactory>`), so `provider_arc()` and the built-in ScopeFactory
329        // must be resolvable while validation executes those factories.
330        let sp_arc = Arc::new(Self {
331            store: Arc::new(store),
332            type_map: Arc::new(type_map),
333            singleton_cache,
334            root_scoped_cache: LazyCache::new(),
335            named: Arc::new(RwLock::new(HashMap::new())),
336            self_weak: OnceLock::new(),
337            scope_factory_cache: OnceLock::new(),
338            disposables: Mutex::new(Vec::new()),
339            shared: Arc::new(SharedProviderState::new()),
340            disposed: AtomicBool::new(false),
341            is_root: true,
342            validate_scopes: options.validate_scopes,
343        });
344        sp_arc.self_weak.get_or_init(|| Arc::downgrade(&sp_arc));
345
346        // Phase 2: Validate dependencies (cycle detection, captive dependency)
347        // and cache the singleton instances built along the way.
348        Self::validate_dependencies(&sp_arc)?;
349
350        // Phase 3: eagerly execute any sync singleton whose factory was not
351        // already run by validation.
352        Self::init_sync_singletons(&sp_arc);
353        Ok(sp_arc)
354    }
355
356    /// Collect sync singleton entries in **registration order** and eagerly
357    /// execute their factories.
358    ///
359    /// Reuses instances cached by validation (build time) so factories aren't
360    /// double-fired. Called by both `new` and `new_async` (async singletons skipped).
361    ///
362    /// Ordering is deterministic (sorted by `cache_key` = registration index)
363    /// instead of relying on `HashMap` iteration order, so side effects and
364    /// validation errors are reproducible across runs.
365    fn init_sync_singletons(sp_arc: &Arc<Self>) {
366        let mut singleton_entries: Vec<(usize, ServiceFactory)> = sp_arc
367            .store
368            .values()
369            .flat_map(|entries| entries.iter())
370            .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_none())
371            .map(|e| (e.cache_key, e.factory.clone()))
372            .collect();
373        singleton_entries.sort_by_key(|(cache_key, _)| *cache_key);
374
375        for (ck, factory) in &singleton_entries {
376            let resolver = sp_arc.as_ref() as &dyn IServiceResolver;
377            let factory = factory.clone();
378            sp_arc
379                .singleton_cache
380                .get_or_init_with(*ck, move || factory(resolver));
381        }
382    }
383
384    /// Build a `ServiceProvider` with async factory support.
385    ///
386    /// Async singleton factories are executed during build and their results
387    /// are cached. Async transient/scoped factories are stored for later
388    /// resolution via `get_async` / `get_keyed_async`.
389    ///
390    /// Returns `Arc<ServiceProvider>` so that `provider_arc()` works for
391    /// async resolution (async factories receive `Arc<ServiceProvider>`).
392    pub(crate) async fn new_async_with(
393        store: ServiceStore,
394        options: ServiceProviderOptions,
395    ) -> Result<Arc<Self>, RdiError> {
396        // Build type_name → TypeId lookup
397        let mut type_map = HashMap::new();
398        for (&tid, entries) in &store {
399            if let Some(e) = entries.first() {
400                type_map.entry(e.type_name).or_insert(tid);
401            }
402        }
403
404        let singleton_cache = Arc::new(LazyCache::new());
405
406        // Phase 1: create the provider in an Arc **before** validation so that
407        // singleton factories depending on `ServiceProvider` / `ScopeFactory`
408        // can be constructed eagerly (same contract as the sync `build()`).
409        let sp_arc = Arc::new(Self {
410            store: Arc::new(store),
411            type_map: Arc::new(type_map),
412            singleton_cache,
413            root_scoped_cache: LazyCache::new(),
414            named: Arc::new(RwLock::new(HashMap::new())),
415            self_weak: OnceLock::new(),
416            scope_factory_cache: OnceLock::new(),
417            disposables: Mutex::new(Vec::new()),
418            shared: Arc::new(SharedProviderState::new()),
419            disposed: AtomicBool::new(false),
420            is_root: true,
421            validate_scopes: options.validate_scopes,
422        });
423        sp_arc.self_weak.get_or_init(|| Arc::downgrade(&sp_arc));
424
425        // Phase 2: validate sync singleton dependencies and cache instances.
426        Self::validate_dependencies(&sp_arc)?;
427
428        // Phase 3: eagerly execute sync singletons not already built.
429        Self::init_sync_singletons(&sp_arc);
430
431        // Phase 4: execute async singleton factories (deterministic order,
432        // panics converted to typed errors).
433        let mut async_singletons: Vec<(usize, &'static str, AsyncServiceFactory)> = sp_arc
434            .store
435            .values()
436            .flat_map(|entries| entries.iter())
437            .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_some())
438            .map(|e| {
439                (
440                    e.cache_key,
441                    e.type_name,
442                    e.async_factory.clone().expect("async singleton factory"),
443                )
444            })
445            .collect();
446        async_singletons.sort_by_key(|(cache_key, _, _)| *cache_key);
447
448        for (ck, type_name, async_factory) in async_singletons {
449            let result = match futures::FutureExt::catch_unwind(AssertUnwindSafe(async_factory(
450                Arc::clone(&sp_arc),
451            )))
452            .await
453            {
454                Ok(value) => value,
455                Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
456            };
457            sp_arc.singleton_cache.get_or_init_with(ck, || result);
458        }
459
460        Ok(sp_arc)
461    }
462
463    /// 创建一个 scope 范围的 ServiceProvider,共享 store/type_map/singleton_cache/named,
464    /// 独立 scoped 缓存、disposables 与 self_weak。
465    ///
466    /// 供 [`Scope::new`](crate::scope::Scope::new) 调用。这使 `#[inject(provider)]`
467    /// 字段拿到的是 **scope 范围的 provider** 而非根 provider——经该字段解析 Scoped 服务
468    /// 会命中 scope 自己的 scoped 缓存,符合 MEDI `IServiceScope` 语义。
469    pub(crate) fn new_scope(parent: &Arc<Self>) -> Arc<Self> {
470        let sp = Self {
471            store: Arc::clone(&parent.store),
472            type_map: Arc::clone(&parent.type_map),
473            singleton_cache: Arc::clone(&parent.singleton_cache),
474            root_scoped_cache: LazyCache::new(),
475            named: Arc::clone(&parent.named),
476            self_weak: OnceLock::new(),
477            scope_factory_cache: OnceLock::new(),
478            disposables: Mutex::new(Vec::new()),
479            shared: Arc::clone(&parent.shared),
480            disposed: AtomicBool::new(false),
481            is_root: false,
482            validate_scopes: parent.validate_scopes,
483        };
484        let arc = Arc::new(sp);
485        let this: &Self = &arc;
486        this.self_weak.get_or_init(|| Arc::downgrade(&arc));
487        arc
488    }
489
490    /// Register a cleanup closure for scoped services/owned resources.
491    ///
492    /// Closures run (in **reverse registration order**) when
493    /// [`Self::dispose`] is called — either explicitly or by [`Scope`](crate::Scope)'s
494    /// `Drop` for scope providers.
495    pub fn register_disposable(&self, cleanup: Box<dyn FnOnce() + Send>) {
496        self.disposables.lock().unwrap().push(cleanup);
497    }
498
499    /// Dispose this provider: release cached instances in reverse creation order,
500    /// run registered cleanups in reverse registration order, and mark the
501    /// provider unusable.
502    ///
503    /// - Root provider: also marks the whole provider tree disposed (existing
504    ///   scopes can no longer resolve), drains the singleton cache, and clears
505    ///   named registrations. Singleton instances are released in reverse
506    ///   creation order (LIFO), so dependents drop before their dependencies.
507    /// - Scope provider: releases the scoped instances created in that scope and
508    ///   runs its cleanups. Singletons are untouched.
509    ///
510    /// Idempotent. Instances are released by dropping the container's strong
511    /// references; a service's `Drop` runs when no other owner keeps it alive.
512    /// Services obtained via `get_owned` are caller-owned and are not tracked.
513    ///
514    /// The caller must not resolve services concurrently with disposal (same
515    /// contract as MEDI's `ServiceProvider.Dispose`). A panicking cleanup closure
516    /// does not stop the remaining cleanups; the first panic is re-raised after
517    /// disposal (and swallowed when the thread is already unwinding, e.g. during
518    /// `Scope`'s `Drop`).
519    pub fn dispose(&self) {
520        if self.disposed.swap(true, Ordering::SeqCst) {
521            return;
522        }
523        if self.is_root {
524            self.shared.disposed.store(true, Ordering::SeqCst);
525        }
526
527        // Release instances (reverse LIFO order). User `Drop` panics are
528        // collected so the remaining instances/cleanups still run.
529        let mut first_panic = drop_instances_safely(self.root_scoped_cache.drain_reverse());
530
531        if self.is_root {
532            // Release singletons (reverse creation order) and clear plugins.
533            let singleton_panic = drop_instances_safely(self.singleton_cache.drain_reverse());
534            if first_panic.is_none() {
535                first_panic = singleton_panic;
536            }
537            self.named.write().unwrap().clear();
538        }
539
540        let cleanup_panic = self.run_cleanups();
541        if first_panic.is_none() {
542            first_panic = cleanup_panic;
543        }
544
545        if let Some(payload) = first_panic {
546            if !std::thread::panicking() {
547                std::panic::resume_unwind(payload);
548            }
549        }
550    }
551
552    /// Drain and execute cleanup closures in reverse registration order.
553    ///
554    /// The first cleanup panic is returned to the caller instead of being
555    /// raised here, so disposal can finish all remaining work first. During
556    /// unwinding (drop path) the panic is swallowed to avoid a double-panic
557    /// abort.
558    fn run_cleanups(&self) -> Option<Box<dyn Any + Send>> {
559        let mut cleanups: Vec<Box<dyn FnOnce() + Send>> = {
560            let mut guard = self.disposables.lock().unwrap();
561            std::mem::take(&mut *guard)
562        };
563        cleanups.reverse();
564
565        let mut first_panic: Option<Box<dyn Any + Send>> = None;
566        for cleanup in cleanups {
567            if let Err(payload) = std::panic::catch_unwind(AssertUnwindSafe(cleanup)) {
568                if first_panic.is_none() {
569                    first_panic = Some(payload);
570                }
571            }
572        }
573        first_panic
574    }
575
576    /// Validate all dependencies: detect cycles and captive dependencies.
577    /// Instances built during validation are stored in the provider's singleton
578    /// cache so they can be reused by the subsequent eager-init phase.
579    ///
580    /// Validation runs **after** the provider `Arc` exists: factories may inject
581    /// the provider itself (`#[inject(provider)]`) or the built-in
582    /// [`ScopeFactory`], which requires `provider_arc()` and `self_weak` to be
583    /// live. The validation resolver still executes factories itself, so
584    /// cycle/captive-dependency accounting is preserved.
585    ///
586    /// Validation order is deterministic (sorted by `cache_key` = registration
587    /// index), so the first reported error is stable across runs.
588    fn validate_dependencies(sp: &Arc<Self>) -> Result<(), RdiError> {
589        // Build TypeId → type_name map for error messages
590        let type_names: HashMap<TypeId, &'static str> = sp
591            .store
592            .iter()
593            .map(|(&tid, entries)| {
594                let name = entries.first().map(|e| e.type_name).unwrap_or("<unknown>");
595                (tid, name)
596            })
597            .collect();
598
599        let mut singletons: Vec<&ServiceEntry> = sp
600            .store
601            .values()
602            .flat_map(|entries| entries.iter())
603            .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_none())
604            .collect();
605        singletons.sort_by_key(|e| e.cache_key);
606
607        // Validate each sync singleton by attempting to resolve it.
608        // Scoped/Transient are not eagerly executed at build (avoids side effects);
609        // their cycles are detected at runtime via a thread-local resolution stack.
610        //
611        // Each registration is validated individually: duplicate registrations
612        // (MEDI override semantics) are all constructed eagerly, and each factory
613        // must pass the cycle/captive checks under its own cache key.
614        for entry in singletons {
615            let resolver = ValidationResolver::new(
616                &sp.store,
617                &type_names,
618                &sp.singleton_cache,
619                Arc::clone(sp),
620            );
621            let type_name = entry.type_name;
622
623            let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
624                resolver.validate_entry(entry)
625            }));
626
627            if let Some(err) = resolver.take_error() {
628                return Err(err);
629            }
630
631            match result {
632                Ok(_) => {}
633                Err(panic_info) => {
634                    return Err(RdiError::from_panic_payload(type_name, panic_info));
635                }
636            }
637        }
638
639        Ok(())
640    }
641
642    // ── Registration lookup (single-service resolution: last registration wins) ──
643
644    /// Last unkeyed registration for `tid` (MEDI: later registrations override
645    /// earlier ones when resolving a single service).
646    fn unkeyed_entry(&self, tid: TypeId) -> Option<&ServiceEntry> {
647        self.store.get(&tid)?.iter().rev().find(|e| e.key.is_none())
648    }
649
650    /// Last registration for `tid` + `key` (same-key duplicates: last wins).
651    fn keyed_entry(&self, tid: TypeId, key: &str) -> Option<&ServiceEntry> {
652        self.store
653            .get(&tid)?
654            .iter()
655            .rev()
656            .find(|e| e.key.as_deref() == Some(key))
657    }
658
659    fn entry_by_str(&self, type_name: &str, key: Option<&str>) -> Option<&ServiceEntry> {
660        let tid = *self.type_map.get(type_name)?;
661        match key {
662            Some(k) => self.keyed_entry(tid, k),
663            None => self.unkeyed_entry(tid),
664        }
665    }
666
667    // ── Liveness / scope validation ──
668
669    /// Whether this provider (or its root) has been disposed.
670    fn check_alive(&self) -> Result<(), RdiError> {
671        if self.shared.disposed.load(Ordering::SeqCst) {
672            return Err(RdiError::ProviderDisposed);
673        }
674        if self.disposed.load(Ordering::SeqCst) {
675            return Err(RdiError::ScopeDisposed);
676        }
677        Ok(())
678    }
679
680    /// MEDI `ValidateScopes` equivalent: a scoped service must not be resolved
681    /// from the root provider (it would be cached for the container lifetime).
682    fn check_scope_validation(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
683        if entry.lifetime == ServiceLifetime::Scoped && self.is_root && self.validate_scopes {
684            return Err(RdiError::ScopedFromRootProvider {
685                service: entry.type_name.to_string(),
686            });
687        }
688        Ok(())
689    }
690
691    fn check_resolvable(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
692        self.check_alive()?;
693        self.check_scope_validation(entry)
694    }
695
696    // ── Resolution cores ──
697
698    /// Resolve a single entry, converting liveness/scope violations, cycles and
699    /// factory panics into typed [`RdiError`].
700    fn resolve_entry_catching(&self, entry: &ServiceEntry) -> Result<AnyService, RdiError> {
701        self.check_resolvable(entry)?;
702        match std::panic::catch_unwind(AssertUnwindSafe(|| self.get_any_by_entry(entry))) {
703            Ok(Some(v)) => Ok(v),
704            Ok(None) => Err(RdiError::not_found(entry.type_name, None)),
705            Err(payload) => Err(RdiError::from_panic_payload(entry.type_name, payload)),
706        }
707    }
708
709    /// Resolve a single entry, panicking with a typed [`RdiError`] on liveness or
710    /// scope violations (used by [`IServiceResolver`], whose contract is
711    /// infallible `Option`; required-resolution APIs catch these panics and
712    /// return `Err`).
713    fn resolve_entry_panicking(&self, entry: &ServiceEntry) -> AnyService {
714        if let Err(err) = self.check_resolvable(entry) {
715            std::panic::panic_any(err);
716        }
717        match self.get_any_by_entry(entry) {
718            Some(v) => v,
719            None => std::panic::panic_any(RdiError::not_found(entry.type_name, None)),
720        }
721    }
722
723    /// Type-erased resolution by type name, for the resolver trait.
724    ///
725    /// Single-service semantics: **last registration wins** (MEDI), both for
726    /// unkeyed and for same-key keyed registrations.
727    fn resolve_unkeyed_optional<T: ?Sized + Send + Sync + 'static>(
728        &self,
729    ) -> Result<Option<Arc<T>>, RdiError> {
730        self.check_alive()?;
731        if let Some(entry) = self.unkeyed_entry(TypeId::of::<T>()) {
732            return Ok(Self::extract(self.resolve_entry_catching(entry)?));
733        }
734        // Built-in container services (ScopeFactory / ServiceProvider) are
735        // always available from a built provider; explicit registrations win
736        // because the store lookup above runs first.
737        Ok(self
738            .builtin_service_by_type_id(TypeId::of::<T>())
739            .and_then(Self::extract))
740    }
741
742    /// Resolve a service by type. Works uniformly for concrete types and trait objects.
743    /// Returns `Err(RdiError::ServiceNotFound)` if not registered.
744    ///
745    /// [`ScopeFactory`] is always available from a built provider (no manual
746    /// registration required). An explicit `singleton::<dyn ScopeFactory>(...)`
747    /// registration still takes precedence. Later registrations override earlier
748    /// ones (MEDI semantics).
749    pub fn get<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, RdiError> {
750        let type_name = std::any::type_name::<T>();
751        match self.resolve_unkeyed_optional::<T>() {
752            Ok(Some(v)) => Ok(v),
753            Ok(None) => Err(RdiError::not_found(type_name, None)),
754            Err(e) => Err(e),
755        }
756    }
757
758    /// Resolve a service by type, returning `None` if it is not registered **or
759    /// not resolvable at this point** (e.g. a scoped service under root scope
760    /// validation, or a disposed provider). Use [`Self::get`] when you need the
761    /// concrete error.
762    pub fn get_optional<T: ?Sized + Send + Sync + 'static>(&self) -> Option<Arc<T>> {
763        self.resolve_unkeyed_optional::<T>().ok().flatten()
764    }
765
766    /// Resolve an async service (transient or scoped) by type.
767    ///
768    /// - Singletons are resolved synchronously (already cached during `build_async`).
769    /// - Scoped services are cached in this provider's scoped cache (one instance per scope).
770    /// - Transient services call the async factory fresh each time.
771    pub async fn get_async<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, RdiError> {
772        let type_name = std::any::type_name::<T>();
773        let tid = TypeId::of::<T>();
774        let entry = self
775            .unkeyed_entry(tid)
776            .ok_or_else(|| RdiError::not_found(type_name, None))?;
777
778        if entry.lifetime == ServiceLifetime::Singleton {
779            // Building an async singleton is only valid after `build_async`
780            // initialized it. Resolving one during build (e.g. another async
781            // singleton factory awaiting it) yields a clear, actionable error
782            // instead of the generic `AsyncServiceRequiresBuildAsync` panic from
783            // the sync fallback factory.
784            if entry.async_factory.is_some() && self.singleton_cache.get(entry.cache_key).is_none()
785            {
786                return Err(RdiError::FactoryPanic {
787                    service: type_name.to_string(),
788                    payload: format!(
789                        "async singleton '{type_name}' was resolved before its build-time \
790                         initialization completed; async singletons are initialized in \
791                         registration order, so register dependencies before their dependents"
792                    ),
793                });
794            }
795            return self.get::<T>();
796        }
797        self.check_resolvable(entry)?;
798
799        match self.resolve_async_any(entry, type_name).await? {
800            Some(arc_any) => {
801                Self::extract(arc_any).ok_or_else(|| RdiError::not_found(type_name, None))
802            }
803            None => self.get::<T>(),
804        }
805    }
806
807    /// Resolve an async keyed service by type and key.
808    pub async fn get_keyed_async<T: ?Sized + Send + Sync + 'static>(
809        &self,
810        key: &str,
811    ) -> Result<Arc<T>, RdiError> {
812        let type_name = std::any::type_name::<T>();
813        let tid = TypeId::of::<T>();
814        let entry = self
815            .keyed_entry(tid, key)
816            .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
817
818        if entry.lifetime == ServiceLifetime::Singleton {
819            if entry.async_factory.is_some() && self.singleton_cache.get(entry.cache_key).is_none()
820            {
821                return Err(RdiError::FactoryPanic {
822                    service: type_name.to_string(),
823                    payload: format!(
824                        "async singleton '{type_name}' (key '{key}') was resolved before its \
825                         build-time initialization completed; async singletons are initialized \
826                         in registration order, so register dependencies before their dependents"
827                    ),
828                });
829            }
830            return self.get_keyed::<T>(key);
831        }
832        self.check_resolvable(entry)?;
833
834        match self.resolve_async_any(entry, type_name).await? {
835            Some(arc_any) => Self::extract(arc_any)
836                .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None)),
837            None => self.get_keyed::<T>(key),
838        }
839    }
840
841    /// Resolve async Scoped/Transient factory, returning `Some(AnyService)`.
842    /// Returns `None` if the entry has no async factory (caller falls back to the
843    /// synchronous resolution path).
844    ///
845    /// A resolution guard is taken for the duration of the async factory so a
846    /// factory that recursively awaits a service already being resolved returns
847    /// [`RdiError::CircularDependency`] instead of dead-locking on its own cache
848    /// lock. (Detection is thread-local and covers the recursive poll chain; an
849    /// async factory must not recurse into the service it is building.)
850    async fn resolve_async_any(
851        &self,
852        entry: &ServiceEntry,
853        type_name: &'static str,
854    ) -> Result<Option<AnyService>, RdiError> {
855        match entry.lifetime {
856            ServiceLifetime::Scoped => {
857                // Sync-registered scoped service: fall back to the synchronous
858                // path (caller resolves via `get`), preserving mixed sync/async
859                // graphs.
860                let Some(async_factory) = entry.async_factory.clone() else {
861                    return Ok(None);
862                };
863                // Nested self-await would dead-lock on the per-key async lock.
864                check_not_resolving(entry.cache_key, entry.type_name)?;
865                let provider_arc = self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
866                    service: type_name.to_string(),
867                    payload: "provider_arc() returned None for async resolution".into(),
868                })?;
869                poll_guard(
870                    entry.cache_key,
871                    entry.type_name,
872                    self.root_scoped_cache
873                        .get_or_init_with_async(entry.cache_key, || {
874                            Self::run_async_factory_safely(type_name, async_factory, provider_arc)
875                        }),
876                )
877                .await
878                .map(Some)
879            }
880            ServiceLifetime::Transient => {
881                if let Some(async_factory) = entry.async_factory.clone() {
882                    check_not_resolving(entry.cache_key, entry.type_name)?;
883                    let provider_arc =
884                        self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
885                            service: type_name.to_string(),
886                            payload: "provider_arc() returned None for async resolution".into(),
887                        })?;
888                    poll_guard(
889                        entry.cache_key,
890                        entry.type_name,
891                        Self::run_async_factory_safely(type_name, async_factory, provider_arc),
892                    )
893                    .await
894                    .map(Some)
895                } else {
896                    Ok(None)
897                }
898            }
899            _ => Ok(None),
900        }
901    }
902
903    /// Execute an async factory and catch panics, converting to `RdiError::FactoryPanic`.
904    ///
905    /// async 工厂 panic 无法自然传播到 `.await` 点之外(会终止 task),
906    /// 需用 `catch_unwind` 捕获并转为类型安全的 `RdiError`。
907    async fn run_async_factory_safely(
908        type_name: &'static str,
909        async_factory: AsyncServiceFactory,
910        provider_arc: Arc<ServiceProvider>,
911    ) -> Result<AnyService, RdiError> {
912        let fut = async_factory(provider_arc);
913        match futures::FutureExt::catch_unwind(AssertUnwindSafe(fut)).await {
914            Ok(arc_any) => Ok(arc_any),
915            Err(payload) => Err(RdiError::from_panic_payload(type_name, payload)),
916        }
917    }
918
919    /// Resolve a keyed service by type and key.
920    /// Returns `Err(RdiError::KeyedServiceNotFound)` if not found.
921    pub fn get_keyed<T: ?Sized + Send + Sync + 'static>(
922        &self,
923        key: &str,
924    ) -> Result<Arc<T>, RdiError> {
925        let type_name = std::any::type_name::<T>();
926        if let Some(entry) = self.keyed_entry(TypeId::of::<T>(), key) {
927            let any = self.resolve_entry_catching(entry)?;
928            return Self::extract(any)
929                .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None));
930        }
931        Err(RdiError::keyed_not_found(type_name, key, None))
932    }
933
934    /// Resolve owned `T` (bypass cache, fresh each call).
935    /// Returns `Err` if not registered or the service is Singleton.
936    ///
937    /// Owned resolution hands the instance to the caller: it is not tracked by
938    /// the container and stays valid after `dispose`. Scoped ownership bypasses
939    /// the scope cache, so a root scope-validation error is not raised for the
940    /// owned instance itself; its *dependencies* still obey scope validation.
941    pub fn get_owned<T: Send + Sync + 'static>(&self) -> Result<T, RdiError> {
942        let type_name = std::any::type_name::<T>();
943        let tid = TypeId::of::<T>();
944        let entry = self
945            .unkeyed_entry(tid)
946            .ok_or_else(|| RdiError::not_found(type_name, None))?;
947        if entry.lifetime == ServiceLifetime::Singleton {
948            return Err(RdiError::OwnedNotSupported(type_name));
949        }
950        self.check_alive()?;
951        let arc_any = match std::panic::catch_unwind(AssertUnwindSafe(|| {
952            self.create_owned_any_by_entry(entry)
953        })) {
954            Ok(Some(v)) => v,
955            Ok(None) => return Err(RdiError::not_found(type_name, None)),
956            Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
957        };
958        let arc_t = Self::extract(arc_any).ok_or_else(|| RdiError::not_found(type_name, None))?;
959        Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
960    }
961
962    /// Resolve owned `T`, returning `None` if not registered, a Singleton, or the
963    /// provider/scope is disposed.
964    pub fn try_get_owned<T: Send + Sync + 'static>(&self) -> Option<T> {
965        self.get_owned().ok()
966    }
967
968    /// Resolve owned keyed `T`.
969    /// Returns `Err` if not found or Singleton.
970    pub fn get_keyed_owned<T: Send + Sync + 'static>(&self, key: &str) -> Result<T, RdiError> {
971        let type_name = std::any::type_name::<T>();
972        let tid = TypeId::of::<T>();
973        let entry = self
974            .keyed_entry(tid, key)
975            .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
976        if entry.lifetime == ServiceLifetime::Singleton {
977            return Err(RdiError::OwnedNotSupported(type_name));
978        }
979        self.check_alive()?;
980        let arc_any = match std::panic::catch_unwind(AssertUnwindSafe(|| {
981            self.create_owned_any_by_entry(entry)
982        })) {
983            Ok(Some(v)) => v,
984            Ok(None) => return Err(RdiError::keyed_not_found(type_name, key, None)),
985            Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
986        };
987        let arc_t = Self::extract(arc_any)
988            .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
989        Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
990    }
991
992    /// Resolve owned keyed `T`, returning `None` if not found, a Singleton, or
993    /// the provider/scope is disposed.
994    pub fn try_get_keyed_owned<T: Send + Sync + 'static>(&self, key: &str) -> Option<T> {
995        self.get_keyed_owned(key).ok()
996    }
997
998    /// Return all **unkeyed** registered instances of the given type, in
999    /// registration order (MEDI `GetServices<T>()` / `IEnumerable<T>` parity).
1000    ///
1001    /// Keyed implementations are excluded — use [`Self::get_all_keyed`] for
1002    /// those. Under root scope validation, scoped services are not resolvable at
1003    /// the root and are omitted; other resolution failures panic with a typed
1004    /// [`RdiError`] payload (mirroring MEDI, where enumeration throws).
1005    pub fn get_all<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
1006        self.collect_all::<T>(false)
1007    }
1008
1009    /// Return all **keyed** registered instances of the given type, in
1010    /// registration order (MEDI `GetKeyedServices<T>(KeyedService.AnyKey)` parity).
1011    pub fn get_all_keyed<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
1012        self.collect_all::<T>(true)
1013    }
1014
1015    fn collect_all<T: ?Sized + Send + Sync + 'static>(&self, keyed_only: bool) -> Vec<Arc<T>> {
1016        if self.check_alive().is_err() {
1017            return Vec::new();
1018        }
1019        let Some(entries) = self.store.get(&TypeId::of::<T>()) else {
1020            return Vec::new();
1021        };
1022        let mut out = Vec::new();
1023        for entry in entries.iter().filter(|e| e.key.is_some() == keyed_only) {
1024            match self.resolve_entry_catching(entry) {
1025                Ok(any) => {
1026                    if let Some(v) = Self::extract(any) {
1027                        out.push(v);
1028                    }
1029                }
1030                // Root scope validation: scoped services are not resolvable at
1031                // the root, so they do not appear in enumerations.
1032                Err(RdiError::ScopedFromRootProvider { .. }) => {}
1033                Err(err) => std::panic::panic_any(err),
1034            }
1035        }
1036        out
1037    }
1038
1039    /// Create a new service scope.
1040    ///
1041    /// Analogous to `IServiceProvider.CreateScope()` in MEDI.
1042    /// Scoped-lifetime services are cached within the returned scope.
1043    pub fn scope(self: &Arc<Self>) -> crate::scope::Scope {
1044        crate::scope::Scope::new(self.clone())
1045    }
1046
1047    /// Whether `T` has a resolvable registration (or is a built-in container
1048    /// service). MEDI `IServiceProviderIsService` parity.
1049    ///
1050    /// Reports registration state only: it is still `true` after [`Self::dispose`].
1051    pub fn is_registered<T: ?Sized + Send + Sync + 'static>(&self) -> bool {
1052        let tid = TypeId::of::<T>();
1053        self.store
1054            .get(&tid)
1055            .is_some_and(|entries| entries.iter().any(|e| e.key.is_none()))
1056            || tid == TypeId::of::<dyn ScopeFactory>()
1057            || tid == TypeId::of::<ServiceProvider>()
1058    }
1059
1060    /// Whether `T` has a registration under `key`.
1061    pub fn is_registered_keyed<T: ?Sized + Send + Sync + 'static>(&self, key: &str) -> bool {
1062        self.store
1063            .get(&TypeId::of::<T>())
1064            .is_some_and(|entries| entries.iter().any(|e| e.key.as_deref() == Some(key)))
1065    }
1066
1067    /// Built-in `dyn ScopeFactory` singleton for this provider (weak-backed).
1068    fn builtin_scope_factory(&self) -> Option<Arc<dyn ScopeFactory>> {
1069        let weak = self.self_weak.get()?.clone();
1070        Some(Arc::clone(
1071            self.scope_factory_cache
1072                .get_or_init(|| crate::scope::builtin_scope_factory(weak)),
1073        ))
1074    }
1075
1076    fn builtin_scope_factory_any(&self) -> Option<AnyService> {
1077        Some(crate::scope::builtin_scope_factory_any(
1078            self.builtin_scope_factory()?,
1079        ))
1080    }
1081
1082    /// Cached built-in `dyn ScopeFactory` service for the validation resolver.
1083    ///
1084    /// Exposed `pub(crate)` so eager singletons receive the same factory
1085    /// instance as `provider.get::<dyn ScopeFactory>()` (singleton identity).
1086    pub(crate) fn builtin_scope_factory_any_cached(&self) -> Option<AnyService> {
1087        self.builtin_scope_factory_any()
1088    }
1089
1090    /// Resolve container-provided (built-in) services that need no registration.
1091    ///
1092    /// - `dyn ScopeFactory`: weak-backed singleton factory that creates scopes.
1093    /// - `ServiceProvider`: the container itself (MEDI `IServiceProvider` parity),
1094    ///   enabling `#[inject] Arc<ServiceProvider>` in addition to the dedicated
1095    ///   `#[inject(provider)]` field attribute.
1096    fn builtin_service_by_type_id(&self, tid: TypeId) -> Option<AnyService> {
1097        if tid == TypeId::of::<dyn ScopeFactory>() {
1098            return self.builtin_scope_factory_any();
1099        }
1100        if tid == TypeId::of::<ServiceProvider>() {
1101            let provider = self.self_weak.get()?.upgrade()?;
1102            return Some(Arc::new(provider) as AnyService);
1103        }
1104        None
1105    }
1106
1107    /// String-keyed variant of [`Self::builtin_service_by_type_id`] for the
1108    /// `IServiceResolver::get_any` path used by the inject macros.
1109    fn builtin_service_by_name(&self, key: &str) -> Option<AnyService> {
1110        if key == std::any::type_name::<dyn ScopeFactory>() {
1111            return self.builtin_scope_factory_any();
1112        }
1113        if key == std::any::type_name::<ServiceProvider>() {
1114            let provider = self.self_weak.get()?.upgrade()?;
1115            return Some(Arc::new(provider) as AnyService);
1116        }
1117        None
1118    }
1119
1120    pub(crate) fn get_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
1121        reject_build_time_provider_resolution(entry.type_name);
1122        let _guard = match enter_resolve(entry.cache_key, entry.type_name) {
1123            Ok(g) => g,
1124            Err(e) => std::panic::panic_any(e),
1125        };
1126        match entry.lifetime {
1127            ServiceLifetime::Singleton => {
1128                // LazyCache::get_or_init_with:build 阶段已预热的走 fast path,
1129                // 未预热的(交叉引用边缘情况)懒执行工厂并缓存。
1130                // per-key OnceLock 保证多线程下工厂只执行一次,无 TOCTOU 竞态。
1131                // 工厂 panic 时 OnceLock 不缓存(std 行为),下次解析重试。
1132                let factory = entry.factory.clone();
1133                let resolver = self as &dyn IServiceResolver;
1134                Some(
1135                    self.singleton_cache
1136                        .get_or_init_with(entry.cache_key, move || factory(resolver)),
1137                )
1138            }
1139            ServiceLifetime::Scoped => {
1140                let factory = entry.factory.clone();
1141                let resolver = self as &dyn IServiceResolver;
1142                Some(
1143                    self.root_scoped_cache
1144                        .get_or_init_with(entry.cache_key, move || factory(resolver)),
1145                )
1146            }
1147            ServiceLifetime::Transient => Some((entry.factory)(self)),
1148        }
1149    }
1150
1151    /// Bypass cache and invoke the factory fresh (owned resolution only).
1152    ///
1153    /// - Singleton → `None` (shared singleton cannot be owned).
1154    /// - Scoped/Transient → invoke factory directly without touching
1155    ///   `singleton_cache` / scoped cache. The factory uses `self`
1156    ///   (ServiceProvider, i.e. current scope) as resolver, so Scoped
1157    ///   dependencies resolved transitively bind to this provider's scoped cache.
1158    pub(crate) fn create_owned_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
1159        reject_build_time_provider_resolution(entry.type_name);
1160        match entry.lifetime {
1161            ServiceLifetime::Singleton => None,
1162            ServiceLifetime::Scoped | ServiceLifetime::Transient => {
1163                let _guard = match enter_resolve(entry.cache_key, entry.type_name) {
1164                    Ok(g) => g,
1165                    Err(e) => std::panic::panic_any(e),
1166                };
1167                Some((entry.factory)(self as &dyn IServiceResolver))
1168            }
1169        }
1170    }
1171
1172    /// Extract `Arc<T>` from `Arc<Arc<T>>` stored inside `Arc<dyn Any>`.
1173    /// The factory double-wraps: inner `Arc<T>`, outer `Arc<dyn Any>`.
1174    pub(crate) fn extract<T: ?Sized + Send + Sync + 'static>(
1175        arc: Arc<dyn Any + Send + Sync>,
1176    ) -> Option<Arc<T>> {
1177        let double: Arc<Arc<T>> = arc.downcast::<Arc<T>>().ok()?;
1178        Some(Arc::clone(&*double))
1179    }
1180
1181    /// Cross-DLL safe named service resolution (generic).
1182    pub fn get_named<T: Send + Sync + 'static>(&self, name: &str) -> Option<Arc<T>> {
1183        self.named
1184            .read()
1185            .unwrap()
1186            .get(name)?
1187            .clone()
1188            .downcast::<T>()
1189            .ok()
1190    }
1191
1192    /// Non-generic named resolution; returns `Arc<dyn Any>` for trait-object dispatch.
1193    pub fn get_named_any(&self, name: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1194        self.named.read().unwrap().get(name).cloned()
1195    }
1196
1197    /// Register a named service for cross-DLL plugin access.
1198    ///
1199    /// No-op after the provider/scope has been disposed (the named registry is
1200    /// cleared by [`Self::dispose`]).
1201    pub fn register_named<T: Send + Sync + 'static>(&self, name: &str, service: Arc<T>) {
1202        if self.check_alive().is_err() {
1203            return;
1204        }
1205        self.named
1206            .write()
1207            .unwrap()
1208            .insert(name.to_string(), service);
1209    }
1210
1211    /// Remove a named service (for plugin unload).
1212    pub fn remove_named(&self, name: &str) {
1213        if self.check_alive().is_err() {
1214            return;
1215        }
1216        self.named.write().unwrap().remove(name);
1217    }
1218
1219    /// Register a named service (for [`IProvider`](crate::bridge::IProvider) trait).
1220    ///
1221    /// No-op after the provider/scope has been disposed.
1222    pub fn rdi_register_named(&self, name: &str, service: Arc<dyn Any + Send + Sync>) {
1223        if self.check_alive().is_err() {
1224            return;
1225        }
1226        self.named
1227            .write()
1228            .unwrap()
1229            .insert(name.to_string(), service);
1230    }
1231
1232    /// Remove a named service (for [`IProvider`](crate::bridge::IProvider) trait).
1233    pub fn rdi_remove_named(&self, name: &str) {
1234        if self.check_alive().is_err() {
1235            return;
1236        }
1237        self.named.write().unwrap().remove(name);
1238    }
1239
1240    /// Built-in container services resolvable through the trait path, honoring
1241    /// liveness (a disposed provider no longer serves them; the violation is
1242    /// raised as a typed panic so required-resolution APIs convert it to `Err`).
1243    fn builtin_service_checked(&self, key: &str) -> Option<AnyService> {
1244        if let Err(err) = self.check_alive() {
1245            std::panic::panic_any(err);
1246        }
1247        self.builtin_service_by_name(key)
1248    }
1249
1250    fn builtin_service_by_type_id_checked(&self, tid: TypeId) -> Option<AnyService> {
1251        if let Err(err) = self.check_alive() {
1252            std::panic::panic_any(err);
1253        }
1254        self.builtin_service_by_type_id(tid)
1255    }
1256}
1257
1258impl ScopeFactory for ServiceProvider {
1259    fn create_scope(&self) -> crate::scope::Scope {
1260        // 通过 self_weak 获取 Arc<Self>(new() / new_async() 已初始化 self_weak)。
1261        self.self_weak
1262            .get()
1263            .and_then(|w| w.upgrade())
1264            .map(crate::scope::Scope::new)
1265            .expect("ScopeFactory::create_scope: ServiceProvider self_weak not initialized")
1266    }
1267}
1268
1269impl IServiceResolver for ServiceProvider {
1270    fn get_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1271        if let Some(entry) = self.entry_by_str(key, None) {
1272            return Some(self.resolve_entry_panicking(entry));
1273        }
1274        // Built-in services resolve through the string path used by the inject
1275        // macros (`#[inject] Arc<dyn ScopeFactory>`, `Arc<ServiceProvider>`).
1276        self.builtin_service_checked(key)
1277    }
1278
1279    fn get_keyed_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1280        let entry = self.entry_by_str(key, Some(variant))?;
1281        Some(self.resolve_entry_panicking(entry))
1282    }
1283
1284    fn get_by_type_id(&self, tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
1285        if let Some(entry) = self.unkeyed_entry(tid) {
1286            return Some(self.resolve_entry_panicking(entry));
1287        }
1288        self.builtin_service_by_type_id_checked(tid)
1289    }
1290
1291    fn get_keyed_by_type_id(&self, tid: TypeId, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1292        let entry = self.keyed_entry(tid, key)?;
1293        Some(self.resolve_entry_panicking(entry))
1294    }
1295
1296    fn get_all_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
1297        self.collect_all_any(key, false)
1298    }
1299
1300    fn get_all_keyed_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
1301        self.collect_all_any(key, true)
1302    }
1303
1304    fn get_all_any_result(&self, key: &str) -> Result<Vec<Arc<dyn Any + Send + Sync>>, RdiError> {
1305        self.check_alive()?;
1306        let Some(tid) = self.type_map.get(key) else {
1307            return Ok(Vec::new());
1308        };
1309        let Some(entries) = self.store.get(tid) else {
1310            return Ok(Vec::new());
1311        };
1312        let mut out = Vec::new();
1313        for entry in entries.iter().filter(|e| e.key.is_none()) {
1314            out.push(self.resolve_entry_catching(entry)?);
1315        }
1316        Ok(out)
1317    }
1318
1319    fn get_owned_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1320        let entry = self.entry_by_str(key, None)?;
1321        if entry.lifetime == ServiceLifetime::Singleton {
1322            return None;
1323        }
1324        self.check_alive().ok()?;
1325        self.create_owned_any_by_entry(entry)
1326    }
1327
1328    /// Infallible lookup: reports absence instead of panicking for scope
1329    /// violations / disposal (still returns `Err` for factory failures so
1330    /// callers could distinguish, but [`IServiceResolver::try_get`] maps it to
1331    /// `None`).
1332    fn try_get_any_result(&self, key: &str) -> Result<Option<AnyService>, RdiError> {
1333        self.check_alive()?;
1334        if let Some(entry) = self.entry_by_str(key, None) {
1335            return self.resolve_entry_catching(entry).map(Some);
1336        }
1337        Ok(self.builtin_service_by_name(key))
1338    }
1339
1340    /// Keyed variant of [`IServiceResolver::try_get_any_result`].
1341    fn try_get_keyed_any_result(
1342        &self,
1343        key: &str,
1344        variant: &str,
1345    ) -> Result<Option<AnyService>, RdiError> {
1346        self.check_alive()?;
1347        match self.entry_by_str(key, Some(variant)) {
1348            Some(entry) => self.resolve_entry_catching(entry).map(Some),
1349            None => Ok(None),
1350        }
1351    }
1352
1353    fn get_keyed_owned_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1354        let entry = self.entry_by_str(key, Some(variant))?;
1355        if entry.lifetime == ServiceLifetime::Singleton {
1356            return None;
1357        }
1358        self.check_alive().ok()?;
1359        self.create_owned_any_by_entry(entry)
1360    }
1361
1362    fn provider_arc(&self) -> Option<Arc<ServiceProvider>> {
1363        self.self_weak.get().and_then(|w| w.upgrade())
1364    }
1365}
1366
1367impl ServiceProvider {
1368    fn collect_all_any(&self, key: &str, keyed_only: bool) -> Vec<Arc<dyn Any + Send + Sync>> {
1369        if self.check_alive().is_err() {
1370            return Vec::new();
1371        }
1372        let Some(tid) = self.type_map.get(key) else {
1373            return Vec::new();
1374        };
1375        let Some(entries) = self.store.get(tid) else {
1376            return Vec::new();
1377        };
1378        let mut out = Vec::new();
1379        for entry in entries.iter().filter(|e| e.key.is_some() == keyed_only) {
1380            match self.resolve_entry_catching(entry) {
1381                Ok(any) => out.push(any),
1382                Err(RdiError::ScopedFromRootProvider { .. }) => {}
1383                Err(err) => std::panic::panic_any(err),
1384            }
1385        }
1386        out
1387    }
1388}
1389
1390#[cfg(test)]
1391mod tests {
1392    use super::ServiceProviderOptions;
1393    use crate::collection::ServiceCollection;
1394    use std::sync::Arc;
1395
1396    #[derive(Debug, PartialEq)]
1397    struct Calc(i32);
1398    #[test]
1399    fn optional_missing() {
1400        let p = ServiceCollection::new().build().unwrap();
1401        assert!(p.get_optional::<i32>().is_none());
1402    }
1403    #[test]
1404    fn get_all_includes_only_unkeyed() {
1405        let p = ServiceCollection::new()
1406            .keyed_singleton("a", |_| Arc::new(Calc(1)))
1407            .keyed_singleton("b", |_| Arc::new(Calc(2)))
1408            .build()
1409            .unwrap();
1410        assert_eq!(p.get_all::<Calc>().len(), 0, "get_all excludes keyed");
1411        assert_eq!(p.get_all_keyed::<Calc>().len(), 2);
1412    }
1413    #[test]
1414    fn later_registration_wins() {
1415        let p = ServiceCollection::new()
1416            .singleton(|_| Arc::new(Calc(1)))
1417            .singleton(|_| Arc::new(Calc(2)))
1418            .build()
1419            .unwrap();
1420        assert_eq!(
1421            p.get::<Calc>().unwrap().0,
1422            2,
1423            "MEDI: last registration wins"
1424        );
1425    }
1426    #[test]
1427    fn root_scoped_is_rejected_by_default() {
1428        let p = ServiceCollection::new()
1429            .scoped(|_| Arc::new(Calc(9)))
1430            .build()
1431            .unwrap();
1432        match p.get::<Calc>() {
1433            Err(crate::error::RdiError::ScopedFromRootProvider { service }) => {
1434                assert!(service.contains("Calc"));
1435            }
1436            other => panic!("expected ScopedFromRootProvider, got {other:?}"),
1437        }
1438        assert!(p.get_optional::<Calc>().is_none());
1439        assert!(p.get_all::<Calc>().is_empty());
1440    }
1441    #[test]
1442    fn lenient_options_restore_root_scope() {
1443        let p = ServiceCollection::new()
1444            .scoped(|_| Arc::new(Calc(9)))
1445            .build_with(ServiceProviderOptions::lenient())
1446            .unwrap();
1447        assert_eq!(p.get::<Calc>().unwrap().0, 9);
1448        assert!(Arc::ptr_eq(
1449            &p.get::<Calc>().unwrap(),
1450            &p.get::<Calc>().unwrap()
1451        ));
1452    }
1453    #[test]
1454    fn scope_resolution_works_and_is_cached() {
1455        let p = ServiceCollection::new()
1456            .scoped(|_| Arc::new(Calc(3)))
1457            .build()
1458            .unwrap();
1459        let s1 = p.scope();
1460        let a = s1.get::<Calc>().unwrap();
1461        let b = s1.get::<Calc>().unwrap();
1462        assert!(Arc::ptr_eq(&a, &b));
1463        let s2 = p.scope();
1464        assert!(!Arc::ptr_eq(&a, &s2.get::<Calc>().unwrap()));
1465    }
1466    #[test]
1467    fn is_registered_reports_lookup_state() {
1468        let p = ServiceCollection::new()
1469            .singleton(|_| Arc::new(Calc(1)))
1470            .keyed_singleton("k", |_| Arc::new(Calc(2)))
1471            .build()
1472            .unwrap();
1473        assert!(p.is_registered::<Calc>());
1474        assert!(p.is_registered::<crate::ServiceProvider>());
1475        assert!(p.is_registered::<dyn crate::ScopeFactory>());
1476        assert!(!p.is_registered::<String>());
1477        assert!(p.is_registered_keyed::<Calc>("k"));
1478        assert!(!p.is_registered_keyed::<Calc>("missing"));
1479    }
1480    #[test]
1481    fn dispose_is_idempotent_and_blocks_resolution() {
1482        let p = ServiceCollection::new()
1483            .singleton(|_| Arc::new(Calc(1)))
1484            .build()
1485            .unwrap();
1486        p.dispose();
1487        p.dispose();
1488        assert!(matches!(
1489            p.get::<Calc>(),
1490            Err(crate::error::RdiError::ProviderDisposed)
1491        ));
1492        assert!(p.get_optional::<Calc>().is_none());
1493        assert!(p.get_all::<Calc>().is_empty());
1494    }
1495    #[test]
1496    fn dispose_releases_singletons_in_reverse_creation_order() {
1497        use std::sync::Mutex;
1498        static DROPS: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
1499        #[derive(Debug)]
1500        struct Tracked(&'static str);
1501        impl Drop for Tracked {
1502            fn drop(&mut self) {
1503                DROPS.lock().unwrap().push(self.0);
1504            }
1505        }
1506        struct First(#[allow(dead_code)] Arc<Tracked>);
1507        struct Second(#[allow(dead_code)] Arc<Tracked>);
1508
1509        let p = ServiceCollection::new()
1510            .singleton(|_| Arc::new(First(Arc::new(Tracked("first")))))
1511            .singleton(|_| Arc::new(Second(Arc::new(Tracked("second")))))
1512            .build()
1513            .unwrap();
1514        p.dispose();
1515
1516        let drops = DROPS.lock().unwrap().clone();
1517        assert_eq!(
1518            drops,
1519            vec!["second", "first"],
1520            "singletons must be released in reverse creation order"
1521        );
1522    }
1523
1524    #[test]
1525    fn eager_singletons_are_created_in_registration_order() {
1526        use std::sync::Mutex;
1527        static CREATED: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
1528        #[derive(Debug)]
1529        struct A;
1530        #[derive(Debug)]
1531        struct B;
1532        let p = ServiceCollection::new()
1533            .singleton(|_| {
1534                CREATED.lock().unwrap().push("a");
1535                Arc::new(A)
1536            })
1537            .singleton(|_| {
1538                CREATED.lock().unwrap().push("b");
1539                Arc::new(B)
1540            })
1541            .build()
1542            .unwrap();
1543        assert_eq!(
1544            *CREATED.lock().unwrap(),
1545            vec!["a", "b"],
1546            "eager init must be deterministic (registration order)"
1547        );
1548        drop(p);
1549    }
1550
1551    #[test]
1552    fn async_singleton_panic_becomes_typed_error() {
1553        let result = futures::executor::block_on(
1554            ServiceCollection::new()
1555                .async_singleton::<Calc>(|_| Box::pin(async { panic!("boom") }))
1556                .build_async(),
1557        );
1558        match result {
1559            Ok(_) => panic!("build_async must fail when an async singleton factory panics"),
1560            Err(crate::error::RdiError::FactoryPanic { payload, .. }) => {
1561                assert!(payload.contains("boom"), "payload={payload}");
1562            }
1563            Err(other) => panic!("expected FactoryPanic, got {other:?}"),
1564        }
1565    }
1566}