feat: update root props

This commit is contained in:
Jonathan Kelley 2021-09-01 15:45:53 -04:00
parent c321532a6c
commit fac2e56ed6
9 changed files with 96 additions and 55 deletions

View file

@ -1,3 +1,3 @@
{
"rust-analyzer.inlayHints.enable": false
"rust-analyzer.inlayHints.enable": true
}

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
pub fn fin_head<'b>(&'b self) -> &'b VNode<'b> {
let cur_head = &self.finished_frame().head_node;

View file

@ -633,16 +633,16 @@ pub mod on {
DownArrow = 40,
Insert = 45,
Delete = 46,
_0 = 48,
_1 = 49,
_2 = 50,
_3 = 51,
_4 = 52,
_5 = 53,
_6 = 54,
_7 = 55,
_8 = 56,
_9 = 57,
Num0 = 48,
Num1 = 49,
Num2 = 50,
Num3 = 51,
Num4 = 52,
Num5 = 53,
Num6 = 54,
Num7 = 55,
Num8 = 56,
Num9 = 57,
A = 65,
B = 66,
C = 67,
@ -738,16 +738,16 @@ pub mod on {
40 => DownArrow,
45 => Insert,
46 => Delete,
48 => _0,
49 => _1,
50 => _2,
51 => _3,
52 => _4,
53 => _5,
54 => _6,
55 => _7,
56 => _8,
57 => _9,
48 => Num0,
49 => Num1,
50 => Num2,
51 => Num3,
52 => Num4,
53 => Num5,
54 => Num6,
55 => Num7,
56 => Num8,
57 => Num9,
65 => A,
66 => B,
67 => C,

View file

@ -3,7 +3,7 @@ use std::{
cell::{Cell, RefCell, UnsafeCell},
};
pub struct HookList {
pub(crate) struct HookList {
vals: RefCell<Vec<InnerHook<Box<dyn Any>>>>,
idx: Cell<usize>,
}
@ -20,6 +20,7 @@ impl Default for HookList {
struct InnerHook<T> {
cell: UnsafeCell<T>,
}
impl<T> InnerHook<T> {
fn new(new: T) -> Self {
Self {
@ -27,6 +28,7 @@ impl<T> InnerHook<T> {
}
}
}
impl HookList {
pub(crate) fn next<T: 'static>(&self) -> Option<&mut T> {
self.vals.borrow().get(self.idx.get()).and_then(|inn| {

View file

@ -3,11 +3,11 @@
//! This module contains all the low-level built-in hooks that require 1st party support to work.
//!
//! Hooks:
//! - use_hook
//! - use_state_provider
//! - use_state_consumer
//! - use_task
//! - use_suspense
//! - [`use_hook`]
//! - [`use_state_provider`]
//! - [`use_state_consumer`]
//! - [`use_task`]
//! - [`use_suspense`]
use crate::innerlude::*;
use futures_util::FutureExt;
@ -53,15 +53,7 @@ where
(true, true) => {}
// Needs to be initialized
(false, false) => {
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,
);
}
(false, false) => cx.add_shared_state(init()),
_ => debug_assert!(false, "Cannot initialize two contexts of the same type"),
};
@ -205,7 +197,10 @@ where
cx.render(LazyNodes::new(|f| {
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| {
let val = value.borrow();
@ -218,11 +213,12 @@ where
user_callback(sus, out)
});
let callback = unsafe { BumpBox::from_raw(f) };
VNode::Suspended(bump.alloc(VSuspended {
dom_id: empty_cell(),
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 value: Rc<RefCell<Option<Box<dyn Any>>>>,
}
type SuspendedCallback = Box<dyn for<'a> Fn(SuspendedContext<'a>) -> DomTree<'a>>;
pub struct SuspendedContext<'a> {
pub(crate) inner: Context<'a, ()>,
}
impl<'src> SuspendedContext<'src> {
pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
self,

View file

@ -38,7 +38,7 @@ pub(crate) mod innerlude {
pub use crate::diff_stack::*;
pub use crate::events::*;
pub use crate::heuristics::*;
pub use crate::hooklist::*;
pub(crate) use crate::hooklist::*;
pub use crate::hooks::*;
pub use crate::mutations::*;
pub use crate::nodes::*;

View file

@ -283,7 +283,8 @@ pub struct VComponent<'src> {
pub struct VSuspended<'a> {
pub task_id: u64,
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.
@ -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>,
raw_props: *const (),
) -> Rc<dyn for<'r> Fn(&'r Scope) -> DomTree<'r>> {
@ -530,12 +531,8 @@ impl<'a> NodeFactory<'a> {
props: safe_props,
scope: scp,
};
let res = component(cx);
let g2 = unsafe { std::mem::transmute(res) };
g2
unsafe { std::mem::transmute(res) }
});
unsafe { std::mem::transmute::<_, Captured<'static>>(caller) }
}

View file

@ -36,8 +36,7 @@ pub struct Scope {
// Listeners
pub(crate) listeners: RefCell<Vec<*const Listener<'static>>>,
pub(crate) borrowed_props: RefCell<Vec<*const VComponent<'static>>>,
pub(crate) suspended_nodes: RefCell<HashMap<u64, *const VNode<'static>>>,
pub(crate) suspended_nodes: RefCell<HashMap<u64, *const VSuspended<'static>>>,
// State
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
/// 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
debug_assert!(
self.pending_garbage.borrow().is_empty(),
@ -220,6 +219,26 @@ impl Scope {
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> {
self.pending_garbage
.borrow_mut()

View file

@ -23,6 +23,7 @@ use futures_util::{Future, FutureExt};
use std::{
any::{Any, TypeId},
pin::Pin,
rc::Rc,
};
/// An integrated virtual node system that progresses events and diffs UI trees.
@ -39,6 +40,8 @@ pub struct VirtualDom {
base_scope: ScopeId,
root_fc: Box<dyn Any>,
root_prop_type: std::any::TypeId,
root_props: Pin<Box<dyn std::any::Any>>,
@ -120,6 +123,7 @@ impl VirtualDom {
});
Self {
root_fc: Box::new(root),
base_scope,
scheduler,
root_props: _root_props,
@ -135,6 +139,32 @@ impl VirtualDom {
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
///
/// The diff machine expects the RealDom's stack to be the root of the application