1use std::any::Any;
2use thiserror::Error;
3
4#[derive(Error, Debug, Clone)]
5pub enum RdiError {
6 #[error("service not registered: {ty}{}", context.as_ref().map(|c| format!(" (while resolving {c})")).unwrap_or_default())]
7 ServiceNotFound {
8 ty: &'static str,
9 context: Option<String>,
10 },
11 #[error("keyed service not registered: key={key}, type={ty}{}", context.as_ref().map(|c| format!(" (while resolving {c})")).unwrap_or_default())]
12 KeyedServiceNotFound {
13 key: String,
14 ty: &'static str,
15 context: Option<String>,
16 },
17 #[error("circular dependency detected: {0}")]
18 CircularDependency(String),
19 #[error("singleton '{singleton}' cannot depend on scoped service '{scoped}'")]
20 SingletonDependsOnScoped { singleton: String, scoped: String },
21 #[error("factory panicked while resolving service '{service}': {payload}")]
22 FactoryPanic { service: String, payload: String },
23 #[error("cannot resolve owned instance of '{0}': Singleton services cannot be owned")]
24 OwnedNotSupported(&'static str),
25 #[error(
26 "async service '{service}' cannot be built with build(); use ServiceCollection::build_async() instead"
27 )]
28 AsyncServiceRequiresBuildAsync { service: String },
29}
30
31impl RdiError {
32 pub fn not_found(ty: &'static str, context: impl Into<Option<String>>) -> Self {
34 Self::ServiceNotFound {
35 ty,
36 context: context.into(),
37 }
38 }
39
40 pub fn keyed_not_found(
42 ty: &'static str,
43 key: impl Into<String>,
44 context: impl Into<Option<String>>,
45 ) -> Self {
46 Self::KeyedServiceNotFound {
47 key: key.into(),
48 ty,
49 context: context.into(),
50 }
51 }
52
53 pub fn from_panic_payload(service: &str, payload: Box<dyn Any + Send>) -> Self {
58 match payload.downcast::<RdiError>() {
59 Ok(err) => *err,
60 Err(payload) => {
61 let msg = payload
62 .downcast_ref::<&'static str>()
63 .map(|s| (*s).to_string())
64 .or_else(|| payload.downcast_ref::<String>().cloned())
65 .unwrap_or_else(|| "<non-string panic payload>".to_string());
66 Self::FactoryPanic {
67 service: service.to_string(),
68 payload: msg,
69 }
70 }
71 }
72 }
73}
74
75#[doc(hidden)]
80pub fn inject_arc<T: Send + Sync + 'static>(result: Result<std::sync::Arc<T>, RdiError>) -> std::sync::Arc<T> {
81 match result {
82 Ok(v) => v,
83 Err(e) => std::panic::panic_any(e),
84 }
85}