mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-15 00:47:09 +00:00
wip: it compiles cleanly
This commit is contained in:
parent
059294ab55
commit
fd0c384dac
3 changed files with 158 additions and 244 deletions
|
@ -108,7 +108,7 @@ pub struct DiffState<'bump> {
|
||||||
pub mutations: Mutations<'bump>,
|
pub mutations: Mutations<'bump>,
|
||||||
pub(crate) stack: DiffStack<'bump>,
|
pub(crate) stack: DiffStack<'bump>,
|
||||||
pub seen_scopes: FxHashSet<ScopeId>,
|
pub seen_scopes: FxHashSet<ScopeId>,
|
||||||
pub(crate) cfg: DiffCfg,
|
pub force_diff: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'bump> DiffState<'bump> {
|
impl<'bump> DiffState<'bump> {
|
||||||
|
@ -117,68 +117,14 @@ impl<'bump> DiffState<'bump> {
|
||||||
mutations,
|
mutations,
|
||||||
stack: DiffStack::new(),
|
stack: DiffStack::new(),
|
||||||
seen_scopes: Default::default(),
|
seen_scopes: Default::default(),
|
||||||
cfg: Default::default(),
|
force_diff: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct DiffCfg {
|
impl<'bump> ScopeArena {
|
||||||
pub force_diff: bool,
|
pub fn diff_scope(&'bump self, state: &mut DiffState<'bump>, id: &ScopeId) {
|
||||||
}
|
if let Some(component) = self.get_scope(&id) {
|
||||||
impl Default for DiffCfg {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
force_diff: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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(crate) struct SavedDiffWork<'bump> {
|
|
||||||
pub mutations: Mutations<'bump>,
|
|
||||||
pub stack: DiffStack<'bump>,
|
|
||||||
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) -> DiffState<'b> {
|
|
||||||
let extended: SavedDiffWork<'b> = std::mem::transmute(self);
|
|
||||||
DiffState {
|
|
||||||
cfg: DiffCfg::default(),
|
|
||||||
mutations: extended.mutations,
|
|
||||||
stack: extended.stack,
|
|
||||||
seen_scopes: extended.seen_scopes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'bump> VirtualDom {
|
|
||||||
// impl<'bump> DiffState<'bump> {
|
|
||||||
// pub(crate) fn new(mutations: Mutations<'bump>) -> Self {
|
|
||||||
// Self {
|
|
||||||
// mutations,
|
|
||||||
// cfg: DiffCfg::default(),
|
|
||||||
// stack: DiffStack::new(),
|
|
||||||
// seen_scopes: FxHashSet::default(),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn save(self) -> SavedDiffWork<'bump> {
|
|
||||||
// SavedDiffWork {
|
|
||||||
// mutations: state.mutations,
|
|
||||||
// stack: state.stack,
|
|
||||||
// seen_scopes: self.seen_scopes,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn diff_scope(&'bump self, state: &mut DiffState<'bump>, id: ScopeId) {
|
|
||||||
if let Some(component) = self.scopes.get(&id) {
|
|
||||||
let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
|
let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
|
||||||
state.stack.push(DiffInstruction::Diff { new, old });
|
state.stack.push(DiffInstruction::Diff { new, old });
|
||||||
self.work(state, || false);
|
self.work(state, || false);
|
||||||
|
@ -382,7 +328,7 @@ impl<'bump> VirtualDom {
|
||||||
state.stack.add_child_count(1);
|
state.stack.add_child_count(1);
|
||||||
|
|
||||||
if let Some(cur_scope_id) = state.stack.current_scope() {
|
if let Some(cur_scope_id) = state.stack.current_scope() {
|
||||||
let scope = self.scopes.get(&cur_scope_id).unwrap();
|
let scope = self.get_scope(&cur_scope_id).unwrap();
|
||||||
|
|
||||||
for listener in *listeners {
|
for listener in *listeners {
|
||||||
self.attach_listener_to_scope(state, listener, scope);
|
self.attach_listener_to_scope(state, listener, scope);
|
||||||
|
@ -427,7 +373,7 @@ impl<'bump> VirtualDom {
|
||||||
let parent_scope = self.get_scope(&parent_idx).unwrap();
|
let parent_scope = self.get_scope(&parent_idx).unwrap();
|
||||||
|
|
||||||
let new_idx: ScopeId = todo!();
|
let new_idx: ScopeId = todo!();
|
||||||
// self.scopes
|
// self
|
||||||
// .new_with_key(fc_ptr, vcomp, parent_scope, height, subtree, sender);
|
// .new_with_key(fc_ptr, vcomp, parent_scope, height, subtree, sender);
|
||||||
|
|
||||||
// .(|new_idx| {
|
// .(|new_idx| {
|
||||||
|
@ -445,7 +391,7 @@ impl<'bump> VirtualDom {
|
||||||
vcomponent.associated_scope.set(Some(new_idx));
|
vcomponent.associated_scope.set(Some(new_idx));
|
||||||
|
|
||||||
if !vcomponent.can_memoize {
|
if !vcomponent.can_memoize {
|
||||||
let cur_scope = self.scopes.get(&parent_idx).unwrap();
|
let cur_scope = self.get_scope(&parent_idx).unwrap();
|
||||||
let extended = vcomponent as *const VComponent;
|
let extended = vcomponent as *const VComponent;
|
||||||
let extended: *const VComponent<'static> = unsafe { std::mem::transmute(extended) };
|
let extended: *const VComponent<'static> = unsafe { std::mem::transmute(extended) };
|
||||||
|
|
||||||
|
@ -456,7 +402,7 @@ impl<'bump> VirtualDom {
|
||||||
// add noderefs to current noderef list Noderefs
|
// add noderefs to current noderef list Noderefs
|
||||||
// add effects to current effect list Effects
|
// add effects to current effect list Effects
|
||||||
|
|
||||||
let new_component = self.scopes.get(&new_idx).unwrap();
|
let new_component = self.get_scope(&new_idx).unwrap();
|
||||||
|
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"initializing component {:?} with height {:?}",
|
"initializing component {:?} with height {:?}",
|
||||||
|
@ -606,7 +552,7 @@ impl<'bump> VirtualDom {
|
||||||
//
|
//
|
||||||
// TODO: take a more efficient path than this
|
// TODO: take a more efficient path than this
|
||||||
if let Some(cur_scope_id) = state.stack.current_scope() {
|
if let Some(cur_scope_id) = state.stack.current_scope() {
|
||||||
let scope = self.scopes.get(&cur_scope_id).unwrap();
|
let scope = self.get_scope(&cur_scope_id).unwrap();
|
||||||
|
|
||||||
if old.listeners.len() == new.listeners.len() {
|
if old.listeners.len() == new.listeners.len() {
|
||||||
for (old_l, new_l) in old.listeners.iter().zip(new.listeners.iter()) {
|
for (old_l, new_l) in old.listeners.iter().zip(new.listeners.iter()) {
|
||||||
|
@ -664,7 +610,7 @@ impl<'bump> VirtualDom {
|
||||||
new.associated_scope.set(Some(scope_addr));
|
new.associated_scope.set(Some(scope_addr));
|
||||||
|
|
||||||
// make sure the component's caller function is up to date
|
// make sure the component's caller function is up to date
|
||||||
let scope = self.scopes.get(&scope_addr).unwrap();
|
let scope = self.get_scope(&scope_addr).unwrap();
|
||||||
scope.update_vcomp(new);
|
scope.update_vcomp(new);
|
||||||
|
|
||||||
// React doesn't automatically memoize, but we do.
|
// React doesn't automatically memoize, but we do.
|
||||||
|
@ -1312,7 +1258,7 @@ impl<'bump> VirtualDom {
|
||||||
|
|
||||||
VNode::Component(c) => {
|
VNode::Component(c) => {
|
||||||
let scope_id = c.associated_scope.get().unwrap();
|
let scope_id = c.associated_scope.get().unwrap();
|
||||||
let scope = self.scopes.get(&scope_id).unwrap();
|
let scope = self.get_scope(&scope_id).unwrap();
|
||||||
let root = scope.root_node();
|
let root = scope.root_node();
|
||||||
self.remove_nodes(state, Some(root), gen_muts);
|
self.remove_nodes(state, Some(root), gen_muts);
|
||||||
|
|
||||||
|
@ -1366,7 +1312,7 @@ impl<'bump> VirtualDom {
|
||||||
if let Some(scope) = state
|
if let Some(scope) = state
|
||||||
.stack
|
.stack
|
||||||
.current_scope()
|
.current_scope()
|
||||||
.and_then(|id| self.scopes.get(&id))
|
.and_then(|id| self.get_scope(&id))
|
||||||
{
|
{
|
||||||
// safety: this lifetime is managed by the logic on scope
|
// safety: this lifetime is managed by the logic on scope
|
||||||
let extended: &VSuspended<'static> = unsafe { std::mem::transmute(suspended) };
|
let extended: &VSuspended<'static> = unsafe { std::mem::transmute(suspended) };
|
||||||
|
|
|
@ -21,18 +21,20 @@ pub(crate) struct ScopeArena {
|
||||||
bump: Bump,
|
bump: Bump,
|
||||||
scopes: Vec<*mut ScopeState>,
|
scopes: Vec<*mut ScopeState>,
|
||||||
free_scopes: Vec<ScopeId>,
|
free_scopes: Vec<ScopeId>,
|
||||||
|
pub(crate) sender: UnboundedSender<SchedulerMsg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScopeArena {
|
impl ScopeArena {
|
||||||
pub fn new() -> Self {
|
pub fn new(sender: UnboundedSender<SchedulerMsg>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bump: Bump::new(),
|
bump: Bump::new(),
|
||||||
scopes: Vec::new(),
|
scopes: Vec::new(),
|
||||||
free_scopes: Vec::new(),
|
free_scopes: Vec::new(),
|
||||||
|
sender,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, id: &ScopeId) -> Option<&ScopeState> {
|
pub fn get_scope(&self, id: &ScopeId) -> Option<&ScopeState> {
|
||||||
unsafe { Some(&*self.scopes[id.0]) }
|
unsafe { Some(&*self.scopes[id.0]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,5 +88,18 @@ impl ScopeArena {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_remove(&self, id: &ScopeId) -> Option<ScopeState> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reserve_node(&self, node: &VNode) -> ElementId {
|
||||||
|
todo!()
|
||||||
|
// self.node_reservations.insert(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn collect_garbage(&self, id: ElementId) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
// scopes never get dropepd
|
// scopes never get dropepd
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,8 +88,6 @@ pub struct VirtualDom {
|
||||||
pending_messages: VecDeque<SchedulerMsg>,
|
pending_messages: VecDeque<SchedulerMsg>,
|
||||||
dirty_scopes: IndexSet<ScopeId>,
|
dirty_scopes: IndexSet<ScopeId>,
|
||||||
|
|
||||||
saved_state: Option<SavedDiffWork<'static>>,
|
|
||||||
|
|
||||||
in_progress: bool,
|
in_progress: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +162,7 @@ impl VirtualDom {
|
||||||
sender: UnboundedSender<SchedulerMsg>,
|
sender: UnboundedSender<SchedulerMsg>,
|
||||||
receiver: UnboundedReceiver<SchedulerMsg>,
|
receiver: UnboundedReceiver<SchedulerMsg>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut scopes = ScopeArena::new();
|
let mut scopes = ScopeArena::new(sender.clone());
|
||||||
|
|
||||||
let base_scope = scopes.new_with_key(
|
let base_scope = scopes.new_with_key(
|
||||||
//
|
//
|
||||||
|
@ -191,7 +189,6 @@ impl VirtualDom {
|
||||||
pending_futures: Default::default(),
|
pending_futures: Default::default(),
|
||||||
dirty_scopes: Default::default(),
|
dirty_scopes: Default::default(),
|
||||||
|
|
||||||
saved_state: None,
|
|
||||||
in_progress: false,
|
in_progress: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +213,7 @@ impl VirtualDom {
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
pub fn get_scope<'a>(&'a self, id: &ScopeId) -> Option<&'a ScopeState> {
|
pub fn get_scope<'a>(&'a self, id: &ScopeId) -> Option<&'a ScopeState> {
|
||||||
self.scopes.get(&id)
|
self.scopes.get_scope(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an [`UnboundedSender`] handle to the channel used by the scheduler.
|
/// Get an [`UnboundedSender`] handle to the channel used by the scheduler.
|
||||||
|
@ -246,10 +243,12 @@ impl VirtualDom {
|
||||||
/// This lets us poll async tasks during idle periods without blocking the main thread.
|
/// This lets us poll async tasks during idle periods without blocking the main thread.
|
||||||
pub async fn wait_for_work(&mut self) {
|
pub async fn wait_for_work(&mut self) {
|
||||||
// todo: poll the events once even if there is work to do to prevent starvation
|
// todo: poll the events once even if there is work to do to prevent starvation
|
||||||
if self.has_any_work() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// if there's no futures in the virtualdom, just wait for a scheduler message and put it into the queue to be processed
|
||||||
|
if self.pending_futures.is_empty() {
|
||||||
|
self.pending_messages
|
||||||
|
.push_front(self.receiver.next().await.unwrap());
|
||||||
|
} else {
|
||||||
struct PollTasks<'a> {
|
struct PollTasks<'a> {
|
||||||
pending_futures: &'a FxHashSet<ScopeId>,
|
pending_futures: &'a FxHashSet<ScopeId>,
|
||||||
scopes: &'a ScopeArena,
|
scopes: &'a ScopeArena,
|
||||||
|
@ -258,12 +257,18 @@ impl VirtualDom {
|
||||||
impl<'a> Future for PollTasks<'a> {
|
impl<'a> Future for PollTasks<'a> {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
|
fn poll(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
) -> Poll<Self::Output> {
|
||||||
let mut all_pending = true;
|
let mut all_pending = true;
|
||||||
|
|
||||||
// Poll every scope manually
|
// Poll every scope manually
|
||||||
for fut in self.pending_futures.iter() {
|
for fut in self.pending_futures.iter() {
|
||||||
let scope = self.scopes.get(fut).expect("Scope should never be moved");
|
let scope = self
|
||||||
|
.scopes
|
||||||
|
.get_scope(fut)
|
||||||
|
.expect("Scope should never be moved");
|
||||||
|
|
||||||
let mut items = scope.items.borrow_mut();
|
let mut items = scope.items.borrow_mut();
|
||||||
for task in items.tasks.iter_mut() {
|
for task in items.tasks.iter_mut() {
|
||||||
|
@ -271,17 +276,17 @@ impl VirtualDom {
|
||||||
|
|
||||||
// todo: does this make sense?
|
// todo: does this make sense?
|
||||||
// I don't usually write futures by hand
|
// I don't usually write futures by hand
|
||||||
|
// I think the futures neeed to be pinned using bumpbox or something
|
||||||
|
// right now, they're bump allocated so this shouldn't matter anyway - they're not going to move
|
||||||
let unpinned = unsafe { Pin::new_unchecked(task) };
|
let unpinned = unsafe { Pin::new_unchecked(task) };
|
||||||
match unpinned.poll(cx) {
|
|
||||||
Poll::Ready(_) => {
|
if let Poll::Ready(_) = unpinned.poll(cx) {
|
||||||
all_pending = false;
|
all_pending = false
|
||||||
}
|
|
||||||
Poll::Pending => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the future if any task is ready
|
// Resolve the future if any singular task is ready
|
||||||
match all_pending {
|
match all_pending {
|
||||||
true => Poll::Pending,
|
true => Poll::Pending,
|
||||||
false => Poll::Ready(()),
|
false => Poll::Ready(()),
|
||||||
|
@ -289,21 +294,24 @@ impl VirtualDom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Poll both the futures and the scheduler message queue simulataneously
|
||||||
|
use futures_util::future::{select, Either};
|
||||||
|
|
||||||
let scheduler_fut = self.receiver.next();
|
let scheduler_fut = self.receiver.next();
|
||||||
let tasks_fut = PollTasks {
|
let tasks_fut = PollTasks {
|
||||||
pending_futures: &self.pending_futures,
|
pending_futures: &self.pending_futures,
|
||||||
scopes: &self.scopes,
|
scopes: &self.scopes,
|
||||||
};
|
};
|
||||||
|
|
||||||
use futures_util::future::{select, Either};
|
|
||||||
match select(tasks_fut, scheduler_fut).await {
|
match select(tasks_fut, scheduler_fut).await {
|
||||||
// Tasks themselves don't generate work
|
// Futures don't generate work
|
||||||
Either::Left((_, _)) => {}
|
Either::Left((_, _)) => {}
|
||||||
|
|
||||||
// Save these messages in FIFO to be processed later
|
// Save these messages in FIFO to be processed later
|
||||||
Either::Right((msg, _)) => self.pending_messages.push_front(msg.unwrap()),
|
Either::Right((msg, _)) => self.pending_messages.push_front(msg.unwrap()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Run the virtualdom with a deadline.
|
/// Run the virtualdom with a deadline.
|
||||||
///
|
///
|
||||||
|
@ -333,10 +341,15 @@ impl VirtualDom {
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// static App: FC<()> = |(cx, props)|rsx!(cx, div {"hello"} );
|
/// static App: FC<()> = |(cx, props)|rsx!(cx, div {"hello"} );
|
||||||
|
///
|
||||||
/// let mut dom = VirtualDom::new(App);
|
/// let mut dom = VirtualDom::new(App);
|
||||||
|
///
|
||||||
/// loop {
|
/// loop {
|
||||||
/// let deadline = TimeoutFuture::from_ms(16);
|
/// let mut timeout = TimeoutFuture::from_ms(16);
|
||||||
|
/// let deadline = move || timeout.now_or_never();
|
||||||
|
///
|
||||||
/// let mutations = dom.run_with_deadline(deadline).await;
|
/// let mutations = dom.run_with_deadline(deadline).await;
|
||||||
|
///
|
||||||
/// apply_mutations(mutations);
|
/// apply_mutations(mutations);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -352,124 +365,91 @@ impl VirtualDom {
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
mut deadline: impl FnMut() -> bool,
|
mut deadline: impl FnMut() -> bool,
|
||||||
) -> Vec<Mutations<'a>> {
|
) -> Vec<Mutations<'a>> {
|
||||||
let mut committed_mutations = Vec::<Mutations<'static>>::new();
|
let mut committed_mutations = Vec::<Mutations>::new();
|
||||||
|
|
||||||
while self.has_any_work() {
|
while self.has_any_work() {
|
||||||
while let Ok(Some(msg)) = self.receiver.try_next() {
|
while let Ok(Some(msg)) = self.receiver.try_next() {
|
||||||
self.pending_messages.push_front(msg);
|
self.pending_messages.push_front(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
for msg in self.pending_messages.drain(..) {
|
while let Some(msg) = self.pending_messages.pop_back() {
|
||||||
match msg {
|
match msg {
|
||||||
SchedulerMsg::Immediate(id) => {
|
SchedulerMsg::Immediate(id) => {
|
||||||
// it's dirty
|
|
||||||
self.dirty_scopes.insert(id);
|
self.dirty_scopes.insert(id);
|
||||||
}
|
}
|
||||||
SchedulerMsg::UiEvent(event) => {
|
SchedulerMsg::UiEvent(event) => {
|
||||||
// there's an event
|
|
||||||
let scope = self.scopes.get(&event.scope_id).unwrap();
|
|
||||||
if let Some(element) = event.mounted_dom_id {
|
if let Some(element) = event.mounted_dom_id {
|
||||||
log::info!("Calling listener {:?}, {:?}", event.scope_id, element);
|
log::info!("Calling listener {:?}, {:?}", event.scope_id, element);
|
||||||
|
|
||||||
|
let scope = self.scopes.get_scope(&event.scope_id).unwrap();
|
||||||
|
|
||||||
// TODO: bubble properly here
|
// TODO: bubble properly here
|
||||||
scope.call_listener(event, element);
|
scope.call_listener(event, element);
|
||||||
|
|
||||||
while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
|
while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
|
||||||
match dirty_scope {
|
self.pending_messages.push_front(dirty_scope);
|
||||||
SchedulerMsg::Immediate(im) => {
|
|
||||||
self.dirty_scopes.insert(im);
|
|
||||||
}
|
|
||||||
SchedulerMsg::UiEvent(e) => self.ui_events.push_back(e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log::debug!("User event without a targetted ElementId. Unsure how to proceed. {:?}", event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let work_complete = {
|
let mut diff_state: DiffState = DiffState::new(Mutations::new());
|
||||||
// Work through the current subtree, and commit the results when it finishes
|
|
||||||
// When the deadline expires, give back the work
|
|
||||||
let saved_state = unsafe { self.load_work() };
|
|
||||||
|
|
||||||
// We have to split away some parts of ourself - current lane is borrowed mutably
|
|
||||||
let mut machine = unsafe { saved_state.promote() };
|
|
||||||
|
|
||||||
let mut ran_scopes = FxHashSet::default();
|
let mut ran_scopes = FxHashSet::default();
|
||||||
|
|
||||||
if machine.stack.is_empty() {
|
// todo: the 2021 version of rust will let us not have to force the borrow
|
||||||
todo!("order scopes");
|
let scopes = &self.scopes;
|
||||||
// self.dirty_scopes.retain(|id| self.get_scope(id).is_some());
|
|
||||||
// self.dirty_scopes.sort_by(|a, b| {
|
// Sort the scopes by height. Theoretically, we'll de-duplicate scopes by height
|
||||||
// let h1 = self.get_scope(a).unwrap().height;
|
self.dirty_scopes
|
||||||
// let h2 = self.get_scope(b).unwrap().height;
|
.retain(|id| scopes.get_scope(id).is_some());
|
||||||
// h1.cmp(&h2).reverse()
|
|
||||||
// });
|
self.dirty_scopes.sort_by(|a, b| {
|
||||||
|
let h1 = scopes.get_scope(a).unwrap().height;
|
||||||
|
let h2 = scopes.get_scope(b).unwrap().height;
|
||||||
|
h1.cmp(&h2).reverse()
|
||||||
|
});
|
||||||
|
|
||||||
if let Some(scopeid) = self.dirty_scopes.pop() {
|
if let Some(scopeid) = self.dirty_scopes.pop() {
|
||||||
log::info!("handling dirty scope {:?}", scopeid);
|
log::info!("handling dirty scope {:?}", scopeid);
|
||||||
|
|
||||||
if !ran_scopes.contains(&scopeid) {
|
if !ran_scopes.contains(&scopeid) {
|
||||||
ran_scopes.insert(scopeid);
|
ran_scopes.insert(scopeid);
|
||||||
|
|
||||||
log::debug!("about to run scope {:?}", scopeid);
|
log::debug!("about to run scope {:?}", scopeid);
|
||||||
|
|
||||||
// if let Some(component) = self.get_scope_mut(&scopeid) {
|
|
||||||
if self.run_scope(&scopeid) {
|
if self.run_scope(&scopeid) {
|
||||||
todo!("diff the scope")
|
let scope = self.scopes.get_scope(&scopeid).unwrap();
|
||||||
// let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
|
let (old, new) = (scope.frames.wip_head(), scope.frames.fin_head());
|
||||||
// // let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
|
diff_state.stack.scope_stack.push(scopeid);
|
||||||
// machine.stack.scope_stack.push(scopeid);
|
diff_state.stack.push(DiffInstruction::Diff { new, old });
|
||||||
// machine.stack.push(DiffInstruction::Diff { new, old });
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let work_completed: bool = todo!();
|
let work_completed = self.scopes.work(&mut diff_state, &mut deadline);
|
||||||
// let work_completed = machine.work(deadline_reached);
|
|
||||||
|
|
||||||
// log::debug!("raw edits {:?}", machine.mutations.edits);
|
|
||||||
|
|
||||||
let mut machine: DiffState<'static> = unsafe { std::mem::transmute(machine) };
|
|
||||||
// let mut saved = machine.save();
|
|
||||||
|
|
||||||
if work_completed {
|
if work_completed {
|
||||||
for node in machine.seen_scopes.drain() {
|
let DiffState {
|
||||||
// self.dirty_scopes.clear();
|
mutations,
|
||||||
// self.ui_events.clear();
|
seen_scopes,
|
||||||
self.dirty_scopes.remove(&node);
|
stack,
|
||||||
// self.dirty_scopes.remove(&node);
|
..
|
||||||
|
} = diff_state;
|
||||||
|
|
||||||
|
for scope in seen_scopes {
|
||||||
|
self.dirty_scopes.remove(&scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_mutations = Mutations::new();
|
// I think the stack should be empty at the end of diffing?
|
||||||
|
debug_assert_eq!(stack.scope_stack.len(), 0);
|
||||||
|
|
||||||
for edit in machine.mutations.edits.drain(..) {
|
committed_mutations.push(mutations);
|
||||||
new_mutations.edits.push(edit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// for edit in saved.edits.drain(..) {
|
|
||||||
// new_mutations.edits.push(edit);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// std::mem::swap(&mut new_mutations, &mut saved.mutations);
|
|
||||||
|
|
||||||
mutations.push(new_mutations);
|
|
||||||
|
|
||||||
// log::debug!("saved edits {:?}", mutations);
|
|
||||||
|
|
||||||
todo!();
|
|
||||||
// let mut saved = machine.save();
|
|
||||||
// self.save_work(saved);
|
|
||||||
true
|
|
||||||
|
|
||||||
// self.save_work(saved);
|
|
||||||
// false
|
|
||||||
} else {
|
} else {
|
||||||
false
|
todo!("don't have a mechanism to pause work (yet)");
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if !work_complete {
|
|
||||||
return committed_mutations;
|
return committed_mutations;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -495,7 +475,13 @@ impl VirtualDom {
|
||||||
/// apply_edits(edits);
|
/// apply_edits(edits);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn rebuild(&mut self) -> Mutations {
|
pub fn rebuild(&mut self) -> Mutations {
|
||||||
self.hard_diff(&self.base_scope)
|
// todo: I think we need to append a node or something
|
||||||
|
// diff_machine
|
||||||
|
// .stack
|
||||||
|
// .create_node(cur_component.frames.fin_head(), MountType::Append);
|
||||||
|
|
||||||
|
let scope = self.base_scope;
|
||||||
|
self.hard_diff(&scope).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute a manual diff of the VirtualDOM between states.
|
/// Compute a manual diff of the VirtualDOM between states.
|
||||||
|
@ -532,59 +518,26 @@ impl VirtualDom {
|
||||||
///
|
///
|
||||||
/// let edits = dom.diff();
|
/// let edits = dom.diff();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn hard_diff<'a>(&'a mut self, base_scope: &ScopeId) -> Mutations<'a> {
|
pub fn hard_diff<'a>(&'a mut self, scope_id: &ScopeId) -> Option<Mutations<'a>> {
|
||||||
// // TODO: drain any in-flight work
|
log::debug!("hard diff {:?}", scope_id);
|
||||||
// // We run the component. If it succeeds, then we can diff it and add the changes to the dom.
|
|
||||||
// if self.run_scope(&base_scope) {
|
|
||||||
// let cur_component = self
|
|
||||||
// .get_scope_mut(&base_scope)
|
|
||||||
// .expect("The base scope should never be moved");
|
|
||||||
|
|
||||||
// log::debug!("rebuild {:?}", base_scope);
|
if self.run_scope(&scope_id) {
|
||||||
|
|
||||||
// let mut diff_machine = DiffState::new(Mutations::new());
|
|
||||||
// diff_machine
|
|
||||||
// .stack
|
|
||||||
// .create_node(cur_component.frames.fin_head(), MountType::Append);
|
|
||||||
|
|
||||||
// diff_machine.stack.scope_stack.push(base_scope);
|
|
||||||
|
|
||||||
// todo!()
|
|
||||||
// // self.work(&mut diff_machine, || false);
|
|
||||||
// // diff_machine.work(|| false);
|
|
||||||
// } else {
|
|
||||||
// // todo: should this be a hard error?
|
|
||||||
// log::warn!(
|
|
||||||
// "Component failed to run successfully during rebuild.
|
|
||||||
// This does not result in a failed rebuild, but indicates a logic failure within your app."
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// todo!()
|
|
||||||
// // unsafe { std::mem::transmute(diff_machine.mutations) }
|
|
||||||
|
|
||||||
let cur_component = self
|
|
||||||
.scopes
|
|
||||||
.get(&base_scope)
|
|
||||||
.expect("The base scope should never be moved");
|
|
||||||
|
|
||||||
log::debug!("hard diff {:?}", base_scope);
|
|
||||||
|
|
||||||
if self.run_scope(&base_scope) {
|
|
||||||
let mut diff_machine = DiffState::new(Mutations::new());
|
let mut diff_machine = DiffState::new(Mutations::new());
|
||||||
diff_machine.cfg.force_diff = true;
|
|
||||||
self.diff_scope(&mut diff_machine, base_scope);
|
diff_machine.force_diff = true;
|
||||||
// diff_machine.diff_scope(base_scope);
|
|
||||||
diff_machine.mutations
|
self.scopes.diff_scope(&mut diff_machine, scope_id);
|
||||||
|
|
||||||
|
Some(diff_machine.mutations)
|
||||||
} else {
|
} else {
|
||||||
Mutations::new()
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_scope(&mut self, id: &ScopeId) -> bool {
|
pub fn run_scope(&self, id: &ScopeId) -> bool {
|
||||||
let scope = self
|
let scope = self
|
||||||
.scopes
|
.scopes
|
||||||
.get(id)
|
.get_scope(id)
|
||||||
.expect("The base scope should never be moved");
|
.expect("The base scope should never be moved");
|
||||||
|
|
||||||
// Cycle to the next frame and then reset it
|
// Cycle to the next frame and then reset it
|
||||||
|
|
Loading…
Reference in a new issue