1
0
= 2 жил өмнө
parent
commit
170a3669f7

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

@@ -48,7 +48,20 @@ impl<'a> Mutations<'a> {
 
     /// Push a new mutation into the dom_edits list
     pub(crate) fn push(&mut self, mutation: Mutation<'static>) {
-        unsafe { self.edits.push(std::mem::transmute(mutation)) }
+        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)) },
+        }
     }
 }
 
@@ -244,3 +257,9 @@ pub enum Mutation<'a> {
         id: ElementId,
     },
 }
+
+impl Mutation<'static> {
+    pub(crate) fn downcast_lifetime<'a>(self) -> Mutation<'a> {
+        unsafe { std::mem::transmute(self) }
+    }
+}

+ 22 - 30
packages/core/src/nodes.rs

@@ -8,6 +8,7 @@ use std::{
     cell::{Cell, RefCell},
     fmt::Arguments,
     future::Future,
+    ops::Deref,
 };
 
 pub type TemplateId = &'static str;
@@ -416,26 +417,14 @@ impl AnyValueContainer {
         return Self(std::rc::Rc::new(value));
     }
 
-    /// Returns a reference to the inner value without checking the type.
-    ///
-    /// # Safety
-    /// The caller must ensure that the type of the inner value is `T`.
-    pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
-        unsafe { &*(self.0.as_ref() as *const _ as *const T) }
-    }
-
     /// Returns a reference to the inner value.
     pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
-        if self.0.our_typeid() == TypeId::of::<T>() {
-            Some(unsafe { self.downcast_ref_unchecked() })
-        } else {
-            None
-        }
+        self.0.deref().as_any().downcast_ref()
     }
 
-    /// Checks if the inner value is of type `T`.
+    /// Checks if the type of the inner value is 'T'.
     pub fn is<T: Any>(&self) -> bool {
-        self.0.our_typeid() == TypeId::of::<T>()
+        self.0.deref().as_any().is::<T>()
     }
 }
 
@@ -446,9 +435,6 @@ fn test_any_value_rc() {
     assert_eq!(a.downcast_ref::<i64>(), None);
     assert!(a.is::<i32>());
     assert!(!a.is::<i64>());
-    unsafe {
-        assert_eq!(a.downcast_ref_unchecked::<i32>(), &1i32);
-    }
 }
 
 #[cfg(feature = "serialize")]
@@ -503,45 +489,51 @@ impl<'a> PartialEq for AttributeValue<'a> {
 // The sync_attributes flag restricts any valuse to be sync and send.
 #[doc(hidden)]
 #[cfg(feature = "sync_attributes")]
-pub trait AnyValue: Sync + Send {
+pub trait AnyValue: Sync + Send + 'static {
     fn any_cmp(&self, other: &dyn AnyValue) -> bool;
-    fn our_typeid(&self) -> TypeId;
+    fn as_any(&self) -> &dyn Any;
+    fn type_id(&self) -> TypeId {
+        self.as_any().type_id()
+    }
 }
 
 #[cfg(feature = "sync_attributes")]
-impl<T: Any + PartialEq + Send + Sync> AnyValue for T {
+impl<T: Any + PartialEq + Send + Sync + 'static> AnyValue for T {
     fn any_cmp(&self, other: &dyn AnyValue) -> bool {
-        if self.our_typeid() != other.our_typeid() {
+        if self.type_id() != other.type_id() {
             return false;
         }
 
         self == unsafe { &*(other as *const _ as *const T) }
     }
 
-    fn our_typeid(&self) -> TypeId {
-        self.type_id()
+    fn as_any(&self) -> &dyn Any {
+        self
     }
 }
 
 #[doc(hidden)]
 #[cfg(not(feature = "sync_attributes"))]
-pub trait AnyValue {
+pub trait AnyValue: 'static {
     fn any_cmp(&self, other: &dyn AnyValue) -> bool;
-    fn our_typeid(&self) -> TypeId;
+    fn as_any(&self) -> &dyn Any;
+    fn type_id(&self) -> TypeId {
+        self.as_any().type_id()
+    }
 }
 
 #[cfg(not(feature = "sync_attributes"))]
-impl<T: Any + PartialEq> AnyValue for T {
+impl<T: Any + PartialEq + 'static> AnyValue for T {
     fn any_cmp(&self, other: &dyn AnyValue) -> bool {
-        if self.our_typeid() != other.our_typeid() {
+        if self.type_id() != other.type_id() {
             return false;
         }
 
         self == unsafe { &*(other as *const _ as *const T) }
     }
 
-    fn our_typeid(&self) -> TypeId {
-        self.type_id()
+    fn as_any(&self) -> &dyn Any {
+        self
     }
 }
 

+ 5 - 8
packages/core/src/virtual_dom.rs

@@ -489,7 +489,7 @@ impl VirtualDom {
             RenderReturn::Async(_) => unreachable!("Root scope cannot be an async component"),
         }
 
-        unsafe { std::mem::transmute(self.finalize()) }
+        self.finalize()
     }
 
     /// Render whatever the VirtualDom has ready as fast as possible without requiring an executor to progress
@@ -594,7 +594,7 @@ impl VirtualDom {
 
             // If there's no pending suspense, then we have no reason to wait for anything
             if self.scheduler.leaves.borrow().is_empty() {
-                return unsafe { std::mem::transmute(self.finalize()) };
+                return self.finalize();
             }
 
             // Poll the suspense leaves in the meantime
@@ -608,17 +608,14 @@ impl VirtualDom {
             if let Either::Left((_, _)) = select(&mut deadline, pinned).await {
                 // release the borrowed
                 drop(work);
-                return unsafe { std::mem::transmute(self.finalize()) };
+                return self.finalize();
             }
         }
     }
 
     /// Swap the current mutations with a new
-    fn finalize(&mut self) -> Mutations<'static> {
-        // todo: make this a routine
-        let mut out = Mutations::default();
-        std::mem::swap(&mut self.mutations, &mut out);
-        out
+    fn finalize<'a>(&'a mut self) -> Mutations<'a> {
+        self.mutations.take()
     }
 }