wip: move testdom methods into virtualdom

This commit is contained in:
Jonathan Kelley committed 2021-11-09 12:10:11 -05:00
1 parent f2e343c154
commit d2f0547692
11 files changed
+247 -310

No files matched your search

+18 -39
View File
@@ -89,9 +89,7 @@
//! - https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/
use crate::innerlude::*;
use futures_channel::mpsc::UnboundedSender;
use fxhash::{FxHashMap, FxHashSet};
use slab::Slab;
use DomEdit::*;
/// Our DiffMachine is an iterative tree differ.
@@ -325,30 +323,20 @@ impl<'bump> DiffState<'bump> {
}
fn create_component_node(&mut self, vcomponent: &'bump VComponent<'bump>) {
// let caller = vcomponent.caller;
let parent_idx = self.stack.current_scope().unwrap();
let shared: UnboundedSender<SchedulerMsg> = todo!();
// let shared: UnboundedSender<SchedulerMsg> = self.sender.clone();
// Insert a new scope into our component list
let parent_scope = self.scopes.get_scope(&parent_idx).unwrap();
let height = parent_scope.height + 1;
let subtree = parent_scope.subtree.get();
let new_idx: ScopeId = todo!();
// self
// .new_with_key(fc_ptr, vcomp, parent_scope, height, subtree, sender);
let parent_scope = unsafe { self.scopes.get_scope_mut(&parent_idx) };
let caller = unsafe { std::mem::transmute(vcomponent.caller as *const _) };
let fc_ptr = vcomponent.user_fc;
// .(|new_idx| {
// // ScopeInner::new(
// vcomponent,
// new_idx,
// Some(parent_idx),
// parent_scope.height + 1,
// parent_scope.subtree(),
// shared,
// // )
// });
let new_idx = self
.scopes
.new_with_key(fc_ptr, caller, parent_scope, height, subtree);
// Actually initialize the caller's slot with the right address
vcomponent.associated_scope.set(Some(new_idx));
@@ -356,7 +344,7 @@ impl<'bump> DiffState<'bump> {
if !vcomponent.can_memoize {
let cur_scope = self.scopes.get_scope(&parent_idx).unwrap();
let extended = unsafe { std::mem::transmute(vcomponent) };
cur_scope.items.get_mut().borrowed_props.push(extended);
cur_scope.items.borrow_mut().borrowed_props.push(extended);
}
// TODO:
@@ -368,28 +356,19 @@ impl<'bump> DiffState<'bump> {
log::debug!(
"initializing component {:?} with height {:?}",
new_idx,
parent_scope.height + 1
height + 1
);
// Run the scope for one iteration to initialize it
//
todo!("run scope");
// if new_component.run_scope(self) {
// // Take the node that was just generated from running the component
// let nextnode = new_component.frames.fin_head();
// self.stack.create_component(new_idx, nextnode);
if self.scopes.run_scope(&new_idx) {
// Take the node that was just generated from running the component
let nextnode = self.scopes.fin_head(&new_idx);
self.stack.create_component(new_idx, nextnode);
// //
// /*
// tree_item {
// }
// */
// if new_component.is_subtree_root.get() {
// self.stack.push_subtree();
// }
// }
if new_component.is_subtree_root.get() {
self.stack.push_subtree();
}
}
// Finally, insert this scope as a seen node.
self.seen_scopes.insert(new_idx);
+4 -5
View File
@@ -21,7 +21,6 @@ pub(crate) mod mutations;
pub(crate) mod nodes;
pub(crate) mod scope;
pub(crate) mod scopearena;
pub(crate) mod test_dom;
pub(crate) mod virtual_dom;
pub(crate) mod innerlude {
@@ -34,7 +33,6 @@ pub(crate) mod innerlude {
pub use crate::nodes::*;
pub use crate::scope::*;
pub use crate::scopearena::*;
pub use crate::test_dom::*;
pub use crate::virtual_dom::*;
pub type Element = Option<NodeLink>;
@@ -42,9 +40,10 @@ pub(crate) mod innerlude {
}
pub use crate::innerlude::{
Attribute, Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, LazyNodes,
Listener, MountType, Mutations, NodeFactory, Properties, SchedulerMsg, ScopeChildren, ScopeId,
TestDom, UserEvent, VAnchor, VElement, VFragment, VNode, VSuspended, VirtualDom, FC,
Attribute, Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, IntoVNode,
LazyNodes, Listener, MountType, Mutations, NodeFactory, Properties, SchedulerMsg,
ScopeChildren, ScopeId, UserEvent, VAnchor, VElement, VFragment, VNode, VSuspended, VirtualDom,
FC,
};
pub mod prelude {
+5 -4
View File
@@ -20,6 +20,8 @@ use std::{
///
/// It is used during the diffing/rendering process as a runtime key into an existing set of nodes. The "render" key
/// is essentially a unique key to guarantee safe usage of the Node.
///
/// todo: remove "clone"
#[derive(Clone, Debug)]
pub struct NodeLink {
pub(crate) link_idx: usize,
@@ -177,7 +179,7 @@ impl<'src> VNode<'src> {
}
}
pub fn children(&self) -> &[VNode<'src>] {
pub(crate) fn children(&self) -> &[VNode<'src>] {
match &self {
VNode::Fragment(f) => f.children,
VNode::Component(c) => todo!("children are not accessible through this"),
@@ -396,7 +398,6 @@ pub struct VComponent<'src> {
pub(crate) comparator: Option<&'src dyn Fn(&VComponent) -> bool>,
pub(crate) drop_props: RefCell<Option<BumpBox<'src, dyn FnMut()>>>,
// pub(crate) comparator: Option<BumpBox<'src, dyn Fn(&VComponent) -> bool + 'src>>,
}
pub struct VSuspended<'a> {
@@ -825,7 +826,7 @@ impl IntoVNode<'_> for Arguments<'_> {
/// ## Example
///
/// ```rust
/// const App: FC<()> = |(cx, props)|{
/// const App: FC<()> = |cx, props|{
/// cx.render(rsx!{
/// CustomCard {
/// h1 {}
@@ -834,7 +835,7 @@ impl IntoVNode<'_> for Arguments<'_> {
/// })
/// }
///
/// const CustomCard: FC<()> = |(cx, props)|{
/// const CustomCard: FC<()> = |cx, props|{
/// cx.render(rsx!{
/// div {
/// h1 {"Title card"}
+14 -11
View File
@@ -26,7 +26,7 @@ use bumpalo::{boxed::Box as BumpBox, Bump};
/// name: String
/// }
///
/// fn Example((cx, props): Scope<Props>) -> Element {
/// fn Example(cx: Context, props: &ExampleProps) -> Element {
/// cx.render(rsx!{ div {"Hello, {props.name}"} })
/// }
/// ```
@@ -42,8 +42,6 @@ pub type Context<'a> = &'a Scope;
/// We expose the `Scope` type so downstream users can traverse the Dioxus VirtualDOM for whatever
/// use case they might have.
pub struct Scope {
// Book-keeping about our spot in the arena
// safety:
//
// pointers to scopes are *always* valid since they are bump allocated and never freed until this scope is also freed
@@ -113,7 +111,7 @@ impl Scope {
/// # Example
///
/// ```rust
/// let mut dom = VirtualDom::new(|(cx, props)|cx.render(rsx!{ div {} }));
/// let mut dom = VirtualDom::new(|cx, props|cx.render(rsx!{ div {} }));
/// dom.rebuild();
///
/// let base = dom.base_scope();
@@ -131,7 +129,7 @@ impl Scope {
/// # Example
///
/// ```rust
/// let mut dom = VirtualDom::new(|(cx, props)|cx.render(rsx!{ div {} }));
/// let mut dom = VirtualDom::new(|cx, props|cx.render(rsx!{ div {} }));
/// dom.rebuild();
///
/// let base = dom.base_scope();
@@ -151,7 +149,7 @@ impl Scope {
/// # Example
///
/// ```rust
/// let mut dom = VirtualDom::new(|(cx, props)|cx.render(rsx!{ div {} }));
/// let mut dom = VirtualDom::new(|cx, props|cx.render(rsx!{ div {} }));
/// dom.rebuild();
///
/// let base = dom.base_scope();
@@ -172,7 +170,7 @@ impl Scope {
/// # Example
///
/// ```rust
/// let mut dom = VirtualDom::new(|(cx, props)|cx.render(rsx!{ div {} }));
/// let mut dom = VirtualDom::new(|cx, props|cx.render(rsx!{ div {} }));
/// dom.rebuild();
/// let base = dom.base_scope();
///
@@ -307,12 +305,12 @@ impl Scope {
/// ```
/// struct SharedState(&'static str);
///
/// static App: FC<()> = |(cx, props)|{
/// static App: FC<()> = |cx, props|{
/// cx.use_hook(|_| cx.provide_state(SharedState("world")), |_| {}, |_| {});
/// rsx!(cx, Child {})
/// }
///
/// static Child: FC<()> = |(cx, props)|{
/// static Child: FC<()> = |cx, props|{
/// let state = cx.consume_state::<SharedState>();
/// rsx!(cx, div { "hello {state.0}" })
/// }
@@ -356,7 +354,7 @@ impl Scope {
/// # Example
///
/// ```rust
/// static App: FC<()> = |(cx, props)| {
/// static App: FC<()> = |cx, props| {
/// todo!();
/// rsx!(cx, div { "Subtree {id}"})
/// };
@@ -373,7 +371,7 @@ impl Scope {
/// # Example
///
/// ```rust
/// static App: FC<()> = |(cx, props)| {
/// static App: FC<()> = |cx, props| {
/// let id = cx.get_current_subtree();
/// rsx!(cx, div { "Subtree {id}"})
/// };
@@ -529,3 +527,8 @@ impl BumpFrame {
nodes.len() - 1
}
}
#[test]
fn sizeof() {
dbg!(std::mem::size_of::<Scope>());
}
+18 -46
View File
@@ -1,8 +1,5 @@
use slab::Slab;
use std::{
borrow::BorrowMut,
cell::{Cell, RefCell},
};
use std::cell::{Cell, RefCell};
use bumpalo::{boxed::Box as BumpBox, Bump};
use futures_channel::mpsc::UnboundedSender;
@@ -23,8 +20,8 @@ pub struct Heuristic {
// has an internal heuristics engine to pre-allocate arenas to the right size
pub(crate) struct ScopeArena {
bump: Bump,
scopes: Vec<*mut Scope>,
free_scopes: Vec<ScopeId>,
scopes: RefCell<Vec<*mut Scope>>,
free_scopes: RefCell<Vec<ScopeId>>,
nodes: RefCell<Slab<*const VNode<'static>>>,
pub(crate) sender: UnboundedSender<SchedulerMsg>,
}
@@ -33,38 +30,38 @@ impl ScopeArena {
pub fn new(sender: UnboundedSender<SchedulerMsg>) -> Self {
Self {
bump: Bump::new(),
scopes: Vec::new(),
free_scopes: Vec::new(),
scopes: RefCell::new(Vec::new()),
free_scopes: RefCell::new(Vec::new()),
nodes: RefCell::new(Slab::new()),
sender,
}
}
pub fn get_scope(&self, id: &ScopeId) -> Option<&Scope> {
unsafe { Some(&*self.scopes[id.0]) }
unsafe { Some(&*self.scopes.borrow()[id.0]) }
}
// this is unsafe
pub unsafe fn get_scope_mut(&self, id: &ScopeId) -> Option<*mut Scope> {
Some(self.scopes[id.0])
Some(self.scopes.borrow()[id.0])
}
pub fn new_with_key(
&mut self,
&self,
fc_ptr: *const (),
caller: *const dyn Fn(&Scope) -> Element,
parent_scope: Option<*mut Scope>,
height: u32,
subtree: u32,
) -> ScopeId {
if let Some(id) = self.free_scopes.pop() {
if let Some(id) = self.free_scopes.borrow_mut().pop() {
// have already called drop on it - the slot is still chillin tho
let scope = unsafe { &mut *self.scopes[id.0 as usize] };
// let scope = unsafe { &mut *self.scopes.borrow()[id.0 as usize] };
todo!("override the scope contents");
id
} else {
let scope_id = ScopeId(self.scopes.len());
let scope_id = ScopeId(self.scopes.borrow().len());
let old_root = NodeLink {
link_idx: 0,
@@ -93,8 +90,6 @@ impl ScopeArena {
old_root: RefCell::new(Some(old_root)),
new_root: RefCell::new(Some(new_root)),
// old_root: RefCell::new(Some(old_root)),
// new_root: RefCell::new(None),
items: RefCell::new(SelfReferentialItems {
listeners: Default::default(),
borrowed_props: Default::default(),
@@ -105,7 +100,7 @@ impl ScopeArena {
};
let stable = self.bump.alloc(new_scope);
self.scopes.push(stable);
self.scopes.borrow_mut().push(stable);
scope_id
}
}
@@ -119,8 +114,8 @@ impl ScopeArena {
let entry = els.vacant_entry();
let key = entry.key();
let id = ElementId(key);
let node = node as *const _;
let node = unsafe { std::mem::transmute(node) };
let node: *const VNode = node as *const _;
let node = unsafe { std::mem::transmute::<*const VNode, *const VNode>(node) };
entry.insert(node);
id
@@ -183,7 +178,6 @@ impl ScopeArena {
.borrow_mut()
.listeners
.drain(..)
.map(|li| unsafe { &*li })
.for_each(|listener| drop(listener.callback.borrow_mut().take()));
}
@@ -256,39 +250,17 @@ impl ScopeArena {
let wip_frame = scope.wip_frame();
let nodes = wip_frame.nodes.borrow();
let node = nodes.get(0).unwrap();
unsafe { std::mem::transmute(node) }
// let root = scope.old_root.borrow();
// let link = root.as_ref().unwrap();
// dbg!(link);
// // for now, components cannot pass portals through each other
// assert_eq!(link.scope_id, *id);
// // assert_eq!(link.gen_id, scope.generation.get() - 1);
// // let items = scope.items.borrow();
// let nodes = scope.wip_frame().nodes.borrow();
// let node = nodes.get(link.link_idx).unwrap();
// unsafe { std::mem::transmute(node) }
unsafe { std::mem::transmute::<&VNode, &VNode>(node) }
}
pub fn fin_head(&self, id: &ScopeId) -> &VNode {
let scope = self.get_scope(id).unwrap();
let wip_frame = scope.fin_frame();
let nodes = wip_frame.nodes.borrow();
let node = nodes.get(0).unwrap();
unsafe { std::mem::transmute(node) }
// let scope = self.get_scope(id).unwrap();
// let root = scope.new_root.borrow();
// let link = root.as_ref().unwrap();
// // for now, components cannot pass portals through each other
// assert_eq!(link.scope_id, *id);
// // assert_eq!(link.gen_id, scope.generation.get());
// let nodes = scope.fin_frame().nodes.borrow();
// let node = nodes.get(link.link_idx).unwrap();
// unsafe { std::mem::transmute(node) }
let node: &VNode = nodes.get(0).unwrap();
unsafe { std::mem::transmute::<&VNode, &VNode>(node) }
}
pub fn root_node(&self, id: &ScopeId) -> &VNode {
self.wip_head(id)
}
-93
View File
@@ -1,93 +0,0 @@
//! A DOM for testing - both internal and external code.
use bumpalo::Bump;
use crate::innerlude::*;
use crate::nodes::IntoVNode;
pub struct TestDom {
bump: Bump,
// scheduler: Scheduler,
}
impl TestDom {
pub fn new() -> TestDom {
let bump = Bump::new();
let (sender, receiver) = futures_channel::mpsc::unbounded::<SchedulerMsg>();
todo!()
// let scheduler = Scheduler::new(sender, receiver, 10, 100);
// TestDom { bump, scheduler }
}
pub fn new_factory(&self) -> NodeFactory {
NodeFactory::new(&self.bump)
}
pub fn render_direct<'a>(&'a self, lazy_nodes: Option<LazyNodes<'a, '_>>) -> VNode<'a> {
lazy_nodes.into_vnode(NodeFactory::new(&self.bump))
}
pub fn render<'a>(&'a self, lazy_nodes: Option<LazyNodes<'a, '_>>) -> &'a VNode<'a> {
self.bump
.alloc(lazy_nodes.into_vnode(NodeFactory::new(&self.bump)))
}
pub fn diff<'a>(&'a self, old: &'a VNode<'a>, new: &'a VNode<'a>) -> Mutations<'a> {
let mutations = Mutations::new();
let mut machine: DiffState = todo!();
// let mut machine = DiffState::new(mutations);
// let mut machine = DiffState::new(mutations);
machine.stack.push(DiffInstruction::Diff { new, old });
machine.mutations
}
pub fn create<'a>(&'a self, left: Option<LazyNodes<'a, '_>>) -> Mutations<'a> {
let old = self.bump.alloc(self.render_direct(left));
let mut machine: DiffState = todo!();
// let mut machine = DiffState::new(Mutations::new());
// let mut machine = DiffState::new(Mutations::new());
machine.stack.create_node(old, MountType::Append);
todo!()
// machine.work(&mut || false);
// machine.mutations
}
pub fn lazy_diff<'a>(
&'a self,
left: Option<LazyNodes<'a, '_>>,
right: Option<LazyNodes<'a, '_>>,
) -> (Mutations<'a>, Mutations<'a>) {
let (old, new) = (self.render(left), self.render(right));
let mut machine: DiffState = todo!();
// let mut machine = DiffState::new(Mutations::new());
machine.stack.create_node(old, MountType::Append);
todo!()
// machine.work(|| false);
// let create_edits = machine.mutations;
// let mut machine: DiffState = todo!();
// // let mut machine = DiffState::new(Mutations::new());
// machine.stack.push(DiffInstruction::Diff { old, new });
// machine.work(&mut || false);
// let edits = machine.mutations;
// (create_edits, edits)
}
}
impl Default for TestDom {
fn default() -> Self {
Self::new()
}
}
+154 -40
View File
@@ -1,23 +1,6 @@
//! # VirtualDOM Implementation for Rust
//!
//! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
//!
//! In this file, multiple items are defined. This file is big, but should be documented well to
//! navigate the inner workings of the Dom. We try to keep these main mechanics in this file to limit
//! the possible exposed API surface (keep fields private). This particular implementation of VDOM
//! is extremely efficient, but relies on some unsafety under the hood to do things like manage
//! micro-heaps for components. We are currently working on refactoring the safety out into safe(r)
//! abstractions, but current tests (MIRI and otherwise) show no issues with the current implementation.
//!
//! Included is:
//! - The [`VirtualDom`] itself
//! - The [`Scope`] object for managing component lifecycle
//! - The [`ActiveFrame`] object for managing the Scope`s microheap
//! - The [`Context`] object for exposing VirtualDOM API to components
//! - The [`NodeFactory`] object for lazily exposing the `Context` API to the nodebuilder API
//!
//! This module includes just the barebones for a complete VirtualDOM API.
//! Additional functionality is defined in the respective files.
use crate::innerlude::*;
use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
@@ -28,33 +11,92 @@ use std::pin::Pin;
use std::task::Poll;
use std::{any::Any, collections::VecDeque};
/// An integrated virtual node system that progresses events and diffs UI trees.
/// A virtual node system that progresses user events and diffs UI trees.
///
/// Differences are converted into patches which a renderer can use to draw the UI.
/// Components are defined as simple functions that take [`Context`] and a [`Properties`] type and return an [`Element`].
///
/// If you are building an App with Dioxus, you probably won't want to reach for this directly, instead opting to defer
/// to a particular crate's wrapper over the [`VirtualDom`] API.
///
/// Example
/// ```rust
/// static App: FC<()> = |(cx, props)|{
/// #[derive(Props, PartialEq)]
/// struct AppProps {
/// title: String
/// }
///
/// fn App(cx: Context, props: &AppProps) -> Element {
/// cx.render(rsx!(
/// div {"hello, {props.title}"}
/// ))
/// }
/// ```
///
/// Components may be composed to make complex apps.
///
/// ```rust
/// fn App(cx: Context, props: &AppProps) -> Element {
/// cx.render(rsx!(
/// NavBar { routes: ROUTES }
/// Title { "{props.title}" }
/// Footer {}
/// ))
/// }
/// ```
///
/// To start an app, create a [`VirtualDom`] and call [`VirtualDom::rebuild`] to get the list of edits required to
/// draw the UI.
///
/// ```rust
/// let mut vdom = VirtualDom::new(App);
/// let edits = vdom.rebuild();
/// ```
///
/// To inject UserEvents into the VirtualDom, call [`VirtualDom::get_scheduler_channel`] to get access to the scheduler.
///
/// ```rust
/// let channel = vdom.get_scheduler_channel();
/// channel.send_unbounded(SchedulerMsg::UserEvent(UserEvent {
/// // ...
/// }))
/// ```
///
/// While waiting for UserEvents to occur, call [`VirtualDom::wait_for_work`] to poll any futures inside the VirtualDom.
///
/// ```rust
/// vdom.wait_for_work().await;
/// ```
///
/// Once work is ready, call [`VirtualDom::work_with_deadline`] to compute the differences between the previous and
/// current UI trees. This will return a [`Mutations`] object that contains Edits, Effects, and NodeRefs that need to be
/// handled by the renderer.
///
/// ```rust
/// let mutations = vdom.work_with_deadline(|| false);
/// for edit in mutations {
/// apply(edit);
/// }
/// ```
///
/// ## Building an event loop around Dioxus:
///
/// Putting everything together, you can build an event loop around Dioxus by using the methods outlined above.
///
/// ```rust
/// fn App(cx: Context, props: &()) -> Element {
/// cx.render(rsx!{
/// div {
/// "Hello World"
/// }
/// div { "Hello World" }
/// })
/// }
///
/// async fn main() {
/// let mut dom = VirtualDom::new(App);
///
/// let mut inital_edits = dom.rebuild();
/// initialize_screen(inital_edits);
/// apply_edits(inital_edits);
///
/// loop {
/// let next_frame = TimeoutFuture::new(Duration::from_millis(16));
/// let edits = dom.run_with_deadline(next_frame).await;
/// dom.wait_for_work().await;
/// let frame_timeout = TimeoutFuture::new(Duration::from_millis(16));
/// let deadline = || (&mut frame_timeout).now_or_never();
/// let edits = dom.run_with_deadline(deadline).await;
/// apply_edits(edits);
/// render_frame();
/// }
/// }
/// ```
@@ -145,9 +187,9 @@ impl VirtualDom {
sender: UnboundedSender<SchedulerMsg>,
receiver: UnboundedReceiver<SchedulerMsg>,
) -> Self {
let mut scopes = ScopeArena::new(sender.clone());
let scopes = ScopeArena::new(sender.clone());
let caller = Box::new(move |f: &Scope| -> Element { root(f, &root_props) });
let caller = Box::new(move |scp: &Scope| -> Element { root(scp, &root_props) });
let caller_ref: *mut dyn Fn(&Scope) -> Element = Box::into_raw(caller);
let base_scope = scopes.new_with_key(root as _, caller_ref, None, 0, 0);
@@ -164,7 +206,7 @@ impl VirtualDom {
}
}
/// Get the [`ScopeState`] for the root component.
/// Get the [`Scope`] for the root component.
///
/// This is useful for traversing the tree from the root for heuristics or alternsative renderers that use Dioxus
/// directly.
@@ -174,7 +216,7 @@ impl VirtualDom {
self.get_scope(&self.base_scope).unwrap()
}
/// Get the [`ScopeState`] for a component given its [`ScopeId`]
/// Get the [`Scope`] for a component given its [`ScopeId`]
///
/// # Example
///
@@ -305,7 +347,7 @@ impl VirtualDom {
/// # Example
///
/// ```no_run
/// static App: FC<()> = |(cx, props)|rsx!(cx, div {"hello"} );
/// static App: FC<()> = |cx, props|rsx!(cx, div {"hello"} );
///
/// let mut dom = VirtualDom::new(App);
///
@@ -436,7 +478,7 @@ impl VirtualDom {
///
/// # Example
/// ```
/// static App: FC<()> = |(cx, props)| cx.render(rsx!{ "hello world" });
/// static App: FC<()> = |cx, props| cx.render(rsx!{ "hello world" });
/// let mut dom = VirtualDom::new();
/// let edits = dom.rebuild();
///
@@ -453,7 +495,7 @@ impl VirtualDom {
diff_state.stack.scope_stack.push(scope_id);
let work_completed = diff_state.work(|| false);
diff_state.work(|| false);
}
diff_state.mutations
@@ -474,7 +516,7 @@ impl VirtualDom {
/// value: Shared<&'static str>,
/// }
///
/// static App: FC<AppProps> = |(cx, props)|{
/// static App: FC<AppProps> = |cx, props|{
/// let val = cx.value.borrow();
/// cx.render(rsx! { div { "{val}" } })
/// };
@@ -501,7 +543,7 @@ impl VirtualDom {
diff_machine.force_diff = true;
let work_completed = diff_machine.work(|| false);
diff_machine.work(|| false);
// let scopes = &mut self.scopes;
// crate::diff::diff_scope(&mut diff_machine, scope_id);
// self.scopes.diff_scope(&mut diff_machine, scope_id);
@@ -523,6 +565,78 @@ impl VirtualDom {
None
}
}
/// Renders an `rsx` call into the Base Scope's allocator.
///
/// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
pub fn render_vnodes<'a>(&'a self, lazy_nodes: Option<LazyNodes<'a, '_>>) -> &'a VNode<'a> {
todo!()
}
/// Renders an `rsx` call into the Base Scope's allocator.
///
/// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
pub fn diff_vnodes<'a>(&'a self, old: &'a VNode<'a>, new: &'a VNode<'a>) -> Mutations<'a> {
todo!()
// let mutations = Mutations::new();
// let mut machine: DiffState = todo!();
// // let mut machine = DiffState::new(mutations);
// // let mut machine = DiffState::new(mutations);
// machine.stack.push(DiffInstruction::Diff { new, old });
// machine.mutations
}
/// Renders an `rsx` call into the Base Scope's allocator.
///
/// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
pub fn create_vnodes<'a>(&'a self, left: Option<LazyNodes<'a, '_>>) -> Mutations<'a> {
todo!()
// let old = self.bump.alloc(self.render_direct(left));
// let mut machine: DiffState = todo!();
// // let mut machine = DiffState::new(Mutations::new());
// // let mut machine = DiffState::new(Mutations::new());
// machine.stack.create_node(old, MountType::Append);
// todo!()
// // machine.work(&mut || false);
// // machine.mutations
}
/// Renders an `rsx` call into the Base Scope's allocator.
///
/// Useful when needing to render nodes from outside the VirtualDom, such as in a test.
pub fn diff_lazynodes<'a>(
&'a self,
left: Option<LazyNodes<'a, '_>>,
right: Option<LazyNodes<'a, '_>>,
) -> (Mutations<'a>, Mutations<'a>) {
let (old, new) = (self.render_vnodes(left), self.render_vnodes(right));
// let mut machine: DiffState = todo!();
// let mut machine = DiffState::new(Mutations::new());
// machine.stack.create_node(old, MountType::Append);
todo!()
// machine.work(|| false);
// let create_edits = machine.mutations;
// let mut machine: DiffState = todo!();
// // let mut machine = DiffState::new(Mutations::new());
// machine.stack.push(DiffInstruction::Diff { old, new });
// machine.work(&mut || false);
// let edits = machine.mutations;
// (create_edits, edits)
}
}
pub enum SchedulerMsg {