wip: move hooklist into scope
This commit is contained in:
1 parent
d2f0547692
commit
b9fc5fc251
5 files changed
+178
-189
No files matched your search
@@ -90,6 +90,7 @@
|
|||||||
|
|
||||||
use crate::innerlude::*;
|
use crate::innerlude::*;
|
||||||
use fxhash::{FxHashMap, FxHashSet};
|
use fxhash::{FxHashMap, FxHashSet};
|
||||||
|
use smallvec::{smallvec, SmallVec};
|
||||||
use DomEdit::*;
|
use DomEdit::*;
|
||||||
|
|
||||||
/// Our DiffMachine is an iterative tree differ.
|
/// Our DiffMachine is an iterative tree differ.
|
||||||
@@ -124,6 +125,117 @@ impl<'bump> DiffState<'bump> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The stack instructions we use to diff and create new nodes.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum DiffInstruction<'a> {
|
||||||
|
Diff {
|
||||||
|
old: &'a VNode<'a>,
|
||||||
|
new: &'a VNode<'a>,
|
||||||
|
},
|
||||||
|
|
||||||
|
Create {
|
||||||
|
node: &'a VNode<'a>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// pushes the node elements onto the stack for use in mount
|
||||||
|
PrepareMove {
|
||||||
|
node: &'a VNode<'a>,
|
||||||
|
},
|
||||||
|
|
||||||
|
Mount {
|
||||||
|
and: MountType<'a>,
|
||||||
|
},
|
||||||
|
|
||||||
|
PopScope,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum MountType<'a> {
|
||||||
|
Absorb,
|
||||||
|
Append,
|
||||||
|
Replace { old: &'a VNode<'a> },
|
||||||
|
InsertAfter { other_node: &'a VNode<'a> },
|
||||||
|
InsertBefore { other_node: &'a VNode<'a> },
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct DiffStack<'bump> {
|
||||||
|
pub(crate) instructions: Vec<DiffInstruction<'bump>>,
|
||||||
|
nodes_created_stack: SmallVec<[usize; 10]>,
|
||||||
|
pub scope_stack: SmallVec<[ScopeId; 5]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'bump> DiffStack<'bump> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
instructions: Vec::with_capacity(1000),
|
||||||
|
nodes_created_stack: smallvec![],
|
||||||
|
scope_stack: smallvec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) -> Option<DiffInstruction<'bump>> {
|
||||||
|
self.instructions.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_off_scope(&mut self) {
|
||||||
|
self.scope_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, instruction: DiffInstruction<'bump>) {
|
||||||
|
self.instructions.push(instruction)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_children(&mut self, children: &'bump [VNode<'bump>], and: MountType<'bump>) {
|
||||||
|
self.nodes_created_stack.push(0);
|
||||||
|
self.instructions.push(DiffInstruction::Mount { and });
|
||||||
|
|
||||||
|
for child in children.iter().rev() {
|
||||||
|
self.instructions
|
||||||
|
.push(DiffInstruction::Create { node: child });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_subtree(&mut self) {
|
||||||
|
self.nodes_created_stack.push(0);
|
||||||
|
self.instructions.push(DiffInstruction::Mount {
|
||||||
|
and: MountType::Append,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_nodes_created(&mut self, count: usize) {
|
||||||
|
self.nodes_created_stack.push(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_node(&mut self, node: &'bump VNode<'bump>, and: MountType<'bump>) {
|
||||||
|
self.nodes_created_stack.push(0);
|
||||||
|
self.instructions.push(DiffInstruction::Mount { and });
|
||||||
|
self.instructions.push(DiffInstruction::Create { node });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_child_count(&mut self, count: usize) {
|
||||||
|
*self.nodes_created_stack.last_mut().unwrap() += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_nodes_created(&mut self) -> usize {
|
||||||
|
self.nodes_created_stack.pop().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_scope(&self) -> Option<ScopeId> {
|
||||||
|
self.scope_stack.last().copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_component(&mut self, idx: ScopeId, node: &'bump VNode<'bump>) {
|
||||||
|
// Push the new scope onto the stack
|
||||||
|
self.scope_stack.push(idx);
|
||||||
|
|
||||||
|
self.instructions.push(DiffInstruction::PopScope);
|
||||||
|
|
||||||
|
// Run the creation algorithm with this scope on the stack
|
||||||
|
// ?? I think we treat components as fragments??
|
||||||
|
self.instructions.push(DiffInstruction::Create { node });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'bump> DiffState<'bump> {
|
impl<'bump> DiffState<'bump> {
|
||||||
pub fn diff_scope(&mut self, id: &ScopeId) {
|
pub fn diff_scope(&mut self, id: &ScopeId) {
|
||||||
let (old, new) = (self.scopes.wip_head(id), self.scopes.fin_head(id));
|
let (old, new) = (self.scopes.wip_head(id), self.scopes.fin_head(id));
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
use crate::innerlude::*;
|
|
||||||
use smallvec::{smallvec, SmallVec};
|
|
||||||
|
|
||||||
/// The stack instructions we use to diff and create new nodes.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) enum DiffInstruction<'a> {
|
|
||||||
Diff {
|
|
||||||
old: &'a VNode<'a>,
|
|
||||||
new: &'a VNode<'a>,
|
|
||||||
},
|
|
||||||
|
|
||||||
Create {
|
|
||||||
node: &'a VNode<'a>,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// pushes the node elements onto the stack for use in mount
|
|
||||||
PrepareMove {
|
|
||||||
node: &'a VNode<'a>,
|
|
||||||
},
|
|
||||||
|
|
||||||
Mount {
|
|
||||||
and: MountType<'a>,
|
|
||||||
},
|
|
||||||
|
|
||||||
PopScope,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum MountType<'a> {
|
|
||||||
Absorb,
|
|
||||||
Append,
|
|
||||||
Replace { old: &'a VNode<'a> },
|
|
||||||
InsertAfter { other_node: &'a VNode<'a> },
|
|
||||||
InsertBefore { other_node: &'a VNode<'a> },
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct DiffStack<'bump> {
|
|
||||||
pub(crate) instructions: Vec<DiffInstruction<'bump>>,
|
|
||||||
nodes_created_stack: SmallVec<[usize; 10]>,
|
|
||||||
pub scope_stack: SmallVec<[ScopeId; 5]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'bump> DiffStack<'bump> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
instructions: Vec::with_capacity(1000),
|
|
||||||
nodes_created_stack: smallvec![],
|
|
||||||
scope_stack: smallvec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop(&mut self) -> Option<DiffInstruction<'bump>> {
|
|
||||||
self.instructions.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_off_scope(&mut self) {
|
|
||||||
self.scope_stack.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, instruction: DiffInstruction<'bump>) {
|
|
||||||
self.instructions.push(instruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_children(&mut self, children: &'bump [VNode<'bump>], and: MountType<'bump>) {
|
|
||||||
self.nodes_created_stack.push(0);
|
|
||||||
self.instructions.push(DiffInstruction::Mount { and });
|
|
||||||
|
|
||||||
for child in children.iter().rev() {
|
|
||||||
self.instructions
|
|
||||||
.push(DiffInstruction::Create { node: child });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_subtree(&mut self) {
|
|
||||||
self.nodes_created_stack.push(0);
|
|
||||||
self.instructions.push(DiffInstruction::Mount {
|
|
||||||
and: MountType::Append,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_nodes_created(&mut self, count: usize) {
|
|
||||||
self.nodes_created_stack.push(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_node(&mut self, node: &'bump VNode<'bump>, and: MountType<'bump>) {
|
|
||||||
self.nodes_created_stack.push(0);
|
|
||||||
self.instructions.push(DiffInstruction::Mount { and });
|
|
||||||
self.instructions.push(DiffInstruction::Create { node });
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_child_count(&mut self, count: usize) {
|
|
||||||
*self.nodes_created_stack.last_mut().unwrap() += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_nodes_created(&mut self) -> usize {
|
|
||||||
self.nodes_created_stack.pop().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn current_scope(&self) -> Option<ScopeId> {
|
|
||||||
self.scope_stack.last().copied()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_component(&mut self, idx: ScopeId, node: &'bump VNode<'bump>) {
|
|
||||||
// Push the new scope onto the stack
|
|
||||||
self.scope_stack.push(idx);
|
|
||||||
|
|
||||||
self.instructions.push(DiffInstruction::PopScope);
|
|
||||||
|
|
||||||
// Run the creation algorithm with this scope on the stack
|
|
||||||
// ?? I think we treat components as fragments??
|
|
||||||
self.instructions.push(DiffInstruction::Create { node });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
use std::{
|
|
||||||
any::Any,
|
|
||||||
cell::{Cell, RefCell},
|
|
||||||
};
|
|
||||||
|
|
||||||
use bumpalo::Bump;
|
|
||||||
|
|
||||||
/// An abstraction over internally stored data using a hook-based memory layout.
|
|
||||||
///
|
|
||||||
/// Hooks are allocated using Boxes and then our stored references are given out.
|
|
||||||
///
|
|
||||||
/// It's unsafe to "reset" the hooklist, but it is safe to add hooks into it.
|
|
||||||
///
|
|
||||||
/// Todo: this could use its very own bump arena, but that might be a tad overkill
|
|
||||||
#[derive(Default)]
|
|
||||||
pub(crate) struct HookList {
|
|
||||||
arena: Bump,
|
|
||||||
vals: RefCell<Vec<*mut dyn Any>>,
|
|
||||||
idx: Cell<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HookList {
|
|
||||||
pub(crate) fn next<T: 'static>(&self) -> Option<&mut T> {
|
|
||||||
self.vals.borrow().get(self.idx.get()).and_then(|inn| {
|
|
||||||
self.idx.set(self.idx.get() + 1);
|
|
||||||
let raw_box = unsafe { &mut **inn };
|
|
||||||
raw_box.downcast_mut::<T>()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This resets the internal iterator count
|
|
||||||
/// It's okay that we've given out each hook, but now we have the opportunity to give it out again
|
|
||||||
/// Therefore, resetting is considered unsafe
|
|
||||||
///
|
|
||||||
/// This should only be ran by Dioxus itself before "running scope".
|
|
||||||
/// Dioxus knows how to descend through the tree to prevent mutable aliasing.
|
|
||||||
pub(crate) unsafe fn reset(&self) {
|
|
||||||
self.idx.set(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn push_hook<T: 'static>(&self, new: T) {
|
|
||||||
let val = self.arena.alloc(new);
|
|
||||||
self.vals.borrow_mut().push(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn len(&self) -> usize {
|
|
||||||
self.vals.borrow().len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn cur_idx(&self) -> usize {
|
|
||||||
self.idx.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn at_end(&self) -> bool {
|
|
||||||
self.cur_idx() >= self.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear_hooks(&mut self) {
|
|
||||||
self.vals.borrow_mut().drain(..).for_each(|state| {
|
|
||||||
let as_mut = unsafe { &mut *state };
|
|
||||||
let boxed = unsafe { bumpalo::boxed::Box::from_raw(as_mut) };
|
|
||||||
drop(boxed);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the ammount of memory a hooklist uses
|
|
||||||
/// Used in heuristics
|
|
||||||
pub fn get_hook_arena_size(&self) -> usize {
|
|
||||||
self.arena.allocated_bytes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,8 +14,6 @@ Some utilities
|
|||||||
*/
|
*/
|
||||||
pub(crate) mod component;
|
pub(crate) mod component;
|
||||||
pub(crate) mod diff;
|
pub(crate) mod diff;
|
||||||
pub(crate) mod diff_stack;
|
|
||||||
pub(crate) mod hooklist;
|
|
||||||
pub(crate) mod lazynodes;
|
pub(crate) mod lazynodes;
|
||||||
pub(crate) mod mutations;
|
pub(crate) mod mutations;
|
||||||
pub(crate) mod nodes;
|
pub(crate) mod nodes;
|
||||||
@@ -25,9 +23,7 @@ pub(crate) mod virtual_dom;
|
|||||||
|
|
||||||
pub(crate) mod innerlude {
|
pub(crate) mod innerlude {
|
||||||
pub use crate::component::*;
|
pub use crate::component::*;
|
||||||
pub(crate) use crate::diff::*;
|
pub use crate::diff::*;
|
||||||
pub use crate::diff_stack::*;
|
|
||||||
pub(crate) use crate::hooklist::*;
|
|
||||||
pub use crate::lazynodes::*;
|
pub use crate::lazynodes::*;
|
||||||
pub use crate::mutations::*;
|
pub use crate::mutations::*;
|
||||||
pub use crate::nodes::*;
|
pub use crate::nodes::*;
|
||||||
|
|||||||
@@ -528,6 +528,71 @@ impl BumpFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An abstraction over internally stored data using a hook-based memory layout.
|
||||||
|
///
|
||||||
|
/// Hooks are allocated using Boxes and then our stored references are given out.
|
||||||
|
///
|
||||||
|
/// It's unsafe to "reset" the hooklist, but it is safe to add hooks into it.
|
||||||
|
///
|
||||||
|
/// Todo: this could use its very own bump arena, but that might be a tad overkill
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(crate) struct HookList {
|
||||||
|
arena: Bump,
|
||||||
|
vals: RefCell<Vec<*mut dyn Any>>,
|
||||||
|
idx: Cell<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HookList {
|
||||||
|
pub(crate) fn next<T: 'static>(&self) -> Option<&mut T> {
|
||||||
|
self.vals.borrow().get(self.idx.get()).and_then(|inn| {
|
||||||
|
self.idx.set(self.idx.get() + 1);
|
||||||
|
let raw_box = unsafe { &mut **inn };
|
||||||
|
raw_box.downcast_mut::<T>()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This resets the internal iterator count
|
||||||
|
/// It's okay that we've given out each hook, but now we have the opportunity to give it out again
|
||||||
|
/// Therefore, resetting is considered unsafe
|
||||||
|
///
|
||||||
|
/// This should only be ran by Dioxus itself before "running scope".
|
||||||
|
/// Dioxus knows how to descend through the tree to prevent mutable aliasing.
|
||||||
|
pub(crate) unsafe fn reset(&self) {
|
||||||
|
self.idx.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn push_hook<T: 'static>(&self, new: T) {
|
||||||
|
let val = self.arena.alloc(new);
|
||||||
|
self.vals.borrow_mut().push(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn len(&self) -> usize {
|
||||||
|
self.vals.borrow().len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn cur_idx(&self) -> usize {
|
||||||
|
self.idx.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn at_end(&self) -> bool {
|
||||||
|
self.cur_idx() >= self.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_hooks(&mut self) {
|
||||||
|
self.vals.borrow_mut().drain(..).for_each(|state| {
|
||||||
|
let as_mut = unsafe { &mut *state };
|
||||||
|
let boxed = unsafe { bumpalo::boxed::Box::from_raw(as_mut) };
|
||||||
|
drop(boxed);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the ammount of memory a hooklist uses
|
||||||
|
/// Used in heuristics
|
||||||
|
pub fn get_hook_arena_size(&self) -> usize {
|
||||||
|
self.arena.allocated_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sizeof() {
|
fn sizeof() {
|
||||||
dbg!(std::mem::size_of::<Scope>());
|
dbg!(std::mem::size_of::<Scope>());
|
||||||
|
|||||||
Reference in new issue
Block a user