mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-14 08:27:07 +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(crate) stack: DiffStack<'bump>,
|
||||
pub seen_scopes: FxHashSet<ScopeId>,
|
||||
pub(crate) cfg: DiffCfg,
|
||||
pub force_diff: bool,
|
||||
}
|
||||
|
||||
impl<'bump> DiffState<'bump> {
|
||||
|
@ -117,68 +117,14 @@ impl<'bump> DiffState<'bump> {
|
|||
mutations,
|
||||
stack: DiffStack::new(),
|
||||
seen_scopes: Default::default(),
|
||||
cfg: Default::default(),
|
||||
force_diff: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct DiffCfg {
|
||||
pub force_diff: bool,
|
||||
}
|
||||
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) {
|
||||
impl<'bump> ScopeArena {
|
||||
pub fn diff_scope(&'bump self, state: &mut DiffState<'bump>, id: &ScopeId) {
|
||||
if let Some(component) = self.get_scope(&id) {
|
||||
let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
|
||||
state.stack.push(DiffInstruction::Diff { new, old });
|
||||
self.work(state, || false);
|
||||
|
@ -382,7 +328,7 @@ impl<'bump> VirtualDom {
|
|||
state.stack.add_child_count(1);
|
||||
|
||||
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 {
|
||||
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 new_idx: ScopeId = todo!();
|
||||
// self.scopes
|
||||
// self
|
||||
// .new_with_key(fc_ptr, vcomp, parent_scope, height, subtree, sender);
|
||||
|
||||
// .(|new_idx| {
|
||||
|
@ -445,7 +391,7 @@ impl<'bump> VirtualDom {
|
|||
vcomponent.associated_scope.set(Some(new_idx));
|
||||
|
||||
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: *const VComponent<'static> = unsafe { std::mem::transmute(extended) };
|
||||
|
||||
|
@ -456,7 +402,7 @@ impl<'bump> VirtualDom {
|
|||
// add noderefs to current noderef list Noderefs
|
||||
// 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!(
|
||||
"initializing component {:?} with height {:?}",
|
||||
|
@ -606,7 +552,7 @@ impl<'bump> VirtualDom {
|
|||
//
|
||||
// TODO: take a more efficient path than this
|
||||
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() {
|
||||
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));
|
||||
|
||||
// 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);
|
||||
|
||||
// React doesn't automatically memoize, but we do.
|
||||
|
@ -1312,7 +1258,7 @@ impl<'bump> VirtualDom {
|
|||
|
||||
VNode::Component(c) => {
|
||||
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();
|
||||
self.remove_nodes(state, Some(root), gen_muts);
|
||||
|
||||
|
@ -1366,7 +1312,7 @@ impl<'bump> VirtualDom {
|
|||
if let Some(scope) = state
|
||||
.stack
|
||||
.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
|
||||
let extended: &VSuspended<'static> = unsafe { std::mem::transmute(suspended) };
|
||||
|
|
|
@ -21,18 +21,20 @@ pub(crate) struct ScopeArena {
|
|||
bump: Bump,
|
||||
scopes: Vec<*mut ScopeState>,
|
||||
free_scopes: Vec<ScopeId>,
|
||||
pub(crate) sender: UnboundedSender<SchedulerMsg>,
|
||||
}
|
||||
|
||||
impl ScopeArena {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(sender: UnboundedSender<SchedulerMsg>) -> Self {
|
||||
Self {
|
||||
bump: Bump::new(),
|
||||
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]) }
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -88,8 +88,6 @@ pub struct VirtualDom {
|
|||
pending_messages: VecDeque<SchedulerMsg>,
|
||||
dirty_scopes: IndexSet<ScopeId>,
|
||||
|
||||
saved_state: Option<SavedDiffWork<'static>>,
|
||||
|
||||
in_progress: bool,
|
||||
}
|
||||
|
||||
|
@ -164,7 +162,7 @@ impl VirtualDom {
|
|||
sender: UnboundedSender<SchedulerMsg>,
|
||||
receiver: UnboundedReceiver<SchedulerMsg>,
|
||||
) -> Self {
|
||||
let mut scopes = ScopeArena::new();
|
||||
let mut scopes = ScopeArena::new(sender.clone());
|
||||
|
||||
let base_scope = scopes.new_with_key(
|
||||
//
|
||||
|
@ -191,7 +189,6 @@ impl VirtualDom {
|
|||
pending_futures: Default::default(),
|
||||
dirty_scopes: Default::default(),
|
||||
|
||||
saved_state: None,
|
||||
in_progress: false,
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +213,7 @@ impl VirtualDom {
|
|||
///
|
||||
///
|
||||
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.
|
||||
|
@ -246,62 +243,73 @@ impl VirtualDom {
|
|||
/// This lets us poll async tasks during idle periods without blocking the main thread.
|
||||
pub async fn wait_for_work(&mut self) {
|
||||
// todo: poll the events once even if there is work to do to prevent starvation
|
||||
if self.has_any_work() {
|
||||
return;
|
||||
}
|
||||
|
||||
struct PollTasks<'a> {
|
||||
pending_futures: &'a FxHashSet<ScopeId>,
|
||||
scopes: &'a ScopeArena,
|
||||
}
|
||||
// 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> {
|
||||
pending_futures: &'a FxHashSet<ScopeId>,
|
||||
scopes: &'a ScopeArena,
|
||||
}
|
||||
|
||||
impl<'a> Future for PollTasks<'a> {
|
||||
type Output = ();
|
||||
impl<'a> Future for PollTasks<'a> {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
|
||||
let mut all_pending = true;
|
||||
fn poll(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> Poll<Self::Output> {
|
||||
let mut all_pending = true;
|
||||
|
||||
// Poll every scope manually
|
||||
for fut in self.pending_futures.iter() {
|
||||
let scope = self.scopes.get(fut).expect("Scope should never be moved");
|
||||
// Poll every scope manually
|
||||
for fut in self.pending_futures.iter() {
|
||||
let scope = self
|
||||
.scopes
|
||||
.get_scope(fut)
|
||||
.expect("Scope should never be moved");
|
||||
|
||||
let mut items = scope.items.borrow_mut();
|
||||
for task in items.tasks.iter_mut() {
|
||||
let task = task.as_mut();
|
||||
let mut items = scope.items.borrow_mut();
|
||||
for task in items.tasks.iter_mut() {
|
||||
let task = task.as_mut();
|
||||
|
||||
// todo: does this make sense?
|
||||
// I don't usually write futures by hand
|
||||
let unpinned = unsafe { Pin::new_unchecked(task) };
|
||||
match unpinned.poll(cx) {
|
||||
Poll::Ready(_) => {
|
||||
all_pending = false;
|
||||
// todo: does this make sense?
|
||||
// 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) };
|
||||
|
||||
if let Poll::Ready(_) = unpinned.poll(cx) {
|
||||
all_pending = false
|
||||
}
|
||||
Poll::Pending => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the future if any task is ready
|
||||
match all_pending {
|
||||
true => Poll::Pending,
|
||||
false => Poll::Ready(()),
|
||||
// Resolve the future if any singular task is ready
|
||||
match all_pending {
|
||||
true => Poll::Pending,
|
||||
false => Poll::Ready(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let scheduler_fut = self.receiver.next();
|
||||
let tasks_fut = PollTasks {
|
||||
pending_futures: &self.pending_futures,
|
||||
scopes: &self.scopes,
|
||||
};
|
||||
// Poll both the futures and the scheduler message queue simulataneously
|
||||
use futures_util::future::{select, Either};
|
||||
|
||||
use futures_util::future::{select, Either};
|
||||
match select(tasks_fut, scheduler_fut).await {
|
||||
// Tasks themselves don't generate work
|
||||
Either::Left((_, _)) => {}
|
||||
let scheduler_fut = self.receiver.next();
|
||||
let tasks_fut = PollTasks {
|
||||
pending_futures: &self.pending_futures,
|
||||
scopes: &self.scopes,
|
||||
};
|
||||
|
||||
// Save these messages in FIFO to be processed later
|
||||
Either::Right((msg, _)) => self.pending_messages.push_front(msg.unwrap()),
|
||||
match select(tasks_fut, scheduler_fut).await {
|
||||
// Futures don't generate work
|
||||
Either::Left((_, _)) => {}
|
||||
|
||||
// Save these messages in FIFO to be processed later
|
||||
Either::Right((msg, _)) => self.pending_messages.push_front(msg.unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,10 +341,15 @@ impl VirtualDom {
|
|||
///
|
||||
/// ```no_run
|
||||
/// static App: FC<()> = |(cx, props)|rsx!(cx, div {"hello"} );
|
||||
///
|
||||
/// let mut dom = VirtualDom::new(App);
|
||||
///
|
||||
/// 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;
|
||||
///
|
||||
/// apply_mutations(mutations);
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -352,124 +365,91 @@ impl VirtualDom {
|
|||
&'a mut self,
|
||||
mut deadline: impl FnMut() -> bool,
|
||||
) -> Vec<Mutations<'a>> {
|
||||
let mut committed_mutations = Vec::<Mutations<'static>>::new();
|
||||
let mut committed_mutations = Vec::<Mutations>::new();
|
||||
|
||||
while self.has_any_work() {
|
||||
while let Ok(Some(msg)) = self.receiver.try_next() {
|
||||
self.pending_messages.push_front(msg);
|
||||
}
|
||||
|
||||
for msg in self.pending_messages.drain(..) {
|
||||
while let Some(msg) = self.pending_messages.pop_back() {
|
||||
match msg {
|
||||
SchedulerMsg::Immediate(id) => {
|
||||
// it's dirty
|
||||
self.dirty_scopes.insert(id);
|
||||
}
|
||||
SchedulerMsg::UiEvent(event) => {
|
||||
// there's an event
|
||||
let scope = self.scopes.get(&event.scope_id).unwrap();
|
||||
if let Some(element) = event.mounted_dom_id {
|
||||
log::info!("Calling listener {:?}, {:?}", event.scope_id, element);
|
||||
|
||||
let scope = self.scopes.get_scope(&event.scope_id).unwrap();
|
||||
|
||||
// TODO: bubble properly here
|
||||
scope.call_listener(event, element);
|
||||
|
||||
while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
|
||||
match dirty_scope {
|
||||
SchedulerMsg::Immediate(im) => {
|
||||
self.dirty_scopes.insert(im);
|
||||
}
|
||||
SchedulerMsg::UiEvent(e) => self.ui_events.push_back(e),
|
||||
}
|
||||
self.pending_messages.push_front(dirty_scope);
|
||||
}
|
||||
} else {
|
||||
log::debug!("User event without a targetted ElementId. Unsure how to proceed. {:?}", event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let work_complete = {
|
||||
// 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() };
|
||||
let mut diff_state: DiffState = DiffState::new(Mutations::new());
|
||||
|
||||
// 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();
|
||||
// todo: the 2021 version of rust will let us not have to force the borrow
|
||||
let scopes = &self.scopes;
|
||||
|
||||
if machine.stack.is_empty() {
|
||||
todo!("order scopes");
|
||||
// self.dirty_scopes.retain(|id| self.get_scope(id).is_some());
|
||||
// self.dirty_scopes.sort_by(|a, b| {
|
||||
// let h1 = self.get_scope(a).unwrap().height;
|
||||
// let h2 = self.get_scope(b).unwrap().height;
|
||||
// h1.cmp(&h2).reverse()
|
||||
// });
|
||||
// Sort the scopes by height. Theoretically, we'll de-duplicate scopes by height
|
||||
self.dirty_scopes
|
||||
.retain(|id| scopes.get_scope(id).is_some());
|
||||
|
||||
if let Some(scopeid) = self.dirty_scopes.pop() {
|
||||
log::info!("handling dirty scope {:?}", scopeid);
|
||||
if !ran_scopes.contains(&scopeid) {
|
||||
ran_scopes.insert(scopeid);
|
||||
log::debug!("about to run scope {:?}", scopeid);
|
||||
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(component) = self.get_scope_mut(&scopeid) {
|
||||
if self.run_scope(&scopeid) {
|
||||
todo!("diff the scope")
|
||||
// let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
|
||||
// // let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
|
||||
// machine.stack.scope_stack.push(scopeid);
|
||||
// machine.stack.push(DiffInstruction::Diff { new, old });
|
||||
}
|
||||
// }
|
||||
}
|
||||
if let Some(scopeid) = self.dirty_scopes.pop() {
|
||||
log::info!("handling dirty scope {:?}", scopeid);
|
||||
|
||||
if !ran_scopes.contains(&scopeid) {
|
||||
ran_scopes.insert(scopeid);
|
||||
|
||||
log::debug!("about to run scope {:?}", scopeid);
|
||||
|
||||
if self.run_scope(&scopeid) {
|
||||
let scope = self.scopes.get_scope(&scopeid).unwrap();
|
||||
let (old, new) = (scope.frames.wip_head(), scope.frames.fin_head());
|
||||
diff_state.stack.scope_stack.push(scopeid);
|
||||
diff_state.stack.push(DiffInstruction::Diff { new, old });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let work_completed: bool = todo!();
|
||||
// let work_completed = machine.work(deadline_reached);
|
||||
let work_completed = self.scopes.work(&mut diff_state, &mut deadline);
|
||||
|
||||
// log::debug!("raw edits {:?}", machine.mutations.edits);
|
||||
if work_completed {
|
||||
let DiffState {
|
||||
mutations,
|
||||
seen_scopes,
|
||||
stack,
|
||||
..
|
||||
} = diff_state;
|
||||
|
||||
let mut machine: DiffState<'static> = unsafe { std::mem::transmute(machine) };
|
||||
// let mut saved = machine.save();
|
||||
|
||||
if work_completed {
|
||||
for node in machine.seen_scopes.drain() {
|
||||
// self.dirty_scopes.clear();
|
||||
// self.ui_events.clear();
|
||||
self.dirty_scopes.remove(&node);
|
||||
// self.dirty_scopes.remove(&node);
|
||||
}
|
||||
|
||||
let mut new_mutations = Mutations::new();
|
||||
|
||||
for edit in machine.mutations.edits.drain(..) {
|
||||
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 {
|
||||
false
|
||||
for scope in seen_scopes {
|
||||
self.dirty_scopes.remove(&scope);
|
||||
}
|
||||
};
|
||||
|
||||
if !work_complete {
|
||||
// I think the stack should be empty at the end of diffing?
|
||||
debug_assert_eq!(stack.scope_stack.len(), 0);
|
||||
|
||||
committed_mutations.push(mutations);
|
||||
} else {
|
||||
todo!("don't have a mechanism to pause work (yet)");
|
||||
return committed_mutations;
|
||||
}
|
||||
}
|
||||
|
@ -495,7 +475,13 @@ impl VirtualDom {
|
|||
/// apply_edits(edits);
|
||||
/// ```
|
||||
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.
|
||||
|
@ -532,59 +518,26 @@ impl VirtualDom {
|
|||
///
|
||||
/// let edits = dom.diff();
|
||||
/// ```
|
||||
pub fn hard_diff<'a>(&'a mut self, base_scope: &ScopeId) -> Mutations<'a> {
|
||||
// // TODO: drain any in-flight work
|
||||
// // 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");
|
||||
pub fn hard_diff<'a>(&'a mut self, scope_id: &ScopeId) -> Option<Mutations<'a>> {
|
||||
log::debug!("hard diff {:?}", scope_id);
|
||||
|
||||
// log::debug!("rebuild {:?}", base_scope);
|
||||
|
||||
// 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) {
|
||||
if self.run_scope(&scope_id) {
|
||||
let mut diff_machine = DiffState::new(Mutations::new());
|
||||
diff_machine.cfg.force_diff = true;
|
||||
self.diff_scope(&mut diff_machine, base_scope);
|
||||
// diff_machine.diff_scope(base_scope);
|
||||
diff_machine.mutations
|
||||
|
||||
diff_machine.force_diff = true;
|
||||
|
||||
self.scopes.diff_scope(&mut diff_machine, scope_id);
|
||||
|
||||
Some(diff_machine.mutations)
|
||||
} else {
|
||||
Mutations::new()
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_scope(&mut self, id: &ScopeId) -> bool {
|
||||
pub fn run_scope(&self, id: &ScopeId) -> bool {
|
||||
let scope = self
|
||||
.scopes
|
||||
.get(id)
|
||||
.get_scope(id)
|
||||
.expect("The base scope should never be moved");
|
||||
|
||||
// Cycle to the next frame and then reset it
|
||||
|
|
Loading…
Reference in a new issue