reduce usage of unsafe

This commit is contained in:
= committed 2022-12-26 08:37:50 -06:00
1 parent 738f1b3ce0
commit 170a3669f7
3 files changed
+47 -39

No files matched your search

+20 -1
View File
@@ -48,7 +48,20 @@ impl<'a> Mutations<'a> {
/// Push a new mutation into the dom_edits list /// Push a new mutation into the dom_edits list
pub(crate) fn push(&mut self, mutation: Mutation<'static>) { 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, id: ElementId,
}, },
} }
impl Mutation<'static> {
pub(crate) fn downcast_lifetime<'a>(self) -> Mutation<'a> {
unsafe { std::mem::transmute(self) }
}
}
+22 -30
View File
@@ -8,6 +8,7 @@ use std::{
cell::{Cell, RefCell}, cell::{Cell, RefCell},
fmt::Arguments, fmt::Arguments,
future::Future, future::Future,
ops::Deref,
}; };
pub type TemplateId = &'static str; pub type TemplateId = &'static str;
@@ -416,26 +417,14 @@ impl AnyValueContainer {
return Self(std::rc::Rc::new(value)); 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. /// Returns a reference to the inner value.
pub fn downcast_ref<T: Any>(&self) -> Option<&T> { pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
if self.0.our_typeid() == TypeId::of::<T>() { self.0.deref().as_any().downcast_ref()
Some(unsafe { self.downcast_ref_unchecked() })
} else {
None
}
} }
/// 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 { 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_eq!(a.downcast_ref::<i64>(), None);
assert!(a.is::<i32>()); assert!(a.is::<i32>());
assert!(!a.is::<i64>()); assert!(!a.is::<i64>());
unsafe {
assert_eq!(a.downcast_ref_unchecked::<i32>(), &1i32);
}
} }
#[cfg(feature = "serialize")] #[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. // The sync_attributes flag restricts any valuse to be sync and send.
#[doc(hidden)] #[doc(hidden)]
#[cfg(feature = "sync_attributes")] #[cfg(feature = "sync_attributes")]
pub trait AnyValue: Sync + Send { pub trait AnyValue: Sync + Send + 'static {
fn any_cmp(&self, other: &dyn AnyValue) -> bool; 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")] #[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 { fn any_cmp(&self, other: &dyn AnyValue) -> bool {
if self.our_typeid() != other.our_typeid() { if self.type_id() != other.type_id() {
return false; return false;
} }
self == unsafe { &*(other as *const _ as *const T) } self == unsafe { &*(other as *const _ as *const T) }
} }
fn our_typeid(&self) -> TypeId { fn as_any(&self) -> &dyn Any {
self.type_id() self
} }
} }
#[doc(hidden)] #[doc(hidden)]
#[cfg(not(feature = "sync_attributes"))] #[cfg(not(feature = "sync_attributes"))]
pub trait AnyValue { pub trait AnyValue: 'static {
fn any_cmp(&self, other: &dyn AnyValue) -> bool; 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"))] #[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 { fn any_cmp(&self, other: &dyn AnyValue) -> bool {
if self.our_typeid() != other.our_typeid() { if self.type_id() != other.type_id() {
return false; return false;
} }
self == unsafe { &*(other as *const _ as *const T) } self == unsafe { &*(other as *const _ as *const T) }
} }
fn our_typeid(&self) -> TypeId { fn as_any(&self) -> &dyn Any {
self.type_id() self
} }
} }
+5 -8
View File
@@ -489,7 +489,7 @@ impl VirtualDom {
RenderReturn::Async(_) => unreachable!("Root scope cannot be an async component"), 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 /// 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 there's no pending suspense, then we have no reason to wait for anything
if self.scheduler.leaves.borrow().is_empty() { if self.scheduler.leaves.borrow().is_empty() {
return unsafe { std::mem::transmute(self.finalize()) }; return self.finalize();
} }
// Poll the suspense leaves in the meantime // Poll the suspense leaves in the meantime
@@ -608,17 +608,14 @@ impl VirtualDom {
if let Either::Left((_, _)) = select(&mut deadline, pinned).await { if let Either::Left((_, _)) = select(&mut deadline, pinned).await {
// release the borrowed // release the borrowed
drop(work); drop(work);
return unsafe { std::mem::transmute(self.finalize()) }; return self.finalize();
} }
} }
} }
/// Swap the current mutations with a new /// Swap the current mutations with a new
fn finalize(&mut self) -> Mutations<'static> { fn finalize<'a>(&'a mut self) -> Mutations<'a> {
// todo: make this a routine self.mutations.take()
let mut out = Mutations::default();
std::mem::swap(&mut self.mutations, &mut out);
out
} }
} }