From 170a3669f76e1b41d9459e3e975750db4d569346 Mon Sep 17 00:00:00 2001 From: = Date: Mon, 26 Dec 2022 08:37:50 -0600 Subject: [PATCH] reduce usage of unsafe --- packages/core/src/mutations.rs | 21 ++++++++++++- packages/core/src/nodes.rs | 52 ++++++++++++++------------------ packages/core/src/virtual_dom.rs | 13 +++----- 3 files changed, 47 insertions(+), 39 deletions(-) diff --git a/packages/core/src/mutations.rs b/packages/core/src/mutations.rs index 1d27769a2..06116f5dc 100644 --- a/packages/core/src/mutations.rs +++ b/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) } + } +} diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 8fa33e526..cc9ac2829 100644 --- a/packages/core/src/nodes.rs +++ b/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(&self) -> &T { - unsafe { &*(self.0.as_ref() as *const _ as *const T) } - } - /// Returns a reference to the inner value. pub fn downcast_ref(&self) -> Option<&T> { - if self.0.our_typeid() == TypeId::of::() { - 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(&self) -> bool { - self.0.our_typeid() == TypeId::of::() + self.0.deref().as_any().is::() } } @@ -446,9 +435,6 @@ fn test_any_value_rc() { assert_eq!(a.downcast_ref::(), None); assert!(a.is::()); assert!(!a.is::()); - unsafe { - assert_eq!(a.downcast_ref_unchecked::(), &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 AnyValue for T { +impl 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 AnyValue for T { +impl 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 } } diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index c862a3e39..9afbe2ce9 100644 --- a/packages/core/src/virtual_dom.rs +++ b/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() } }