nestforge_core/
provider.rs1use std::marker::PhantomData;
2
3use anyhow::{anyhow, Result};
4
5use crate::{framework_log, Container};
6
7pub struct Provider;
8
9pub struct ValueProvider<T> {
10 value: T,
11}
12
13pub struct FactoryProvider<T, F> {
14 factory: F,
15 _marker: PhantomData<fn() -> T>,
16}
17
18impl Provider {
19 pub fn value<T>(value: T) -> ValueProvider<T>
20 where
21 T: Send + Sync + 'static,
22 {
23 ValueProvider { value }
24 }
25
26 pub fn factory<T, F>(factory: F) -> FactoryProvider<T, F>
27 where
28 T: Send + Sync + 'static,
29 F: FnOnce(&Container) -> Result<T> + Send + 'static,
30 {
31 FactoryProvider {
32 factory,
33 _marker: PhantomData,
34 }
35 }
36}
37
38pub trait RegisterProvider {
39 fn register(self, container: &Container) -> Result<()>;
40}
41
42impl<T> RegisterProvider for ValueProvider<T>
43where
44 T: Send + Sync + 'static,
45{
46 fn register(self, container: &Container) -> Result<()> {
47 framework_log(format!(
48 "Registering service {}.",
49 std::any::type_name::<T>()
50 ));
51 container.register(self.value)?;
52 Ok(())
53 }
54}
55
56impl<T, F> RegisterProvider for FactoryProvider<T, F>
57where
58 T: Send + Sync + 'static,
59 F: FnOnce(&Container) -> Result<T> + Send + 'static,
60{
61 fn register(self, container: &Container) -> Result<()> {
62 framework_log(format!(
63 "Registering service {} (factory).",
64 std::any::type_name::<T>()
65 ));
66 let value = (self.factory)(container).map_err(|err| {
67 anyhow!(
68 "Failed to build provider `{}`: {}",
69 std::any::type_name::<T>(),
70 err
71 )
72 })?;
73 container.register(value)?;
74 Ok(())
75 }
76}
77
78pub fn register_provider<P>(container: &Container, provider: P) -> Result<()>
79where
80 P: RegisterProvider,
81{
82 provider.register(container)
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[derive(Clone)]
90 struct AppConfig {
91 app_name: &'static str,
92 }
93
94 struct AppService {
95 config_name: &'static str,
96 }
97
98 #[test]
99 fn registers_value_provider() {
100 let container = Container::new();
101 let result = register_provider(
102 &container,
103 Provider::value(AppConfig {
104 app_name: "nestforge",
105 }),
106 );
107
108 assert!(result.is_ok(), "value provider registration should succeed");
109 let config = container
110 .resolve::<AppConfig>()
111 .expect("config should be registered");
112 assert_eq!(config.app_name, "nestforge");
113 }
114
115 #[test]
116 fn registers_factory_provider() {
117 let container = Container::new();
118 register_provider(
119 &container,
120 Provider::value(AppConfig {
121 app_name: "nestforge",
122 }),
123 )
124 .expect("seed config");
125
126 let result = register_provider(
127 &container,
128 Provider::factory(|c| {
129 let cfg = c.resolve::<AppConfig>()?;
130 Ok(AppService {
131 config_name: cfg.app_name,
132 })
133 }),
134 );
135
136 assert!(
137 result.is_ok(),
138 "factory provider registration should succeed"
139 );
140 let service = container
141 .resolve::<AppService>()
142 .expect("service should be registered");
143 assert_eq!(service.config_name, "nestforge");
144 }
145
146 #[test]
147 fn factory_error_includes_type_name() {
148 let container = Container::new();
149 let err = register_provider(
150 &container,
151 Provider::factory::<AppService, _>(|_| Err(anyhow!("boom"))),
152 )
153 .expect_err("factory should fail");
154
155 assert!(err.to_string().contains("AppService"));
156 }
157}