ferroui_splat/builder/
app_builder.rs1use crate::service_location::{AppLocator, IMutableDependencyResolver, IReadonlyDependencyResolver};
4use std::cell::{Cell, RefCell};
5use std::rc::Rc;
6
7pub trait IModule {
9 fn configure(&self, resolver: &dyn IMutableDependencyResolver);
11}
12
13pub trait IAppInstance {
15 fn current(&self) -> Option<Rc<dyn IReadonlyDependencyResolver>>;
17
18 fn current_mutable(&self) -> Rc<dyn IMutableDependencyResolver>;
20}
21
22pub trait IAppBuilder {
25 fn build(&self) -> &dyn IAppInstance;
27
28 fn use_current_splat_locator(&self) -> &dyn IAppBuilder;
31
32 fn using_module(&self, registration_module: Rc<dyn IModule>) -> &dyn IAppBuilder;
34
35 fn with_core_services(&self) -> &dyn IAppBuilder;
37
38 fn with_custom_registration(
40 &self,
41 configure_action: Rc<dyn Fn(&dyn IMutableDependencyResolver)>,
42 ) -> &dyn IAppBuilder;
43}
44
45ferroui_system::ferro_thread_local! {
48 static HAS_BEEN_BUILT: Cell<bool> = const { Cell::new(false) };
49 static USING_BUILDER: Cell<bool> = const { Cell::new(false) };
50}
51
52type Registration = Rc<dyn Fn(&dyn IMutableDependencyResolver)>;
53type ResolverProvider = Rc<dyn Fn() -> Rc<dyn IMutableDependencyResolver>>;
54type ServiceProvider = Rc<dyn Fn() -> Option<Rc<dyn IReadonlyDependencyResolver>>>;
55
56pub struct AppBuilder {
62 registrations: RefCell<Vec<Registration>>,
63 resolver_provider: RefCell<ResolverProvider>,
64 service_provider: RefCell<ServiceProvider>,
65 current: RefCell<Option<Rc<dyn IReadonlyDependencyResolver>>>,
66 current_mutable: Rc<dyn IMutableDependencyResolver>,
67}
68
69impl AppBuilder {
70 pub fn new(resolver: Rc<dyn IMutableDependencyResolver>) -> Self {
72 Self::with_current(resolver, None)
73 }
74
75 pub fn with_current(
78 resolver: Rc<dyn IMutableDependencyResolver>,
79 current: Option<Rc<dyn IReadonlyDependencyResolver>>,
80 ) -> Self {
81 USING_BUILDER.with(|flag| flag.set(true));
82 let provided_mutable = resolver.clone();
83 let provided_current = current.clone();
84 Self {
85 registrations: RefCell::new(Vec::new()),
86 resolver_provider: RefCell::new(Rc::new(move || provided_mutable.clone())),
87 service_provider: RefCell::new(Rc::new(move || provided_current.clone())),
88 current: RefCell::new(current),
89 current_mutable: resolver,
90 }
91 }
92
93 pub fn create_splat_builder() -> Self {
95 Self::with_current(AppLocator::current_mutable(), Some(AppLocator::current()))
96 }
97
98 pub fn has_been_built() -> bool {
100 HAS_BEEN_BUILT.with(|flag| flag.get())
101 }
102
103 pub fn using_builder() -> bool {
105 USING_BUILDER.with(|flag| flag.get())
106 }
107
108 pub fn reset_builder_state_for_tests() {
111 Self::restore_state(false, false);
112 }
113
114 #[doc(hidden)]
116 pub fn get_state() -> (bool, bool) {
117 (Self::has_been_built(), Self::using_builder())
118 }
119
120 #[doc(hidden)]
122 pub fn restore_state(has_been_built: bool, using_builder: bool) {
123 HAS_BEEN_BUILT.with(|flag| flag.set(has_been_built));
124 USING_BUILDER.with(|flag| flag.set(using_builder));
125 }
126
127 #[doc(hidden)]
129 pub fn reset_state() {
130 Self::restore_state(false, false);
131 }
132}
133
134impl IAppInstance for AppBuilder {
135 fn current(&self) -> Option<Rc<dyn IReadonlyDependencyResolver>> {
136 self.current.borrow().clone()
137 }
138
139 fn current_mutable(&self) -> Rc<dyn IMutableDependencyResolver> {
140 self.current_mutable.clone()
141 }
142}
143
144impl IAppBuilder for AppBuilder {
145 fn build(&self) -> &dyn IAppInstance {
146 if Self::has_been_built() {
148 return self;
149 }
150
151 HAS_BEEN_BUILT.with(|flag| flag.set(true));
152
153 let _ = self.with_core_services();
155
156 let registrations: Vec<Registration> = self.registrations.borrow().clone();
158 for registration in registrations {
159 let provider = self.resolver_provider.borrow().clone();
160 let target_resolver = provider();
161 registration(&*target_resolver);
162 }
163
164 let provider = self.service_provider.borrow().clone();
165 *self.current.borrow_mut() = provider();
166 self
167 }
168
169 fn use_current_splat_locator(&self) -> &dyn IAppBuilder {
170 *self.resolver_provider.borrow_mut() = Rc::new(AppLocator::current_mutable);
171 *self.service_provider.borrow_mut() = Rc::new(|| Some(AppLocator::current()));
172 self
173 }
174
175 fn using_module(&self, registration_module: Rc<dyn IModule>) -> &dyn IAppBuilder {
176 self.registrations
177 .borrow_mut()
178 .push(Rc::new(move |resolver: &dyn IMutableDependencyResolver| registration_module.configure(resolver)));
179 self
180 }
181
182 fn with_core_services(&self) -> &dyn IAppBuilder {
183 self
184 }
185
186 fn with_custom_registration(
187 &self,
188 configure_action: Rc<dyn Fn(&dyn IMutableDependencyResolver)>,
189 ) -> &dyn IAppBuilder {
190 self.registrations.borrow_mut().push(configure_action);
191 self
192 }
193}
194
195pub trait ModuleExt {
197 fn apply(&self);
200}
201
202impl<M: IModule + ?Sized> ModuleExt for M {
203 fn apply(&self) {
204 self.configure(&*AppLocator::current_mutable());
205 }
206}
207
208pub trait SplatBuilderExt {
210 fn create_splat_builder(&self) -> AppBuilder;
212
213 fn create_splat_builder_with(
216 &self,
217 configure_action: impl Fn(&dyn IMutableDependencyResolver) + 'static,
218 ) -> AppBuilder;
219}
220
221impl<R: IMutableDependencyResolver + 'static> SplatBuilderExt for Rc<R> {
222 fn create_splat_builder(&self) -> AppBuilder {
223 AppBuilder::new(self.clone())
224 }
225
226 fn create_splat_builder_with(
227 &self,
228 configure_action: impl Fn(&dyn IMutableDependencyResolver) + 'static,
229 ) -> AppBuilder {
230 let builder = AppBuilder::new(self.clone());
231 let _ = builder.with_custom_registration(Rc::new(configure_action));
232 builder
233 }
234}
235
236impl SplatBuilderExt for Rc<dyn IMutableDependencyResolver> {
237 fn create_splat_builder(&self) -> AppBuilder {
238 AppBuilder::new(self.clone())
239 }
240
241 fn create_splat_builder_with(
242 &self,
243 configure_action: impl Fn(&dyn IMutableDependencyResolver) + 'static,
244 ) -> AppBuilder {
245 let builder = AppBuilder::new(self.clone());
246 let _ = builder.with_custom_registration(Rc::new(configure_action));
247 builder
248 }
249}