Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 0 additions & 203 deletions packages/core-types/src/event.rs

This file was deleted.

108 changes: 98 additions & 10 deletions packages/core/src/events.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::{properties::SuperFrom, runtime::RuntimeGuard, Runtime, ScopeId};
use crate::{
prelude::current_scope_id, properties::SuperFrom, runtime::RuntimeGuard, Runtime, ScopeId,
};
use generational_box::GenerationalBox;
use std::{cell::RefCell, marker::PhantomData, panic::Location, rc::Rc};
use std::{any::Any, cell::RefCell, marker::PhantomData, panic::Location, rc::Rc};

/// A wrapper around some generic data that handles the event's state
///
Expand Down Expand Up @@ -67,6 +69,17 @@ impl<T: ?Sized> Event<T> {
}
}

/// Convert this event into a boxed event with a dynamic type
pub fn into_any(self) -> Event<dyn Any>
where
T: Sized,
{
Event {
data: self.data as Rc<dyn Any>,
metadata: self.metadata,
}
}

/// Prevent this event from continuing to bubble up the tree to parent elements.
///
/// # Example
Expand Down Expand Up @@ -376,6 +389,25 @@ impl<
}
}

impl<
Function: FnMut(Event<T>) -> Spawn + 'static,
T: 'static,
Spawn: SpawnIfAsync<Marker> + 'static,
Marker,
> SuperFrom<Function, MarkerWrapper<Marker>> for ListenerCb<T>
{
fn super_from(input: Function) -> Self {
ListenerCb::new(input)
}
}

// ListenerCb<T> can be created from Callback<Event<T>>
impl<T: 'static> SuperFrom<Callback<Event<T>>> for ListenerCb<T> {
fn super_from(input: Callback<Event<T>>) -> Self {
ListenerCb::new(move |event| input(event))
}
}

#[doc(hidden)]
pub struct UnitClosure<Marker>(PhantomData<Marker>);

Expand Down Expand Up @@ -471,14 +503,6 @@ impl<Args: 'static, Ret: 'static> Callback<Args, Ret> {
Self { callback, origin }
}

/// Leak a new reference to the [`Callback`] that will not be dropped unless the callback is dropped manually
pub(crate) fn leak_reference(&self) -> generational_box::BorrowResult<Callback<Args, Ret>> {
Ok(Callback {
callback: self.callback.leak_reference()?,
origin: self.origin,
})
}

/// Call this callback with the appropriate argument type
///
/// This borrows the callback using a RefCell. Recursively calling a callback will cause a panic.
Expand Down Expand Up @@ -559,3 +583,67 @@ impl<Args: 'static, Ret: 'static> std::ops::Deref for Callback<Args, Ret> {
reference_to_closure as &_
}
}

/// An owned callback type used in [`AttributeValue::Listener`]
pub struct ListenerCb<T = ()> {
pub(crate) origin: ScopeId,
callback: Rc<RefCell<dyn FnMut(Event<dyn Any>)>>,
_marker: PhantomData<T>,
}

impl<T> Clone for ListenerCb<T> {
fn clone(&self) -> Self {
Self {
origin: self.origin,
callback: self.callback.clone(),
_marker: PhantomData,
}
}
}

impl<T> PartialEq for ListenerCb<T> {
fn eq(&self, other: &Self) -> bool {
// We compare the pointers of the callbacks, since they are unique
Rc::ptr_eq(&self.callback, &other.callback) && self.origin == other.origin
}
}

impl<T> ListenerCb<T> {
/// Create a new [`ListenerCb`] from a callback
pub fn new<MaybeAsync: SpawnIfAsync<Marker>, Marker>(
mut f: impl FnMut(Event<T>) -> MaybeAsync + 'static,
) -> Self
where
T: 'static,
{
Self {
origin: current_scope_id().expect("ListenerCb must be created within a scope"),
callback: Rc::new(RefCell::new(move |event: Event<dyn Any>| {
let data = event.data.downcast::<T>().unwrap();
f(Event {
metadata: event.metadata.clone(),
data,
})
.spawn();
})),
_marker: PhantomData,
}
}

/// Call the callback with an event
pub fn call(&self, event: Event<dyn Any>) {
let runtime = Runtime::current().expect("ListenerCb must be called within a runtime");
runtime.with_scope_on_stack(self.origin, || {
(self.callback.borrow_mut())(event);
});
}

/// Erase the type of the callback, allowing it to be used with any type of event
pub fn erase(self) -> ListenerCb {
ListenerCb {
origin: self.origin,
callback: self.callback,
_marker: PhantomData,
}
}
}
8 changes: 4 additions & 4 deletions packages/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ pub(crate) mod innerlude {
pub use crate::innerlude::{
fc_to_builder, generation, schedule_update, schedule_update_any, use_hook, vdom_is_rendering,
AnyValue, Attribute, AttributeValue, CapturedError, Component, ComponentFunction, DynamicNode,
Element, ElementId, Event, Fragment, HasAttributes, IntoDynNode, LaunchConfig, MarkerWrapper,
Mutation, Mutations, NoOpMutations, Ok, Properties, Result, Runtime, ScopeId, ScopeState,
SpawnIfAsync, Task, Template, TemplateAttribute, TemplateNode, VComponent, VNode, VNodeInner,
VPlaceholder, VText, VirtualDom, WriteMutations,
Element, ElementId, Event, Fragment, HasAttributes, IntoDynNode, LaunchConfig, ListenerCb,
MarkerWrapper, Mutation, Mutations, NoOpMutations, Ok, Properties, Result, Runtime, ScopeId,
ScopeState, SpawnIfAsync, Task, Template, TemplateAttribute, TemplateNode, VComponent, VNode,
VNodeInner, VPlaceholder, VText, VirtualDom, WriteMutations,
};

/// The purpose of this module is to alleviate imports of many common types
Expand Down
Loading
Loading