1use std::marker::PhantomData;
7
8use crate::component::{
9 Component, ComponentError, ComponentId, Context, LifecyclePhase, MountContext, Node, Props,
10 StateChanges, UnmountContext,
11};
12
13pub trait HigherOrderComponent<T: Component> {
15 type HOCProps: Props + Clone;
17 fn transform_props(hoc_props: &Self::HOCProps) -> T::Props;
19
20 fn enhance_component(
22 component: &mut T,
23 hoc_props: &Self::HOCProps,
24 ) -> Result<(), ComponentError> {
25 let _ = (component, hoc_props);
27 Ok(())
28 }
29
30 fn on_wrapped_mount(
32 component: &mut T,
33 context: &MountContext,
34 hoc_props: &Self::HOCProps,
35 ) -> Result<(), ComponentError> {
36 let _ = (component, context, hoc_props);
37 Ok(())
38 }
39
40 fn on_wrapped_update(
42 component: &mut T,
43 changes: &StateChanges,
44 hoc_props: &Self::HOCProps,
45 ) -> Result<(), ComponentError> {
46 let _ = (component, changes, hoc_props);
47 Ok(())
48 }
49
50 fn on_wrapped_unmount(
52 component: &mut T,
53 context: &UnmountContext,
54 hoc_props: &Self::HOCProps,
55 ) -> Result<(), ComponentError> {
56 let _ = (component, context, hoc_props);
57 Ok(())
58 }
59}
60
61pub struct HOCWrapper<H, T>
63where
64 H: HigherOrderComponent<T>,
65 T: Component,
66{
67 wrapped_component: T,
69 hoc_props: H::HOCProps,
71 component_id: ComponentId,
73 lifecycle_phase: LifecyclePhase,
75 _phantom: PhantomData<H>,
77}
78
79impl<H, T> HOCWrapper<H, T>
80where
81 H: HigherOrderComponent<T>,
82 T: Component,
83{
84 pub fn new(hoc_props: H::HOCProps, context: Context) -> Result<Self, ComponentError>
86 where
87 T: Component,
88 {
89 let wrapped_props = H::transform_props(&hoc_props);
90 let mut wrapped_component = T::create(wrapped_props, context);
91
92 H::enhance_component(&mut wrapped_component, &hoc_props)?;
94
95 Ok(Self {
96 wrapped_component,
97 hoc_props,
98 component_id: ComponentId::new(),
99 lifecycle_phase: LifecyclePhase::Created,
100 _phantom: PhantomData,
101 })
102 }
103
104 pub fn wrapped_component(&self) -> &T {
106 &self.wrapped_component
107 }
108
109 pub fn wrapped_component_mut(&mut self) -> &mut T {
111 &mut self.wrapped_component
112 }
113
114 pub fn hoc_props(&self) -> &H::HOCProps {
116 &self.hoc_props
117 }
118}
119
120impl<H, T> Component for HOCWrapper<H, T>
121where
122 H: HigherOrderComponent<T> + Send + Sync + 'static,
123 T: Component + Send + Sync + 'static,
124 H::HOCProps: Send + Sync + 'static,
125{
126 type Props = H::HOCProps;
127
128 fn component_id(&self) -> ComponentId {
129 self.component_id
130 }
131
132 fn create(props: Self::Props, context: Context) -> Self
133 where
134 Self: Sized,
135 {
136 Self::new(props, context).expect("Failed to create HOC wrapper")
137 }
138
139 fn initialize(&mut self) -> Result<(), ComponentError> {
140 self.wrapped_component.initialize()
141 }
142
143 fn before_mount(&mut self) -> Result<(), ComponentError> {
144 self.wrapped_component.before_mount()
145 }
146
147 fn on_mount(&mut self, context: &MountContext) -> Result<(), ComponentError> {
148 H::on_wrapped_mount(&mut self.wrapped_component, context, &self.hoc_props)?;
150 self.wrapped_component.on_mount(context)
152 }
153
154 fn after_mount(&mut self) -> Result<(), ComponentError> {
155 self.wrapped_component.after_mount()
156 }
157
158 fn on_update(&mut self, changes: &StateChanges) -> Result<(), ComponentError> {
159 H::on_wrapped_update(&mut self.wrapped_component, changes, &self.hoc_props)?;
161 self.wrapped_component.on_update(changes)
163 }
164 fn should_update(&self, new_props: &Self::Props) -> bool {
165 let wrapped_props = H::transform_props(new_props);
167 self.wrapped_component.should_update(&wrapped_props)
168 }
169
170 fn before_update(&mut self, new_props: &Self::Props) -> Result<(), ComponentError> {
171 let wrapped_props = H::transform_props(new_props);
172 self.wrapped_component.before_update(&wrapped_props)
173 }
174
175 fn update(&mut self, props: Self::Props) -> Result<(), ComponentError> {
176 let wrapped_props = H::transform_props(&props);
177 self.hoc_props = props;
178 self.wrapped_component.update(wrapped_props)
179 }
180
181 fn after_update(&mut self) -> Result<(), ComponentError> {
182 self.wrapped_component.after_update()
183 }
184
185 fn before_unmount(&mut self) -> Result<(), ComponentError> {
186 self.wrapped_component.before_unmount()
187 }
188
189 fn on_unmount(&mut self, context: &UnmountContext) -> Result<(), ComponentError> {
190 H::on_wrapped_unmount(&mut self.wrapped_component, context, &self.hoc_props)?;
192 self.wrapped_component.on_unmount(context)
194 }
195
196 fn after_unmount(&mut self) -> Result<(), ComponentError> {
197 self.wrapped_component.after_unmount()
198 }
199
200 fn render(&self) -> Result<Vec<Node>, ComponentError> {
201 self.wrapped_component.render()
202 }
203 fn lifecycle_phase(&self) -> LifecyclePhase {
204 self.lifecycle_phase
205 }
206
207 fn mount(&mut self) -> Result<(), ComponentError> {
208 self.wrapped_component.mount()
209 }
210
211 fn unmount(&mut self) -> Result<(), ComponentError> {
212 self.wrapped_component.unmount()
213 }
214
215 fn cleanup(&mut self) -> Result<(), ComponentError> {
216 self.wrapped_component.cleanup()
217 }
218
219 fn state_changed(&mut self, state_key: &str) -> Result<(), ComponentError> {
220 self.wrapped_component.state_changed(state_key)
221 }
222 fn request_update(&mut self) -> Result<(), ComponentError> {
223 <T as Component>::request_update(&mut self.wrapped_component)
224 }
225
226 fn as_any(&self) -> &dyn std::any::Any {
227 self
228 }
229
230 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
231 self
232 }
233}
234
235pub struct WithLogging;
239
240impl<T: Component> HigherOrderComponent<T> for WithLogging {
241 type HOCProps = T::Props;
242
243 fn transform_props(hoc_props: &Self::HOCProps) -> T::Props {
244 hoc_props.clone()
245 }
246 fn on_wrapped_mount(
247 component: &mut T,
248 _context: &MountContext,
249 _hoc_props: &Self::HOCProps,
250 ) -> Result<(), ComponentError> {
251 println!(
252 "🔄 Component {} mounted",
253 Component::component_id(component)
254 );
255 Ok(())
256 }
257
258 fn on_wrapped_update(
259 component: &mut T,
260 changes: &StateChanges,
261 _hoc_props: &Self::HOCProps,
262 ) -> Result<(), ComponentError> {
263 println!(
264 "🔄 Component {} updated with {} changes",
265 Component::component_id(component),
266 changes.changes.len()
267 );
268 Ok(())
269 }
270 fn on_wrapped_unmount(
271 component: &mut T,
272 _context: &UnmountContext,
273 _hoc_props: &Self::HOCProps,
274 ) -> Result<(), ComponentError> {
275 println!(
276 "🔄 Component {} unmounted",
277 Component::component_id(component)
278 );
279 Ok(())
280 }
281}
282
283pub struct WithPerformanceMonitoring;
285
286impl<T: Component> HigherOrderComponent<T> for WithPerformanceMonitoring {
287 type HOCProps = T::Props;
288
289 fn transform_props(hoc_props: &Self::HOCProps) -> T::Props {
290 hoc_props.clone()
291 }
292 fn on_wrapped_mount(
293 component: &mut T,
294 _context: &MountContext,
295 _hoc_props: &Self::HOCProps,
296 ) -> Result<(), ComponentError> {
297 let start = std::time::Instant::now();
298 let result = component.mount();
299 let duration = start.elapsed();
300 println!(
301 "âš¡ Component {} mount took {:?}",
302 Component::component_id(component),
303 duration
304 );
305 result
306 }
307
308 fn on_wrapped_update(
309 component: &mut T,
310 changes: &StateChanges,
311 _hoc_props: &Self::HOCProps,
312 ) -> Result<(), ComponentError> {
313 let start = std::time::Instant::now();
314 let result = component.on_update(changes);
315 let duration = start.elapsed();
316 println!(
317 "âš¡ Component {} update took {:?}",
318 Component::component_id(component),
319 duration
320 );
321 result
322 }
323}
324
325pub type LoggedComponent<T> = HOCWrapper<WithLogging, T>;
327pub type MonitoredComponent<T> = HOCWrapper<WithPerformanceMonitoring, T>;
328
329#[macro_export]
331macro_rules! with_hoc {
332 ($hoc:ty, $component:ty, $props:expr, $context:expr) => {
333 HOCWrapper::<$hoc, $component>::new($props, $context)
334 };
335}
336
337#[macro_export]
339macro_rules! hoc_chain {
340 ($component:ty, $props:expr, $context:expr, $($hoc:ty),+) => {{
341 let mut component = $component::create($props, $context);
342 $(
343 component = HOCWrapper::<$hoc, _>::new(component.props().clone(), $context)?;
344 )+
345 component
346 }};
347}
348
349#[cfg(test)]
350mod tests {
351 use super::*;
352 use crate::component::{ComponentBase, Context};
353
354 #[derive(Clone, Debug)]
355 struct TestProps {
356 name: String,
357 }
358 struct TestComponent {
361 base: ComponentBase,
362 props: TestProps,
363 }
364
365 impl Component for TestComponent {
366 type Props = TestProps;
367
368 fn component_id(&self) -> ComponentId {
369 self.base.id()
370 }
371
372 fn create(props: Self::Props, context: Context) -> Self {
373 Self {
374 base: ComponentBase::new(context),
375 props,
376 }
377 }
378
379 fn update(&mut self, props: Self::Props) -> Result<(), ComponentError> {
380 self.props = props;
381 Ok(())
382 }
383
384 fn render(&self) -> Result<Vec<Node>, ComponentError> {
385 Ok(vec![])
386 }
387
388 fn as_any(&self) -> &dyn std::any::Any {
389 self
390 }
391
392 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
393 self
394 }
395 }
396
397 #[test]
398 fn test_logging_hoc() {
399 let context = Context::new();
400 let props = TestProps {
401 name: "test".to_string(),
402 };
403
404 let mut logged_component = LoggedComponent::<TestComponent>::new(props, context).unwrap();
405
406 assert_eq!(logged_component.wrapped_component().props.name, "test");
408
409 assert!(logged_component.initialize().is_ok());
411 assert!(logged_component.before_mount().is_ok());
412 }
413
414 #[test]
415 fn test_performance_monitoring_hoc() {
416 let context = Context::new();
417 let props = TestProps {
418 name: "test".to_string(),
419 };
420
421 let mut monitored_component =
422 MonitoredComponent::<TestComponent>::new(props, context).unwrap();
423
424 assert!(monitored_component.initialize().is_ok());
426 }
427}