1use std::any::Any;
2use thiserror::Error;
3
4#[derive(Error, Debug, Clone)]
9#[non_exhaustive]
10pub enum RdiError {
11 #[error("service not registered: {ty}{}", context.as_ref().map(|c| format!(" (while resolving {c})")).unwrap_or_default())]
12 ServiceNotFound {
13 ty: &'static str,
14 context: Option<String>,
15 },
16 #[error("keyed service not registered: key={key}, type={ty}{}", context.as_ref().map(|c| format!(" (while resolving {c})")).unwrap_or_default())]
17 KeyedServiceNotFound {
18 key: String,
19 ty: &'static str,
20 context: Option<String>,
21 },
22 #[error("circular dependency detected: {0}")]
23 CircularDependency(String),
24 #[error("singleton '{singleton}' cannot depend on scoped service '{scoped}'")]
25 SingletonDependsOnScoped { singleton: String, scoped: String },
26 #[error("factory panicked while resolving service '{service}': {payload}")]
27 FactoryPanic { service: String, payload: String },
28 #[error("cannot resolve owned instance of '{0}': Singleton services cannot be owned")]
29 OwnedNotSupported(&'static str),
30 #[error(
31 "async service '{service}' cannot be built with build(); use ServiceCollection::build_async() instead"
32 )]
33 AsyncServiceRequiresBuildAsync { service: String },
34 #[error(
39 "scoped service '{service}' cannot be resolved from the root provider; \
40 create a scope with provider.scope() and resolve it there, or build with \
41 ServiceProviderOptions{{ validate_scopes: false }} to restore 0.7 root-scope behavior"
42 )]
43 ScopedFromRootProvider { service: String },
44 #[error("the service provider has been disposed; resolution is no longer allowed")]
46 ProviderDisposed,
47 #[error("the scope has been disposed; resolution is no longer allowed")]
49 ScopeDisposed,
50}
51
52impl RdiError {
53 pub fn not_found(ty: &'static str, context: impl Into<Option<String>>) -> Self {
55 Self::ServiceNotFound {
56 ty,
57 context: context.into(),
58 }
59 }
60
61 pub fn keyed_not_found(
63 ty: &'static str,
64 key: impl Into<String>,
65 context: impl Into<Option<String>>,
66 ) -> Self {
67 Self::KeyedServiceNotFound {
68 key: key.into(),
69 ty,
70 context: context.into(),
71 }
72 }
73
74 pub fn scoped_from_root(service: &'static str) -> Self {
76 Self::ScopedFromRootProvider {
77 service: service.to_string(),
78 }
79 }
80
81 pub fn from_panic_payload(service: &str, payload: Box<dyn Any + Send>) -> Self {
86 match payload.downcast::<RdiError>() {
87 Ok(err) => *err,
88 Err(payload) => {
89 let msg = payload
90 .downcast_ref::<&'static str>()
91 .map(|s| (*s).to_string())
92 .or_else(|| payload.downcast_ref::<String>().cloned())
93 .unwrap_or_else(|| "<non-string panic payload>".to_string());
94 Self::FactoryPanic {
95 service: service.to_string(),
96 payload: msg,
97 }
98 }
99 }
100 }
101}
102
103#[doc(hidden)]
108pub fn inject_arc<T: Send + Sync + 'static>(
109 result: Result<std::sync::Arc<T>, RdiError>,
110) -> std::sync::Arc<T> {
111 match result {
112 Ok(v) => v,
113 Err(e) => std::panic::panic_any(e),
114 }
115}