Evan Almloff 2 лет назад
Родитель
Сommit
c0f9355648

+ 2 - 2
packages/core/src/arena.rs

@@ -160,8 +160,8 @@ impl VirtualDom {
                 AttributeValue::Listener(l) => {
                     _ = l.take();
                 }
-                AttributeValue::Any(_) => {
-                    todo!()
+                AttributeValue::Any(a) => {
+                    _ = a.take();
                 }
                 _ => (),
             }

+ 3 - 3
packages/core/src/lib.rs

@@ -81,9 +81,9 @@ pub use crate::innerlude::{
 /// This includes types like [`Scope`], [`Element`], and [`Component`].
 pub mod prelude {
     pub use crate::innerlude::{
-        fc_to_builder, Component, Element, Event, EventHandler, Fragment, IntoAttributeValue,
-        LazyNodes, Properties, Scope, ScopeId, ScopeState, Scoped, TaskId, Template,
-        TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom,
+        fc_to_builder, AnyValue, Component, Element, Event, EventHandler, Fragment,
+        IntoAttributeValue, LazyNodes, Properties, Scope, ScopeId, ScopeState, Scoped, TaskId,
+        Template, TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom,
     };
 }
 

+ 1 - 20
packages/core/src/mutations.rs

@@ -48,20 +48,7 @@ impl<'a> Mutations<'a> {
 
     /// Push a new mutation into the dom_edits list
     pub(crate) fn push(&mut self, mutation: Mutation<'static>) {
-        self.edits.push(mutation.downcast_lifetime())
-    }
-}
-
-impl Mutations<'static> {
-    pub(crate) fn take<'a>(&mut self) -> Mutations<'a> {
-        Mutations::<'a> {
-            subtree: self.subtree,
-            dirty_scopes: self.dirty_scopes.drain().collect(),
-            templates: self.templates.split_off(0),
-            // Safety: this downcasts the lifetime from 'static to 'a
-            // This is safe because 'static outlives 'a
-            edits: unsafe { std::mem::transmute(self.edits.split_off(0)) },
-        }
+        self.edits.push(mutation)
     }
 }
 
@@ -257,9 +244,3 @@ pub enum Mutation<'a> {
         id: ElementId,
     },
 }
-
-impl Mutation<'static> {
-    pub(crate) fn downcast_lifetime<'a>(self) -> Mutation<'a> {
-        unsafe { std::mem::transmute(self) }
-    }
-}

+ 23 - 8
packages/core/src/nodes.rs

@@ -5,7 +5,7 @@ use bumpalo::boxed::Box as BumpBox;
 use bumpalo::Bump;
 use std::{
     any::{Any, TypeId},
-    cell::{Cell, RefCell, UnsafeCell},
+    cell::{self, Cell, RefCell, UnsafeCell},
     fmt::{Arguments, Debug},
     future::Future,
 };
@@ -523,7 +523,7 @@ pub enum AttributeValue<'a> {
     Listener(RefCell<Option<ListenerCb<'a>>>),
 
     /// An arbitrary value that implements PartialEq and is static
-    Any(BumpBox<'a, dyn AnyValue>),
+    Any(RefCell<Option<BumpBox<'a, dyn AnyValue>>>),
 
     /// A "none" value, resulting in the removal of an attribute from the dom
     None,
@@ -557,7 +557,7 @@ pub enum BorrowedAttributeValue<'a> {
             serialize_with = "serialize_any_value"
         )
     )]
-    Any(&'a dyn AnyValue),
+    Any(std::cell::Ref<'a, dyn AnyValue>),
 
     /// A "none" value, resulting in the removal of an attribute from the dom
     None,
@@ -573,7 +573,12 @@ impl<'a> From<&'a AttributeValue<'a>> for BorrowedAttributeValue<'a> {
             AttributeValue::Listener(_) => {
                 panic!("A listener cannot be turned into a borrowed value")
             }
-            AttributeValue::Any(value) => BorrowedAttributeValue::Any(&**value),
+            AttributeValue::Any(value) => {
+                let value = value.borrow();
+                BorrowedAttributeValue::Any(std::cell::Ref::map(value, |value| {
+                    &**value.as_ref().unwrap()
+                }))
+            }
             AttributeValue::None => BorrowedAttributeValue::None,
         }
     }
@@ -606,7 +611,7 @@ impl PartialEq for BorrowedAttributeValue<'_> {
 }
 
 #[cfg(feature = "serialize")]
