1use crate::{innerlude::CapturedPanic, ComponentFunction, Element};
2use std::{any::Any, panic::AssertUnwindSafe};
3
4pub(crate) type BoxedAnyProps = Box<dyn AnyProps>;
5
6pub(crate) trait AnyProps: 'static {
8 fn render(&self) -> Element;
10 fn memoize(&mut self, other: &dyn Any) -> bool;
12 fn props(&self) -> &dyn Any;
14 fn props_mut(&mut self) -> &mut dyn Any;
16 fn duplicate(&self) -> BoxedAnyProps;
18}
19
20pub(crate) struct VProps<F: ComponentFunction<P, M>, P, M> {
22 render_fn: F,
23 memo: fn(&mut P, &P) -> bool,
24 props: P,
25 name: &'static str,
26 phantom: std::marker::PhantomData<M>,
27}
28
29impl<F: ComponentFunction<P, M>, P: Clone, M> Clone for VProps<F, P, M> {
30 fn clone(&self) -> Self {
31 Self {
32 render_fn: self.render_fn.clone(),
33 memo: self.memo,
34 props: self.props.clone(),
35 name: self.name,
36 phantom: std::marker::PhantomData,
37 }
38 }
39}
40
41impl<F: ComponentFunction<P, M> + Clone, P: Clone + 'static, M: 'static> VProps<F, P, M> {
42 pub fn new(
44 render_fn: F,
45 memo: fn(&mut P, &P) -> bool,
46 props: P,
47 name: &'static str,
48 ) -> VProps<F, P, M> {
49 VProps {
50 render_fn,
51 memo,
52 props,
53 name,
54 phantom: std::marker::PhantomData,
55 }
56 }
57}
58
59impl<F: ComponentFunction<P, M> + Clone, P: Clone + 'static, M: 'static> AnyProps
60 for VProps<F, P, M>
61{
62 fn memoize(&mut self, other: &dyn Any) -> bool {
63 match other.downcast_ref::<P>() {
64 Some(other) => (self.memo)(&mut self.props, other),
65 None => false,
66 }
67 }
68
69 fn props(&self) -> &dyn Any {
70 &self.props
71 }
72
73 fn props_mut(&mut self) -> &mut dyn Any {
74 &mut self.props
75 }
76
77 fn render(&self) -> Element {
78 fn render_inner(_name: &str, res: Result<Element, Box<dyn Any + Send>>) -> Element {
79 match res {
80 Ok(node) => node,
81 Err(err) => {
82 #[cfg(not(target_arch = "wasm32"))]
85 {
86 tracing::error!("Panic while rendering component `{_name}`: {err:?}");
87 }
88 Element::Err(CapturedPanic(err).into())
89 }
90 }
91 }
92
93 render_inner(
94 self.name,
95 std::panic::catch_unwind(AssertUnwindSafe(move || {
96 self.render_fn.rebuild(self.props.clone())
97 })),
98 )
99 }
100
101 fn duplicate(&self) -> BoxedAnyProps {
102 Box::new(Self {
103 render_fn: self.render_fn.clone(),
104 memo: self.memo,
105 props: self.props.clone(),
106 name: self.name,
107 phantom: std::marker::PhantomData,
108 })
109 }
110}