wip: got the structure figured out!

This commit is contained in:
Jonathan Kelley committed 2021-08-10 01:21:13 -04:00
1 parent 85e2dc259a
commit 97745c6a7f
2 files changed
+235 -80

No files matched your search

+96 -77
View File
@@ -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 { .. } => {}
let mut is_ready_deadline = deadline_future.clone();
let mut is_ready = || -> bool { (&mut is_ready_deadline).now_or_never().is_some() };
// 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();
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);
}
// 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();
// 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
//
//
//
//
let cx = Context { scope, props: &() };
let scx = SuspendedContext { inner: cx };
while let Some(trigger) = self.scheduler.next_event() {
match &trigger.event {
VirtualEvent::AsyncEvent { .. } => {}
// generate the new node!
let nodes: Option<VNode> = (&hook.callback)(scx);
// 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();
if let Some(nodes) = nodes {
// allocate inside the finished frame - not the WIP frame
let nodes = scope.frames.finished_frame().bump.alloc(nodes);
// // 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();
// 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);
// let cx = Context { scope, props: &() };
// let scx = SuspendedContext { inner: cx };
// push these new nodes onto the diff machines stack
let meta = diff_machine.create_vnode(&*nodes);
// // generate the new node!
// let nodes: Option<VNode> = (&hook.callback)(scx);
// 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 >:(."
);
// 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)?;
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)
// 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> {