1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Lifecycle hook traits for `post_construct` and `pre_destruct`.
//!
//! These traits are automatically implemented by the `#[derive(Injectable)]`
//! macro when `#[injectable(post_construct)]` or `#[injectable(pre_destruct)]` annotations are
//! present on methods.
//!
//! # Error Handling
//!
//! Both hooks return `Result<(), Box<dyn std::error::Error + Send + Sync>>`,
//! allowing errors to be propagated:
//!
//! - **`post_construct`**: If a hook fails, the error is wrapped in
//! [`InjectableError::LifecycleHookFailed`](crate::InjectableError::LifecycleHookFailed)
//! and the entire resolution fails.
//!
//! - **`pre_destruct`**: If a hook fails, the error is collected. All
//! remaining destructors still run (best-effort cleanup). The accumulated
//! errors are returned from [`Container::shutdown`](crate::Container::shutdown).
//!
//! Hooks that cannot fail may return `Ok(())` — the macro generates code
//! that adapts both `-> ()` and `-> Result<...>` methods automatically.
/// A specialized result type for lifecycle hooks.
///
/// Uses `Box<dyn Error + Send + Sync>` so that hooks can return any
/// error type without being constrained to a specific error enum.
pub type HookResult = ;
/// Trait for post-construction lifecycle hooks.
///
/// When a type has a method annotated with `#[injectable(post_construct)]`, the
/// derive macro generates an implementation of this trait that calls
/// the annotated method.
///
/// # Execution Order
///
/// Post-construct hooks run **after** the constructor returns but
/// **before** the value is returned from the provider. This ensures
/// the instance is fully initialized before any consumer receives it.
///
/// # Error Handling
///
/// If a `post_construct` hook returns an error, the entire resolution
/// fails with `InjectableError::LifecycleHookFailed`. The instance
/// is discarded — it will not be available to consumers.
///
/// # Use Cases
///
/// - Database connection establishment
/// - Cache warming
/// - Spawning background workers
/// - Registering with external services
///
/// # Example
///
/// ```rust,ignore
/// #[derive(Injectable)]
/// pub struct Database {
/// pool_size: usize,
/// }
///
/// impl Database {
/// #[injectable(ctor)]
/// pub async fn new() -> Self { Self { pool_size: 10 } }
///
/// #[injectable(post_construct)]
/// async fn connect(&self) -> Result<(), std::io::Error> {
/// self.establish_connection().await?;
/// Ok(())
/// }
/// }
/// ```
///
/// Hooks that cannot fail may return `()`:
///
/// ```rust,ignore
/// #[injectable(post_construct)]
/// fn log_startup(&self) {
/// println!("Service started");
/// }
/// ```
/// Trait for pre-destruction lifecycle hooks.
///
/// When a type has a method annotated with `#[injectable(pre_destruct)]`, the
/// derive macro generates an implementation of this trait that calls
/// the annotated method.
///
/// # Execution Order
///
/// Pre-destruct hooks run in **reverse topological order** during
/// container shutdown. Dependencies are destroyed before the types
/// that depend on them.
///
/// # Error Handling
///
/// If a `pre_destruct` hook returns an error, it is collected. All
/// remaining destructors still run (best-effort cleanup). After all
/// destructors have been called, the accumulated errors are returned
/// from `Container::shutdown()`.
///
/// # Use Cases
///
/// - Graceful database disconnection
/// - Flushing buffers
/// - Stopping background workers
/// - Releasing external resources
///
/// # Example
///
/// ```rust,ignore
/// impl Database {
/// #[injectable(pre_destruct)]
/// async fn shutdown(&self) -> Result<(), std::io::Error> {
/// self.close_connections().await?;
/// Ok(())
/// }
/// }
/// ```