wip: groundwork for noderefs

This commit is contained in:
Jonathan Kelley committed 2021-08-09 17:09:33 -04:00
1 parent a44e9fcffa
commit c1afeba1ef
21 files changed
+184 -103

No files matched your search

+1 -1
View File
@@ -110,7 +110,7 @@ impl<'r, 'bump> DiffMachine<'r, 'bump> {
/// This will PANIC if any component elements are passed in.
pub fn new_headless(shared: &'bump SharedResources) -> Self {
Self {
mutations: Mutations { edits: Vec::new() },
mutations: Mutations::new(),
scope_stack: smallvec![ScopeId(0)],
vdom: shared,
diffed: FxHashSet::default(),
+3
View File
@@ -447,7 +447,10 @@ pub mod on {
onmousemove
/// onmouseout
onmouseout
/// onmouseover
///
/// Triggered when the users's mouse hovers over an element.
onmouseover
/// onmouseup
onmouseup
+28
View File
@@ -256,3 +256,31 @@ impl<'src> SuspendedContext<'src> {
Some(lazy_nodes.into_vnode(NodeFactory { bump }))
}
}
#[derive(Clone, Copy)]
pub struct NodeRef<'src, T: 'static>(&'src RefCell<T>);
// impl NodeRef<'src, T> {
// fn set_ref(&self, new: Box<dyn Any>)
// }
// impl<'a, T> std::ops::Deref for NodeRef<'a, T> {
// type Target = Option<&'a T>;
// fn deref(&self) -> &Self::Target {
// // &self.node
// }
// }
pub fn use_node_ref<T, P>(cx: Context<P>) -> NodeRef<T> {
cx.use_hook(
|f| {},
|f| {
//
todo!()
// NodeRef {}
},
|f| {
//
},
)
}
View File
Whitespace-only changes.
+55 -14
View File
@@ -47,11 +47,11 @@ pub struct VirtualDom {
///
/// This is wrapped in an UnsafeCell because we will need to get mutable access to unique values in unique bump arenas
/// and rusts's guartnees cannot prove that this is safe. We will need to maintain the safety guarantees manually.
pub shared: SharedResources,
shared: SharedResources,
/// The index of the root component
/// Should always be the first (gen=0, id=0)
pub base_scope: ScopeId,
base_scope: ScopeId,
active_fibers: Vec<Fiber<'static>>,
@@ -197,8 +197,7 @@ impl VirtualDom {
///
pub fn rebuild<'s>(&'s mut self) -> Result<Vec<DomEdit<'s>>> {
let mut edits = Vec::new();
let mutations = Mutations { edits: Vec::new() };
let mut diff_machine = DiffMachine::new(mutations, self.base_scope, &self.shared);
let mut diff_machine = DiffMachine::new(Mutations::new(), self.base_scope, &self.shared);
let cur_component = diff_machine
.get_scope_mut(&self.base_scope)
@@ -274,7 +273,7 @@ impl VirtualDom {
self.run_with_deadline(async {}).await
}
/// Run the virtualdom with a time limit.
/// Run the virtualdom with a deadline.
///
/// This method will progress async tasks until the deadline is reached. If tasks are completed before the deadline,
/// and no tasks are pending, this method will return immediately. If tasks are still pending, then this method will
@@ -287,7 +286,7 @@ impl VirtualDom {
/// is exceeded. However, the deadline won't be met precisely, so you might want to build some wiggle room into the
/// deadline closure manually.
///
/// The deadline is checked before starting to diff components. This strikes a balance between the overhead of checking
/// The deadline is polled before starting to diff components. This strikes a balance between the overhead of checking
/// the deadline and just completing the work. However, if an individual component takes more than 16ms to render, then
/// the screen will "jank" up. In debug, this will trigger an alert.
///
@@ -309,6 +308,14 @@ impl VirtualDom {
/// apply_mutations(mutations);
/// }
/// ```
///
/// ## Mutations
///
/// This method returns "mutations" - IE the necessary changes to get the RealDOM to match the VirtualDOM. It also
/// includes a list of NodeRefs that need to be applied and effects that need to be triggered after the RealDOM has
/// applied the edits.
///
/// Mutations are the only link between the RealDOM and the VirtualDOM.
pub async fn run_with_deadline<'s>(
&'s mut self,
mut deadline: impl Future<Output = ()>,
@@ -319,11 +326,7 @@ impl VirtualDom {
let is_ready = || -> bool { (&mut deadline_future).now_or_never().is_some() };
let mut diff_machine = DiffMachine::new(
Mutations { edits: Vec::new() },
self.base_scope,
&self.shared,
);
let mut diff_machine = DiffMachine::new(Mutations::new(), self.base_scope, &self.shared);
/*
Strategy:
@@ -348,6 +351,11 @@ impl VirtualDom {
// 1. Consume any pending events and create new fibers
let mut receiver = self.shared.task_receiver.borrow_mut();
let current_fiber = {
//
self.active_fibers.get_mut(0).unwrap()
};
// On the primary event queue, there is no batching.
let mut trigger = {
match receiver.try_next() {
@@ -357,6 +365,8 @@ impl VirtualDom {
let mut tasks = self.shared.async_tasks.borrow_mut();
let tasks_tasks = tasks.next();
// if the new event generates work more important than our current fiber, we should consider switching
// only switch if it impacts different scopes.
let mut receiver = self.shared.task_receiver.borrow_mut();
let reciv_task = receiver.next();
@@ -365,10 +375,9 @@ impl VirtualDom {
// Poll the event receiver and the future pool for work
// Abort early if our deadline has ran out
use futures_util::select;
let mut deadline = (&mut deadline_future).fuse();
let trig = select! {
let trig = futures_util::select! {
trigger = tasks_tasks => trigger,
trigger = reciv_task => trigger,
_ = deadline => { return Ok(diff_machine.mutations); }
@@ -401,6 +410,7 @@ impl VirtualDom {
| VirtualEvent::ToggleEvent(_)
| VirtualEvent::MouseEvent(_)
| VirtualEvent::PointerEvent(_) => {
//
if let Some(scope) = self.shared.get_scope_mut(trigger.originator) {
scope.call_listener(trigger)?;
}
@@ -411,7 +421,7 @@ impl VirtualDom {
// These shouldn't normally be received, but if they are, it's done because some task set state manually
// Instead of processing it serially,
// We will batch all the scheduled updates together in one go.
VirtualEvent::ScheduledUpdate { height: u32 } => {}
VirtualEvent::ScheduledUpdate { .. } => {}
// Suspense Events! A component's suspended node is updated
VirtualEvent::SuspenseEvent { hook_idx, domnode } => {
@@ -556,4 +566,35 @@ pub struct Mutations<'s> {
// todo: apply node refs
// todo: apply effects
pub edits: Vec<DomEdit<'s>>,
pub noderefs: Vec<NodeRefMutation<'s>>,
}
impl<'s> Mutations<'s> {
pub fn new() -> Self {
let edits = Vec::new();
let noderefs = Vec::new();
Self { edits, noderefs }
}
}
// refs are only assigned once
pub struct NodeRefMutation<'a> {
element: &'a mut Option<once_cell::sync::OnceCell<Box<dyn Any>>>,
element_id: ElementId,
}
impl<'a> NodeRefMutation<'a> {
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
self.element
.as_ref()
.and_then(|f| f.get())
.and_then(|f| f.downcast_ref::<T>())
}
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.element
.as_mut()
.and_then(|f| f.get_mut())
.and_then(|f| f.downcast_mut::<T>())
}
}