Skip to main content

dioxus_core/
any_props.rs

1use crate::{innerlude::CapturedPanic, ComponentFunction, Element};
2use std::{any::Any, panic::AssertUnwindSafe};
3
4pub(crate) type BoxedAnyProps = Box<dyn AnyProps>;
5
6/// A trait for a component that can be rendered.
7pub(crate) trait AnyProps: 'static {
8    /// Render the component with the internal props.
9    fn render(&self) -> Element;
10    /// Make the old props equal to the new type erased props. Return if the props were equal and should be memoized.
11    fn memoize(&mut self, other: &dyn Any) -> bool;
12    /// Get the props as a type erased `dyn Any`.
13    fn props(&self) -> &dyn Any;
14    /// Get the props as a type erased `dyn Any`.
15    fn props_mut(&mut self) -> &mut dyn Any;
16    /// Duplicate this component into a new boxed component.
17    fn duplicate(&self) -> BoxedAnyProps;
18}
19
20/// A component along with the props the component uses to render.
21pub(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    /// Create a [`VProps`] object.
43    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                    // on wasm this massively bloats binary sizes and we can't even capture the panic
83                    // so do nothing
84                    #[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}