diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index e5440fd85..a11fc69ba 100644 --- a/packages/core/src/arena.rs +++ b/packages/core/src/arena.rs @@ -160,8 +160,8 @@ impl VirtualDom { AttributeValue::Listener(l) => { _ = l.take(); } - AttributeValue::Any(_) => { - todo!() + AttributeValue::Any(a) => { + _ = a.take(); } _ => (), } diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 4e26f5a56..c4f162580 100644 --- a/packages/core/src/lib.rs +++ b/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, }; } diff --git a/packages/core/src/mutations.rs b/packages/core/src/mutations.rs index b02e89581..551069c45 100644 --- a/packages/core/src/mutations.rs +++ b/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) } - } -} diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index d17863c20..bb9f6734b 100644 --- a/packages/core/src/nodes.rs +++ b/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>>), /// An arbitrary value that implements PartialEq and is static - Any(BumpBox<'a, dyn AnyValue>), + Any(RefCell>>), /// 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(_: &&dyn AnyValue, _: S) -> Result +fn serialize_any_value(_: &cell::Ref<'_, dyn AnyValue>, _: S) -> Result 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, 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))) } } diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index d07b52704..03ce08d57 100644 --- a/packages/core/src/scopes.rs +++ b/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(&'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 diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 043e7fafb..f8c625a20 100644 --- a/packages/core/src/virtual_dom.rs +++ b/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) } } diff --git a/packages/native-core/src/node.rs b/packages/native-core/src/node.rs index 3b91cee45..f5e93e2f5 100644 --- a/packages/native-core/src/node.rs +++ b/packages/native-core/src/node.rs @@ -111,7 +111,7 @@ impl From> for OwnedAttributeValue 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, } }