feat: update root props

This commit is contained in:
Jonathan Kelley committed 2021-09-01 15:45:53 -04:00
1 parent c321532a6c
commit fac2e56ed6
9 files changed
+96 -55

No files matched your search

+1 -1
View File
@@ -1,3 +1,3 @@
{ {
"rust-analyzer.inlayHints.enable": false "rust-analyzer.inlayHints.enable": true
} }
-6
View File
@@ -67,12 +67,6 @@ impl ActiveFrame {
} }
} }
pub fn finished_frame_mut(&mut self) -> &mut BumpFrame {
match self.generation.get() & 1 == 1 {
true => &mut self.frames[0],
false => &mut self.frames[1],
}
}
/// Give out our self-referential item with our own borrowed lifetime /// Give out our self-referential item with our own borrowed lifetime
pub fn fin_head<'b>(&'b self) -> &'b VNode<'b> { pub fn fin_head<'b>(&'b self) -> &'b VNode<'b> {
let cur_head = &self.finished_frame().head_node; let cur_head = &self.finished_frame().head_node;
+20 -20
View File
@@ -633,16 +633,16 @@ pub mod on {
DownArrow = 40, DownArrow = 40,
Insert = 45, Insert = 45,
Delete = 46, Delete = 46,
_0 = 48, Num0 = 48,
_1 = 49, Num1 = 49,
_2 = 50, Num2 = 50,
_3 = 51, Num3 = 51,
_4 = 52, Num4 = 52,
_5 = 53, Num5 = 53,
_6 = 54, Num6 = 54,
_7 = 55, Num7 = 55,
_8 = 56, Num8 = 56,
_9 = 57, Num9 = 57,
A = 65, A = 65,
B = 66, B = 66,
C = 67, C = 67,
@@ -738,16 +738,16 @@ pub mod on {
40 => DownArrow, 40 => DownArrow,
45 => Insert, 45 => Insert,
46 => Delete, 46 => Delete,
48 => _0, 48 => Num0,
49 => _1, 49 => Num1,
50 => _2, 50 => Num2,
51 => _3, 51 => Num3,
52 => _4, 52 => Num4,
53 => _5, 53 => Num5,
54 => _6, 54 => Num6,
55 => _7, 55 => Num7,
56 => _8, 56 => Num8,
57 => _9, 57 => Num9,
65 => A, 65 => A,
66 => B, 66 => B,
67 => C, 67 => C,
+3 -1
View File
@@ -3,7 +3,7 @@ use std::{
cell::{Cell, RefCell, UnsafeCell}, cell::{Cell, RefCell, UnsafeCell},
}; };
pub struct HookList { pub(crate) struct HookList {
vals: RefCell<Vec<InnerHook<Box<dyn Any>>>>, vals: RefCell<Vec<InnerHook<Box<dyn Any>>>>,
idx: Cell<usize>, idx: Cell<usize>,
} }
@@ -20,6 +20,7 @@ impl Default for HookList {
struct InnerHook<T> { struct InnerHook<T> {
cell: UnsafeCell<T>, cell: UnsafeCell<T>,
} }
impl<T> InnerHook<T> { impl<T> InnerHook<T> {
fn new(new: T) -> Self { fn new(new: T) -> Self {
Self { Self {
@@ -27,6 +28,7 @@ impl<T> InnerHook<T> {
} }
} }
} }
impl HookList { impl HookList {
pub(crate) fn next<T: 'static>(&self) -> Option<&mut T> { pub(crate) fn next<T: 'static>(&self) -> Option<&mut T> {
self.vals.borrow().get(self.idx.get()).and_then(|inn| { self.vals.borrow().get(self.idx.get()).and_then(|inn| {
+15 -16
View File
@@ -3,11 +3,11 @@
//! This module contains all the low-level built-in hooks that require 1st party support to work. //! This module contains all the low-level built-in hooks that require 1st party support to work.
//! //!
//! Hooks: //! Hooks:
//! - use_hook //! - [`use_hook`]
//! - use_state_provider //! - [`use_state_provider`]
//! - use_state_consumer //! - [`use_state_consumer`]
//! - use_task //! - [`use_task`]
//! - use_suspense //! - [`use_suspense`]
use crate::innerlude::*; use crate::innerlude::*;
use futures_util::FutureExt; use futures_util::FutureExt;
@@ -53,15 +53,7 @@ where
(true, true) => {} (true, true) => {}
// Needs to be initialized // Needs to be initialized
(false, false) => { (false, false) => cx.add_shared_state(init()),
log::debug!("Initializing context...");
cx.add_shared_state(init());
log::info!(
"There are now {} shared contexts for scope {:?}",
cx.scope.shared_contexts.borrow().len(),
cx.scope.our_arena_idx,
);
}
_ => debug_assert!(false, "Cannot initialize two contexts of the same type"), _ => debug_assert!(false, "Cannot initialize two contexts of the same type"),
}; };
@@ -205,7 +197,10 @@ where
cx.render(LazyNodes::new(|f| { cx.render(LazyNodes::new(|f| {
let bump = f.bump(); let bump = f.bump();
let g: &dyn FnOnce(SuspendedContext<'src>) -> DomTree<'src> =
use bumpalo::boxed::Box as BumpBox;
let f: &mut dyn FnMut(SuspendedContext<'src>) -> DomTree<'src> =
bump.alloc(move |sus| { bump.alloc(move |sus| {
let val = value.borrow(); let val = value.borrow();
@@ -218,11 +213,12 @@ where
user_callback(sus, out) user_callback(sus, out)
}); });
let callback = unsafe { BumpBox::from_raw(f) };
VNode::Suspended(bump.alloc(VSuspended { VNode::Suspended(bump.alloc(VSuspended {
dom_id: empty_cell(), dom_id: empty_cell(),
task_id: hook.handle.our_id, task_id: hook.handle.our_id,
callback: RefCell::new(Some(g)), callback: RefCell::new(Some(callback)),
})) }))
})) }))
} }
@@ -235,10 +231,13 @@ pub(crate) struct SuspenseHook {
pub handle: TaskHandle, pub handle: TaskHandle,
pub value: Rc<RefCell<Option<Box<dyn Any>>>>, pub value: Rc<RefCell<Option<Box<dyn Any>>>>,
} }
type SuspendedCallback = Box<dyn for<'a> Fn(SuspendedContext<'a>) -> DomTree<'a>>; type SuspendedCallback = Box<dyn for<'a> Fn(SuspendedContext<'a>) -> DomTree<'a>>;
pub struct SuspendedContext<'a> { pub struct SuspendedContext<'a> {
pub(crate) inner: Context<'a, ()>, pub(crate) inner: Context<'a, ()>,
} }
impl<'src> SuspendedContext<'src> { impl<'src> SuspendedContext<'src> {
pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>( pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
self, self,
+1 -1
View File
@@ -38,7 +38,7 @@ pub(crate) mod innerlude {
pub use crate::diff_stack::*; pub use crate::diff_stack::*;
pub use crate::events::*; pub use crate::events::*;
pub use crate::heuristics::*; pub use crate::heuristics::*;
pub use crate::hooklist::*; pub(crate) use crate::hooklist::*;
pub use crate::hooks::*; pub use crate::hooks::*;
pub use crate::mutations::*; pub use crate::mutations::*;
pub use crate::nodes::*; pub use crate::nodes::*;
+4 -7
View File
@@ -283,7 +283,8 @@ pub struct VComponent<'src> {
pub struct VSuspended<'a> { pub struct VSuspended<'a> {
pub task_id: u64, pub task_id: u64,
pub dom_id: Cell<Option<ElementId>>, pub dom_id: Cell<Option<ElementId>>,
pub(crate) callback: RefCell<Option<&'a dyn FnOnce(SuspendedContext<'a>) -> DomTree<'a>>>, pub(crate) callback:
RefCell<Option<BumpBox<'a, dyn FnMut(SuspendedContext<'a>) -> DomTree<'a>>>>,
} }
/// This struct provides an ergonomic API to quickly build VNodes. /// This struct provides an ergonomic API to quickly build VNodes.
@@ -518,7 +519,7 @@ impl<'a> NodeFactory<'a> {
})) }))
} }
pub fn create_component_caller<'g, P: 'g>( pub(crate) fn create_component_caller<'g, P: 'g>(
component: FC<P>, component: FC<P>,
raw_props: *const (), raw_props: *const (),
) -> Rc<dyn for<'r> Fn(&'r Scope) -> DomTree<'r>> { ) -> Rc<dyn for<'r> Fn(&'r Scope) -> DomTree<'r>> {
@@ -530,12 +531,8 @@ impl<'a> NodeFactory<'a> {
props: safe_props, props: safe_props,
scope: scp, scope: scp,
}; };
let res = component(cx); let res = component(cx);
unsafe { std::mem::transmute(res) }
let g2 = unsafe { std::mem::transmute(res) };
g2
}); });
unsafe { std::mem::transmute::<_, Captured<'static>>(caller) } unsafe { std::mem::transmute::<_, Captured<'static>>(caller) }
} }
+22 -3
View File
@@ -36,8 +36,7 @@ pub struct Scope {
// Listeners // Listeners
pub(crate) listeners: RefCell<Vec<*const Listener<'static>>>, pub(crate) listeners: RefCell<Vec<*const Listener<'static>>>,
pub(crate) borrowed_props: RefCell<Vec<*const VComponent<'static>>>, pub(crate) borrowed_props: RefCell<Vec<*const VComponent<'static>>>,
pub(crate) suspended_nodes: RefCell<HashMap<u64, *const VSuspended<'static>>>,
pub(crate) suspended_nodes: RefCell<HashMap<u64, *const VNode<'static>>>,
// State // State
pub(crate) hooks: HookList, pub(crate) hooks: HookList,
@@ -146,7 +145,7 @@ impl Scope {
/// ///
/// Refrences to hook data can only be stored in listeners and component props. During diffing, we make sure to log /// Refrences to hook data can only be stored in listeners and component props. During diffing, we make sure to log
/// all listeners and borrowed props so we can clear them here. /// all listeners and borrowed props so we can clear them here.
fn ensure_drop_safety(&mut self, pool: &ResourcePool) { pub(crate) fn ensure_drop_safety(&mut self, pool: &ResourcePool) {
// make sure all garabge is collected before trying to proceed with anything else // make sure all garabge is collected before trying to proceed with anything else
debug_assert!( debug_assert!(
self.pending_garbage.borrow().is_empty(), self.pending_garbage.borrow().is_empty(),
@@ -220,6 +219,26 @@ impl Scope {
unsafe { self.child_nodes.shorten_lifetime() } unsafe { self.child_nodes.shorten_lifetime() }
} }
pub fn call_suspended_node<'a>(&'a self, task: u64) {
let g = self.suspended_nodes.borrow_mut();
if let Some(suspended) = g.get(&task) {
let sus: &'a VSuspended<'static> = unsafe { &**suspended };
let sus: &'a VSuspended<'a> = unsafe { std::mem::transmute(sus) };
let bump = self.frames.wip_frame();
let mut cb = sus.callback.borrow_mut();
let mut _cb = cb.take().unwrap();
let cx: SuspendedContext<'a> = SuspendedContext {
inner: Context {
props: &(),
scope: &self,
},
};
let n: DomTree<'a> = (_cb)(cx);
}
}
pub fn consume_garbage(&self) -> Vec<&VNode> { pub fn consume_garbage(&self) -> Vec<&VNode> {
self.pending_garbage self.pending_garbage
.borrow_mut() .borrow_mut()
+30
View File
@@ -23,6 +23,7 @@ use futures_util::{Future, FutureExt};
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
pin::Pin, pin::Pin,
rc::Rc,
}; };
/// An integrated virtual node system that progresses events and diffs UI trees. /// An integrated virtual node system that progresses events and diffs UI trees.
@@ -39,6 +40,8 @@ pub struct VirtualDom {
base_scope: ScopeId, base_scope: ScopeId,
root_fc: Box<dyn Any>,
root_prop_type: std::any::TypeId, root_prop_type: std::any::TypeId,
root_props: Pin<Box<dyn std::any::Any>>, root_props: Pin<Box<dyn std::any::Any>>,
@@ -120,6 +123,7 @@ impl VirtualDom {
}); });
Self { Self {
root_fc: Box::new(root),
base_scope, base_scope,
scheduler, scheduler,
root_props: _root_props, root_props: _root_props,
@@ -135,6 +139,32 @@ impl VirtualDom {
self.scheduler.pool.get_scope(id) self.scheduler.pool.get_scope(id)
} }
/// Update the root props of this VirtualDOM.
///
/// This method retuns None if the old props could not be removed. The entire VirtualDOM will be rebuilt immediately,
/// so calling this method will block the main thread until computation is done.
pub fn update_root_props<'s, P: 'static>(&'s mut self, root_props: P) -> Option<Mutations<'s>> {
let root_scope = self.scheduler.pool.get_scope_mut(self.base_scope).unwrap();
root_scope.ensure_drop_safety(&self.scheduler.pool);
let mut _root_props: Pin<Box<dyn Any>> = Box::pin(root_props);
let _root_prop_type = TypeId::of::<P>();
if let Some(props_ptr) = _root_props.downcast_ref::<P>().map(|p| p as *const P) {
std::mem::swap(&mut self.root_props, &mut _root_props);
let root = *self.root_fc.downcast_ref::<FC<P>>().unwrap();
let new_caller = NodeFactory::create_component_caller(root, props_ptr as *const _);
root_scope.update_scope_dependencies(new_caller, ScopeChildren(&[]));
Some(self.rebuild())
} else {
None
}
}
/// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch /// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch
/// ///
/// The diff machine expects the RealDom's stack to be the root of the application /// The diff machine expects the RealDom's stack to be the root of the application