-fn serialize_any_value<S>(_: &&dyn AnyValue, _: S) -> Result<S::Ok, S::Error>
+fn serialize_any_value<S>(_: &cell::Ref<'_, dyn AnyValue>, _: S) -> Result<S::Ok, S::Error>
 where
     S: serde::Serializer,
 {
@@ -614,7 +619,7 @@ where
 }
 
 #[cfg(feature = "serialize")]
-fn deserialize_any_value<'de, 'a, D>(_: D) -> Result<&'a dyn AnyValue, D::Error>
+fn deserialize_any_value<'de, 'a, D>(_: D) -> Result<cell::Ref<'a, dyn AnyValue>, D::Error>
 where
     D: serde::Deserializer<'de>,
 {
@@ -643,7 +648,11 @@ impl<'a> PartialEq for AttributeValue<'a> {
             (Self::Int(l0), Self::Int(r0)) => l0 == r0,
             (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
             (Self::Listener(_), Self::Listener(_)) => true,
-            (Self::Any(l0), Self::Any(r0)) => l0.any_cmp(&**r0),
+            (Self::Any(l0), Self::Any(r0)) => {
+                let l0 = l0.borrow();
+                let r0 = r0.borrow();
+                l0.as_ref().unwrap().any_cmp(&**r0.as_ref().unwrap())
+            }
             _ => false,
         }
     }
@@ -835,6 +844,12 @@ pub trait IntoAttributeValue<'a> {
     fn into_value(self, bump: &'a Bump) -> AttributeValue<'a>;
 }
 
+impl<'a> IntoAttributeValue<'a> for AttributeValue<'a> {
+    fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
+        self
+    }
+}
+
 impl<'a> IntoAttributeValue<'a> for &'a str {
     fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
         AttributeValue::Text(self)
@@ -870,6 +885,6 @@ impl<'a> IntoAttributeValue<'a> for Arguments<'_> {
 
 impl<'a> IntoAttributeValue<'a> for BumpBox<'a, dyn AnyValue> {
     fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
-        AttributeValue::Any(self)
+        AttributeValue::Any(RefCell::new(Some(self)))
     }
 }

+ 12 - 1
packages/core/src/scopes.rs

@@ -7,7 +7,7 @@ use crate::{
     innerlude::{ErrorBoundary, Scheduler, SchedulerMsg},
     lazynodes::LazyNodes,
     nodes::{ComponentReturn, IntoAttributeValue, IntoDynNode, RenderReturn},
-    Attribute, AttributeValue, Element, Event, Properties, TaskId,
+    AnyValue, Attribute, AttributeValue, Element, Event, Properties, TaskId,
 };
 use bumpalo::{boxed::Box as BumpBox, Bump};
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -513,6 +513,17 @@ impl<'src> ScopeState {
         AttributeValue::Listener(RefCell::new(Some(boxed)))
     }
 
+    /// Create a new [`AttributeValue`] with a value that implements [`AnyValue`]
+    pub fn any_value<T: AnyValue>(&'src self, value: T) -> AttributeValue<'src> {
+        // safety: there's no other way to create a dynamicly-dispatched bump box other than alloc + from-raw
+        // This is the suggested way to build a bumpbox
+        //
+        // In theory, we could just use regular boxes
+        let boxed: BumpBox<'src, dyn AnyValue> =
+            unsafe { BumpBox::from_raw(self.bump().alloc(value)) };
+        AttributeValue::Any(RefCell::new(Some(boxed)))
+    }
+
     /// Inject an error into the nearest error boundary and quit rendering
     ///
     /// The error doesn't need to implement Error or any specific traits since the boundary

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

@@ -641,7 +641,7 @@ impl VirtualDom {
 
     /// Swap the current mutations with a new
     fn finalize(&mut self) -> Mutations {
-        self.mutations.take()
+        std::mem::take(&mut self.mutations)
     }
 }
 

+ 1 - 1
packages/native-core/src/node.rs

@@ -111,7 +111,7 @@ impl<V: FromAnyValue> From<BorrowedAttributeValue<'_>> for OwnedAttributeValue<V
             BorrowedAttributeValue::Float(float) => Self::Float(float),
             BorrowedAttributeValue::Int(int) => Self::Int(int),
             BorrowedAttributeValue::Bool(bool) => Self::Bool(bool),
-            BorrowedAttributeValue::Any(any) => Self::Custom(V::from_any_value(any)),
+            BorrowedAttributeValue::Any(any) => Self::Custom(V::from_any_value(&*any)),
             BorrowedAttributeValue::None => Self::None,
         }
     }