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: initialize async singletons dependency-first.
432        //
433        // Registration order must not matter: an async singleton factory may
434        // `await` another async singleton registered later. `ensure_async_singleton`
435        // recursively initializes dependencies (single-flight, per-poll cycle
436        // detection), so the resulting creation order is a deterministic
437        // dependency-first topological order rather than registration order.
438        let mut async_singletons: Vec<&ServiceEntry> = sp_arc
439            .store
440            .values()
441            .flat_map(|entries| entries.iter())
442            .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_some())
443            .collect();
444        async_singletons.sort_by_key(|e| e.cache_key);
445
446        for entry in async_singletons {
447            sp_arc.ensure_async_singleton(entry).await?;
448        }
449
450        Ok(sp_arc)
451    }
452
453    /// Ensure that an async singleton entry is initialized exactly once.
454    ///
455    /// Dependency-driven and registration-order independent: if a factory
456    /// `await`s an async singleton that has not been initialized yet, the nested
457    /// `get_async` call re-enters this method and recursively initializes the
458    /// dependency first (single-flight via the shared async cache).
459    ///
460    /// Recursive self/cross cycles are detected by the per-poll resolution guard
461    /// and reported as [`RdiError::CircularDependency`] instead of dead-locking.
462    /// Also used as a lazy safety net by `get_async` after build.
463    async fn ensure_async_singleton(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
464        self.check_alive()?;
465        if self.singleton_cache.get(entry.cache_key).is_some() {
466            return Ok(());
467        }
468        let Some(async_factory) = entry.async_factory.clone() else {
469            // Synchronous singleton: already eagerly initialized by build.
470            return Ok(());
471        };
472
473        // Nested self-await would dead-lock on the per-key async cache lock.
474        check_not_resolving(entry.cache_key, entry.type_name)?;
475
476        let key = entry.cache_key;
477        let type_name = entry.type_name;
478        let provider_arc = self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
479            service: type_name.to_string(),
480            payload: "provider_arc() returned None for async singleton initialization".into(),
481        })?;
482
483        self.singleton_cache
484            .get_or_init_with_async(key, || {
485                poll_guard(
486                    key,
487                    type_name,
488                    Self::run_async_factory_safely(type_name, async_factory, provider_arc),
489                )
490            })
491            .await?;
492        Ok(())
493    }
494
495    /// 创建一个 scope 范围的 ServiceProvider,共享 store/type_map/singleton_cache/named,
496    /// 独立 scoped 缓存、disposables 与 self_weak。
497    ///
498    /// 供 [`Scope::new`](crate::scope::Scope::new) 调用。这使 `#[inject(provider)]`
499    /// 字段拿到的是 **scope 范围的 provider** 而非根 provider——经该字段解析 Scoped 服务
500    /// 会命中 scope 自己的 scoped 缓存,符合 MEDI `IServiceScope` 语义。
501    pub(crate) fn new_scope(parent: &Arc<Self>) -> Arc<Self> {
502        let sp = Self {
503            store: Arc::clone(&parent.store),
504            type_map: Arc::clone(&parent.type_map),
505            singleton_cache: Arc::clone(&parent.singleton_cache),
506            root_scoped_cache: LazyCache::new(),
507            named: Arc::clone(&parent.named),
508            self_weak: OnceLock::new(),
509            scope_factory_cache: OnceLock::new(),
510            disposables: Mutex::new(Vec::new()),
511            shared: Arc::clone(&parent.shared),
512            disposed: AtomicBool::new(false),
513            is_root: false,
514            validate_scopes: parent.validate_scopes,
515        };
516        let arc = Arc::new(sp);
517        let this: &Self = &arc;
518        this.self_weak.get_or_init(|| Arc::downgrade(&arc));
519        arc
520    }
521
522    /// Register a cleanup closure for scoped services/owned resources.
523    ///
524    /// Closures run (in **reverse registration order**) when
525    /// [`Self::dispose`] is called — either explicitly or by [`Scope`](crate::Scope)'s
526    /// `Drop` for scope providers.
527    pub fn register_disposable(&self, cleanup: Box<dyn FnOnce() + Send>) {
528        self.disposables.lock().unwrap().push(cleanup);
529    }
530
531    /// Dispose this provider: release cached instances in reverse creation order,
532    /// run registered cleanups in reverse registration order, and mark the
533    /// provider unusable.
534    ///
535    /// - Root provider: also marks the whole provider tree disposed (existing
536    ///   scopes can no longer resolve), drains the singleton cache, and clears
537    ///   named registrations. Singleton instances are released in reverse
538    ///   creation order (LIFO), so dependents drop before their dependencies.
539    /// - Scope provider: releases the scoped instances created in that scope and
540    ///   runs its cleanups. Singletons are untouched.
541    ///
542    /// Idempotent. Instances are released by dropping the container's strong
543    /// references; a service's `Drop` runs when no other owner keeps it alive.
544    /// Services obtained via `get_owned` are caller-owned and are not tracked.
545    ///
546    /// The caller must not resolve services concurrently with disposal (same
547    /// contract as MEDI's `ServiceProvider.Dispose`). A panicking cleanup closure
548    /// does not stop the remaining cleanups; the first panic is re-raised after
549    /// disposal (and swallowed when the thread is already unwinding, e.g. during
550    /// `Scope`'s `Drop`).
551    pub fn dispose(&self) {
552        if self.disposed.swap(true, Ordering::SeqCst) {
553            return;
554        }
555        if self.is_root {
556            self.shared.disposed.store(true, Ordering::SeqCst);
557        }
558
559        // Release instances (reverse LIFO order). User `Drop` panics are
560        // collected so the remaining instances/cleanups still run.
561        let mut first_panic = drop_instances_safely(self.root_scoped_cache.drain_reverse());
562
563        if self.is_root {
564            // Release singletons (reverse creation order) and clear plugins.
565            let singleton_panic = drop_instances_safely(self.singleton_cache.drain_reverse());
566            if first_panic.is_none() {
567                first_panic = singleton_panic;
568            }
569            self.named.write().unwrap().clear();
570        }
571
572        let cleanup_panic = self.run_cleanups();
573        if first_panic.is_none() {
574            first_panic = cleanup_panic;
575        }
576
577        if let Some(payload) = first_panic {
578            if !std::thread::panicking() {
579                std::panic::resume_unwind(payload);
580            }
581        }
582    }
583
584    /// Drain and execute cleanup closures in reverse registration order.
585    ///
586    /// The first cleanup panic is returned to the caller instead of being
587    /// raised here, so disposal can finish all remaining work first. During
588    /// unwinding (drop path) the panic is swallowed to avoid a double-panic
589    /// abort.
590    fn run_cleanups(&self) -> Option<Box<dyn Any + Send>> {
591        let mut cleanups: Vec<Box<dyn FnOnce() + Send>> = {
592            let mut guard = self.disposables.lock().unwrap();
593            std::mem::take(&mut *guard)
594        };
595        cleanups.reverse();
596
597        let mut first_panic: Option<Box<dyn Any + Send>> = None;
598        for cleanup in cleanups {
599            if let Err(payload) = std::panic::catch_unwind(AssertUnwindSafe(cleanup)) {
600                if first_panic.is_none() {
601                    first_panic = Some(payload);
602                }
603            }
604        }
605        first_panic
606    }
607
608    /// Validate all dependencies: detect cycles and captive dependencies.
609    /// Instances built during validation are stored in the provider's singleton
610    /// cache so they can be reused by the subsequent eager-init phase.
611    ///
612    /// Validation runs **after** the provider `Arc` exists: factories may inject
613    /// the provider itself (`#[inject(provider)]`) or the built-in
614    /// [`ScopeFactory`], which requires `provider_arc()` and `self_weak` to be
615    /// live. The validation resolver still executes factories itself, so
616    /// cycle/captive-dependency accounting is preserved.
617    ///
618    /// Validation order is deterministic (sorted by `cache_key` = registration
619    /// index), so the first reported error is stable across runs.
620    fn validate_dependencies(sp: &Arc<Self>) -> Result<(), RdiError> {
621        // Build TypeId → type_name map for error messages
622        let type_names: HashMap<TypeId, &'static str> = sp
623            .store
624            .iter()
625            .map(|(&tid, entries)| {
626                let name = entries.first().map(|e| e.type_name).unwrap_or("<unknown>");
627                (tid, name)
628            })
629            .collect();
630
631        let mut singletons: Vec<&ServiceEntry> = sp
632            .store
633            .values()
634            .flat_map(|entries| entries.iter())
635            .filter(|e| e.lifetime == ServiceLifetime::Singleton && e.async_factory.is_none())
636            .collect();
637        singletons.sort_by_key(|e| e.cache_key);
638
639        // Validate each sync singleton by attempting to resolve it.
640        // Scoped/Transient are not eagerly executed at build (avoids side effects);
641        // their cycles are detected at runtime via a thread-local resolution stack.
642        //
643        // Each registration is validated individually: duplicate registrations
644        // (MEDI override semantics) are all constructed eagerly, and each factory
645        // must pass the cycle/captive checks under its own cache key.
646        for entry in singletons {
647            let resolver = ValidationResolver::new(
648                &sp.store,
649                &type_names,
650                &sp.singleton_cache,
651                Arc::clone(sp),
652            );
653            let type_name = entry.type_name;
654
655            let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
656                resolver.validate_entry(entry)
657            }));
658
659            if let Some(err) = resolver.take_error() {
660                return Err(err);
661            }
662
663            match result {
664                Ok(_) => {}
665                Err(panic_info) => {
666                    return Err(RdiError::from_panic_payload(type_name, panic_info));
667                }
668            }
669        }
670
671        Ok(())
672    }
673
674    // ── Registration lookup (single-service resolution: last registration wins) ──
675
676    /// Last unkeyed registration for `tid` (MEDI: later registrations override
677    /// earlier ones when resolving a single service).
678    fn unkeyed_entry(&self, tid: TypeId) -> Option<&ServiceEntry> {
679        self.store.get(&tid)?.iter().rev().find(|e| e.key.is_none())
680    }
681
682    /// Last registration for `tid` + `key` (same-key duplicates: last wins).
683    fn keyed_entry(&self, tid: TypeId, key: &str) -> Option<&ServiceEntry> {
684        self.store
685            .get(&tid)?
686            .iter()
687            .rev()
688            .find(|e| e.key.as_deref() == Some(key))
689    }
690
691    fn entry_by_str(&self, type_name: &str, key: Option<&str>) -> Option<&ServiceEntry> {
692        let tid = *self.type_map.get(type_name)?;
693        match key {
694            Some(k) => self.keyed_entry(tid, k),
695            None => self.unkeyed_entry(tid),
696        }
697    }
698
699    // ── Liveness / scope validation ──
700
701    /// Whether this provider (or its root) has been disposed.
702    fn check_alive(&self) -> Result<(), RdiError> {
703        if self.shared.disposed.load(Ordering::SeqCst) {
704            return Err(RdiError::ProviderDisposed);
705        }
706        if self.disposed.load(Ordering::SeqCst) {
707            return Err(RdiError::ScopeDisposed);
708        }
709        Ok(())
710    }
711
712    /// MEDI `ValidateScopes` equivalent: a scoped service must not be resolved
713    /// from the root provider (it would be cached for the container lifetime).
714    fn check_scope_validation(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
715        if entry.lifetime == ServiceLifetime::Scoped && self.is_root && self.validate_scopes {
716            return Err(RdiError::ScopedFromRootProvider {
717                service: entry.type_name.to_string(),
718            });
719        }
720        Ok(())
721    }
722
723    fn check_resolvable(&self, entry: &ServiceEntry) -> Result<(), RdiError> {
724        self.check_alive()?;
725        self.check_scope_validation(entry)
726    }
727
728    // ── Resolution cores ──
729
730    /// Resolve a single entry, converting liveness/scope violations, cycles and
731    /// factory panics into typed [`RdiError`].
732    fn resolve_entry_catching(&self, entry: &ServiceEntry) -> Result<AnyService, RdiError> {
733        self.check_resolvable(entry)?;
734        match std::panic::catch_unwind(AssertUnwindSafe(|| self.get_any_by_entry(entry))) {
735            Ok(Some(v)) => Ok(v),
736            Ok(None) => Err(RdiError::not_found(entry.type_name, None)),
737            Err(payload) => Err(RdiError::from_panic_payload(entry.type_name, payload)),
738        }
739    }
740
741    /// Resolve a single entry, panicking with a typed [`RdiError`] on liveness or
742    /// scope violations (used by [`IServiceResolver`], whose contract is
743    /// infallible `Option`; required-resolution APIs catch these panics and
744    /// return `Err`).
745    fn resolve_entry_panicking(&self, entry: &ServiceEntry) -> AnyService {
746        if let Err(err) = self.check_resolvable(entry) {
747            std::panic::panic_any(err);
748        }
749        match self.get_any_by_entry(entry) {
750            Some(v) => v,
751            None => std::panic::panic_any(RdiError::not_found(entry.type_name, None)),
752        }
753    }
754
755    /// Type-erased resolution by type name, for the resolver trait.
756    ///
757    /// Single-service semantics: **last registration wins** (MEDI), both for
758    /// unkeyed and for same-key keyed registrations.
759    fn resolve_unkeyed_optional<T: ?Sized + Send + Sync + 'static>(
760        &self,
761    ) -> Result<Option<Arc<T>>, RdiError> {
762        self.check_alive()?;
763        if let Some(entry) = self.unkeyed_entry(TypeId::of::<T>()) {
764            return Ok(Self::extract(self.resolve_entry_catching(entry)?));
765        }
766        // Built-in container services (ScopeFactory / ServiceProvider) are
767        // always available from a built provider; explicit registrations win
768        // because the store lookup above runs first.
769        Ok(self
770            .builtin_service_by_type_id(TypeId::of::<T>())
771            .and_then(Self::extract))
772    }
773
774    /// Resolve a service by type. Works uniformly for concrete types and trait objects.
775    /// Returns `Err(RdiError::ServiceNotFound)` if not registered.
776    ///
777    /// [`ScopeFactory`] is always available from a built provider (no manual
778    /// registration required). An explicit `singleton::<dyn ScopeFactory>(...)`
779    /// registration still takes precedence. Later registrations override earlier
780    /// ones (MEDI semantics).
781    pub fn get<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, RdiError> {
782        let type_name = std::any::type_name::<T>();
783        match self.resolve_unkeyed_optional::<T>() {
784            Ok(Some(v)) => Ok(v),
785            Ok(None) => Err(RdiError::not_found(type_name, None)),
786            Err(e) => Err(e),
787        }
788    }
789
790    /// Resolve a service by type, returning `None` if it is not registered **or
791    /// not resolvable at this point** (e.g. a scoped service under root scope
792    /// validation, or a disposed provider). Use [`Self::get`] when you need the
793    /// concrete error.
794    pub fn get_optional<T: ?Sized + Send + Sync + 'static>(&self) -> Option<Arc<T>> {
795        self.resolve_unkeyed_optional::<T>().ok().flatten()
796    }
797
798    /// Resolve an async service (transient or scoped) by type.
799    ///
800    /// - Singletons are resolved synchronously (already cached during `build_async`).
801    /// - Scoped services are cached in this provider's scoped cache (one instance per scope).
802    /// - Transient services call the async factory fresh each time.
803    pub async fn get_async<T: ?Sized + Send + Sync + 'static>(&self) -> Result<Arc<T>, RdiError> {
804        let type_name = std::any::type_name::<T>();
805        let tid = TypeId::of::<T>();
806        let entry = self
807            .unkeyed_entry(tid)
808            .ok_or_else(|| RdiError::not_found(type_name, None))?;
809
810        if entry.lifetime == ServiceLifetime::Singleton {
811            // Async singletons are initialized dependency-first; this is also a
812            // lazy safety net after build. Registration order is irrelevant.
813            self.ensure_async_singleton(entry).await?;
814            return self.get::<T>();
815        }
816        self.check_resolvable(entry)?;
817
818        match self.resolve_async_any(entry, type_name).await? {
819            Some(arc_any) => {
820                Self::extract(arc_any).ok_or_else(|| RdiError::not_found(type_name, None))
821            }
822            None => self.get::<T>(),
823        }
824    }
825
826    /// Resolve an async keyed service by type and key.
827    pub async fn get_keyed_async<T: ?Sized + Send + Sync + 'static>(
828        &self,
829        key: &str,
830    ) -> Result<Arc<T>, RdiError> {
831        let type_name = std::any::type_name::<T>();
832        let tid = TypeId::of::<T>();
833        let entry = self
834            .keyed_entry(tid, key)
835            .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
836
837        if entry.lifetime == ServiceLifetime::Singleton {
838            self.ensure_async_singleton(entry).await?;
839            return self.get_keyed::<T>(key);
840        }
841        self.check_resolvable(entry)?;
842
843        match self.resolve_async_any(entry, type_name).await? {
844            Some(arc_any) => Self::extract(arc_any)
845                .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None)),
846            None => self.get_keyed::<T>(key),
847        }
848    }
849
850    /// Resolve async Scoped/Transient factory, returning `Some(AnyService)`.
851    /// Returns `None` if the entry has no async factory (caller falls back to the
852    /// synchronous resolution path).
853    ///
854    /// A resolution guard is taken for the duration of the async factory so a
855    /// factory that recursively awaits a service already being resolved returns
856    /// [`RdiError::CircularDependency`] instead of dead-locking on its own cache
857    /// lock. (Detection is thread-local and covers the recursive poll chain; an
858    /// async factory must not recurse into the service it is building.)
859    async fn resolve_async_any(
860        &self,
861        entry: &ServiceEntry,
862        type_name: &'static str,
863    ) -> Result<Option<AnyService>, RdiError> {
864        match entry.lifetime {
865            ServiceLifetime::Scoped => {
866                // Sync-registered scoped service: fall back to the synchronous
867                // path (caller resolves via `get`), preserving mixed sync/async
868                // graphs.
869                let Some(async_factory) = entry.async_factory.clone() else {
870                    return Ok(None);
871                };
872                // Nested self-await would dead-lock on the per-key async lock.
873                check_not_resolving(entry.cache_key, entry.type_name)?;
874                let provider_arc = self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
875                    service: type_name.to_string(),
876                    payload: "provider_arc() returned None for async resolution".into(),
877                })?;
878                poll_guard(
879                    entry.cache_key,
880                    entry.type_name,
881                    self.root_scoped_cache
882                        .get_or_init_with_async(entry.cache_key, || {
883                            Self::run_async_factory_safely(type_name, async_factory, provider_arc)
884                        }),
885                )
886                .await
887                .map(Some)
888            }
889            ServiceLifetime::Transient => {
890                if let Some(async_factory) = entry.async_factory.clone() {
891                    check_not_resolving(entry.cache_key, entry.type_name)?;
892                    let provider_arc =
893                        self.provider_arc().ok_or_else(|| RdiError::FactoryPanic {
894                            service: type_name.to_string(),
895                            payload: "provider_arc() returned None for async resolution".into(),
896                        })?;
897                    poll_guard(
898                        entry.cache_key,
899                        entry.type_name,
900                        Self::run_async_factory_safely(type_name, async_factory, provider_arc),
901                    )
902                    .await
903                    .map(Some)
904                } else {
905                    Ok(None)
906                }
907            }
908            _ => Ok(None),
909        }
910    }
911
912    /// Execute an async factory and catch panics, converting to `RdiError::FactoryPanic`.
913    ///
914    /// async 工厂 panic 无法自然传播到 `.await` 点之外(会终止 task),
915    /// 需用 `catch_unwind` 捕获并转为类型安全的 `RdiError`。
916    async fn run_async_factory_safely(
917        type_name: &'static str,
918        async_factory: AsyncServiceFactory,
919        provider_arc: Arc<ServiceProvider>,
920    ) -> Result<AnyService, RdiError> {
921        let fut = async_factory(provider_arc);
922        match futures::FutureExt::catch_unwind(AssertUnwindSafe(fut)).await {
923            Ok(arc_any) => Ok(arc_any),
924            Err(payload) => Err(RdiError::from_panic_payload(type_name, payload)),
925        }
926    }
927
928    /// Resolve a keyed service by type and key.
929    /// Returns `Err(RdiError::KeyedServiceNotFound)` if not found.
930    pub fn get_keyed<T: ?Sized + Send + Sync + 'static>(
931        &self,
932        key: &str,
933    ) -> Result<Arc<T>, RdiError> {
934        let type_name = std::any::type_name::<T>();
935        if let Some(entry) = self.keyed_entry(TypeId::of::<T>(), key) {
936            let any = self.resolve_entry_catching(entry)?;
937            return Self::extract(any)
938                .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None));
939        }
940        Err(RdiError::keyed_not_found(type_name, key, None))
941    }
942
943    /// Resolve owned `T` (bypass cache, fresh each call).
944    /// Returns `Err` if not registered or the service is Singleton.
945    ///
946    /// Owned resolution hands the instance to the caller: it is not tracked by
947    /// the container and stays valid after `dispose`. Scoped ownership bypasses
948    /// the scope cache, so a root scope-validation error is not raised for the
949    /// owned instance itself; its *dependencies* still obey scope validation.
950    pub fn get_owned<T: Send + Sync + 'static>(&self) -> Result<T, RdiError> {
951        let type_name = std::any::type_name::<T>();
952        let tid = TypeId::of::<T>();
953        let entry = self
954            .unkeyed_entry(tid)
955            .ok_or_else(|| RdiError::not_found(type_name, None))?;
956        if entry.lifetime == ServiceLifetime::Singleton {
957            return Err(RdiError::OwnedNotSupported(type_name));
958        }
959        self.check_alive()?;
960        let arc_any = match std::panic::catch_unwind(AssertUnwindSafe(|| {
961            self.create_owned_any_by_entry(entry)
962        })) {
963            Ok(Some(v)) => v,
964            Ok(None) => return Err(RdiError::not_found(type_name, None)),
965            Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
966        };
967        let arc_t = Self::extract(arc_any).ok_or_else(|| RdiError::not_found(type_name, None))?;
968        Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
969    }
970
971    /// Resolve owned `T`, returning `None` if not registered, a Singleton, or the
972    /// provider/scope is disposed.
973    pub fn try_get_owned<T: Send + Sync + 'static>(&self) -> Option<T> {
974        self.get_owned().ok()
975    }
976
977    /// Resolve owned keyed `T`.
978    /// Returns `Err` if not found or Singleton.
979    pub fn get_keyed_owned<T: Send + Sync + 'static>(&self, key: &str) -> Result<T, RdiError> {
980        let type_name = std::any::type_name::<T>();
981        let tid = TypeId::of::<T>();
982        let entry = self
983            .keyed_entry(tid, key)
984            .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
985        if entry.lifetime == ServiceLifetime::Singleton {
986            return Err(RdiError::OwnedNotSupported(type_name));
987        }
988        self.check_alive()?;
989        let arc_any = match std::panic::catch_unwind(AssertUnwindSafe(|| {
990            self.create_owned_any_by_entry(entry)
991        })) {
992            Ok(Some(v)) => v,
993            Ok(None) => return Err(RdiError::keyed_not_found(type_name, key, None)),
994            Err(payload) => return Err(RdiError::from_panic_payload(type_name, payload)),
995        };
996        let arc_t = Self::extract(arc_any)
997            .ok_or_else(|| RdiError::keyed_not_found(type_name, key, None))?;
998        Arc::try_unwrap(arc_t).map_err(|_| RdiError::OwnedNotSupported(type_name))
999    }
1000
1001    /// Resolve owned keyed `T`, returning `None` if not found, a Singleton, or
1002    /// the provider/scope is disposed.
1003    pub fn try_get_keyed_owned<T: Send + Sync + 'static>(&self, key: &str) -> Option<T> {
1004        self.get_keyed_owned(key).ok()
1005    }
1006
1007    /// Return all **unkeyed** registered instances of the given type, in
1008    /// registration order (MEDI `GetServices<T>()` / `IEnumerable<T>` parity).
1009    ///
1010    /// Keyed implementations are excluded — use [`Self::get_all_keyed`] for
1011    /// those. Under root scope validation, scoped services are not resolvable at
1012    /// the root and are omitted; other resolution failures panic with a typed
1013    /// [`RdiError`] payload (mirroring MEDI, where enumeration throws).
1014    pub fn get_all<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
1015        self.collect_all::<T>(false)
1016    }
1017
1018    /// Return all **keyed** registered instances of the given type, in
1019    /// registration order (MEDI `GetKeyedServices<T>(KeyedService.AnyKey)` parity).
1020    pub fn get_all_keyed<T: ?Sized + Send + Sync + 'static>(&self) -> Vec<Arc<T>> {
1021        self.collect_all::<T>(true)
1022    }
1023
1024    fn collect_all<T: ?Sized + Send + Sync + 'static>(&self, keyed_only: bool) -> Vec<Arc<T>> {
1025        if self.check_alive().is_err() {
1026            return Vec::new();
1027        }
1028        let Some(entries) = self.store.get(&TypeId::of::<T>()) else {
1029            return Vec::new();
1030        };
1031        let mut out = Vec::new();
1032        for entry in entries.iter().filter(|e| e.key.is_some() == keyed_only) {
1033            match self.resolve_entry_catching(entry) {
1034                Ok(any) => {
1035                    if let Some(v) = Self::extract(any) {
1036                        out.push(v);
1037                    }
1038                }
1039                // Root scope validation: scoped services are not resolvable at
1040                // the root, so they do not appear in enumerations.
1041                Err(RdiError::ScopedFromRootProvider { .. }) => {}
1042                Err(err) => std::panic::panic_any(err),
1043            }
1044        }
1045        out
1046    }
1047
1048    /// Create a new service scope.
1049    ///
1050    /// Analogous to `IServiceProvider.CreateScope()` in MEDI.
1051    /// Scoped-lifetime services are cached within the returned scope.
1052    pub fn scope(self: &Arc<Self>) -> crate::scope::Scope {
1053        crate::scope::Scope::new(self.clone())
1054    }
1055
1056    /// Whether `T` has a resolvable registration (or is a built-in container
1057    /// service). MEDI `IServiceProviderIsService` parity.
1058    ///
1059    /// Reports registration state only: it is still `true` after [`Self::dispose`].
1060    pub fn is_registered<T: ?Sized + Send + Sync + 'static>(&self) -> bool {
1061        let tid = TypeId::of::<T>();
1062        self.store
1063            .get(&tid)
1064            .is_some_and(|entries| entries.iter().any(|e| e.key.is_none()))
1065            || tid == TypeId::of::<dyn ScopeFactory>()
1066            || tid == TypeId::of::<ServiceProvider>()
1067    }
1068
1069    /// Whether `T` has a registration under `key`.
1070    pub fn is_registered_keyed<T: ?Sized + Send + Sync + 'static>(&self, key: &str) -> bool {
1071        self.store
1072            .get(&TypeId::of::<T>())
1073            .is_some_and(|entries| entries.iter().any(|e| e.key.as_deref() == Some(key)))
1074    }
1075
1076    /// Built-in `dyn ScopeFactory` singleton for this provider (weak-backed).
1077    fn builtin_scope_factory(&self) -> Option<Arc<dyn ScopeFactory>> {
1078        let weak = self.self_weak.get()?.clone();
1079        Some(Arc::clone(
1080            self.scope_factory_cache
1081                .get_or_init(|| crate::scope::builtin_scope_factory(weak)),
1082        ))
1083    }
1084
1085    fn builtin_scope_factory_any(&self) -> Option<AnyService> {
1086        Some(crate::scope::builtin_scope_factory_any(
1087            self.builtin_scope_factory()?,
1088        ))
1089    }
1090
1091    /// Cached built-in `dyn ScopeFactory` service for the validation resolver.
1092    ///
1093    /// Exposed `pub(crate)` so eager singletons receive the same factory
1094    /// instance as `provider.get::<dyn ScopeFactory>()` (singleton identity).
1095    pub(crate) fn builtin_scope_factory_any_cached(&self) -> Option<AnyService> {
1096        self.builtin_scope_factory_any()
1097    }
1098
1099    /// Resolve container-provided (built-in) services that need no registration.
1100    ///
1101    /// - `dyn ScopeFactory`: weak-backed singleton factory that creates scopes.
1102    /// - `ServiceProvider`: the container itself (MEDI `IServiceProvider` parity),
1103    ///   enabling `#[inject] Arc<ServiceProvider>` in addition to the dedicated
1104    ///   `#[inject(provider)]` field attribute.
1105    fn builtin_service_by_type_id(&self, tid: TypeId) -> Option<AnyService> {
1106        if tid == TypeId::of::<dyn ScopeFactory>() {
1107            return self.builtin_scope_factory_any();
1108        }
1109        if tid == TypeId::of::<ServiceProvider>() {
1110            let provider = self.self_weak.get()?.upgrade()?;
1111            return Some(Arc::new(provider) as AnyService);
1112        }
1113        None
1114    }
1115
1116    /// String-keyed variant of [`Self::builtin_service_by_type_id`] for the
1117    /// `IServiceResolver::get_any` path used by the inject macros.
1118    fn builtin_service_by_name(&self, key: &str) -> Option<AnyService> {
1119        if key == std::any::type_name::<dyn ScopeFactory>() {
1120            return self.builtin_scope_factory_any();
1121        }
1122        if key == std::any::type_name::<ServiceProvider>() {
1123            let provider = self.self_weak.get()?.upgrade()?;
1124            return Some(Arc::new(provider) as AnyService);
1125        }
1126        None
1127    }
1128
1129    pub(crate) fn get_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
1130        reject_build_time_provider_resolution(entry.type_name);
1131        let _guard = match enter_resolve(entry.cache_key, entry.type_name) {
1132            Ok(g) => g,
1133            Err(e) => std::panic::panic_any(e),
1134        };
1135        match entry.lifetime {
1136            ServiceLifetime::Singleton => {
1137                // LazyCache::get_or_init_with:build 阶段已预热的走 fast path,
1138                // 未预热的(交叉引用边缘情况)懒执行工厂并缓存。
1139                // per-key OnceLock 保证多线程下工厂只执行一次,无 TOCTOU 竞态。
1140                // 工厂 panic 时 OnceLock 不缓存(std 行为),下次解析重试。
1141                let factory = entry.factory.clone();
1142                let resolver = self as &dyn IServiceResolver;
1143                Some(
1144                    self.singleton_cache
1145                        .get_or_init_with(entry.cache_key, move || factory(resolver)),
1146                )
1147            }
1148            ServiceLifetime::Scoped => {
1149                let factory = entry.factory.clone();
1150                let resolver = self as &dyn IServiceResolver;
1151                Some(
1152                    self.root_scoped_cache
1153                        .get_or_init_with(entry.cache_key, move || factory(resolver)),
1154                )
1155            }
1156            ServiceLifetime::Transient => Some((entry.factory)(self)),
1157        }
1158    }
1159
1160    /// Bypass cache and invoke the factory fresh (owned resolution only).
1161    ///
1162    /// - Singleton → `None` (shared singleton cannot be owned).
1163    /// - Scoped/Transient → invoke factory directly without touching
1164    ///   `singleton_cache` / scoped cache. The factory uses `self`
1165    ///   (ServiceProvider, i.e. current scope) as resolver, so Scoped
1166    ///   dependencies resolved transitively bind to this provider's scoped cache.
1167    pub(crate) fn create_owned_any_by_entry(&self, entry: &ServiceEntry) -> Option<AnyService> {
1168        reject_build_time_provider_resolution(entry.type_name);
1169        match entry.lifetime {
1170            ServiceLifetime::Singleton => None,
1171            ServiceLifetime::Scoped | ServiceLifetime::Transient => {
1172                let _guard = match enter_resolve(entry.cache_key, entry.type_name) {
1173                    Ok(g) => g,
1174                    Err(e) => std::panic::panic_any(e),
1175                };
1176                Some((entry.factory)(self as &dyn IServiceResolver))
1177            }
1178        }
1179    }
1180
1181    /// Extract `Arc<T>` from `Arc<Arc<T>>` stored inside `Arc<dyn Any>`.
1182    /// The factory double-wraps: inner `Arc<T>`, outer `Arc<dyn Any>`.
1183    pub(crate) fn extract<T: ?Sized + Send + Sync + 'static>(
1184        arc: Arc<dyn Any + Send + Sync>,
1185    ) -> Option<Arc<T>> {
1186        let double: Arc<Arc<T>> = arc.downcast::<Arc<T>>().ok()?;
1187        Some(Arc::clone(&*double))
1188    }
1189
1190    /// Cross-DLL safe named service resolution (generic).
1191    pub fn get_named<T: Send + Sync + 'static>(&self, name: &str) -> Option<Arc<T>> {
1192        self.named
1193            .read()
1194            .unwrap()
1195            .get(name)?
1196            .clone()
1197            .downcast::<T>()
1198            .ok()
1199    }
1200
1201    /// Non-generic named resolution; returns `Arc<dyn Any>` for trait-object dispatch.
1202    pub fn get_named_any(&self, name: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1203        self.named.read().unwrap().get(name).cloned()
1204    }
1205
1206    /// Register a named service for cross-DLL plugin access.
1207    ///
1208    /// No-op after the provider/scope has been disposed (the named registry is
1209    /// cleared by [`Self::dispose`]).
1210    pub fn register_named<T: Send + Sync + 'static>(&self, name: &str, service: Arc<T>) {
1211        if self.check_alive().is_err() {
1212            return;
1213        }
1214        self.named
1215            .write()
1216            .unwrap()
1217            .insert(name.to_string(), service);
1218    }
1219
1220    /// Remove a named service (for plugin unload).
1221    pub fn remove_named(&self, name: &str) {
1222        if self.check_alive().is_err() {
1223            return;
1224        }
1225        self.named.write().unwrap().remove(name);
1226    }
1227
1228    /// Register a named service (for [`IProvider`](crate::bridge::IProvider) trait).
1229    ///
1230    /// No-op after the provider/scope has been disposed.
1231    pub fn rdi_register_named(&self, name: &str, service: Arc<dyn Any + Send + Sync>) {
1232        if self.check_alive().is_err() {
1233            return;
1234        }
1235        self.named
1236            .write()
1237            .unwrap()
1238            .insert(name.to_string(), service);
1239    }
1240
1241    /// Remove a named service (for [`IProvider`](crate::bridge::IProvider) trait).
1242    pub fn rdi_remove_named(&self, name: &str) {
1243        if self.check_alive().is_err() {
1244            return;
1245        }
1246        self.named.write().unwrap().remove(name);
1247    }
1248
1249    /// Built-in container services resolvable through the trait path, honoring
1250    /// liveness (a disposed provider no longer serves them; the violation is
1251    /// raised as a typed panic so required-resolution APIs convert it to `Err`).
1252    fn builtin_service_checked(&self, key: &str) -> Option<AnyService> {
1253        if let Err(err) = self.check_alive() {
1254            std::panic::panic_any(err);
1255        }
1256        self.builtin_service_by_name(key)
1257    }
1258
1259    fn builtin_service_by_type_id_checked(&self, tid: TypeId) -> Option<AnyService> {
1260        if let Err(err) = self.check_alive() {
1261            std::panic::panic_any(err);
1262        }
1263        self.builtin_service_by_type_id(tid)
1264    }
1265}
1266
1267impl ScopeFactory for ServiceProvider {
1268    fn create_scope(&self) -> crate::scope::Scope {
1269        // 通过 self_weak 获取 Arc<Self>(new() / new_async() 已初始化 self_weak)。
1270        self.self_weak
1271            .get()
1272            .and_then(|w| w.upgrade())
1273            .map(crate::scope::Scope::new)
1274            .expect("ScopeFactory::create_scope: ServiceProvider self_weak not initialized")
1275    }
1276}
1277
1278impl IServiceResolver for ServiceProvider {
1279    fn get_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1280        if let Some(entry) = self.entry_by_str(key, None) {
1281            return Some(self.resolve_entry_panicking(entry));
1282        }
1283        // Built-in services resolve through the string path used by the inject
1284        // macros (`#[inject] Arc<dyn ScopeFactory>`, `Arc<ServiceProvider>`).
1285        self.builtin_service_checked(key)
1286    }
1287
1288    fn get_keyed_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1289        let entry = self.entry_by_str(key, Some(variant))?;
1290        Some(self.resolve_entry_panicking(entry))
1291    }
1292
1293    fn get_by_type_id(&self, tid: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
1294        if let Some(entry) = self.unkeyed_entry(tid) {
1295            return Some(self.resolve_entry_panicking(entry));
1296        }
1297        self.builtin_service_by_type_id_checked(tid)
1298    }
1299
1300    fn get_keyed_by_type_id(&self, tid: TypeId, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1301        let entry = self.keyed_entry(tid, key)?;
1302        Some(self.resolve_entry_panicking(entry))
1303    }
1304
1305    fn get_all_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
1306        self.collect_all_any(key, false)
1307    }
1308
1309    fn get_all_keyed_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>> {
1310        self.collect_all_any(key, true)
1311    }
1312
1313    fn get_all_any_result(&self, key: &str) -> Result<Vec<Arc<dyn Any + Send + Sync>>, RdiError> {
1314        self.check_alive()?;
1315        let Some(tid) = self.type_map.get(key) else {
1316            return Ok(Vec::new());
1317        };
1318        let Some(entries) = self.store.get(tid) else {
1319            return Ok(Vec::new());
1320        };
1321        let mut out = Vec::new();
1322        for entry in entries.iter().filter(|e| e.key.is_none()) {
1323            out.push(self.resolve_entry_catching(entry)?);
1324        }
1325        Ok(out)
1326    }
1327
1328    fn get_owned_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1329        let entry = self.entry_by_str(key, None)?;
1330        if entry.lifetime == ServiceLifetime::Singleton {
1331            return None;
1332        }
1333        self.check_alive().ok()?;
1334        self.create_owned_any_by_entry(entry)
1335    }
1336
1337    /// Infallible lookup: reports absence instead of panicking for scope
1338    /// violations / disposal (still returns `Err` for factory failures so
1339    /// callers could distinguish, but [`IServiceResolver::try_get`] maps it to
1340    /// `None`).
1341    fn try_get_any_result(&self, key: &str) -> Result<Option<AnyService>, RdiError> {
1342        self.check_alive()?;
1343        if let Some(entry) = self.entry_by_str(key, None) {
1344            return self.resolve_entry_catching(entry).map(Some);
1345        }
1346        Ok(self.builtin_service_by_name(key))
1347    }
1348
1349    /// Keyed variant of [`IServiceResolver::try_get_any_result`].
1350    fn try_get_keyed_any_result(
1351        &self,
1352        key: &str,
1353        variant: &str,
1354    ) -> Result<Option<AnyService>, RdiError> {
1355        self.check_alive()?;
1356        match self.entry_by_str(key, Some(variant)) {
1357            Some(entry) => self.resolve_entry_catching(entry).map(Some),
1358            None => Ok(None),
1359        }
1360    }
1361
1362    fn get_keyed_owned_any(&self, key: &str, variant: &str) -> Option<Arc<dyn Any + Send + Sync>> {
1363        let entry = self.entry_by_str(key, Some(variant))?;
1364        if entry.lifetime == ServiceLifetime::Singleton {
1365            return None;
1366        }
1367        self.check_alive().ok()?;
1368        self.create_owned_any_by_entry(entry)
1369    }
1370
1371    fn provider_arc(&self) -> Option<Arc<ServiceProvider>> {
1372        self.self_weak.get().and_then(|w| w.upgrade())
1373    }
1374}
1375
1376impl ServiceProvider {
1377    fn collect_all_any(&self, key: &str, keyed_only: bool) -> Vec<Arc<dyn Any + Send + Sync>> {
1378        if self.check_alive().is_err() {
1379            return Vec::new();
1380        }
1381        let Some(tid) = self.type_map.get(key) else {
1382            return Vec::new();
1383        };
1384        let Some(entries) = self.store.get(tid) else {
1385            return Vec::new();
1386        };
1387        let mut out = Vec::new();
1388        for entry in entries.iter().filter(|e| e.key.is_some() == keyed_only) {
1389            match self.resolve_entry_catching(entry) {
1390                Ok(any) => out.push(any),
1391                Err(RdiError::ScopedFromRootProvider { .. }) => {}
1392                Err(err) => std::panic::panic_any(err),
1393            }
1394        }
1395        out
1396    }
1397}
1398
1399#[cfg(test)]
1400mod tests {
1401    use super::ServiceProviderOptions;
1402    use crate::collection::ServiceCollection;
1403    use std::sync::Arc;
1404
1405    #[derive(Debug, PartialEq)]
1406    struct Calc(i32);
1407    #[test]
1408    fn optional_missing() {
1409        let p = ServiceCollection::new().build().unwrap();
1410        assert!(p.get_optional::<i32>().is_none());
1411    }
1412    #[test]
1413    fn get_all_includes_only_unkeyed() {
1414        let p = ServiceCollection::new()
1415            .keyed_singleton("a", |_| Arc::new(Calc(1)))
1416            .keyed_singleton("b", |_| Arc::new(Calc(2)))
1417            .build()
1418            .unwrap();
1419        assert_eq!(p.get_all::<Calc>().len(), 0, "get_all excludes keyed");
1420        assert_eq!(p.get_all_keyed::<Calc>().len(), 2);
1421    }
1422    #[test]
1423    fn later_registration_wins() {
1424        let p = ServiceCollection::new()
1425            .singleton(|_| Arc::new(Calc(1)))
1426            .singleton(|_| Arc::new(Calc(2)))
1427            .build()
1428            .unwrap();
1429        assert_eq!(
1430            p.get::<Calc>().unwrap().0,
1431            2,
1432            "MEDI: last registration wins"
1433        );
1434    }
1435    #[test]
1436    fn root_scoped_is_rejected_by_default() {
1437        let p = ServiceCollection::new()
1438            .scoped(|_| Arc::new(Calc(9)))
1439            .build()
1440            .unwrap();
1441        match p.get::<Calc>() {
1442            Err(crate::error::RdiError::ScopedFromRootProvider { service }) => {
1443                assert!(service.contains("Calc"));
1444            }
1445            other => panic!("expected ScopedFromRootProvider, got {other:?}"),
1446        }
1447        assert!(p.get_optional::<Calc>().is_none());
1448        assert!(p.get_all::<Calc>().is_empty());
1449    }
1450    #[test]
1451    fn lenient_options_restore_root_scope() {
1452        let p = ServiceCollection::new()
1453            .scoped(|_| Arc::new(Calc(9)))
1454            .build_with(ServiceProviderOptions::lenient())
1455            .unwrap();
1456        assert_eq!(p.get::<Calc>().unwrap().0, 9);
1457        assert!(Arc::ptr_eq(
1458            &p.get::<Calc>().unwrap(),
1459            &p.get::<Calc>().unwrap()
1460        ));
1461    }
1462    #[test]
1463    fn scope_resolution_works_and_is_cached() {
1464        let p = ServiceCollection::new()
1465            .scoped(|_| Arc::new(Calc(3)))
1466            .build()
1467            .unwrap();
1468        let s1 = p.scope();
1469        let a = s1.get::<Calc>().unwrap();
1470        let b = s1.get::<Calc>().unwrap();
1471        assert!(Arc::ptr_eq(&a, &b));
1472        let s2 = p.scope();
1473        assert!(!Arc::ptr_eq(&a, &s2.get::<Calc>().unwrap()));
1474    }
1475    #[test]
1476    fn is_registered_reports_lookup_state() {
1477        let p = ServiceCollection::new()
1478            .singleton(|_| Arc::new(Calc(1)))
1479            .keyed_singleton("k", |_| Arc::new(Calc(2)))
1480            .build()
1481            .unwrap();
1482        assert!(p.is_registered::<Calc>());
1483        assert!(p.is_registered::<crate::ServiceProvider>());
1484        assert!(p.is_registered::<dyn crate::ScopeFactory>());
1485        assert!(!p.is_registered::<String>());
1486        assert!(p.is_registered_keyed::<Calc>("k"));
1487        assert!(!p.is_registered_keyed::<Calc>("missing"));
1488    }
1489    #[test]
1490    fn dispose_is_idempotent_and_blocks_resolution() {
1491        let p = ServiceCollection::new()
1492            .singleton(|_| Arc::new(Calc(1)))
1493            .build()
1494            .unwrap();
1495        p.dispose();
1496        p.dispose();
1497        assert!(matches!(
1498            p.get::<Calc>(),
1499            Err(crate::error::RdiError::ProviderDisposed)
1500        ));
1501        assert!(p.get_optional::<Calc>().is_none());
1502        assert!(p.get_all::<Calc>().is_empty());
1503    }
1504    #[test]
1505    fn dispose_releases_singletons_in_reverse_creation_order() {
1506        use std::sync::Mutex;
1507        static DROPS: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
1508        #[derive(Debug)]
1509        struct Tracked(&'static str);
1510        impl Drop for Tracked {
1511            fn drop(&mut self) {
1512                DROPS.lock().unwrap().push(self.0);
1513            }
1514        }
1515        struct First(#[allow(dead_code)] Arc<Tracked>);
1516        struct Second(#[allow(dead_code)] Arc<Tracked>);
1517
1518        let p = ServiceCollection::new()
1519            .singleton(|_| Arc::new(First(Arc::new(Tracked("first")))))
1520            .singleton(|_| Arc::new(Second(Arc::new(Tracked("second")))))
1521            .build()
1522            .unwrap();
1523        p.dispose();
1524
1525        let drops = DROPS.lock().unwrap().clone();
1526        assert_eq!(
1527            drops,
1528            vec!["second", "first"],
1529            "singletons must be released in reverse creation order"
1530        );
1531    }
1532
1533    #[test]
1534    fn eager_singletons_are_created_in_registration_order() {
1535        use std::sync::Mutex;
1536        static CREATED: Mutex<Vec<&'static str>> = Mutex::new(Vec::new());
1537        #[derive(Debug)]
1538        struct A;
1539        #[derive(Debug)]
1540        struct B;
1541        let p = ServiceCollection::new()
1542            .singleton(|_| {
1543                CREATED.lock().unwrap().push("a");
1544                Arc::new(A)
1545            })
1546            .singleton(|_| {
1547                CREATED.lock().unwrap().push("b");
1548                Arc::new(B)
1549            })
1550            .build()
1551            .unwrap();
1552        assert_eq!(
1553            *CREATED.lock().unwrap(),
1554            vec!["a", "b"],
1555            "eager init must be deterministic (registration order)"
1556        );
1557        drop(p);
1558    }
1559
1560    #[test]
1561    fn async_singleton_panic_becomes_typed_error() {
1562        let result = futures::executor::block_on(
1563            ServiceCollection::new()
1564                .async_singleton::<Calc>(|_| Box::pin(async { panic!("boom") }))
1565                .build_async(),
1566        );
1567        match result {
1568            Ok(_) => panic!("build_async must fail when an async singleton factory panics"),
1569            Err(crate::error::RdiError::FactoryPanic { payload, .. }) => {
1570                assert!(payload.contains("boom"), "payload={payload}");
1571            }
1572            Err(other) => panic!("expected FactoryPanic, got {other:?}"),
1573        }
1574    }
1575}