dependency_injector/
provider.rs

1//! Provider traits for dependency injection
2//!
3//! These traits define what types can be injected and how they behave.
4
5use std::any::TypeId;
6
7/// Marker trait for types that can be injected via the DI container.
8///
9/// This is automatically implemented for all types that are `Send + Sync + 'static`.
10/// You never need to implement this manually.
11///
12/// # Examples
13///
14/// ```rust
15/// // Any type that is Send + Sync + 'static works automatically
16/// #[derive(Clone)]
17/// struct MyService {
18///     name: String,
19/// }
20///
21/// // No impl needed - it just works!
22/// ```
23pub trait Injectable: Send + Sync + 'static {
24    /// Returns the TypeId of this type (for internal use)
25    #[inline]
26    fn type_id_of() -> TypeId
27    where
28        Self: Sized,
29    {
30        TypeId::of::<Self>()
31    }
32
33    /// Returns the type name for debugging
34    #[inline]
35    fn type_name_of() -> &'static str
36    where
37        Self: Sized,
38    {
39        std::any::type_name::<Self>()
40    }
41}
42
43// Blanket implementation - everything that's Send + Sync + 'static is Injectable
44impl<T: Send + Sync + 'static> Injectable for T {}
45
46/// Backward compatibility alias
47pub trait Provider: Injectable {}
48impl<T: Injectable> Provider for T {}
49
50/// Service lifetime specification
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
52pub enum Lifetime {
53    /// Single instance shared across all resolves
54    #[default]
55    Singleton,
56
57    /// New instance created lazily on first access, then shared
58    Lazy,
59
60    /// New instance created on every resolve
61    Transient,
62
63    /// One instance per scope
64    Scoped,
65}
66
67/// Registration information for a provider (used by module system)
68#[derive(Clone)]
69pub struct ProviderRegistration {
70    /// TypeId of the provider
71    pub type_id: TypeId,
72    /// Human-readable type name
73    pub type_name: &'static str,
74    /// Registration function
75    pub register_fn: fn(&crate::Container),
76}
77
78impl ProviderRegistration {
79    /// Create a new registration for type T
80    #[inline]
81    pub fn new<T: Injectable>(register_fn: fn(&crate::Container)) -> Self {
82        Self {
83            type_id: TypeId::of::<T>(),
84            type_name: std::any::type_name::<T>(),
85            register_fn,
86        }
87    }
88
89    /// Create from a singleton value
90    ///
91    /// Note: This creates a no-op registration. For actual registration,
92    /// use `Container::singleton()` directly.
93    pub fn singleton<T: Injectable + Clone>(_value: T) -> Self {
94        Self {
95            type_id: TypeId::of::<T>(),
96            type_name: std::any::type_name::<T>(),
97            register_fn: |_container| {
98                // No-op: actual registration should use Container::singleton()
99            },
100        }
101    }
102}
103
104impl std::fmt::Debug for ProviderRegistration {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        f.debug_struct("ProviderRegistration")
107            .field("type_id", &self.type_id)
108            .field("type_name", &self.type_name)
109            .finish()
110    }
111}
112
113/// Helper macro to create a provider registration
114#[macro_export]
115macro_rules! provider {
116    ($type:ty, $factory:expr) => {
117        $crate::ProviderRegistration {
118            type_id: std::any::TypeId::of::<$type>(),
119            type_name: std::any::type_name::<$type>(),
120            register_fn: |container| {
121                container.singleton($factory);
122            },
123        }
124    };
125    (lazy $type:ty, $factory:expr) => {
126        $crate::ProviderRegistration {
127            type_id: std::any::TypeId::of::<$type>(),
128            type_name: std::any::type_name::<$type>(),
129            register_fn: |container| {
130                container.lazy($factory);
131            },
132        }
133    };
134    (transient $type:ty, $factory:expr) => {
135        $crate::ProviderRegistration {
136            type_id: std::any::TypeId::of::<$type>(),
137            type_name: std::any::type_name::<$type>(),
138            register_fn: |container| {
139                container.transient($factory);
140            },
141        }
142    };
143}