Prechádzať zdrojové kódy

wip: it compiles again

Jonathan Kelley 3 rokov pred
rodič
commit
07efb6a

+ 1 - 1
packages/core/.vscode/settings.json

@@ -1,3 +1,3 @@
 {
-  "rust-analyzer.inlayHints.enable": false
+  "rust-analyzer.inlayHints.enable": true
 }

+ 2 - 2
packages/core/src/diff.rs

@@ -107,7 +107,7 @@ use DomEdit::*;
 pub struct DiffMachine<'bump> {
     vdom: &'bump Scheduler,
 
-    pub mutations: &'bump mut Mutations<'bump>,
+    pub mutations: Mutations<'bump>,
 
     pub stack: DiffStack<'bump>,
     pub diffed: FxHashSet<ScopeId>,
@@ -116,7 +116,7 @@ pub struct DiffMachine<'bump> {
 
 impl<'bump> DiffMachine<'bump> {
     pub(crate) fn new(
-        edits: &'bump mut Mutations<'bump>,
+        edits: Mutations<'bump>,
         cur_scope: ScopeId,
         shared: &'bump Scheduler,
     ) -> Self {

+ 5 - 3
packages/core/src/hooks.rs

@@ -208,14 +208,16 @@ where
                 cx.render(LazyNodes::new(|f| {
                     let bump = f.bump();
                     let g: &dyn FnOnce(SuspendedContext<'src>) -> DomTree<'src> =
-                        bump.alloc(|sus| {
-                            let out = value
-                                .borrow()
+                        bump.alloc(move |sus| {
+                            let val = value.borrow();
+
+                            let out = val
                                 .as_ref()
                                 .unwrap()
                                 .as_ref()
                                 .downcast_ref::<Out>()
                                 .unwrap();
+
                             user_callback(sus, out)
                         });
 

+ 193 - 213
packages/core/src/scheduler.rs

@@ -95,7 +95,7 @@ pub struct Scheduler {
     // scheduler stuff
     pub current_priority: EventPriority,
 
-    pub pending_events: VecDeque<EventTrigger>,
+    pub ui_events: VecDeque<EventTrigger>,
 
     pub pending_immediates: VecDeque<ScopeId>,
 
@@ -131,7 +131,7 @@ impl Scheduler {
             }),
             get_shared_context: {
                 let components = components.clone();
-                Rc::new(|id, ty| {
+                Rc::new(move |id, ty| {
                     let components = unsafe { &*components.get() };
                     let mut search: Option<&Scope> = components.get(id.0);
                     while let Some(inner) = search.take() {
@@ -159,7 +159,7 @@ impl Scheduler {
             raw_elements,
 
             // a storage for our receiver to dump into
-            pending_events: VecDeque::new(),
+            ui_events: VecDeque::new(),
 
             pending_immediates: VecDeque::new(),
 
@@ -216,12 +216,14 @@ impl Scheduler {
     }
 
     pub fn reserve_node(&self) -> ElementId {
-        ElementId(self.raw_elements.insert(()))
+        todo!("reserving wip until it's fast enough again")
+        // ElementId(self.raw_elements.insert(()))
     }
 
     /// return the id, freeing the space of the original node
     pub fn collect_garbage(&self, id: ElementId) {
-        self.raw_elements.remove(id.0);
+        todo!("garabge collection currently WIP")
+        // self.raw_elements.remove(id.0);
     }
 
     pub fn insert_scope_with_key(&self, f: impl FnOnce(ScopeId) -> Scope) -> ScopeId {
@@ -233,163 +235,101 @@ impl Scheduler {
     }
 
     pub fn clean_up_garbage(&mut self) {
-        let mut scopes_to_kill = Vec::new();
-        let mut garbage_list = Vec::new();
-
-        for scope in self.garbage_scopes.drain() {
-            let scope = self.get_scope_mut(scope).unwrap();
-            for node in scope.consume_garbage() {
-                garbage_list.push(node);
-            }
-
-            while let Some(node) = garbage_list.pop() {
-                match &node {
-                    VNode::Text(_) => {
-                        self.collect_garbage(node.direct_id());
-                    }
-                    VNode::Anchor(_) => {
-                        self.collect_garbage(node.direct_id());
-                    }
-                    VNode::Suspended(_) => {
-                        self.collect_garbage(node.direct_id());
-                    }
-
-                    VNode::Element(el) => {
-                        self.collect_garbage(node.direct_id());
-                        for child in el.children {
-                            garbage_list.push(child);
-                        }
-                    }
-
-                    VNode::Fragment(frag) => {
-                        for child in frag.children {
-                            garbage_list.push(child);
-                        }
-                    }
-
-                    VNode::Component(comp) => {
-                        // TODO: run the hook destructors and then even delete the scope
-
-                        let scope_id = comp.ass_scope.get().unwrap();
-                        let scope = self.get_scope(scope_id).unwrap();
-                        let root = scope.root();
-                        garbage_list.push(root);
-                        scopes_to_kill.push(scope_id);
-                    }
-                }
-            }
-        }
-
-        for scope in scopes_to_kill.drain(..) {
-            //
-            // kill em
-        }
-    }
-
-    // channels don't have these methods, so we just implement our own wrapper
-    pub fn next_event(&mut self) -> Option<EventTrigger> {
-        // pop the last event off the internal queue
-        self.pending_events.pop_back().or_else(|| {
-            self.ui_event_receiver
-                .borrow_mut()
-                .try_next()
-                .ok()
-                .flatten()
-        })
+        // let mut scopes_to_kill = Vec::new();
+        // let mut garbage_list = Vec::new();
+
+        todo!("garbage collection is currently immediate")
+        // for scope in self.garbage_scopes.drain() {
+        //     let scope = self.get_scope_mut(scope).unwrap();
+        //     for node in scope.consume_garbage() {
+        //         garbage_list.push(node);
+        //     }
+
+        //     while let Some(node) = garbage_list.pop() {
+        //         match &node {
+        //             VNode::Text(_) => {
+        //                 self.collect_garbage(node.direct_id());
+        //             }
+        //             VNode::Anchor(_) => {
+        //                 self.collect_garbage(node.direct_id());
+        //             }
+        //             VNode::Suspended(_) => {
+        //                 self.collect_garbage(node.direct_id());
+        //             }
+
+        //             VNode::Element(el) => {
+        //                 self.collect_garbage(node.direct_id());
+        //                 for child in el.children {
+        //                     garbage_list.push(child);
+        //                 }
+        //             }
+
+        //             VNode::Fragment(frag) => {
+        //                 for child in frag.children {
+        //                     garbage_list.push(child);
+        //                 }
+        //             }
+
+        //             VNode::Component(comp) => {
+        //                 // TODO: run the hook destructors and then even delete the scope
+
+        //                 let scope_id = comp.ass_scope.get().unwrap();
+        //                 let scope = self.get_scope(scope_id).unwrap();
+        //                 let root = scope.root();
+        //                 garbage_list.push(root);
+        //                 scopes_to_kill.push(scope_id);
+        //             }
+        //         }
+        //     }
+        // }
+
+        // for scope in scopes_to_kill.drain(..) {
+        //     //
+        //     // kill em
+        // }
     }
 
     pub fn manually_poll_events(&mut self) {
-        // 1. Poll the UI event receiver
-        // 2. Poll the set_state receiver
-
-        // poll the immediates first, creating work out of them
-        let shared_receiver = self.immediate_receiver.clone();
-        let mut receiver = shared_receiver.borrow_mut();
-        while let Ok(Some(trigger)) = receiver.try_next() {
-            self.add_dirty_scope(trigger, EventPriority::Low);
-        }
-
-        // next poll the UI events,
-        let mut receiver = self.ui_event_receiver.borrow_mut();
-        while let Ok(Some(trigger)) = receiver.try_next() {
-            self.pending_events.push_back(trigger);
+        while let Ok(Some(msg)) = self.receiver.try_next() {
+            self.handle_channel_msg(msg);
         }
     }
 
     // Converts UI events into dirty scopes with various priorities
     pub fn consume_pending_events(&mut self) -> Result<()> {
-        while let Some(trigger) = self.pending_events.pop_back() {
-            match &trigger.event {
-                SyntheticEvent::AsyncEvent { .. } => {}
-
-                // This suspense system works, but it's not the most elegant solution.
-                // TODO: Replace this system
-                SyntheticEvent::SuspenseEvent { hook_idx, domnode } => {
-                    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
-                    // 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 >:(."
-                    //     );
-                    // }
-                }
-
-                SyntheticEvent::ClipboardEvent(_)
-                | SyntheticEvent::CompositionEvent(_)
-                | SyntheticEvent::KeyboardEvent(_)
-                | SyntheticEvent::FocusEvent(_)
-                | SyntheticEvent::FormEvent(_)
-                | SyntheticEvent::SelectionEvent(_)
-                | SyntheticEvent::TouchEvent(_)
-                | SyntheticEvent::UIEvent(_)
-                | SyntheticEvent::WheelEvent(_)
-                | SyntheticEvent::MediaEvent(_)
-                | SyntheticEvent::AnimationEvent(_)
-                | SyntheticEvent::TransitionEvent(_)
-                | SyntheticEvent::ToggleEvent(_)
-                | SyntheticEvent::MouseEvent(_)
-                | SyntheticEvent::PointerEvent(_) => {
-                    if let Some(scope) = self.get_scope_mut(trigger.scope) {
-                        if let Some(element) = trigger.mounted_dom_id {
-                            scope.call_listener(trigger.event, element)?;
-
-                            let receiver = self.immediate_receiver.clone();
-                            let mut receiver = receiver.borrow_mut();
-
-                            // Drain the immediates into the dirty scopes, setting the appropiate priorities
-                            while let Ok(Some(dirty_scope)) = receiver.try_next() {
-                                self.add_dirty_scope(dirty_scope, trigger.priority)
-                            }
-                        }
-                    }
-                }
-            }
-        }
+        // while let Some(trigger) = self.ui_events.pop_back() {
+        //     match &trigger.event {
+        //         SyntheticEvent::ClipboardEvent(_)
+        //         | SyntheticEvent::CompositionEvent(_)
+        //         | SyntheticEvent::KeyboardEvent(_)
+        //         | SyntheticEvent::FocusEvent(_)
+        //         | SyntheticEvent::FormEvent(_)
+        //         | SyntheticEvent::SelectionEvent(_)
+        //         | SyntheticEvent::TouchEvent(_)
+        //         | SyntheticEvent::UIEvent(_)
+        //         | SyntheticEvent::WheelEvent(_)
+        //         | SyntheticEvent::MediaEvent(_)
+        //         | SyntheticEvent::AnimationEvent(_)
+        //         | SyntheticEvent::TransitionEvent(_)
+        //         | SyntheticEvent::ToggleEvent(_)
+        //         | SyntheticEvent::MouseEvent(_)
+        //         | SyntheticEvent::PointerEvent(_) => {
+        //             if let Some(scope) = self.get_scope_mut(trigger.scope) {
+        //                 if let Some(element) = trigger.mounted_dom_id {
+        //                     scope.call_listener(trigger.event, element)?;
+
+        //                     // let receiver = self.immediate_receiver.clone();
+        //                     // let mut receiver = receiver.borrow_mut();
+
+        //                     // // Drain the immediates into the dirty scopes, setting the appropiate priorities
+        //                     // while let Ok(Some(dirty_scope)) = receiver.try_next() {
+        //                     //     self.add_dirty_scope(dirty_scope, trigger.priority)
+        //                     // }
+        //                 }
+        //             }
+        //         }
+        //     }
+        // }
 
         Ok(())
     }
@@ -400,13 +340,14 @@ impl Scheduler {
     }
 
     pub fn has_pending_events(&self) -> bool {
-        self.pending_events.len() > 0
+        self.ui_events.len() > 0
     }
 
     pub fn has_work(&self) -> bool {
-        self.high_priorty.has_work()
-            || self.medium_priority.has_work()
-            || self.low_priority.has_work()
+        todo!()
+        // self.high_priorty.has_work()
+        //     || self.medium_priority.has_work()
+        //     || self.low_priority.has_work()
     }
 
     pub fn has_pending_garbage(&self) -> bool {
@@ -414,66 +355,104 @@ impl Scheduler {
     }
 
     fn get_current_fiber<'a>(&'a mut self) -> &mut DiffMachine<'a> {
-        let fib = match self.current_priority {
-            EventPriority::High => &mut self.high_priorty,
-            EventPriority::Medium => &mut self.medium_priority,
-            EventPriority::Low => &mut self.low_priority,
-        };
-        unsafe { std::mem::transmute(fib) }
+        todo!()
+        // let fib = match self.current_priority {
+        //     EventPriority::High => &mut self.high_priorty,
+        //     EventPriority::Medium => &mut self.medium_priority,
+        //     EventPriority::Low => &mut self.low_priority,
+        // };
+        // unsafe { std::mem::transmute(fib) }
     }
 
     /// If a the fiber finishes its works (IE needs to be committed) the scheduler will drop the dirty scope
+    ///
+    ///
+    ///
     pub async fn work_with_deadline<'a>(
         &'a mut self,
-        mutations: &mut Mutations<'a>,
         deadline: &mut Pin<Box<impl FusedFuture<Output = ()>>>,
-    ) -> bool {
-        // check if we need to elevate priority
-        self.current_priority = match (
-            self.high_priorty.has_work(),
-            self.medium_priority.has_work(),
-            self.low_priority.has_work(),
-        ) {
-            (true, _, _) => EventPriority::High,
-            (false, true, _) => EventPriority::Medium,
-            (false, false, _) => EventPriority::Low,
-        };
-
-        // let mut machine = DiffMachine::new(mutations, ScopeId(0), &self);
-
-        let dirty_root = {
-            let dirty_roots = match self.current_priority {
-                EventPriority::High => &self.high_priorty.dirty_scopes,
-                EventPriority::Medium => &self.medium_priority.dirty_scopes,
-                EventPriority::Low => &self.low_priority.dirty_scopes,
-            };
-            let mut height = 0;
-            let mut dirty_root = {
-                let root = dirty_roots.iter().next();
-                if root.is_none() {
-                    return true;
-                }
-                root.unwrap()
-            };
-
-            for root in dirty_roots {
-                if let Some(scope) = self.get_scope(*root) {
-                    if scope.height < height {
-                        height = scope.height;
-                        dirty_root = root;
-                    }
+    ) -> Vec<Mutations<'a>> {
+        let mut committed_mutations = Vec::new();
+
+        // TODO:
+        // the scheduler uses a bunch of different receivers to mimic a "topic" queue system. The futures-channel implementation
+        // doesn't really have a concept of a "topic" queue, so there's a lot of noise in the hand-rolled scheduler. We should
+        // explore abstracting the scheduler into a topic-queue channel system - similar to Kafka or something similar.
+        loop {
+            // Internalize any pending work since the last time we ran
+            self.manually_poll_events();
+
+            // Wait for any new events if we have nothing to do
+            if !self.has_any_work() {
+                self.clean_up_garbage();
+                let deadline_expired = self.wait_for_any_trigger(deadline).await;
+
+                if deadline_expired {
+                    return committed_mutations;
                 }
             }
-            dirty_root
-        };
 
-        let fut = machine.diff_scope(*dirty_root).fuse();
-        pin_mut!(fut);
-
-        match futures_util::future::select(deadline, fut).await {
-            futures_util::future::Either::Left((deadline, work_fut)) => true,
-            futures_util::future::Either::Right((_, deadline_fut)) => false,
+            // Create work from the pending event queue
+            self.consume_pending_events().unwrap();
+
+            // Work through the current subtree, and commit the results when it finishes
+            // When the deadline expires, give back the work
+            let mut new_mutations = Mutations::new();
+            // match self.work_with_deadline(&mut deadline).await {
+            //     Some(mutations) => {
+            //         // safety: the scheduler will never let us mutate
+            //         let extended: Mutations<'static> = unsafe { std::mem::transmute(mutations) };
+            //         committed_mutations.push(extended)
+            //     }
+            //     None => return committed_mutations,
+            // }
         }
+        // // check if we need to elevate priority
+        // self.current_priority = match (
+        //     self.high_priorty.has_work(),
+        //     self.medium_priority.has_work(),
+        //     self.low_priority.has_work(),
+        // ) {
+        //     (true, _, _) => EventPriority::High,
+        //     (false, true, _) => EventPriority::Medium,
+        //     (false, false, _) => EventPriority::Low,
+        // };
+
+        // // let mut machine = DiffMachine::new(mutations, ScopeId(0), &self);
+
+        // let dirty_root = {
+        //     let dirty_roots = match self.current_priority {
+        //         EventPriority::High => &self.high_priorty.dirty_scopes,
+        //         EventPriority::Medium => &self.medium_priority.dirty_scopes,
+        //         EventPriority::Low => &self.low_priority.dirty_scopes,
+        //     };
+        //     let mut height = 0;
+        //     let mut dirty_root = {
+        //         let root = dirty_roots.iter().next();
+        //         if root.is_none() {
+        //             return true;
+        //         }
+        //         root.unwrap()
+        //     };
+
+        //     for root in dirty_roots {
+        //         if let Some(scope) = self.get_scope(*root) {
+        //             if scope.height < height {
+        //                 height = scope.height;
+        //                 dirty_root = root;
+        //             }
+        //         }
+        //     }
+        //     dirty_root
+        // };
+
+        // let fut = machine.diff_scope(*dirty_root).fuse();
+        // pin_mut!(fut);
+
+        // match futures_util::future::select(deadline, fut).await {
+        //     futures_util::future::Either::Left((deadline, work_fut)) => true,
+        //     futures_util::future::Either::Right((_, deadline_fut)) => false,
+        // }
     }
 
     // waits for a trigger, canceling early if the deadline is reached
@@ -509,11 +488,12 @@ impl Scheduler {
     }
 
     pub fn add_dirty_scope(&mut self, scope: ScopeId, priority: EventPriority) {
-        match priority {
-            EventPriority::High => self.high_priorty.dirty_scopes.insert(scope),
-            EventPriority::Medium => self.medium_priority.dirty_scopes.insert(scope),
-            EventPriority::Low => self.low_priority.dirty_scopes.insert(scope),
-        };
+        todo!()
+        // match priority {
+        //     EventPriority::High => self.high_priorty.dirty_scopes.insert(scope),
+        //     EventPriority::Medium => self.medium_priority.dirty_scopes.insert(scope),
+        //     EventPriority::Low => self.low_priority.dirty_scopes.insert(scope),
+        // };
     }
 }
 

+ 2 - 51
packages/core/src/virtual_dom.rs

@@ -271,58 +271,9 @@ impl VirtualDom {
     pub async fn run_with_deadline<'s>(
         &'s mut self,
         deadline: impl Future<Output = ()>,
-    ) -> Option<Vec<Mutations<'s>>> {
-        let mut committed_mutations = Vec::new();
+    ) -> Vec<Mutations<'s>> {
         let mut deadline = Box::pin(deadline.fuse());
-
-        // TODO:
-        // the scheduler uses a bunch of different receivers to mimic a "topic" queue system. The futures-channel implementation
-        // doesn't really have a concept of a "topic" queue, so there's a lot of noise in the hand-rolled scheduler. We should
-        // explore abstracting the scheduler into a topic-queue channel system - similar to Kafka or something similar.
-        loop {
-            // Internalize any pending work since the last time we ran
-            self.scheduler.manually_poll_events();
-
-            // Wait for any new events if we have nothing to do
-            if !self.scheduler.has_any_work() {
-                self.scheduler.clean_up_garbage();
-                let deadline_expired = self.scheduler.wait_for_any_trigger(&mut deadline).await;
-
-                if deadline_expired {
-                    return Some(committed_mutations);
-                }
-            }
-
-            // Create work from the pending event queue
-            self.scheduler.consume_pending_events().unwrap();
-
-            // Work through the current subtree, and commit the results when it finishes
-            // When the deadline expires, give back the work
-            let mut new_mutations = Mutations::new();
-            match self.scheduler.work_with_deadline(&mut deadline).await {
-                FiberResult::Done => {
-                    // return Some(mutations);
-                    // for edit in mutations.edits {
-                    //     committed_mutations.edits.push(edit);
-                    // }
-                    // committed_mutations.extend(&mut mutations);
-
-                    /*
-                    quick return if there's no work left, so we can commit before the deadline expires
-                    When we loop over again, we'll re-wait for any new work.
-
-                    I'm not quite sure how this *should* work.
-
-                    It makes sense to try and progress the DOM faster
-                    */
-
-                    // if !self.scheduler.has_any_work() {
-                    //     return Some(committed_mutations);
-                    // }
-                }
-                FiberResult::Interrupted => return None,
-            }
-        }
+        self.scheduler.work_with_deadline(&mut deadline).await
     }
 
     pub fn get_event_sender(&self) -> futures_channel::mpsc::UnboundedSender<SchedulerMsg> {