wip: foregin eq from comparapable comp type.

This commit adds the framework for "comparable components". This allows
complete sealing of bump-allocated properties types, and a comparison method
that performs a "safe" cast without transmute. This lets us completely erase types
but still be able to perform partialeq over render frames
This commit is contained in:
Jonathan Kelley committed 2021-03-12 13:03:37 -05:00
1 parent 5ad81885e4
commit ec801eab16
6 files changed
+94 -34

No files matched your search

+1 -1
View File
@@ -17,7 +17,7 @@ static Header: FC<()> = |ctx, props| {
.child(VNode::Component(VComponent::new( .child(VNode::Component(VComponent::new(
Bottom, Bottom,
// //
(), &mut (),
))) )))
.finish() .finish()
}) })
+53 -7
View File
@@ -7,13 +7,64 @@
use crate::innerlude::FC; use crate::innerlude::FC;
use self::sized_any::SizedAny;
pub type ScopeIdx = generational_arena::Index; pub type ScopeIdx = generational_arena::Index;
struct ComparableComp<'s> {
fc_raw: *const (),
f: &'s dyn SizedAny,
}
impl<'s> ComparableComp<'s> {
fn compare_to<P: Properties>(&self, other: &ComparableComp) -> bool {
if self.fc_raw == other.fc_raw {
let real_other = unsafe { &*(other.f as *const _ as *const P) };
true
} else {
false
}
}
}
struct TestProps {}
fn test() {}
mod sized_any {
use std::any::TypeId;
// don't allow other implementations of `SizedAny`; `SizedAny` must only be
// implemented for sized types.
mod seal {
// it must be a `pub trait`, but not be reachable - hide it in
// private mod.
pub trait Seal {}
}
pub trait SizedAny: seal::Seal {}
impl<T> seal::Seal for T {}
impl<T> SizedAny for T {}
// `SizedAny + ?Sized` means it can be a trait object, but `SizedAny` was
// implemented for the underlying sized type.
pub fn downcast_ref<From, To>(v: &From) -> Option<&To>
where
From: SizedAny + ?Sized + 'static,
To: 'static,
{
// if TypeId::of::<To>() == < From as SizedAny>::get_type_id(v) {
Some(unsafe { &*(v as *const From as *const To) })
// } else {
// None
// }
}
}
pub trait Properties: PartialEq { pub trait Properties: PartialEq {
type Builder; type Builder;
type StaticOutput: Properties + 'static;
fn builder() -> Self::Builder; fn builder() -> Self::Builder;
unsafe fn into_static(self) -> Self::StaticOutput;
} }
pub struct EmptyBuilder; pub struct EmptyBuilder;
@@ -25,15 +76,10 @@ impl EmptyBuilder {
impl Properties for () { impl Properties for () {
type Builder = EmptyBuilder; type Builder = EmptyBuilder;
type StaticOutput = ();
fn builder() -> Self::Builder { fn builder() -> Self::Builder {
EmptyBuilder {} EmptyBuilder {}
} }
unsafe fn into_static(self) -> Self::StaticOutput {
std::mem::transmute(self)
}
} }
pub fn fc_to_builder<T: Properties>(_f: FC<T>) -> T::Builder { pub fn fc_to_builder<T: Properties>(_f: FC<T>) -> T::Builder {
+1 -1
View File
@@ -76,9 +76,9 @@ impl<'a> Context<'a> {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct NodeCtx<'a> { pub struct NodeCtx<'a> {
pub bump: &'a Bump, pub bump: &'a Bump,
pub listeners: &'a RefCell<Vec<*const dyn Fn(crate::events::VirtualEvent)>>,
pub idx: RefCell<usize>, pub idx: RefCell<usize>,
pub scope: ScopeIdx, pub scope: ScopeIdx,
pub listeners: &'a RefCell<Vec<*const dyn Fn(crate::events::VirtualEvent)>>,
} }
impl<'a> Context<'a> { impl<'a> Context<'a> {
+26 -8
View File
@@ -1,6 +1,6 @@
//! Helpers for building virtual DOM VNodes. //! Helpers for building virtual DOM VNodes.
use std::{borrow::BorrowMut, intrinsics::transmute}; use std::{any::Any, borrow::BorrowMut, intrinsics::transmute, u128};
use crate::{ use crate::{
context::NodeCtx, context::NodeCtx,
@@ -521,12 +521,30 @@ pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> {
// } // }
// } // }
// _f: crate::innerlude::FC<T>,
// _props: T
pub fn virtual_child<'a, T: Properties>(ctx: &NodeCtx<'a>, f: FC<T>, p: T) -> VNode<'a> { pub fn virtual_child<'a, T: Properties>(ctx: &NodeCtx<'a>, f: FC<T>, p: T) -> VNode<'a> {
// alloc props into the bump; VNode::Component(crate::nodes::VComponent::new(f, ctx.bump.alloc(p)))
// erase the lifetime
let p_static = unsafe { p.into_static() };
VNode::Component(crate::nodes::VComponent::new(f, p_static))
} }
trait Bany {
// fn compare_to<P: Properties>(other: &P) -> bool;
}
pub fn test_vchild<T: Properties>(p: &T) {
// let r = p as *const dyn Bany;
// let r = p as *const dyn Bany;
// std::any::Any
// let r = p as &dyn Any;
// let g = p as *const u128;
// let l = unsafe { std::mem::transmute::<&T, &dyn Any>(p) };
}
/*
Problem:
compare two props that we know are the same type without transmute
*/
+12 -17
View File
@@ -269,8 +269,8 @@ pub type StableScopeAddres = Rc<RefCell<Option<usize>>>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct VComponent<'src> { pub struct VComponent<'src> {
pub stable_addr: StableScopeAddres, pub stable_addr: StableScopeAddres,
pub raw_props: Rc<dyn Any>, pub raw_props: Rc<*mut dyn Any>,
pub comparator: Comparator, // pub comparator: Comparator,
pub caller: Caller, pub caller: Caller,
pub caller_ref: *const (), pub caller_ref: *const (),
_p: PhantomData<&'src ()>, _p: PhantomData<&'src ()>,
@@ -278,8 +278,8 @@ pub struct VComponent<'src> {
pub trait PropsComparator {} pub trait PropsComparator {}
#[derive(Clone)] #[derive(Clone)]
pub struct Comparator(pub Rc<dyn Fn(&dyn PropsComparator) -> bool>); // pub struct Comparator(pub Rc<dyn Fn(&dyn PropsComparator) -> bool>);
// pub struct Comparator(pub Rc<dyn Fn(&dyn Any) -> bool>); pub struct Comparator(pub Rc<dyn Fn(&dyn Any) -> bool>);
impl std::fmt::Debug for Comparator { impl std::fmt::Debug for Comparator {
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Ok(()) Ok(())
@@ -300,29 +300,24 @@ impl<'a> VComponent<'a> {
// - perform comparisons when diffing (memoization) // - perform comparisons when diffing (memoization)
// TODO: lift the requirement that props need to be static // TODO: lift the requirement that props need to be static
// we want them to borrow references... maybe force implementing a "to_static_unsafe" trait // we want them to borrow references... maybe force implementing a "to_static_unsafe" trait
pub fn new<P0: Properties, P: Properties + 'static>(caller: FC<P0>, props: P) -> Self { pub fn new<P: Properties>(caller: FC<P>, props: &mut P) -> Self {
let caller_ref = caller as *const (); let caller_ref = caller as *const ();
let props = Rc::new(props); let props = Rc::new(props);
// used for memoization // used for memoization
let p1 = props.clone(); let p1 = props.clone();
let props_comparator = move |new_props: ()| -> bool {
false // let props_comparator = move |new_props| -> bool {
// let props_comparator = move |new_props: &dyn Any| -> bool { // false
// new_props // let p = new_props.downcast_ref::<P::StaticOutput>().expect("");
// .downcast_ref::<P>() // let r = unsafe { std::mem::transmute::<_, &P>(p) };
// .map(|new_p| p1.as_ref() == new_p) // &r == p1.as_ref()
// .unwrap_or_else(|| { // };
// log::debug!("downcasting failed, this receovered but SHOULD NOT FAIL");
// false
// })
};
// used for actually rendering the custom component // used for actually rendering the custom component
let p2 = props.clone(); let p2 = props.clone();
let caller = move |ctx: Context| -> DomTree { let caller = move |ctx: Context| -> DomTree {
//
// cast back into the right lifetime // cast back into the right lifetime
caller(ctx, p2.as_ref()) caller(ctx, p2.as_ref())
}; };
+1
View File
@@ -45,3 +45,4 @@ fn main() {
}) })
})); }));
} }