2022-12-20 19:13:06 +00:00
|
|
|
use std::{marker::PhantomData, panic::AssertUnwindSafe};
|
2022-11-04 00:34:42 +00:00
|
|
|
|
2022-10-20 16:56:09 +00:00
|
|
|
use crate::{
|
2022-11-09 03:39:37 +00:00
|
|
|
innerlude::Scoped,
|
2022-12-03 00:24:49 +00:00
|
|
|
nodes::{ComponentReturn, RenderReturn},
|
2022-10-28 04:58:47 +00:00
|
|
|
scopes::{Scope, ScopeState},
|
2022-11-03 08:38:18 +00:00
|
|
|
Element,
|
2022-10-20 16:56:09 +00:00
|
|
|
};
|
|
|
|
|
2022-11-20 23:58:05 +00:00
|
|
|
/// A trait that essentially allows VComponentProps to be used generically
|
2022-11-29 21:46:25 +00:00
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// This should not be implemented outside this module
|
|
|
|
pub(crate) unsafe trait AnyProps<'a> {
|
2022-11-20 23:58:05 +00:00
|
|
|
fn props_ptr(&self) -> *const ();
|
2022-11-04 03:56:31 +00:00
|
|
|
fn render(&'a self, bump: &'a ScopeState) -> RenderReturn<'a>;
|
2022-10-28 04:58:47 +00:00
|
|
|
unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
|
2022-10-20 16:56:09 +00:00
|
|
|
}
|
|
|
|
|
2022-11-20 23:58:05 +00:00
|
|
|
pub(crate) struct VProps<'a, P, A, F: ComponentReturn<'a, A> = Element<'a>> {
|
2022-11-04 00:34:42 +00:00
|
|
|
pub render_fn: fn(Scope<'a, P>) -> F,
|
2022-10-20 16:56:09 +00:00
|
|
|
pub memo: unsafe fn(&P, &P) -> bool,
|
2022-11-09 18:58:11 +00:00
|
|
|
pub props: P,
|
2022-11-20 23:58:05 +00:00
|
|
|
_marker: PhantomData<A>,
|
2022-10-20 16:56:09 +00:00
|
|
|
}
|
|
|
|
|
2022-11-20 23:58:05 +00:00
|
|
|
impl<'a, P, A, F> VProps<'a, P, A, F>
|
|
|
|
where
|
|
|
|
F: ComponentReturn<'a, A>,
|
|
|
|
{
|
2022-10-28 04:58:47 +00:00
|
|
|
pub(crate) fn new(
|
2022-11-04 00:34:42 +00:00
|
|
|
render_fn: fn(Scope<'a, P>) -> F,
|
2022-10-28 04:58:47 +00:00
|
|
|
memo: unsafe fn(&P, &P) -> bool,
|
2022-11-09 18:58:11 +00:00
|
|
|
props: P,
|
2022-10-28 04:58:47 +00:00
|
|
|
) -> Self {
|
|
|
|
Self {
|
2022-11-03 09:37:41 +00:00
|
|
|
render_fn,
|
2022-10-28 04:58:47 +00:00
|
|
|
memo,
|
|
|
|
props,
|
2022-11-04 00:34:42 +00:00
|
|
|
_marker: PhantomData,
|
2022-10-28 04:58:47 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-20 16:56:09 +00:00
|
|
|
}
|
|
|
|
|
2022-11-20 23:58:05 +00:00
|
|
|
unsafe impl<'a, P, A, F> AnyProps<'a> for VProps<'a, P, A, F>
|
|
|
|
where
|
|
|
|
F: ComponentReturn<'a, A>,
|
|
|
|
{
|
|
|
|
fn props_ptr(&self) -> *const () {
|
2022-10-20 16:56:09 +00:00
|
|
|
&self.props as *const _ as *const ()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Safety:
|
|
|
|
// this will downcast the other ptr as our swallowed type!
|
|
|
|
// you *must* make this check *before* calling this method
|
|
|
|
// if your functions are not the same, then you will downcast a pointer into a different type (UB)
|
|
|
|
unsafe fn memoize(&self, other: &dyn AnyProps) -> bool {
|
2022-11-20 23:58:05 +00:00
|
|
|
let real_other: &P = &*(other.props_ptr() as *const _ as *const P);
|
|
|
|
let real_us: &P = &*(self.props_ptr() as *const _ as *const P);
|
2022-10-20 16:56:09 +00:00
|
|
|
(self.memo)(real_us, real_other)
|
|
|
|
}
|
|
|
|
|
2022-11-09 18:58:11 +00:00
|
|
|
fn render(&'a self, cx: &'a ScopeState) -> RenderReturn<'a> {
|
2022-12-20 19:13:06 +00:00
|
|
|
let res = std::panic::catch_unwind(AssertUnwindSafe(move || {
|
|
|
|
// Call the render function directly
|
|
|
|
let scope: &mut Scoped<P> = cx.bump().alloc(Scoped {
|
|
|
|
props: &self.props,
|
|
|
|
scope: cx,
|
|
|
|
});
|
2022-10-28 04:58:47 +00:00
|
|
|
|
2022-12-20 19:13:06 +00:00
|
|
|
(self.render_fn)(scope).into_return(cx)
|
|
|
|
}));
|
|
|
|
|
|
|
|
match res {
|
|
|
|
Ok(e) => e,
|
|
|
|
Err(_) => RenderReturn::default(),
|
|
|
|
}
|
2022-10-20 16:56:09 +00:00
|
|
|
}
|
|
|
|
}
|