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:
1 parent
5ad81885e4
commit
ec801eab16
6 files changed
+94
-34
No files matched your search
@@ -17,7 +17,7 @@ static Header: FC<()> = |ctx, props| {
|
|||||||
.child(VNode::Component(VComponent::new(
|
.child(VNode::Component(VComponent::new(
|
||||||
Bottom,
|
Bottom,
|
||||||
//
|
//
|
||||||
(),
|
&mut (),
|
||||||
)))
|
)))
|
||||||
.finish()
|
.finish()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
@@ -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
@@ -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())
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,3 +45,4 @@ fn main() {
|
|||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user