use std::cell::Cell; use crate::{ component::Component, element::Element, scopes::{Scope, ScopeState}, }; pub trait AnyProps { fn as_ptr(&self) -> *const (); fn render<'a>(&'a self, bump: &'a ScopeState) -> Element<'a>; unsafe fn memoize(&self, other: &dyn AnyProps) -> bool; } pub(crate) struct VComponentProps
{ pub render_fn: Component
, pub memo: unsafe fn(&P, &P) -> bool, pub props: Scope
, } impl VComponentProps<()> { pub fn new_empty(render_fn: Component<()>) -> Self { Self { render_fn, memo: <() as PartialEq>::eq, props: Scope { props: (), state: Cell::new(std::ptr::null_mut()), }, } } } impl
VComponentProps
{ pub(crate) fn new( render_fn: Component
, memo: unsafe fn(&P, &P) -> bool, props: Scope
, ) -> Self { Self { render_fn, memo, props, } } } impl
AnyProps for VComponentProps
{ fn as_ptr(&self) -> *const () { &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 { let real_other: &P = &*(other.as_ptr() as *const _ as *const P); let real_us: &P = &*(self.as_ptr() as *const _ as *const P); (self.memo)(real_us, real_other) } fn render<'a>(&'a self, scope: &'a ScopeState) -> Element<'a> { // Make sure the scope ptr is not null self.props.state.set(scope); // Call the render function directly // todo: implement async (self.render_fn)(unsafe { std::mem::transmute(&self.props) }) } }