wip: some structure
This commit is contained in:
1 parent
ac3a7b1fbc
commit
bcaa76a37f
3 files changed
+173
-44
No files matched your search
+81
-20
@@ -90,6 +90,7 @@
|
|||||||
|
|
||||||
use crate::{innerlude::*, scheduler::Scheduler};
|
use crate::{innerlude::*, scheduler::Scheduler};
|
||||||
use fxhash::{FxHashMap, FxHashSet};
|
use fxhash::{FxHashMap, FxHashSet};
|
||||||
|
use slab::Slab;
|
||||||
use DomEdit::*;
|
use DomEdit::*;
|
||||||
|
|
||||||
/// Our DiffMachine is an iterative tree differ.
|
/// Our DiffMachine is an iterative tree differ.
|
||||||
@@ -105,19 +106,69 @@ use DomEdit::*;
|
|||||||
/// Funnily enough, this stack machine's entire job is to create instructions for another stack machine to execute. It's
|
/// Funnily enough, this stack machine's entire job is to create instructions for another stack machine to execute. It's
|
||||||
/// stack machines all the way down!
|
/// stack machines all the way down!
|
||||||
pub struct DiffMachine<'bump> {
|
pub struct DiffMachine<'bump> {
|
||||||
pub vdom: &'bump Scheduler,
|
vdom: SharedVdom<'bump>,
|
||||||
|
|
||||||
pub mutations: Mutations<'bump>,
|
pub mutations: Mutations<'bump>,
|
||||||
|
|
||||||
pub stack: DiffStack<'bump>,
|
pub stack: DiffStack<'bump>,
|
||||||
|
|
||||||
pub diffed: FxHashSet<ScopeId>,
|
pub diffed: FxHashSet<ScopeId>,
|
||||||
|
|
||||||
pub seen_scopes: FxHashSet<ScopeId>,
|
pub seen_scopes: FxHashSet<ScopeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SharedVdom<'bump> {
|
||||||
|
pub components: &'bump mut Slab<Scope>,
|
||||||
|
pub elements: &'bump mut Slab<()>,
|
||||||
|
pub channel: EventChannel,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'bump> SharedVdom<'bump> {
|
||||||
|
fn get_scope_mut(&mut self, scope: ScopeId) -> Option<&'bump mut Scope> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_scope(&mut self, scope: ScopeId) -> Option<&'bump Scope> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reserve_node(&mut self) -> ElementId {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn collect_garbage(&mut self, element: ElementId) {}
|
||||||
|
|
||||||
|
pub fn insert_scope_with_key(&mut self, f: impl FnOnce(ScopeId) -> Scope) -> ScopeId {
|
||||||
|
let entry = self.components.vacant_entry();
|
||||||
|
let id = ScopeId(entry.key());
|
||||||
|
entry.insert(f(id));
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// a "saved" form of a diff machine
|
||||||
|
/// in regular diff machine, the &'bump reference is a stack borrow, but the
|
||||||
|
/// bump lifetimes are heap borrows.
|
||||||
|
pub struct SavedDiffWork<'bump> {
|
||||||
|
pub mutations: Mutations<'bump>,
|
||||||
|
pub stack: DiffStack<'bump>,
|
||||||
|
pub diffed: FxHashSet<ScopeId>,
|
||||||
|
pub seen_scopes: FxHashSet<ScopeId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SavedDiffWork<'a> {
|
||||||
|
pub unsafe fn extend(self: SavedDiffWork<'a>) -> SavedDiffWork<'static> {
|
||||||
|
std::mem::transmute(self)
|
||||||
|
}
|
||||||
|
pub unsafe fn promote<'b>(self, vdom: SharedVdom<'b>) -> DiffMachine<'b> {
|
||||||
|
let extended: SavedDiffWork<'b> = std::mem::transmute(self);
|
||||||
|
DiffMachine {
|
||||||
|
vdom,
|
||||||
|
mutations: extended.mutations,
|
||||||
|
stack: extended.stack,
|
||||||
|
diffed: extended.diffed,
|
||||||
|
seen_scopes: extended.seen_scopes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'bump> DiffMachine<'bump> {
|
impl<'bump> DiffMachine<'bump> {
|
||||||
pub(crate) fn new(edits: Mutations<'bump>, shared: &'bump Scheduler) -> Self {
|
pub(crate) fn new(edits: Mutations<'bump>, shared: SharedVdom<'bump>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stack: DiffStack::new(),
|
stack: DiffStack::new(),
|
||||||
mutations: edits,
|
mutations: edits,
|
||||||
@@ -127,6 +178,15 @@ impl<'bump> DiffMachine<'bump> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn save(self) -> SavedDiffWork<'bump> {
|
||||||
|
SavedDiffWork {
|
||||||
|
mutations: self.mutations,
|
||||||
|
stack: self.stack,
|
||||||
|
diffed: self.diffed,
|
||||||
|
seen_scopes: self.seen_scopes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pub fn new_headless(shared: &'bump SharedResources) -> Self {
|
// pub fn new_headless(shared: &'bump SharedResources) -> Self {
|
||||||
// let edits = Mutations::new();
|
// let edits = Mutations::new();
|
||||||
// let cur_scope = ScopeId(0);
|
// let cur_scope = ScopeId(0);
|
||||||
@@ -136,7 +196,6 @@ impl<'bump> DiffMachine<'bump> {
|
|||||||
//
|
//
|
||||||
pub async fn diff_scope(&mut self, id: ScopeId) {
|
pub async fn diff_scope(&mut self, id: ScopeId) {
|
||||||
if let Some(component) = self.vdom.get_scope_mut(id) {
|
if let Some(component) = self.vdom.get_scope_mut(id) {
|
||||||
self.stack.scope_stack.push(id);
|
|
||||||
let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
|
let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
|
||||||
self.stack.push(DiffInstruction::DiffNode { new, old });
|
self.stack.push(DiffInstruction::DiffNode { new, old });
|
||||||
self.work().await;
|
self.work().await;
|
||||||
@@ -152,9 +211,6 @@ impl<'bump> DiffMachine<'bump> {
|
|||||||
// defer to individual functions so the compiler produces better code
|
// defer to individual functions so the compiler produces better code
|
||||||
// large functions tend to be difficult for the compiler to work with
|
// large functions tend to be difficult for the compiler to work with
|
||||||
while let Some(instruction) = self.stack.pop() {
|
while let Some(instruction) = self.stack.pop() {
|
||||||
// todo: call this less frequently, there is a bit of overhead involved
|
|
||||||
yield_now().await;
|
|
||||||
|
|
||||||
match instruction {
|
match instruction {
|
||||||
DiffInstruction::PopScope => {
|
DiffInstruction::PopScope => {
|
||||||
self.stack.pop_scope();
|
self.stack.pop_scope();
|
||||||
@@ -178,12 +234,16 @@ impl<'bump> DiffMachine<'bump> {
|
|||||||
|
|
||||||
DiffInstruction::PrepareMoveNode { node } => {
|
DiffInstruction::PrepareMoveNode { node } => {
|
||||||
log::debug!("Preparing to move node: {:?}", node);
|
log::debug!("Preparing to move node: {:?}", node);
|
||||||
for el in RealChildIterator::new(node, self.vdom) {
|
todo!();
|
||||||
self.mutations.push_root(el.direct_id());
|
// for el in RealChildIterator::new(node, self.vdom) {
|
||||||
self.stack.add_child_count(1);
|
// self.mutations.push_root(el.direct_id());
|
||||||
}
|
// self.stack.add_child_count(1);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// todo: call this less frequently, there is a bit of overhead involved
|
||||||
|
yield_now().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,11 +262,12 @@ impl<'bump> DiffMachine<'bump> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MountType::Replace { old } => {
|
MountType::Replace { old } => {
|
||||||
let mut iter = RealChildIterator::new(old, self.vdom);
|
todo!()
|
||||||
let first = iter.next().unwrap();
|
// let mut iter = RealChildIterator::new(old, self.vdom);
|
||||||
self.mutations
|
// let first = iter.next().unwrap();
|
||||||
.replace_with(first.direct_id(), nodes_created as u32);
|
// self.mutations
|
||||||
self.remove_nodes(iter);
|
// .replace_with(first.direct_id(), nodes_created as u32);
|
||||||
|
// self.remove_nodes(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
MountType::ReplaceByElementId { el: old } => {
|
MountType::ReplaceByElementId { el: old } => {
|
||||||
@@ -309,8 +370,8 @@ impl<'bump> DiffMachine<'bump> {
|
|||||||
|
|
||||||
let shared = self.vdom.channel.clone();
|
let shared = self.vdom.channel.clone();
|
||||||
// Insert a new scope into our component list
|
// Insert a new scope into our component list
|
||||||
|
let parent_scope = self.vdom.get_scope(parent_idx).unwrap();
|
||||||
let new_idx = self.vdom.insert_scope_with_key(|new_idx| {
|
let new_idx = self.vdom.insert_scope_with_key(|new_idx| {
|
||||||
let parent_scope = self.vdom.get_scope(parent_idx).unwrap();
|
|
||||||
let height = parent_scope.height + 1;
|
let height = parent_scope.height + 1;
|
||||||
Scope::new(
|
Scope::new(
|
||||||
caller,
|
caller,
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ For the rest, we defer to the rIC period and work down each queue from high to l
|
|||||||
*/
|
*/
|
||||||
use std::cell::{Cell, RefCell, RefMut};
|
use std::cell::{Cell, RefCell, RefMut};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use std::intrinsics::transmute;
|
||||||
use std::{cell::UnsafeCell, rc::Rc};
|
use std::{cell::UnsafeCell, rc::Rc};
|
||||||
|
|
||||||
use crate::heuristics::*;
|
use crate::heuristics::*;
|
||||||
@@ -174,7 +175,7 @@ pub struct Scheduler {
|
|||||||
|
|
||||||
pub garbage_scopes: HashSet<ScopeId>,
|
pub garbage_scopes: HashSet<ScopeId>,
|
||||||
|
|
||||||
pub fibers: [PriortySystem; 3],
|
pub lanes: [PriortySystem; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scheduler {
|
impl Scheduler {
|
||||||
@@ -253,7 +254,8 @@ impl Scheduler {
|
|||||||
current_priority: EventPriority::Low,
|
current_priority: EventPriority::Low,
|
||||||
|
|
||||||
// a dedicated fiber for each priority
|
// a dedicated fiber for each priority
|
||||||
fibers: [
|
lanes: [
|
||||||
|
PriortySystem::new(),
|
||||||
PriortySystem::new(),
|
PriortySystem::new(),
|
||||||
PriortySystem::new(),
|
PriortySystem::new(),
|
||||||
PriortySystem::new(),
|
PriortySystem::new(),
|
||||||
@@ -456,7 +458,7 @@ impl Scheduler {
|
|||||||
///
|
///
|
||||||
pub async fn work_with_deadline<'a>(
|
pub async fn work_with_deadline<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
deadline: &mut Pin<Box<impl FusedFuture<Output = ()>>>,
|
mut deadline: Pin<Box<impl FusedFuture<Output = ()>>>,
|
||||||
) -> Vec<Mutations<'a>> {
|
) -> Vec<Mutations<'a>> {
|
||||||
/*
|
/*
|
||||||
Strategy:
|
Strategy:
|
||||||
@@ -478,12 +480,8 @@ impl Scheduler {
|
|||||||
- should we batch?
|
- should we batch?
|
||||||
- react says no - they are continuous
|
- react says no - they are continuous
|
||||||
- but if we received both - then we don't need to diff, do we? run as many as we can and then finally diff?
|
- but if we received both - then we don't need to diff, do we? run as many as we can and then finally diff?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
let mut committed_mutations = Vec::new();
|
let mut committed_mutations = Vec::<Mutations<'static>>::new();
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// the scheduler uses a bunch of different receivers to mimic a "topic" queue system. The futures-channel implementation
|
// the scheduler uses a bunch of different receivers to mimic a "topic" queue system. The futures-channel implementation
|
||||||
@@ -496,7 +494,7 @@ impl Scheduler {
|
|||||||
// Wait for any new events if we have nothing to do
|
// Wait for any new events if we have nothing to do
|
||||||
if !self.has_any_work() {
|
if !self.has_any_work() {
|
||||||
self.clean_up_garbage();
|
self.clean_up_garbage();
|
||||||
let deadline_expired = self.wait_for_any_trigger(deadline).await;
|
let deadline_expired = self.wait_for_any_trigger(&mut deadline).await;
|
||||||
|
|
||||||
if deadline_expired {
|
if deadline_expired {
|
||||||
return committed_mutations;
|
return committed_mutations;
|
||||||
@@ -508,7 +506,76 @@ impl Scheduler {
|
|||||||
|
|
||||||
// Work through the current subtree, and commit the results when it finishes
|
// Work through the current subtree, and commit the results when it finishes
|
||||||
// When the deadline expires, give back the work
|
// When the deadline expires, give back the work
|
||||||
let mut new_mutations = Mutations::new();
|
self.current_priority = match (
|
||||||
|
self.lanes[0].has_work(),
|
||||||
|
self.lanes[1].has_work(),
|
||||||
|
self.lanes[2].has_work(),
|
||||||
|
self.lanes[3].has_work(),
|
||||||
|
) {
|
||||||
|
(true, _, _, _) => EventPriority::Immediate,
|
||||||
|
(false, true, _, _) => EventPriority::High,
|
||||||
|
(false, false, true, _) => EventPriority::Medium,
|
||||||
|
(false, false, false, _) => EventPriority::Low,
|
||||||
|
};
|
||||||
|
|
||||||
|
let current_lane = match self.current_priority {
|
||||||
|
EventPriority::Immediate => &mut self.lanes[0],
|
||||||
|
EventPriority::High => &mut self.lanes[1],
|
||||||
|
EventPriority::Medium => &mut self.lanes[2],
|
||||||
|
EventPriority::Low => &mut self.lanes[3],
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.current_priority == EventPriority::Immediate {
|
||||||
|
// IDGAF - get this out the door right now. loop poll if we need to
|
||||||
|
}
|
||||||
|
|
||||||
|
use futures_util::future::{select, Either};
|
||||||
|
|
||||||
|
// if let Some(state) = current_lane.saved_state.take() {
|
||||||
|
// let mut machine = unsafe { state.promote(&self) };
|
||||||
|
// machine.work().await;
|
||||||
|
// } else {
|
||||||
|
if let Some(scope) = current_lane.dirty_scopes.pop() {
|
||||||
|
let (mut saved_work, work_complete): (SavedDiffWork<'static>, bool) = {
|
||||||
|
let shared = SharedVdom {
|
||||||
|
channel: self.channel.clone(),
|
||||||
|
components: unsafe { &mut *self.components.get() },
|
||||||
|
elements: &mut self.raw_elements,
|
||||||
|
};
|
||||||
|
let mut machine = DiffMachine::new(Mutations::new(), shared);
|
||||||
|
|
||||||
|
let work_complete = {
|
||||||
|
let fut = machine.diff_scope(scope);
|
||||||
|
pin_mut!(fut);
|
||||||
|
match select(fut, &mut deadline).await {
|
||||||
|
Either::Left((work, _other)) => {
|
||||||
|
//
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Either::Right((deadline, _other)) => {
|
||||||
|
//
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let saved = machine.save();
|
||||||
|
let extended: SavedDiffWork<'static> = unsafe { transmute(saved) };
|
||||||
|
(extended, work_complete)
|
||||||
|
};
|
||||||
|
|
||||||
|
// release the stack borrow of ourself
|
||||||
|
|
||||||
|
if work_complete {
|
||||||
|
for scope in saved_work.seen_scopes.drain() {
|
||||||
|
current_lane.dirty_scopes.remove(&scope);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
// let mut new_mutations = Mutations::new();
|
||||||
// match self.work_with_deadline(&mut deadline).await {
|
// match self.work_with_deadline(&mut deadline).await {
|
||||||
// Some(mutations) => {
|
// Some(mutations) => {
|
||||||
// // safety: the scheduler will never let us mutate
|
// // safety: the scheduler will never let us mutate
|
||||||
@@ -519,15 +586,6 @@ impl Scheduler {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
// // check if we need to elevate priority
|
// // 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 mut machine = DiffMachine::new(mutations, ScopeId(0), &self);
|
||||||
|
|
||||||
@@ -595,7 +653,17 @@ impl Scheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_channel_msg(&mut self, msg: SchedulerMsg) {
|
pub fn handle_channel_msg(&mut self, msg: SchedulerMsg) {
|
||||||
//
|
match msg {
|
||||||
|
SchedulerMsg::Immediate(_) => todo!(),
|
||||||
|
SchedulerMsg::UiEvent(_) => todo!(),
|
||||||
|
|
||||||
|
//
|
||||||
|
SchedulerMsg::SubmitTask(_, _) => todo!(),
|
||||||
|
SchedulerMsg::ToggleTask(_) => todo!(),
|
||||||
|
SchedulerMsg::PauseTask(_) => todo!(),
|
||||||
|
SchedulerMsg::ResumeTask(_) => todo!(),
|
||||||
|
SchedulerMsg::DropTask(_) => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_dirty_scope(&mut self, scope: ScopeId, priority: EventPriority) {
|
pub fn add_dirty_scope(&mut self, scope: ScopeId, priority: EventPriority) {
|
||||||
@@ -610,13 +678,13 @@ impl Scheduler {
|
|||||||
|
|
||||||
pub struct PriortySystem {
|
pub struct PriortySystem {
|
||||||
pub dirty_scopes: IndexSet<ScopeId>,
|
pub dirty_scopes: IndexSet<ScopeId>,
|
||||||
pub machine: DiffMachine<'static>,
|
pub saved_state: Option<SavedDiffWork<'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PriortySystem {
|
impl PriortySystem {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
machine: DiffMachine::new(edits, shared),
|
saved_state: None,
|
||||||
dirty_scopes: Default::default(),
|
dirty_scopes: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ impl VirtualDom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn diff_async<'s>(&'s mut self) -> Mutations<'s> {
|
pub async fn diff_async<'s>(&'s mut self) -> Mutations<'s> {
|
||||||
let mut diff_machine = DiffMachine::new(Mutations::new(), &self.scheduler);
|
let mut diff_machine = DiffMachine::new(Mutations::new(), todo!());
|
||||||
|
|
||||||
let cur_component = self
|
let cur_component = self
|
||||||
.scheduler
|
.scheduler
|
||||||
@@ -268,7 +268,7 @@ impl VirtualDom {
|
|||||||
deadline: impl Future<Output = ()>,
|
deadline: impl Future<Output = ()>,
|
||||||
) -> Vec<Mutations<'s>> {
|
) -> Vec<Mutations<'s>> {
|
||||||
let mut deadline = Box::pin(deadline.fuse());
|
let mut deadline = Box::pin(deadline.fuse());
|
||||||
self.scheduler.work_with_deadline(&mut deadline).await
|
self.scheduler.work_with_deadline(deadline).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_event_sender(&self) -> futures_channel::mpsc::UnboundedSender<SchedulerMsg> {
|
pub fn get_event_sender(&self) -> futures_channel::mpsc::UnboundedSender<SchedulerMsg> {
|
||||||
|
|||||||
Reference in new issue
Block a user