Bladeren bron

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
Jonathan Kelley 4 jaren geleden
bovenliggende
commit
ec801ea

+ 1 - 1
packages/core/examples/nested.rs

@@ -17,7 +17,7 @@ static Header: FC<()> = |ctx, props| {
             .child(VNode::Component(VComponent::new(
                 Bottom,
                 //
-                (),
+                &mut (),
             )))
             .finish()
     })

+ 53 - 7
packages/core/src/component.rs

@@ -7,13 +7,64 @@
 
 use crate::innerlude::FC;
 
+use self::sized_any::SizedAny;
+
 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 {
     type Builder;
-    type StaticOutput: Properties + 'static;
     fn builder() -> Self::Builder;
-    unsafe fn into_static(self) -> Self::StaticOutput;
 }
 
 pub struct EmptyBuilder;
@@ -25,15 +76,10 @@ impl EmptyBuilder {
 
 impl Properties for () {
     type Builder = EmptyBuilder;
-    type StaticOutput = ();
 
     fn builder() -> Self::Builder {
         EmptyBuilder {}
     }
-
-    unsafe fn into_static(self) -> Self::StaticOutput {
-        std::mem::transmute(self)
-    }
 }
 
 pub fn fc_to_builder<T: Properties>(_f: FC<T>) -> T::Builder {

+ 1 - 1
packages/core/src/context.rs

@@ -76,9 +76,9 @@ impl<'a> Context<'a> {
 #[derive(Debug, Clone)]
 pub struct NodeCtx<'a> {
     pub bump: &'a Bump,
+    pub listeners: &'a RefCell<Vec<*const dyn Fn(crate::events::VirtualEvent)>>,
     pub idx: RefCell<usize>,
     pub scope: ScopeIdx,
-    pub listeners: &'a RefCell<Vec<*const dyn Fn(crate::events::VirtualEvent)>>,
 }
 
 impl<'a> Context<'a> {

+ 25 - 7
packages/core/src/nodebuilder.rs

@@ -1,6 +1,6 @@
 //! Helpers for building virtual DOM VNodes.
 
-use std::{borrow::BorrowMut, intrinsics::transmute};
+use std::{any::Any, borrow::BorrowMut, intrinsics::transmute, u128};
 
 use crate::{
     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> {
-    // 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
packages/core/src/nodes.rs

@@ -269,8 +269,8 @@ pub type StableScopeAddres = Rc<RefCell<Option<usize>>>;
 #[derive(Debug, Clone)]
 pub struct VComponent<'src> {
     pub stable_addr: StableScopeAddres,
-    pub raw_props: Rc<dyn Any>,
-    pub comparator: Comparator,
+    pub raw_props: Rc<*mut dyn Any>,
+    // pub comparator: Comparator,
     pub caller: Caller,
     pub caller_ref: *const (),
     _p: PhantomData<&'src ()>,
@@ -278,8 +278,8 @@ pub struct VComponent<'src> {
 pub trait PropsComparator {}
 
 #[derive(Clone)]
-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 PropsComparator) -> bool>);
+pub struct Comparator(pub Rc<dyn Fn(&dyn Any) -> bool>);
 impl std::fmt::Debug for Comparator {
     fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         Ok(())
@@ -300,29 +300,24 @@ impl<'a> VComponent<'a> {
     // - perform comparisons when diffing (memoization)
     // TODO: lift the requirement that props need to be static
     // 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 props = Rc::new(props);
 
         // used for memoization
         let p1 = props.clone();
-        let props_comparator = move |new_props: ()| -> bool {
-            false
-            // let props_comparator = move |new_props: &dyn Any| -> bool {
-            // new_props
-            //     .downcast_ref::<P>()
-            //     .map(|new_p| p1.as_ref() == new_p)
-            //     .unwrap_or_else(|| {
-            //         log::debug!("downcasting failed, this receovered but SHOULD NOT FAIL");
-            //         false
-            //     })
-        };
+
+        // let props_comparator = move |new_props| -> bool {
+        //     false
+        // let p = new_props.downcast_ref::<P::StaticOutput>().expect("");
+        // let r = unsafe { std::mem::transmute::<_, &P>(p) };
+        // &r == p1.as_ref()
+        // };
 
         // used for actually rendering the custom component
         let p2 = props.clone();
         let caller = move |ctx: Context| -> DomTree {
-            //
             // cast back into the right lifetime
             caller(ctx, p2.as_ref())
         };

+ 1 - 0
packages/web/examples/weather.rs

@@ -45,3 +45,4 @@ fn main() {
         })
     }));
 }
+