wip: some docs and suspense
This commit is contained in:
1 parent
bab21a0aa1
commit
93d4b8ca7c
22 files changed
+210
-252
No files matched your search
+18
-66
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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(),
|
||||
})));
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in new issue
Block a user