|
@@ -142,8 +142,8 @@ impl VirtualDom {
|
|
|
Self {
|
|
|
base_scope,
|
|
|
_root_props: root_props,
|
|
|
+ scheduler: Scheduler::new(components.clone()),
|
|
|
shared: components,
|
|
|
- scheduler: Scheduler::new(),
|
|
|
_root_prop_type: TypeId::of::<P>(),
|
|
|
}
|
|
|
}
|
|
@@ -324,106 +324,125 @@ impl VirtualDom {
|
|
|
and listeners hold references to hook data, it is wrong to run a scope that is already being diffed.
|
|
|
*/
|
|
|
|
|
|
- let mut diff_machine = DiffMachine::new(Mutations::new(), self.base_scope, &self.shared);
|
|
|
+ // let mut diff_machine = DiffMachine::new(Mutations::new(), self.base_scope, &self.shared);
|
|
|
|
|
|
- // 1. Drain the existing immediates.
|
|
|
- //
|
|
|
- // These are generated by async tasks that we never got a chance to finish.
|
|
|
- // All of these get scheduled with the lowest priority.
|
|
|
- while let Ok(Some(dirty_scope)) = self.shared.immediate_receiver.borrow_mut().try_next() {
|
|
|
- self.scheduler
|
|
|
- .add_dirty_scope(dirty_scope, EventPriority::Low);
|
|
|
- }
|
|
|
+ // Configure our deadline
|
|
|
+ use futures_util::FutureExt;
|
|
|
+ let mut deadline_future = deadline.shared();
|
|
|
|
|
|
- // 2. Drain the event queue, calling whatever listeners need to be called
|
|
|
- //
|
|
|
- while let Ok(Some(trigger)) = self.shared.ui_event_receiver.borrow_mut().try_next() {
|
|
|
- match &trigger.event {
|
|
|
- VirtualEvent::AsyncEvent { .. } => {}
|
|
|
-
|
|
|
- // This suspense system works, but it's not the most elegant solution.
|
|
|
- // TODO: Replace this system
|
|
|
- VirtualEvent::SuspenseEvent { hook_idx, domnode } => {
|
|
|
- // Safety: this handler is the only thing that can mutate shared items at this moment in tim
|
|
|
- let scope = diff_machine.get_scope_mut(&trigger.originator).unwrap();
|
|
|
-
|
|
|
- // safety: we are sure that there are no other references to the inner content of suspense hooks
|
|
|
- let hook = unsafe { scope.hooks.get_mut::<SuspenseHook>(*hook_idx) }.unwrap();
|
|
|
-
|
|
|
- let cx = Context { scope, props: &() };
|
|
|
- let scx = SuspendedContext { inner: cx };
|
|
|
-
|
|
|
- // generate the new node!
|
|
|
- let nodes: Option<VNode> = (&hook.callback)(scx);
|
|
|
-
|
|
|
- if let Some(nodes) = nodes {
|
|
|
- // allocate inside the finished frame - not the WIP frame
|
|
|
- let nodes = scope.frames.finished_frame().bump.alloc(nodes);
|
|
|
-
|
|
|
- // push the old node's root onto the stack
|
|
|
- let real_id = domnode.get().ok_or(Error::NotMounted)?;
|
|
|
- diff_machine.edit_push_root(real_id);
|
|
|
-
|
|
|
- // push these new nodes onto the diff machines stack
|
|
|
- let meta = diff_machine.create_vnode(&*nodes);
|
|
|
-
|
|
|
- // replace the placeholder with the new nodes we just pushed on the stack
|
|
|
- diff_machine.edit_replace_with(1, meta.added_to_stack);
|
|
|
- } else {
|
|
|
- log::warn!(
|
|
|
- "Suspense event came through, but there were no generated nodes >:(."
|
|
|
- );
|
|
|
+ let mut is_ready_deadline = deadline_future.clone();
|
|
|
+ let mut is_ready = || -> bool { (&mut is_ready_deadline).now_or_never().is_some() };
|
|
|
+
|
|
|
+ loop {
|
|
|
+ // 1. Drain the existing immediates.
|
|
|
+ //
|
|
|
+ // These are generated by async tasks that we never got a chance to finish.
|
|
|
+ // All of these get scheduled with the lowest priority.
|
|
|
+ while let Ok(Some(dirty_scope)) = self.shared.immediate_receiver.borrow_mut().try_next()
|
|
|
+ {
|
|
|
+ self.scheduler
|
|
|
+ .add_dirty_scope(dirty_scope, EventPriority::Low);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. Drain the event queue, calling whatever listeners need to be called
|
|
|
+ //
|
|
|
+ // First, check if there's any set_states in the queue that we can mark as low priority
|
|
|
+ // Next, check the UI event receiver so we can mark those scopes as medium/high priority
|
|
|
+ // Next, work on any fibers.
|
|
|
+ // Once the fiber work is finished
|
|
|
+ //
|
|
|
+ //
|
|
|
+ //
|
|
|
+ //
|
|
|
+
|
|
|
+ while let Some(trigger) = self.scheduler.next_event() {
|
|
|
+ match &trigger.event {
|
|
|
+ VirtualEvent::AsyncEvent { .. } => {}
|
|
|
+
|
|
|
+ // This suspense system works, but it's not the most elegant solution.
|
|
|
+ // TODO: Replace this system
|
|
|
+ VirtualEvent::SuspenseEvent { hook_idx, domnode } => {
|
|
|
+ todo!();
|
|
|
+ // // Safety: this handler is the only thing that can mutate shared items at this moment in tim
|
|
|
+ // let scope = diff_machine.get_scope_mut(&trigger.originator).unwrap();
|
|
|
+
|
|
|
+ // // safety: we are sure that there are no other references to the inner content of suspense hooks
|
|
|
+ // let hook = unsafe { scope.hooks.get_mut::<SuspenseHook>(*hook_idx) }.unwrap();
|
|
|
+
|
|
|
+ // let cx = Context { scope, props: &() };
|
|
|
+ // let scx = SuspendedContext { inner: cx };
|
|
|
+
|
|
|
+ // // generate the new node!
|
|
|
+ // let nodes: Option<VNode> = (&hook.callback)(scx);
|
|
|
+
|
|
|
+ // if let Some(nodes) = nodes {
|
|
|
+ // // allocate inside the finished frame - not the WIP frame
|
|
|
+ // let nodes = scope.frames.finished_frame().bump.alloc(nodes);
|
|
|
+
|
|
|
+ // // push the old node's root onto the stack
|
|
|
+ // let real_id = domnode.get().ok_or(Error::NotMounted)?;
|
|
|
+ // diff_machine.edit_push_root(real_id);
|
|
|
+
|
|
|
+ // // push these new nodes onto the diff machines stack
|
|
|
+ // let meta = diff_machine.create_vnode(&*nodes);
|
|
|
+
|
|
|
+ // // replace the placeholder with the new nodes we just pushed on the stack
|
|
|
+ // diff_machine.edit_replace_with(1, meta.added_to_stack);
|
|
|
+ // } else {
|
|
|
+ // log::warn!(
|
|
|
+ // "Suspense event came through, but there were no generated nodes >:(."
|
|
|
+ // );
|
|
|
+ // }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- VirtualEvent::ClipboardEvent(_)
|
|
|
- | VirtualEvent::CompositionEvent(_)
|
|
|
- | VirtualEvent::KeyboardEvent(_)
|
|
|
- | VirtualEvent::FocusEvent(_)
|
|
|
- | VirtualEvent::FormEvent(_)
|
|
|
- | VirtualEvent::SelectionEvent(_)
|
|
|
- | VirtualEvent::TouchEvent(_)
|
|
|
- | VirtualEvent::UIEvent(_)
|
|
|
- | VirtualEvent::WheelEvent(_)
|
|
|
- | VirtualEvent::MediaEvent(_)
|
|
|
- | VirtualEvent::AnimationEvent(_)
|
|
|
- | VirtualEvent::TransitionEvent(_)
|
|
|
- | VirtualEvent::ToggleEvent(_)
|
|
|
- | VirtualEvent::MouseEvent(_)
|
|
|
- | VirtualEvent::PointerEvent(_) => {
|
|
|
- if let Some(scope) = self.shared.get_scope_mut(trigger.originator) {
|
|
|
- if let Some(element) = trigger.real_node_id {
|
|
|
- scope.call_listener(trigger.event, element)?;
|
|
|
-
|
|
|
- // Drain the immediates into the dirty scopes, setting the appropiate priorities
|
|
|
- while let Ok(Some(dirty_scope)) =
|
|
|
- self.shared.immediate_receiver.borrow_mut().try_next()
|
|
|
- {
|
|
|
- self.scheduler
|
|
|
- .add_dirty_scope(dirty_scope, trigger.priority)
|
|
|
+ VirtualEvent::ClipboardEvent(_)
|
|
|
+ | VirtualEvent::CompositionEvent(_)
|
|
|
+ | VirtualEvent::KeyboardEvent(_)
|
|
|
+ | VirtualEvent::FocusEvent(_)
|
|
|
+ | VirtualEvent::FormEvent(_)
|
|
|
+ | VirtualEvent::SelectionEvent(_)
|
|
|
+ | VirtualEvent::TouchEvent(_)
|
|
|
+ | VirtualEvent::UIEvent(_)
|
|
|
+ | VirtualEvent::WheelEvent(_)
|
|
|
+ | VirtualEvent::MediaEvent(_)
|
|
|
+ | VirtualEvent::AnimationEvent(_)
|
|
|
+ | VirtualEvent::TransitionEvent(_)
|
|
|
+ | VirtualEvent::ToggleEvent(_)
|
|
|
+ | VirtualEvent::MouseEvent(_)
|
|
|
+ | VirtualEvent::PointerEvent(_) => {
|
|
|
+ if let Some(scope) = self.shared.get_scope_mut(trigger.originator) {
|
|
|
+ if let Some(element) = trigger.real_node_id {
|
|
|
+ scope.call_listener(trigger.event, element)?;
|
|
|
+
|
|
|
+ // Drain the immediates into the dirty scopes, setting the appropiate priorities
|
|
|
+ while let Ok(Some(dirty_scope)) =
|
|
|
+ self.shared.immediate_receiver.borrow_mut().try_next()
|
|
|
+ {
|
|
|
+ self.scheduler
|
|
|
+ .add_dirty_scope(dirty_scope, trigger.priority)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- // 3. Work through the fibers, and wait for any future work to be ready
|
|
|
+ // 3. Work through the fibers, and wait for any future work to be ready
|
|
|
+ let mut machine = DiffMachine::new_headless(&self.shared);
|
|
|
+ self.scheduler.progress_work(&mut machine, &mut is_ready);
|
|
|
|
|
|
- // Configure our deadline
|
|
|
- use futures_util::FutureExt;
|
|
|
- let mut deadline_future = deadline.boxed_local();
|
|
|
- let mut is_ready = || -> bool { (&mut deadline_future).now_or_never().is_some() };
|
|
|
-
|
|
|
- loop {
|
|
|
- if is_ready() {
|
|
|
+ // 4. Wait for any new triggers before looping again
|
|
|
+ if self
|
|
|
+ .scheduler
|
|
|
+ .wait_for_any_trigger(&mut deadline_future)
|
|
|
+ .await
|
|
|
+ {
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
- self.scheduler
|
|
|
}
|
|
|
|
|
|
- Ok(diff_machine.mutations)
|
|
|
+ todo!()
|
|
|
+ // Ok(diff_machine.mutations)
|
|
|
}
|
|
|
|
|
|
pub fn get_event_sender(&self) -> futures_channel::mpsc::UnboundedSender<EventTrigger> {
|