wip: more overhaul on virtualevents

This commit is contained in:
Jonathan Kelley committed 2021-08-25 16:40:18 -04:00
1 parent cef116aa3a
commit 41cc42919d
10 files changed
+165 -181

No files matched your search

+5 -5
View File
@@ -251,7 +251,7 @@ impl<'bump> DiffMachine<'bump> {
fn create_suspended_node(&mut self, suspended: &'bump VSuspended) { fn create_suspended_node(&mut self, suspended: &'bump VSuspended) {
let real_id = self.vdom.reserve_node(); let real_id = self.vdom.reserve_node();
self.mutations.create_placeholder(real_id); self.mutations.create_placeholder(real_id);
suspended.node.set(Some(real_id)); suspended.dom_id.set(Some(real_id));
self.stack.add_child_count(1); self.stack.add_child_count(1);
} }
@@ -372,7 +372,7 @@ impl<'bump> DiffMachine<'bump> {
(Component(old), Component(new)) => self.diff_component_nodes(old, new), (Component(old), Component(new)) => self.diff_component_nodes(old, new),
(Fragment(old), Fragment(new)) => self.diff_fragment_nodes(old, new), (Fragment(old), Fragment(new)) => self.diff_fragment_nodes(old, new),
(Anchor(old), Anchor(new)) => new.dom_id.set(old.dom_id.get()), (Anchor(old), Anchor(new)) => new.dom_id.set(old.dom_id.get()),
(Suspended(old), Suspended(new)) => new.node.set(old.node.get()), (Suspended(old), Suspended(new)) => new.dom_id.set(old.dom_id.get()),
(Element(old), Element(new)) => self.diff_element_nodes(old, new), (Element(old), Element(new)) => self.diff_element_nodes(old, new),
// Anything else is just a basic replace and create // Anything else is just a basic replace and create
@@ -952,7 +952,7 @@ impl<'bump> DiffMachine<'bump> {
match &search_node.take().unwrap() { match &search_node.take().unwrap() {
VNode::Text(t) => break t.dom_id.get(), VNode::Text(t) => break t.dom_id.get(),
VNode::Element(t) => break t.dom_id.get(), VNode::Element(t) => break t.dom_id.get(),
VNode::Suspended(t) => break t.node.get(), VNode::Suspended(t) => break t.dom_id.get(),
VNode::Anchor(t) => break t.dom_id.get(), VNode::Anchor(t) => break t.dom_id.get(),
VNode::Fragment(frag) => { VNode::Fragment(frag) => {
@@ -983,7 +983,7 @@ impl<'bump> DiffMachine<'bump> {
} }
VNode::Text(t) => break t.dom_id.get(), VNode::Text(t) => break t.dom_id.get(),
VNode::Element(t) => break t.dom_id.get(), VNode::Element(t) => break t.dom_id.get(),
VNode::Suspended(t) => break t.node.get(), VNode::Suspended(t) => break t.dom_id.get(),
VNode::Anchor(t) => break t.dom_id.get(), VNode::Anchor(t) => break t.dom_id.get(),
} }
} }
@@ -1016,7 +1016,7 @@ impl<'bump> DiffMachine<'bump> {
}); });
} }
VNode::Suspended(s) => { VNode::Suspended(s) => {
s.node.get().map(|id| { s.dom_id.get().map(|id| {
self.mutations.remove(id.as_u64()); self.mutations.remove(id.as_u64());
self.vdom.collect_garbage(id); self.vdom.collect_garbage(id);
}); });
+27 -33
View File
@@ -3,16 +3,7 @@
//! //!
//! 3rd party renderers are responsible for converting their native events into these virtual event types. Events might //! 3rd party renderers are responsible for converting their native events into these virtual event types. Events might
//! be heavy or need to interact through FFI, so the events themselves are designed to be lazy. //! be heavy or need to interact through FFI, so the events themselves are designed to be lazy.
use crate::innerlude::{ElementId, ScopeId};
use std::{
cell::{Cell, RefCell},
rc::Rc,
};
use crate::{
innerlude::{ElementId, ScopeId},
VNode,
};
#[derive(Debug)] #[derive(Debug)]
pub struct EventTrigger { pub struct EventTrigger {
@@ -23,12 +14,15 @@ pub struct EventTrigger {
pub mounted_dom_id: Option<ElementId>, pub mounted_dom_id: Option<ElementId>,
/// The type of event /// The type of event
pub event: VirtualEvent, pub event: SyntheticEvent,
/// Is consistency important for this event?
/// UI events are the only events where consistency is important.
/// All else may be batched.
pub discrete: bool, pub discrete: bool,
} }
pub enum VirtualEvent { pub enum SyntheticEvent {
KeyboardEvent(on::KeyboardEvent), KeyboardEvent(on::KeyboardEvent),
TouchEvent(on::TouchEvent), TouchEvent(on::TouchEvent),
MouseEvent(on::MouseEvent), MouseEvent(on::MouseEvent),
@@ -47,24 +41,24 @@ pub enum VirtualEvent {
// ImageEvent(event_data::ImageEvent), // ImageEvent(event_data::ImageEvent),
} }
impl std::fmt::Debug for VirtualEvent { impl std::fmt::Debug for SyntheticEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self { let name = match self {
VirtualEvent::ClipboardEvent(_) => "ClipboardEvent", SyntheticEvent::ClipboardEvent(_) => "ClipboardEvent",
VirtualEvent::CompositionEvent(_) => "CompositionEvent", SyntheticEvent::CompositionEvent(_) => "CompositionEvent",
VirtualEvent::KeyboardEvent(_) => "KeyboardEvent", SyntheticEvent::KeyboardEvent(_) => "KeyboardEvent",
VirtualEvent::FocusEvent(_) => "FocusEvent", SyntheticEvent::FocusEvent(_) => "FocusEvent",
VirtualEvent::FormEvent(_) => "FormEvent", SyntheticEvent::FormEvent(_) => "FormEvent",
VirtualEvent::SelectionEvent(_) => "SelectionEvent", SyntheticEvent::SelectionEvent(_) => "SelectionEvent",
VirtualEvent::TouchEvent(_) => "TouchEvent", SyntheticEvent::TouchEvent(_) => "TouchEvent",
VirtualEvent::UIEvent(_) => "UIEvent", SyntheticEvent::UIEvent(_) => "UIEvent",
VirtualEvent::WheelEvent(_) => "WheelEvent", SyntheticEvent::WheelEvent(_) => "WheelEvent",
VirtualEvent::MediaEvent(_) => "MediaEvent", SyntheticEvent::MediaEvent(_) => "MediaEvent",
VirtualEvent::AnimationEvent(_) => "AnimationEvent", SyntheticEvent::AnimationEvent(_) => "AnimationEvent",
VirtualEvent::TransitionEvent(_) => "TransitionEvent", SyntheticEvent::TransitionEvent(_) => "TransitionEvent",
VirtualEvent::ToggleEvent(_) => "ToggleEvent", SyntheticEvent::ToggleEvent(_) => "ToggleEvent",
VirtualEvent::MouseEvent(_) => "MouseEvent", SyntheticEvent::MouseEvent(_) => "MouseEvent",
VirtualEvent::PointerEvent(_) => "PointerEvent", SyntheticEvent::PointerEvent(_) => "PointerEvent",
}; };
f.debug_struct("VirtualEvent").field("type", &name).finish() f.debug_struct("VirtualEvent").field("type", &name).finish()
@@ -90,7 +84,7 @@ pub mod on {
}; };
use std::cell::Cell; use std::cell::Cell;
use super::VirtualEvent; use super::SyntheticEvent;
macro_rules! event_directory { macro_rules! event_directory {
( $( ( $(
@@ -126,12 +120,12 @@ pub mod on {
{ {
let bump = &c.bump(); let bump = &c.bump();
let cb: &mut dyn FnMut(VirtualEvent) = bump.alloc(move |evt: VirtualEvent| match evt { let cb: &mut dyn FnMut(SyntheticEvent) = bump.alloc(move |evt: SyntheticEvent| match evt {
VirtualEvent::$wrapper(event) => callback(event), SyntheticEvent::$wrapper(event) => callback(event),
_ => unreachable!("Downcasted VirtualEvent to wrong event type - this is an internal bug!") _ => unreachable!("Downcasted SyntheticEvent to wrong event type - this is an internal bug!")
}); });
let callback: BumpBox<dyn FnMut(VirtualEvent) + 'a> = unsafe { BumpBox::from_raw(cb) }; let callback: BumpBox<dyn FnMut(SyntheticEvent) + 'a> = unsafe { BumpBox::from_raw(cb) };
let event_name = stringify!($name); let event_name = stringify!($name);
let shortname: &'static str = &event_name[2..]; let shortname: &'static str = &event_name[2..];
+54 -57
View File
@@ -126,14 +126,7 @@ where
let handle = cx.submit_task(Box::pin(task_fut.then(move |output| async move { let handle = cx.submit_task(Box::pin(task_fut.then(move |output| async move {
*slot.as_ref().borrow_mut() = Some(output); *slot.as_ref().borrow_mut() = Some(output);
updater(update_id); updater(update_id);
EventTrigger { originator
event: VirtualEvent::AsyncEvent {
should_rerender: false,
},
scope: originator,
priority: EventPriority::Low,
mounted_dom_id: None,
}
}))); })));
TaskHook { TaskHook {
@@ -172,71 +165,75 @@ where
Out: 'static, Out: 'static,
Cb: for<'a> Fn(SuspendedContext<'a>, &Out) -> DomTree<'a> + 'static, Cb: for<'a> Fn(SuspendedContext<'a>, &Out) -> DomTree<'a> + 'static,
{ {
/*
General strategy:
- Create a slot for the future to dump its output into
- Create a new future feeding off the user's future that feeds the output into that slot
- Submit that future as a task
- Take the task handle id and attach that to our suspended node
- when the hook runs, check if the value exists
- if it does, then we can render the node directly
- if it doesn't, then we render a suspended node along with with the callback and task id
*/
cx.use_hook( cx.use_hook(
move |hook_idx| { move |hook_idx| {
let value = Rc::new(RefCell::new(None)); let value = Rc::new(RefCell::new(None));
let dom_node_id = Rc::new(empty_cell());
let domnode = dom_node_id.clone();
let slot = value.clone(); let slot = value.clone();
let callback: SuspendedCallback = Box::new(move |ctx: SuspendedContext| {
let v: std::cell::Ref<Option<Box<dyn Any>>> = slot.as_ref().borrow();
match v.as_ref() {
Some(a) => {
let v: &dyn Any = a.as_ref();
let real_val = v.downcast_ref::<Out>().unwrap();
user_callback(ctx, real_val)
}
None => {
//
Some(VNode::Suspended(VSuspended {
node: domnode.clone(),
}))
}
}
});
let originator = cx.scope.our_arena_idx.clone(); let originator = cx.scope.our_arena_idx.clone();
let task_fut = task_initializer();
let domnode = dom_node_id.clone();
let slot = value.clone(); let handle = cx.submit_task(Box::pin(task_initializer().then(
cx.submit_task(Box::pin(task_fut.then(move |output| async move { move |output| async move {
// When the new value arrives, set the hooks internal slot *slot.borrow_mut() = Some(Box::new(output) as Box<dyn Any>);
// Dioxus will call the user's callback to generate new nodes outside of the diffing system originator
*slot.borrow_mut() = Some(Box::new(output) as Box<dyn Any>); },
EventTrigger { )));
event: VirtualEvent::SuspenseEvent { hook_idx, domnode },
scope: originator,
priority: EventPriority::Low,
mounted_dom_id: None,
}
})));
SuspenseHook { SuspenseHook { handle, value }
value,
callback,
dom_node_id,
}
}, },
move |hook| { move |hook| match hook.value.borrow().as_ref() {
let cx = Context { Some(value) => {
scope: &cx.scope, let out = value.downcast_ref::<Out>().unwrap();
props: &(), let sus = SuspendedContext {
}; inner: Context {
let csx = SuspendedContext { inner: cx }; props: &(),
(&hook.callback)(csx) scope: cx.scope,
},
};
user_callback(sus, out)
}
None => {
let value = hook.value.clone();
cx.render(LazyNodes::new(|f| {
let bump = f.bump();
let g: &dyn FnOnce(SuspendedContext<'src>) -> DomTree<'src> =
bump.alloc(|sus| {
let out = value
.borrow()
.as_ref()
.unwrap()
.as_ref()
.downcast_ref::<Out>()
.unwrap();
user_callback(sus, out)
});
VNode::Suspended(bump.alloc(VSuspended {
dom_id: empty_cell(),
task_id: hook.handle.our_id,
callback: RefCell::new(Some(g)),
}))
}))
}
}, },
|_| {}, |_| {},
) )
} }
pub(crate) struct SuspenseHook { pub(crate) struct SuspenseHook {
pub handle: TaskHandle,
pub value: Rc<RefCell<Option<Box<dyn Any>>>>, pub value: Rc<RefCell<Option<Box<dyn Any>>>>,
pub callback: SuspendedCallback,
pub dom_node_id: Rc<Cell<Option<ElementId>>>,
} }
type SuspendedCallback = Box<dyn for<'a> Fn(SuspendedContext<'a>) -> DomTree<'a>>; type SuspendedCallback = Box<dyn for<'a> Fn(SuspendedContext<'a>) -> DomTree<'a>>;
pub struct SuspendedContext<'a> { pub struct SuspendedContext<'a> {
+1 -1
View File
@@ -13,7 +13,7 @@
pub use crate::innerlude::{ pub use crate::innerlude::{
format_args_f, html, rsx, Context, DiffInstruction, DioxusElement, DomEdit, DomTree, ElementId, format_args_f, html, rsx, Context, DiffInstruction, DioxusElement, DomEdit, DomTree, ElementId,
EventPriority, EventTrigger, LazyNodes, MountType, Mutations, NodeFactory, Properties, ScopeId, EventPriority, EventTrigger, LazyNodes, MountType, Mutations, NodeFactory, Properties, ScopeId,
SuspendedContext, VNode, VirtualDom, VirtualEvent, FC, SuspendedContext, SyntheticEvent, VNode, VirtualDom, FC,
}; };
pub mod prelude { pub mod prelude {
+8 -11
View File
@@ -4,8 +4,9 @@
//! //!
//! These VNodes should be *very* cheap and *very* fast to construct - building a full tree should be insanely quick. //! These VNodes should be *very* cheap and *very* fast to construct - building a full tree should be insanely quick.
use crate::{ use crate::{
events::VirtualEvent, events::SyntheticEvent,
innerlude::{empty_cell, Context, DomTree, ElementId, Properties, Scope, ScopeId, FC}, innerlude::{empty_cell, Context, DomTree, ElementId, Properties, Scope, ScopeId, FC},
SuspendedContext,
}; };
use bumpalo::{boxed::Box as BumpBox, Bump}; use bumpalo::{boxed::Box as BumpBox, Bump};
use std::{ use std::{
@@ -30,7 +31,7 @@ pub enum VNode<'src> {
Component(&'src VComponent<'src>), Component(&'src VComponent<'src>),
Suspended(VSuspended), Suspended(&'src VSuspended<'src>),
Anchor(VAnchor), Anchor(VAnchor),
} }
@@ -127,7 +128,7 @@ pub struct Listener<'bump> {
pub mounted_node: Cell<Option<ElementId>>, pub mounted_node: Cell<Option<ElementId>>,
pub(crate) callback: RefCell<Option<BumpBox<'bump, dyn FnMut(VirtualEvent) + 'bump>>>, pub(crate) callback: RefCell<Option<BumpBox<'bump, dyn FnMut(SyntheticEvent) + 'bump>>>,
} }
impl Listener<'_> { impl Listener<'_> {
@@ -168,8 +169,10 @@ pub struct VComponent<'src> {
pub(crate) user_fc: *const (), pub(crate) user_fc: *const (),
} }
pub struct VSuspended { pub struct VSuspended<'a> {
pub node: Rc<Cell<Option<ElementId>>>, pub dom_id: Cell<Option<ElementId>>,
pub task_id: u64,
pub callback: RefCell<Option<&'a dyn FnOnce(SuspendedContext<'a>) -> DomTree<'a>>>,
} }
/// This struct provides an ergonomic API to quickly build VNodes. /// This struct provides an ergonomic API to quickly build VNodes.
@@ -301,12 +304,6 @@ impl<'a> NodeFactory<'a> {
})) }))
} }
pub fn suspended() -> VNode<'static> {
VNode::Suspended(VSuspended {
node: Rc::new(empty_cell()),
})
}
pub fn attr( pub fn attr(
&self, &self,
name: &'static str, name: &'static str,
+20 -30
View File
@@ -34,7 +34,7 @@ pub struct EventChannel {
pub enum SchedulerMsg { pub enum SchedulerMsg {
Immediate(ScopeId), Immediate(ScopeId),
UiEvent(), UiEvent(EventTrigger),
SubmitTask(u64), SubmitTask(u64),
ToggleTask(u64), ToggleTask(u64),
PauseTask(u64), PauseTask(u64),
@@ -232,16 +232,6 @@ impl Scheduler {
id id
} }
pub fn make_trigger_key(&self, trigger: &EventTrigger) -> EventKey {
let height = self.get_scope(trigger.scope).map(|f| f.height).unwrap();
EventKey {
height,
originator: trigger.scope,
priority: trigger.priority,
}
}
pub fn clean_up_garbage(&mut self) { pub fn clean_up_garbage(&mut self) {
let mut scopes_to_kill = Vec::new(); let mut scopes_to_kill = Vec::new();
let mut garbage_list = Vec::new(); let mut garbage_list = Vec::new();
@@ -330,11 +320,11 @@ impl Scheduler {
pub fn consume_pending_events(&mut self) -> Result<()> { pub fn consume_pending_events(&mut self) -> Result<()> {
while let Some(trigger) = self.pending_events.pop_back() { while let Some(trigger) = self.pending_events.pop_back() {
match &trigger.event { match &trigger.event {
VirtualEvent::AsyncEvent { .. } => {} SyntheticEvent::AsyncEvent { .. } => {}
// This suspense system works, but it's not the most elegant solution. // This suspense system works, but it's not the most elegant solution.
// TODO: Replace this system // TODO: Replace this system
VirtualEvent::SuspenseEvent { hook_idx, domnode } => { SyntheticEvent::SuspenseEvent { hook_idx, domnode } => {
todo!("suspense needs to be converted into its own channel"); todo!("suspense needs to be converted into its own channel");
// // Safety: this handler is the only thing that can mutate shared items at this moment in tim // // Safety: this handler is the only thing that can mutate shared items at this moment in tim
@@ -369,21 +359,21 @@ impl Scheduler {
// } // }
} }
VirtualEvent::ClipboardEvent(_) SyntheticEvent::ClipboardEvent(_)
| VirtualEvent::CompositionEvent(_) | SyntheticEvent::CompositionEvent(_)
| VirtualEvent::KeyboardEvent(_) | SyntheticEvent::KeyboardEvent(_)
| VirtualEvent::FocusEvent(_) | SyntheticEvent::FocusEvent(_)
| VirtualEvent::FormEvent(_) | SyntheticEvent::FormEvent(_)
| VirtualEvent::SelectionEvent(_) | SyntheticEvent::SelectionEvent(_)
| VirtualEvent::TouchEvent(_) | SyntheticEvent::TouchEvent(_)
| VirtualEvent::UIEvent(_) | SyntheticEvent::UIEvent(_)
| VirtualEvent::WheelEvent(_) | SyntheticEvent::WheelEvent(_)
| VirtualEvent::MediaEvent(_) | SyntheticEvent::MediaEvent(_)
| VirtualEvent::AnimationEvent(_) | SyntheticEvent::AnimationEvent(_)
| VirtualEvent::TransitionEvent(_) | SyntheticEvent::TransitionEvent(_)
| VirtualEvent::ToggleEvent(_) | SyntheticEvent::ToggleEvent(_)
| VirtualEvent::MouseEvent(_) | SyntheticEvent::MouseEvent(_)
| VirtualEvent::PointerEvent(_) => { | SyntheticEvent::PointerEvent(_) => {
if let Some(scope) = self.get_scope_mut(trigger.scope) { if let Some(scope) = self.get_scope_mut(trigger.scope) {
if let Some(element) = trigger.mounted_dom_id { if let Some(element) = trigger.mounted_dom_id {
scope.call_listener(trigger.event, element)?; scope.call_listener(trigger.event, element)?;
@@ -528,8 +518,8 @@ impl Scheduler {
} }
pub struct TaskHandle { pub struct TaskHandle {
channel: EventChannel, pub channel: EventChannel,
our_id: u64, pub our_id: u64,
} }
impl TaskHandle { impl TaskHandle {
+11 -3
View File
@@ -40,6 +40,8 @@ pub struct Scope {
pub(crate) listeners: RefCell<Vec<*const Listener<'static>>>, pub(crate) listeners: RefCell<Vec<*const Listener<'static>>>,
pub(crate) borrowed_props: RefCell<Vec<*const VComponent<'static>>>, pub(crate) borrowed_props: RefCell<Vec<*const VComponent<'static>>>,
pub(crate) suspended_nodes: RefCell<HashMap<u64, *const VNode<'static>>>,
// State // State
pub(crate) hooks: HookList, pub(crate) hooks: HookList,
pub(crate) shared_contexts: RefCell<HashMap<TypeId, Rc<dyn Any>>>, pub(crate) shared_contexts: RefCell<HashMap<TypeId, Rc<dyn Any>>>,
@@ -52,8 +54,9 @@ pub struct Scope {
// The type of closure that wraps calling components // The type of closure that wraps calling components
pub type WrappedCaller = dyn for<'b> Fn(&'b Scope) -> DomTree<'b>; pub type WrappedCaller = dyn for<'b> Fn(&'b Scope) -> DomTree<'b>;
// The type of task that gets sent to the task scheduler /// The type of task that gets sent to the task scheduler
pub type FiberTask = Pin<Box<dyn Future<Output = EventTrigger>>>; /// Submitting a fiber task returns a handle to that task, which can be used to wake up suspended nodes
pub type FiberTask = Pin<Box<dyn Future<Output = ScopeId>>>;
impl Scope { impl Scope {
// we are being created in the scope of an existing component (where the creator_node lifetime comes into play) // we are being created in the scope of an existing component (where the creator_node lifetime comes into play)
@@ -91,6 +94,7 @@ impl Scope {
height, height,
frames: ActiveFrame::new(), frames: ActiveFrame::new(),
hooks: Default::default(), hooks: Default::default(),
suspended_nodes: Default::default(),
shared_contexts: Default::default(), shared_contexts: Default::default(),
listeners: Default::default(), listeners: Default::default(),
borrowed_props: Default::default(), borrowed_props: Default::default(),
@@ -194,7 +198,11 @@ impl Scope {
// A safe wrapper around calling listeners // A safe wrapper around calling listeners
// //
// //
pub(crate) fn call_listener(&mut self, event: VirtualEvent, element: ElementId) -> Result<()> { pub(crate) fn call_listener(
&mut self,
event: SyntheticEvent,
element: ElementId,
) -> Result<()> {
let listners = self.listeners.borrow_mut(); let listners = self.listeners.borrow_mut();
let raw_listener = listners.iter().find(|lis| { let raw_listener = listners.iter().find(|lis| {
+18 -20
View File
@@ -100,24 +100,31 @@ impl VirtualDom {
/// ///
/// Note: the VirtualDOM is not progressed, you must either "run_with_deadline" or use "rebuild" to progress it. /// Note: the VirtualDOM is not progressed, you must either "run_with_deadline" or use "rebuild" to progress it.
pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self { pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
let components = Scheduler::new(); let scheduler = Scheduler::new();
let root_props: Pin<Box<dyn Any>> = Box::pin(root_props); let _root_props: Pin<Box<dyn Any>> = Box::pin(root_props);
let props_ptr = root_props.as_ref().downcast_ref::<P>().unwrap() as *const P; let _root_prop_type = TypeId::of::<P>();
let update_sender = components.immediate_sender.clone(); let props_ptr = _root_props.as_ref().downcast_ref::<P>().unwrap() as *const P;
let base_scope = components.insert_scope_with_key(move |myidx| { let base_scope = scheduler.insert_scope_with_key(|myidx| {
let caller = NodeFactory::create_component_caller(root, props_ptr as *const _); let caller = NodeFactory::create_component_caller(root, props_ptr as *const _);
let name = type_name_of(root); let name = type_name_of(root);
Scope::new(caller, myidx, None, 0, ScopeChildren(&[]), update_sender) Scope::new(
caller,
myidx,
None,
0,
ScopeChildren(&[]),
scheduler.channel.clone(),
)
}); });
Self { Self {
base_scope, base_scope,
_root_props: root_props, _root_props,
scheduler: components, scheduler,
_root_prop_type: TypeId::of::<P>(), _root_prop_type,
} }
} }
@@ -218,15 +225,6 @@ impl VirtualDom {
// .expect("this future will always resolve immediately") // .expect("this future will always resolve immediately")
} }
/// Runs the virtualdom with no time limit.
///
/// If there are pending tasks, they will be progressed before returning. This is useful when rendering an application
/// that has suspended nodes or suspended tasks. Be warned - any async tasks running forever will prevent this method
/// from completing. Consider using `run` and specifing a deadline.
pub async fn run_unbounded<'s>(&'s mut self) -> Mutations<'s> {
self.run_with_deadline(async {}).await.unwrap()
}
/// Run the virtualdom with a deadline. /// Run the virtualdom with a deadline.
/// ///
/// This method will progress async tasks until the deadline is reached. If tasks are completed before the deadline, /// This method will progress async tasks until the deadline is reached. If tasks are completed before the deadline,
@@ -327,8 +325,8 @@ impl VirtualDom {
} }
} }
pub fn get_event_sender(&self) -> futures_channel::mpsc::UnboundedSender<EventTrigger> { pub fn get_event_sender(&self) -> futures_channel::mpsc::UnboundedSender<SchedulerMsg> {
self.scheduler.ui_event_sender.clone() self.scheduler.channel.sender.clone()
} }
pub fn has_work(&self) -> bool { pub fn has_work(&self) -> bool {
+2 -2
View File
@@ -6,7 +6,7 @@ use std::rc::Rc;
use dioxus_core::{ use dioxus_core::{
events::{ events::{
on::{MouseEvent, MouseEventInner}, on::{MouseEvent, MouseEventInner},
VirtualEvent, SyntheticEvent,
}, },
ElementId, EventPriority, EventTrigger, ScopeId, ElementId, EventPriority, EventTrigger, ScopeId,
}; };
@@ -21,7 +21,7 @@ pub fn trigger_from_serialized(val: serde_json::Value) -> EventTrigger {
let mut data: Vec<ImEvent> = serde_json::from_value(val).unwrap(); let mut data: Vec<ImEvent> = serde_json::from_value(val).unwrap();
let data = data.drain(..).next().unwrap(); let data = data.drain(..).next().unwrap();
let event = VirtualEvent::MouseEvent(MouseEvent(Rc::new(WebviewMouseEvent))); let event = SyntheticEvent::MouseEvent(MouseEvent(Rc::new(WebviewMouseEvent)));
let scope = ScopeId(data.scope as usize); let scope = ScopeId(data.scope as usize);
let mounted_dom_id = Some(ElementId(data.mounted_dom_id as usize)); let mounted_dom_id = Some(ElementId(data.mounted_dom_id as usize));
let priority = EventPriority::High; let priority = EventPriority::High;
+19 -19
View File
@@ -1,7 +1,7 @@
use std::{collections::HashMap, fmt::Debug, rc::Rc, sync::Arc}; use std::{collections::HashMap, fmt::Debug, rc::Rc, sync::Arc};
use dioxus_core::{ use dioxus_core::{
events::{on::GenericEventInner, EventTrigger, VirtualEvent}, events::{on::GenericEventInner, EventTrigger, SyntheticEvent},
mutations::NodeRefMutation, mutations::NodeRefMutation,
DomEdit, ElementId, ScopeId, DomEdit, ElementId, ScopeId,
}; };
@@ -436,82 +436,82 @@ impl Stack {
} }
} }
fn virtual_event_from_websys_event(event: web_sys::Event) -> VirtualEvent { fn virtual_event_from_websys_event(event: web_sys::Event) -> SyntheticEvent {
use crate::events::*; use crate::events::*;
use dioxus_core::events::on::*; use dioxus_core::events::on::*;
match event.type_().as_str() { match event.type_().as_str() {
"copy" | "cut" | "paste" => { "copy" | "cut" | "paste" => {
VirtualEvent::ClipboardEvent(ClipboardEvent(Rc::new(WebsysClipboardEvent(event)))) SyntheticEvent::ClipboardEvent(ClipboardEvent(Rc::new(WebsysClipboardEvent(event))))
} }
"compositionend" | "compositionstart" | "compositionupdate" => { "compositionend" | "compositionstart" | "compositionupdate" => {
let evt: web_sys::CompositionEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::CompositionEvent = event.clone().dyn_into().unwrap();
VirtualEvent::CompositionEvent(CompositionEvent(Rc::new(WebsysCompositionEvent(evt)))) SyntheticEvent::CompositionEvent(CompositionEvent(Rc::new(WebsysCompositionEvent(evt))))
} }
"keydown" | "keypress" | "keyup" => { "keydown" | "keypress" | "keyup" => {
let evt: web_sys::KeyboardEvent = event.dyn_into().unwrap(); let evt: web_sys::KeyboardEvent = event.dyn_into().unwrap();
VirtualEvent::KeyboardEvent(KeyboardEvent(Rc::new(WebsysKeyboardEvent(evt)))) SyntheticEvent::KeyboardEvent(KeyboardEvent(Rc::new(WebsysKeyboardEvent(evt))))
} }
"focus" | "blur" => { "focus" | "blur" => {
let evt: web_sys::FocusEvent = event.dyn_into().unwrap(); let evt: web_sys::FocusEvent = event.dyn_into().unwrap();
VirtualEvent::FocusEvent(FocusEvent(Rc::new(WebsysFocusEvent(evt)))) SyntheticEvent::FocusEvent(FocusEvent(Rc::new(WebsysFocusEvent(evt))))
} }
"change" => { "change" => {
let evt = event.dyn_into().unwrap(); let evt = event.dyn_into().unwrap();
VirtualEvent::UIEvent(UIEvent(Rc::new(WebsysGenericUiEvent(evt)))) SyntheticEvent::UIEvent(UIEvent(Rc::new(WebsysGenericUiEvent(evt))))
} }
"input" | "invalid" | "reset" | "submit" => { "input" | "invalid" | "reset" | "submit" => {
let evt: web_sys::InputEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::InputEvent = event.clone().dyn_into().unwrap();
VirtualEvent::FormEvent(FormEvent(Rc::new(WebsysFormEvent(evt)))) SyntheticEvent::FormEvent(FormEvent(Rc::new(WebsysFormEvent(evt))))
} }
"click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit" "click" | "contextmenu" | "doubleclick" | "drag" | "dragend" | "dragenter" | "dragexit"
| "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter" | "dragleave" | "dragover" | "dragstart" | "drop" | "mousedown" | "mouseenter"
| "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => { | "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => {
let evt: web_sys::MouseEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::MouseEvent = event.clone().dyn_into().unwrap();
VirtualEvent::MouseEvent(MouseEvent(Rc::new(WebsysMouseEvent(evt)))) SyntheticEvent::MouseEvent(MouseEvent(Rc::new(WebsysMouseEvent(evt))))
} }
"pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture" "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture"
| "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => { | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => {
let evt: web_sys::PointerEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::PointerEvent = event.clone().dyn_into().unwrap();
VirtualEvent::PointerEvent(PointerEvent(Rc::new(WebsysPointerEvent(evt)))) SyntheticEvent::PointerEvent(PointerEvent(Rc::new(WebsysPointerEvent(evt))))
} }
"select" => { "select" => {
let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap();
VirtualEvent::SelectionEvent(SelectionEvent(Rc::new(WebsysGenericUiEvent(evt)))) SyntheticEvent::SelectionEvent(SelectionEvent(Rc::new(WebsysGenericUiEvent(evt))))
} }
"touchcancel" | "touchend" | "touchmove" | "touchstart" => { "touchcancel" | "touchend" | "touchmove" | "touchstart" => {
let evt: web_sys::TouchEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::TouchEvent = event.clone().dyn_into().unwrap();
VirtualEvent::TouchEvent(TouchEvent(Rc::new(WebsysTouchEvent(evt)))) SyntheticEvent::TouchEvent(TouchEvent(Rc::new(WebsysTouchEvent(evt))))
} }
"scroll" => { "scroll" => {
let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap();
VirtualEvent::UIEvent(UIEvent(Rc::new(WebsysGenericUiEvent(evt)))) SyntheticEvent::UIEvent(UIEvent(Rc::new(WebsysGenericUiEvent(evt))))
} }
"wheel" => { "wheel" => {
let evt: web_sys::WheelEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::WheelEvent = event.clone().dyn_into().unwrap();
VirtualEvent::WheelEvent(WheelEvent(Rc::new(WebsysWheelEvent(evt)))) SyntheticEvent::WheelEvent(WheelEvent(Rc::new(WebsysWheelEvent(evt))))
} }
"animationstart" | "animationend" | "animationiteration" => { "animationstart" | "animationend" | "animationiteration" => {
let evt: web_sys::AnimationEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::AnimationEvent = event.clone().dyn_into().unwrap();
VirtualEvent::AnimationEvent(AnimationEvent(Rc::new(WebsysAnimationEvent(evt)))) SyntheticEvent::AnimationEvent(AnimationEvent(Rc::new(WebsysAnimationEvent(evt))))
} }
"transitionend" => { "transitionend" => {
let evt: web_sys::TransitionEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::TransitionEvent = event.clone().dyn_into().unwrap();
VirtualEvent::TransitionEvent(TransitionEvent(Rc::new(WebsysTransitionEvent(evt)))) SyntheticEvent::TransitionEvent(TransitionEvent(Rc::new(WebsysTransitionEvent(evt))))
} }
"abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted" "abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
| "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play" | "ended" | "error" | "loadeddata" | "loadedmetadata" | "loadstart" | "pause" | "play"
| "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend" | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"
| "timeupdate" | "volumechange" | "waiting" => { | "timeupdate" | "volumechange" | "waiting" => {
let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap();
VirtualEvent::MediaEvent(MediaEvent(Rc::new(WebsysMediaEvent(evt)))) SyntheticEvent::MediaEvent(MediaEvent(Rc::new(WebsysMediaEvent(evt))))
} }
"toggle" => { "toggle" => {
let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap();
VirtualEvent::ToggleEvent(ToggleEvent(Rc::new(WebsysToggleEvent(evt)))) SyntheticEvent::ToggleEvent(ToggleEvent(Rc::new(WebsysToggleEvent(evt))))
} }
_ => { _ => {
let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap(); let evt: web_sys::UiEvent = event.clone().dyn_into().unwrap();
VirtualEvent::UIEvent(UIEvent(Rc::new(WebsysGenericUiEvent(evt)))) SyntheticEvent::UIEvent(UIEvent(Rc::new(WebsysGenericUiEvent(evt))))
} }
} }
} }