wip: some docs and suspense

This commit is contained in:
Jonathan Kelley committed 2021-11-23 15:53:57 -05:00
1 parent bab21a0aa1
commit 93d4b8ca7c
22 files changed
+210 -252

No files matched your search

+18 -66
View File
@@ -284,7 +284,7 @@ impl<'bump> DiffState<'bump> {
// recursively push all the nodes of a tree onto the stack and return how many are there
fn push_all_nodes(&mut self, node: &'bump VNode<'bump>) -> usize {
match node {
VNode::Text(_) | VNode::Anchor(_) | VNode::Suspended(_) => {
VNode::Text(_) | VNode::Placeholder(_) => {
self.mutations.push_root(node.mounted_id());
1
}
@@ -354,8 +354,7 @@ impl<'bump> DiffState<'bump> {
fn create_node(&mut self, node: &'bump VNode<'bump>) {
match node {
VNode::Text(vtext) => self.create_text_node(vtext, node),
VNode::Suspended(suspended) => self.create_suspended_node(suspended, node),
VNode::Anchor(anchor) => self.create_anchor_node(anchor, node),
VNode::Placeholder(anchor) => self.create_anchor_node(anchor, node),
VNode::Element(element) => self.create_element_node(element, node),
VNode::Fragment(frag) => self.create_fragment_node(frag),
VNode::Component(component) => self.create_component_node(component),
@@ -371,17 +370,7 @@ impl<'bump> DiffState<'bump> {
self.stack.add_child_count(1);
}
fn create_suspended_node(&mut self, suspended: &'bump VSuspended, node: &'bump VNode<'bump>) {
let real_id = self.scopes.reserve_node(node);
self.mutations.create_placeholder(real_id);
suspended.dom_id.set(Some(real_id));
self.stack.add_child_count(1);
self.attach_suspended_node_to_scope(suspended);
}
fn create_anchor_node(&mut self, anchor: &'bump VAnchor, node: &'bump VNode<'bump>) {
fn create_anchor_node(&mut self, anchor: &'bump VPlaceholder, node: &'bump VNode<'bump>) {
let real_id = self.scopes.reserve_node(node);
self.mutations.create_placeholder(real_id);
@@ -433,12 +422,10 @@ impl<'bump> DiffState<'bump> {
self.mutations.set_attribute(attr, real_id.as_u64());
}
if !children.is_empty() {
if children.len() == 1 {
if let VNode::Text(vtext) = children[0] {
self.mutations.set_text(vtext.text, real_id.as_u64());
return;
}
if !children.is_empty() && children.len() == 1 {
if let VNode::Text(vtext) = children[0] {
self.mutations.set_text(vtext.text, real_id.as_u64());
return;
}
}
@@ -529,17 +516,14 @@ impl<'bump> DiffState<'bump> {
self.diff_component_nodes(old_node, new_node, old, new)
}
(Fragment(old), Fragment(new)) => self.diff_fragment_nodes(old, new),
(Anchor(old), Anchor(new)) => new.dom_id.set(old.dom_id.get()),
(Suspended(old), Suspended(new)) => self.diff_suspended_nodes(old, new),
(Placeholder(old), Placeholder(new)) => new.dom_id.set(old.dom_id.get()),
(Element(old), Element(new)) => self.diff_element_nodes(old, new, old_node, new_node),
(Linked(old), Linked(new)) => self.diff_linked_nodes(old, new),
// Anything else is just a basic replace and create
(
Linked(_) | Component(_) | Fragment(_) | Text(_) | Element(_) | Anchor(_)
| Suspended(_),
Linked(_) | Component(_) | Fragment(_) | Text(_) | Element(_) | Anchor(_)
| Suspended(_),
Linked(_) | Component(_) | Fragment(_) | Text(_) | Element(_) | Placeholder(_),
Linked(_) | Component(_) | Fragment(_) | Text(_) | Element(_) | Placeholder(_),
) => self
.stack
.create_node(new_node, MountType::Replace { old: old_node }),
@@ -664,7 +648,7 @@ impl<'bump> DiffState<'bump> {
self.mutations.set_text(new_text.text, root.as_u64());
}
}
(VNode::Text(old_text), _) => {
(VNode::Text(_old_text), _) => {
self.stack.element_stack.push(root);
self.stack.instructions.push(DiffInstruction::PopElement);
self.stack.create_node(new1, MountType::Append);
@@ -770,11 +754,6 @@ impl<'bump> DiffState<'bump> {
self.diff_children(old.children, new.children);
}
fn diff_suspended_nodes(&mut self, old: &'bump VSuspended, new: &'bump VSuspended) {
new.dom_id.set(old.dom_id.get());
self.attach_suspended_node_to_scope(new);
}
fn diff_linked_nodes(&mut self, old: &'bump NodeLink, new: &'bump NodeLink) {
if !std::ptr::eq(old.node, new.node) {
// if the ptrs are the same then theyr're the same
@@ -818,14 +797,14 @@ impl<'bump> DiffState<'bump> {
(_, []) => {
self.remove_nodes(old, true);
}
([VNode::Anchor(old_anchor)], [VNode::Anchor(new_anchor)]) => {
([VNode::Placeholder(old_anchor)], [VNode::Placeholder(new_anchor)]) => {
old_anchor.dom_id.set(new_anchor.dom_id.get());
}
([VNode::Anchor(_)], _) => {
([VNode::Placeholder(_)], _) => {
self.stack
.create_children(new, MountType::Replace { old: &old[0] });
}
(_, [VNode::Anchor(_)]) => {
(_, [VNode::Placeholder(_)]) => {
let new: &'bump VNode<'bump> = &new[0];
if let Some(first_old) = old.get(0) {
self.remove_nodes(&old[1..], true);
@@ -1227,8 +1206,7 @@ impl<'bump> DiffState<'bump> {
match &search_node.take().unwrap() {
VNode::Text(t) => break t.dom_id.get(),
VNode::Element(t) => break t.dom_id.get(),
VNode::Suspended(t) => break t.dom_id.get(),
VNode::Anchor(t) => break t.dom_id.get(),
VNode::Placeholder(t) => break t.dom_id.get(),
VNode::Linked(l) => {
let node: &VNode = unsafe { std::mem::transmute(&*l.node) };
self.find_last_element(node);
@@ -1263,8 +1241,7 @@ impl<'bump> DiffState<'bump> {
}
VNode::Text(t) => break t.dom_id.get(),
VNode::Element(t) => break t.dom_id.get(),
VNode::Suspended(t) => break t.dom_id.get(),
VNode::Anchor(t) => break t.dom_id.get(),
VNode::Placeholder(t) => break t.dom_id.get(),
}
}
}
@@ -1282,7 +1259,7 @@ impl<'bump> DiffState<'bump> {
self.remove_nodes(el.children, false);
}
VNode::Text(_) | VNode::Anchor(_) | VNode::Suspended(_) => {
VNode::Text(_) | VNode::Placeholder(_) => {
let id = old
.try_mounted_id()
.unwrap_or_else(|| panic!("broke on {:?}", old));
@@ -1331,15 +1308,7 @@ impl<'bump> DiffState<'bump> {
}
}
}
VNode::Suspended(s) => {
let id = s.dom_id.get().unwrap();
self.scopes.collect_garbage(id);
if gen_muts {
self.mutations.remove(id.as_u64());
}
}
VNode::Anchor(a) => {
VNode::Placeholder(a) => {
let id = a.dom_id.get().unwrap();
self.scopes.collect_garbage(id);
@@ -1386,21 +1355,4 @@ impl<'bump> DiffState<'bump> {
let long_listener = unsafe { std::mem::transmute(listener) };
scope.items.borrow_mut().listeners.push(long_listener)
}
fn attach_suspended_node_to_scope(&mut self, suspended: &'bump VSuspended) {
if let Some(scope) = self
.stack
.current_scope()
.and_then(|id| self.scopes.get_scope(&id))
{
todo!()
// // safety: this lifetime is managed by the logic on scope
// let extended = unsafe { std::mem::transmute(suspended) };
// scope
// .items
// .borrow_mut()
// .suspended_nodes
// .insert(suspended.task_id, extended);
}
}
}
+1 -1
View File
@@ -38,7 +38,7 @@ pub(crate) mod innerlude {
pub use crate::innerlude::{
Attribute, Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, IntoVNode,
LazyNodes, Listener, MountType, Mutations, NodeFactory, Properties, SchedulerMsg, ScopeId,
UserEvent, VAnchor, VElement, VFragment, VNode, VSuspended, VirtualDom, FC,
UserEvent, VElement, VFragment, VNode, VPlaceholder, VSuspended, VirtualDom, FC,
};
pub mod prelude {
+12 -25
View File
@@ -97,19 +97,9 @@ pub enum VNode<'src> {
/// ```
Component(&'src VComponent<'src>),
/// Suspended VNodes represent chunks of the UI tree that are not yet ready to be displayed.
/// Placeholders are a type of placeholder VNode used when fragments don't contain any children.
///
/// # Example
///
/// ```rust, ignore
///
///
/// ```
Suspended(&'src VSuspended),
/// Anchors are a type of placeholder VNode used when fragments don't contain any children.
///
/// Anchors cannot be directly constructed via public APIs.
/// Placeholders cannot be directly constructed via public APIs.
///
/// # Example
///
@@ -123,7 +113,7 @@ pub enum VNode<'src> {
/// assert_eq!(root, VNode::Anchor);
/// }
/// ```
Anchor(&'src VAnchor),
Placeholder(&'src VPlaceholder),
/// A VNode that is actually a pointer to some nodes rather than the nodes directly. Useful when rendering portals
/// or eliding lifetimes on VNodes through runtime checks.
@@ -151,8 +141,7 @@ impl<'src> VNode<'src> {
VNode::Fragment(f) => f.key,
VNode::Text(_t) => None,
VNode::Suspended(_s) => None,
VNode::Anchor(_f) => None,
VNode::Placeholder(_f) => None,
VNode::Linked(_c) => None,
}
}
@@ -171,8 +160,7 @@ impl<'src> VNode<'src> {
match &self {
VNode::Text(el) => el.dom_id.get(),
VNode::Element(el) => el.dom_id.get(),
VNode::Anchor(el) => el.dom_id.get(),
VNode::Suspended(el) => el.dom_id.get(),
VNode::Placeholder(el) => el.dom_id.get(),
VNode::Linked(_) => None,
VNode::Fragment(_) => None,
@@ -194,8 +182,7 @@ impl<'src> VNode<'src> {
VNode::Text(t) => VNode::Text(*t),
VNode::Element(e) => VNode::Element(*e),
VNode::Component(c) => VNode::Component(*c),
VNode::Suspended(s) => VNode::Suspended(*s),
VNode::Anchor(a) => VNode::Anchor(*a),
VNode::Placeholder(a) => VNode::Placeholder(*a),
VNode::Fragment(f) => VNode::Fragment(VFragment {
children: f.children,
key: f.key,
@@ -219,12 +206,11 @@ impl Debug for VNode<'_> {
.finish(),
VNode::Text(t) => write!(s, "VNode::VText {{ text: {} }}", t.text),
VNode::Anchor(_) => write!(s, "VNode::VAnchor"),
VNode::Placeholder(_) => write!(s, "VNode::VAnchor"),
VNode::Fragment(frag) => {
write!(s, "VNode::VFragment {{ children: {:?} }}", frag.children)
}
VNode::Suspended { .. } => write!(s, "VNode::VSuspended"),
VNode::Component(comp) => write!(s, "VNode::VComponent {{ fc: {:?}}}", comp.user_fc),
VNode::Linked(c) => write!(s, "VNode::VCached {{ scope_id: {:?} }}", c.scope_id.get()),
}
@@ -254,7 +240,7 @@ fn empty_cell() -> Cell<Option<ElementId>> {
}
/// A placeholder node only generated when Fragments don't have any children.
pub struct VAnchor {
pub struct VPlaceholder {
pub dom_id: Cell<Option<ElementId>>,
}
@@ -357,6 +343,7 @@ pub struct Listener<'bump> {
pub event: &'static str,
/// The actual callback that the user specified
#[allow(clippy::type_complexity)]
pub(crate) callback:
RefCell<Option<BumpBox<'bump, dyn FnMut(std::sync::Arc<dyn Any + Send + Sync>) + 'bump>>>,
}
@@ -655,7 +642,7 @@ impl<'a> NodeFactory<'a> {
}
if nodes.is_empty() {
nodes.push(VNode::Anchor(bump.alloc(VAnchor {
nodes.push(VNode::Placeholder(bump.alloc(VPlaceholder {
dom_id: empty_cell(),
})));
}
@@ -678,7 +665,7 @@ impl<'a> NodeFactory<'a> {
}
if nodes.is_empty() {
nodes.push(VNode::Anchor(bump.alloc(VAnchor {
nodes.push(VNode::Placeholder(bump.alloc(VPlaceholder {
dom_id: empty_cell(),
})));
}
@@ -722,7 +709,7 @@ impl<'a> NodeFactory<'a> {
}
if nodes.is_empty() {
nodes.push(VNode::Anchor(bump.alloc(VAnchor {
nodes.push(VNode::Placeholder(bump.alloc(VPlaceholder {
dom_id: empty_cell(),
})));
}
+2 -41
View File
@@ -1,7 +1,6 @@
use crate::innerlude::*;
use futures_channel::mpsc::UnboundedSender;
use fxhash::FxHashMap;
use smallvec::SmallVec;
use std::{
any::{Any, TypeId},
@@ -72,7 +71,6 @@ pub struct Scope {
pub struct SelfReferentialItems<'a> {
pub(crate) listeners: Vec<&'a Listener<'a>>,
pub(crate) borrowed_props: Vec<&'a VComponent<'a>>,
pub(crate) suspended_nodes: FxHashMap<u64, &'a VSuspended>,
pub(crate) tasks: Vec<BumpBox<'a, dyn Future<Output = ()>>>,
}
@@ -347,31 +345,6 @@ impl Scope {
Some(link)
}
pub fn suspend<'src, F: Future<Output = Element> + 'src>(
&'src self,
mut fut: impl FnMut() -> F,
) -> Option<VNode> {
let channel = self.sender.clone();
let node_fut = fut();
let scope = self.scope_id();
// self.push_task(move || {
//
// async move {
// //
// let r = node_fut.await;
// if let Some(node) = r {
// channel
// .unbounded_send(SchedulerMsg::Suspended { node, scope })
// .unwrap();
// }
// }
// });
todo!()
}
/// Store a value between renders
///
/// This is *the* foundational hook for all other hooks.
@@ -452,18 +425,6 @@ impl Scope {
self.generation.set(self.generation.get() + 1);
}
// General strategy here is to load up the appropriate suspended task and then run it.
// Suspended nodes cannot be called repeatedly.
pub(crate) fn call_suspended_node<'a>(&'a mut self, task_id: u64) {
let mut nodes = &mut self.items.get_mut().suspended_nodes;
if let Some(suspended) = nodes.remove(&task_id) {
let sus: &'a VSuspended = suspended;
// let mut boxed = sus.callback.borrow_mut().take().unwrap();
// let new_node: Element = boxed();
}
}
pub fn root_node(&self) -> &VNode {
let node = *self.wip_frame().nodes.borrow().get(0).unwrap();
unsafe { std::mem::transmute(&*node) }
@@ -488,7 +449,7 @@ impl BumpFrame {
Self { bump, nodes }
}
pub fn allocated_bytes(&self) -> usize {
pub fn _allocated_bytes(&self) -> usize {
self.bump.allocated_bytes()
}
@@ -569,7 +530,7 @@ impl HookList {
/// Get the ammount of memory a hooklist uses
/// Used in heuristics
pub fn get_hook_arena_size(&self) -> usize {
pub fn _get_hook_arena_size(&self) -> usize {
self.arena.allocated_bytes()
}
}
-5
View File
@@ -186,7 +186,6 @@ impl ScopeArena {
items: RefCell::new(SelfReferentialItems {
listeners: Default::default(),
borrowed_props: Default::default(),
suspended_nodes: Default::default(),
tasks: Default::default(),
}),
});
@@ -225,13 +224,11 @@ impl ScopeArena {
let SelfReferentialItems {
borrowed_props,
listeners,
suspended_nodes,
tasks,
} = scope.items.get_mut();
borrowed_props.clear();
listeners.clear();
suspended_nodes.clear();
tasks.clear();
self.free_scopes.borrow_mut().push(scope);
@@ -323,13 +320,11 @@ impl ScopeArena {
let mut items = scope.items.borrow_mut();
// just forget about our suspended nodes while we're at it
items.suspended_nodes.clear();
items.tasks.clear();
// guarantee that we haven't screwed up - there should be no latent references anywhere
debug_assert!(items.listeners.is_empty());
debug_assert!(items.borrowed_props.is_empty());
debug_assert!(items.suspended_nodes.is_empty());
debug_assert!(items.tasks.is_empty());
// Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders.
-3
View File
@@ -297,7 +297,6 @@ impl VirtualDom {
SchedulerMsg::Immediate(s) => {
self.dirty_scopes.insert(s);
}
SchedulerMsg::Suspended { scope } => todo!(),
}
}
}
@@ -548,8 +547,6 @@ pub enum SchedulerMsg {
// an async task pushed from an event handler (or just spawned)
TaskPushed(ScopeId),
Suspended { scope: ScopeId },
}
/// User Events are events that are shuttled from the renderer into the VirtualDom trhough the scheduler channel.