Feat: remove old macro
This commit is contained in:
1 parent
e66827ec92
commit
9d0727edab
43 files changed
+208
-2306
No files matched your search
@@ -3,7 +3,7 @@
|
||||
//!
|
||||
//! Renderers don't actually need to own the virtual dom (it's up to the implementer).
|
||||
|
||||
use crate::virtual_dom::VirtualDom;
|
||||
use crate::{events::EventTrigger, virtual_dom::VirtualDom};
|
||||
use crate::{innerlude::Result, prelude::*};
|
||||
|
||||
pub struct DebugRenderer {
|
||||
@@ -33,6 +33,10 @@ impl DebugRenderer {
|
||||
Self { internal_dom: dom }
|
||||
}
|
||||
|
||||
pub fn handle_event(&mut self, trigger: EventTrigger) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn step(&mut self, machine: &mut DiffMachine) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+50
-49
@@ -36,13 +36,13 @@ use crate::{innerlude::*, scope::Scope};
|
||||
use bumpalo::Bump;
|
||||
use fxhash::{FxHashMap, FxHashSet};
|
||||
use generational_arena::Arena;
|
||||
use uuid::Uuid;
|
||||
|
||||
use std::{
|
||||
cell::{RefCell, RefMut},
|
||||
cmp::Ordering,
|
||||
collections::VecDeque,
|
||||
rc::{Rc, Weak},
|
||||
sync::atomic::AtomicU32,
|
||||
};
|
||||
|
||||
/// The DiffState is a cursor internal to the VirtualDOM's diffing algorithm that allows persistence of state while
|
||||
@@ -66,13 +66,33 @@ pub struct DiffMachine<'a> {
|
||||
pub enum LifeCycleEvent<'a> {
|
||||
Mount {
|
||||
caller: Weak<dyn for<'r> Fn(Context<'r>) -> DomTree + 'a>,
|
||||
id: Uuid,
|
||||
scope: Weak<VCompAssociatedScope>,
|
||||
id: u32,
|
||||
},
|
||||
PropsChanged {
|
||||
caller: Weak<dyn for<'r> Fn(Context<'r>) -> DomTree + 'a>,
|
||||
scope: Weak<VCompAssociatedScope>,
|
||||
id: u32,
|
||||
},
|
||||
SameProps {
|
||||
caller: Weak<dyn for<'r> Fn(Context<'r>) -> DomTree + 'a>,
|
||||
scope: Weak<VCompAssociatedScope>,
|
||||
id: u32,
|
||||
},
|
||||
Replace {
|
||||
caller: Weak<dyn for<'r> Fn(Context<'r>) -> DomTree + 'a>,
|
||||
old_scope: Weak<VCompAssociatedScope>,
|
||||
new_scope: Weak<VCompAssociatedScope>,
|
||||
id: u32,
|
||||
},
|
||||
PropsChanged,
|
||||
SameProps,
|
||||
Remove,
|
||||
}
|
||||
|
||||
static COUNTER: AtomicU32 = AtomicU32::new(1);
|
||||
fn get_id() -> u32 {
|
||||
COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
|
||||
}
|
||||
|
||||
impl<'a> DiffMachine<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
@@ -128,12 +148,27 @@ impl<'a> DiffMachine<'a> {
|
||||
}
|
||||
|
||||
(VNode::Component(cold), VNode::Component(cnew)) => {
|
||||
todo!("should not happen")
|
||||
// if cold.caller_ref != cnew.caller_ref {
|
||||
// // todo: create a stable addr
|
||||
// self.lifecycle_events.push_back(LifeCycleEvent::Mount);
|
||||
// return;
|
||||
// }
|
||||
// todo!("should not happen")
|
||||
if cold.user_fc == cnew.user_fc {
|
||||
// todo: create a stable addr
|
||||
let caller = Rc::downgrade(&cnew.caller);
|
||||
let id = cold.stable_addr.borrow().unwrap();
|
||||
let scope = Rc::downgrade(&cold.ass_scope);
|
||||
self.lifecycle_events
|
||||
.push_back(LifeCycleEvent::PropsChanged { caller, id, scope });
|
||||
} else {
|
||||
let caller = Rc::downgrade(&cnew.caller);
|
||||
let id = cold.stable_addr.borrow().unwrap();
|
||||
let old_scope = Rc::downgrade(&cold.ass_scope);
|
||||
let new_scope = Rc::downgrade(&cnew.ass_scope);
|
||||
|
||||
self.lifecycle_events.push_back(LifeCycleEvent::Replace {
|
||||
caller,
|
||||
id,
|
||||
old_scope,
|
||||
new_scope,
|
||||
});
|
||||
}
|
||||
|
||||
// let comparator = &cnew.comparator.0;
|
||||
// let old_props = cold.raw_props.as_ref();
|
||||
@@ -151,23 +186,7 @@ impl<'a> DiffMachine<'a> {
|
||||
|
||||
// todo: knock out any listeners
|
||||
(_, VNode::Component(_new)) => {
|
||||
// self.lifecycle_events.push_back(LifeCycleEvent::Mount);
|
||||
// we have no stable reference to work from
|
||||
// push the lifecycle event onto the queue
|
||||
// self.lifecycle_events
|
||||
// .borrow_mut()
|
||||
// .push_back(LifecycleEvent {
|
||||
// event_type: LifecycleType::Mount {
|
||||
// props: new.props,
|
||||
// to: self.cur_idx,
|
||||
// },
|
||||
// });
|
||||
// we need to associaote this new component with a scope...
|
||||
|
||||
// self.change_list.save_known_root(id)
|
||||
self.change_list.commit_traversal();
|
||||
|
||||
// push the current
|
||||
}
|
||||
|
||||
(VNode::Component(_old), _) => {
|
||||
@@ -242,36 +261,18 @@ impl<'a> DiffMachine<'a> {
|
||||
/*
|
||||
todo: integrate re-entrace
|
||||
*/
|
||||
// NodeKind::Cached(ref c) => {
|
||||
// cached_roots.insert(c.id);
|
||||
// let (node, template) = cached_set.get(c.id);
|
||||
// if let Some(template) = template {
|
||||
// create_with_template(
|
||||
// cached_set,
|
||||
// self.change_list,
|
||||
// registry,
|
||||
// template,
|
||||
// node,
|
||||
// cached_roots,
|
||||
// );
|
||||
// } else {
|
||||
// create(cached_set, change_list, registry, node, cached_roots);
|
||||
// }
|
||||
// }
|
||||
VNode::Component(component) => {
|
||||
self.change_list
|
||||
.create_text_node("placeholder for vcomponent");
|
||||
let id = uuid::Uuid::new_v4();
|
||||
|
||||
let id = get_id();
|
||||
*component.stable_addr.as_ref().borrow_mut() = Some(id);
|
||||
self.change_list.save_known_root(id);
|
||||
|
||||
let caller = Rc::downgrade(&component.caller);
|
||||
// let broken_caller: Weak<dyn Fn(Context) -> DomTree + 'static> =
|
||||
// unsafe { std::mem::transmute(caller) };
|
||||
let scope = Rc::downgrade(&component.ass_scope);
|
||||
self.lifecycle_events.push_back(LifeCycleEvent::Mount {
|
||||
caller,
|
||||
// caller: broken_caller,
|
||||
caller: Rc::downgrade(&component.caller),
|
||||
id,
|
||||
scope
|
||||
});
|
||||
}
|
||||
VNode::Suspended => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//! 3rd party renderers are responsible for forming this virtual events from events.
|
||||
//! The goal here is to provide a consistent event interface across all renderer types.
|
||||
//!
|
||||
//! also... websys is kinda bad for rust-analyzer so we coerce for you automatically :)
|
||||
//! also... websys integerates poorly with rust analyzer, so we handle that for you automatically.
|
||||
|
||||
use crate::innerlude::ScopeIdx;
|
||||
|
||||
|
||||
+14
-42
@@ -88,8 +88,8 @@ impl<'a> VNode<'a> {
|
||||
VNode::Suspended => {
|
||||
todo!()
|
||||
}
|
||||
VNode::Component(_) => {
|
||||
todo!()
|
||||
VNode::Component(c) => {
|
||||
c.key
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,27 +107,6 @@ pub struct VElement<'a> {
|
||||
pub attributes: &'a [Attribute<'a>],
|
||||
pub children: &'a [VNode<'a>],
|
||||
pub namespace: Option<&'a str>,
|
||||
// The HTML tag, such as "div"
|
||||
// pub tag: &'a str,
|
||||
|
||||
// pub tag_name: &'a str,
|
||||
// pub attributes: &'a [Attribute<'a>],
|
||||
// todo: hook up listeners
|
||||
// pub listeners: &'a [Listener<'a>],
|
||||
// / HTML attributes such as id, class, style, etc
|
||||
// pub attrs: HashMap<String, String>,
|
||||
// TODO: @JON Get this to not heap allocate, but rather borrow
|
||||
// pub attrs: HashMap<&'static str, &'static str>,
|
||||
|
||||
// TODO @Jon, re-enable "events"
|
||||
//
|
||||
// /// Events that will get added to your real DOM element via `.addEventListener`
|
||||
// pub events: Events,
|
||||
// pub events: HashMap<String, ()>,
|
||||
|
||||
// /// The children of this `VNode`. So a <div> <em></em> </div> structure would
|
||||
// /// have a parent div and one child, em.
|
||||
// pub children: Vec<VNode>,
|
||||
}
|
||||
|
||||
impl<'a> VElement<'a> {
|
||||
@@ -264,10 +243,14 @@ impl<'a> VText<'a> {
|
||||
|
||||
/// Virtual Components for custom user-defined components
|
||||
/// Only supports the functional syntax
|
||||
pub type StableScopeAddres = Rc<RefCell<Option<uuid::Uuid>>>;
|
||||
pub type StableScopeAddres = RefCell<Option<u32>>;
|
||||
pub type VCompAssociatedScope = RefCell<Option<ScopeIdx>>;
|
||||
|
||||
pub struct VComponent<'src> {
|
||||
pub stable_addr: StableScopeAddres,
|
||||
pub key: NodeKey,
|
||||
|
||||
pub stable_addr: Rc<StableScopeAddres>,
|
||||
pub ass_scope: Rc<VCompAssociatedScope>,
|
||||
|
||||
pub comparator: Rc<dyn Fn(&VComponent) -> bool + 'src>,
|
||||
pub caller: Rc<dyn for<'r> Fn(Context<'r>) -> DomTree + 'src>,
|
||||
@@ -276,28 +259,15 @@ pub struct VComponent<'src> {
|
||||
raw_props: *const (),
|
||||
|
||||
// a pointer to the raw fn typ
|
||||
caller_ref: *const (),
|
||||
pub user_fc: *const (),
|
||||
_p: PhantomData<&'src ()>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for VComponent<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
todo!()
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
// pub struct Comparator(pub Rc<dyn Fn(&VComponent) -> bool>);
|
||||
// impl std::fmt::Debug for Comparator {
|
||||
// fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub struct Caller(pub Rc<dyn Fn(Context) -> DomTree>);
|
||||
// impl std::fmt::Debug for Caller {
|
||||
// fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<'a> VComponent<'a> {
|
||||
// use the type parameter on props creation and move it into a portable context
|
||||
@@ -318,7 +288,7 @@ impl<'a> VComponent<'a> {
|
||||
// Therefore, if the render functions are identical (by address), then so will be
|
||||
// props type paramter (because it is the same render function). Therefore, we can be
|
||||
// sure
|
||||
if caller_ref == other.caller_ref {
|
||||
if caller_ref == other.user_fc {
|
||||
let real_other = unsafe { &*(other.raw_props as *const _ as *const P) };
|
||||
real_other == props
|
||||
} else {
|
||||
@@ -333,7 +303,9 @@ impl<'a> VComponent<'a> {
|
||||
};
|
||||
|
||||
Self {
|
||||
caller_ref,
|
||||
key: NodeKey::NONE,
|
||||
ass_scope: Rc::new(RefCell::new(None)),
|
||||
user_fc: caller_ref,
|
||||
raw_props: props as *const P as *const _,
|
||||
_p: PhantomData,
|
||||
caller: Rc::new(caller),
|
||||
|
||||
@@ -94,12 +94,12 @@ pub enum Edit<'src_bump> {
|
||||
// ========================================================
|
||||
// push a known node on to the stack
|
||||
TraverseToKnown {
|
||||
node: uuid::Uuid,
|
||||
node: u32,
|
||||
// node: ScopeIdx,
|
||||
},
|
||||
// Add the current top of the stack to the known nodes
|
||||
MakeKnown {
|
||||
node: uuid::Uuid,
|
||||
node: u32,
|
||||
// node: ScopeIdx,
|
||||
},
|
||||
// Remove the current top of the stack from the known nodes
|
||||
@@ -383,32 +383,16 @@ impl<'a> EditMachine<'a> {
|
||||
// debug!("emit: remove_event_listener({:?})", event);
|
||||
}
|
||||
|
||||
pub fn save_known_root(&mut self, id: uuid::Uuid) {
|
||||
// pub fn save_known_root(&mut self, id: ScopeIdx) {
|
||||
// pub fn save_known_root(&mut self, id: ScopeIdx) {
|
||||
pub fn save_known_root(&mut self, id: u32) {
|
||||
log::debug!("emit: save_known_root({:?})", id);
|
||||
self.emitter.push(Edit::MakeKnown { node: id })
|
||||
}
|
||||
|
||||
pub fn load_known_root(&mut self, id: uuid::Uuid) {
|
||||
pub fn load_known_root(&mut self, id: u32) {
|
||||
log::debug!("emit: TraverseToKnown({:?})", id);
|
||||
self.emitter.push(Edit::TraverseToKnown { node: id })
|
||||
}
|
||||
|
||||
// pub fn save_template(&mut self, id: CacheId) {
|
||||
// debug_assert!(self.traversal_is_committed());
|
||||
// debug_assert!(!self.has_template(id));
|
||||
// // debug!("emit: save_template({:?})", id);
|
||||
// self.templates.insert(id);
|
||||
// self.emitter.save_template(id.into());
|
||||
// }
|
||||
|
||||
// pub fn push_template(&mut self, id: CacheId) {
|
||||
// debug_assert!(self.traversal_is_committed());
|
||||
// debug_assert!(self.has_template(id));
|
||||
// // debug!("emit: push_template({:?})", id);
|
||||
// self.emitter.push_template(id.into());
|
||||
// }
|
||||
}
|
||||
|
||||
// Keeps track of where we are moving in a DOM tree, and shortens traversal
|
||||
|
||||
@@ -96,10 +96,11 @@ impl Scope {
|
||||
scope: self.myidx,
|
||||
listeners: &self.listeners,
|
||||
};
|
||||
let caller = self.caller.upgrade().expect("Failed to get caller");
|
||||
|
||||
todo!()
|
||||
// todo!()
|
||||
// Note that the actual modification of the vnode head element occurs during this call
|
||||
// let _: DomTree = (self.caller.0.as_ref())(ctx);
|
||||
let _: DomTree = (caller.as_ref())(ctx);
|
||||
// let _: DomTree = (self.raw_caller)(ctx, &self.props);
|
||||
|
||||
/*
|
||||
@@ -114,11 +115,13 @@ impl Scope {
|
||||
- Public API cannot drop or destructure VNode
|
||||
*/
|
||||
|
||||
// frame.head_node = node_slot
|
||||
// .deref()
|
||||
// .borrow_mut()
|
||||
// .take()
|
||||
// .expect("Viewing did not happen");
|
||||
frame.head_node = node_slot.as_ref()
|
||||
// .deref()
|
||||
.borrow_mut()
|
||||
.take()
|
||||
.expect("Viewing did not happen");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// A safe wrapper around calling listeners
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
use crate::{error::Error, innerlude::*};
|
||||
use crate::{patch::Edit, scope::Scope};
|
||||
use generational_arena::Arena;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
rc::{Rc, Weak},
|
||||
};
|
||||
use std::{any::TypeId, borrow::Borrow, rc::{Rc, Weak}};
|
||||
use thiserror::private::AsDynError;
|
||||
|
||||
// We actually allocate the properties for components in their parent's properties
|
||||
@@ -82,19 +79,19 @@ impl VirtualDom {
|
||||
.ok_or_else(|| Error::FatalInternal("Acquring base component should never fail"))?;
|
||||
|
||||
component.run_scope()?;
|
||||
let component = &*component;
|
||||
// let component = &*component;
|
||||
|
||||
// // get raw pointer to the arena
|
||||
// let very_unsafe_components = &mut self.components as *mut generational_arena::Arena<Scope>;
|
||||
// get raw pointer to the arena
|
||||
let very_unsafe_components = &mut self.components as *mut generational_arena::Arena<Scope>;
|
||||
|
||||
// {
|
||||
// let component = self
|
||||
// .components
|
||||
// .get(self.base_scope)
|
||||
// .ok_or_else(|| Error::FatalInternal("Acquring base component should never fail"))?
|
||||
{
|
||||
let component = self
|
||||
.components
|
||||
.get(self.base_scope)
|
||||
.ok_or_else(|| Error::FatalInternal("Acquring base component should never fail"))?;
|
||||
|
||||
// diff_machine.diff_node(component.old_frame(), component.new_frame());
|
||||
// }
|
||||
diff_machine.diff_node(component.old_frame(), component.new_frame());
|
||||
}
|
||||
// let p = &mut self.components;
|
||||
// chew down the the lifecycle events until all dirty nodes are computed
|
||||
while let Some(event) = diff_machine.lifecycle_events.pop_front() {
|
||||
@@ -102,31 +99,48 @@ impl VirtualDom {
|
||||
// A new component has been computed from the diffing algorithm
|
||||
// create a new component in the arena, run it, move the diffing machine to this new spot, and then diff it
|
||||
// this will flood the lifecycle queue with new updates
|
||||
LifeCycleEvent::Mount { caller, id } => {
|
||||
LifeCycleEvent::Mount { caller, id, scope } => {
|
||||
log::debug!("Mounting a new component");
|
||||
diff_machine.change_list.load_known_root(id);
|
||||
|
||||
// We're modifying the component arena while holding onto references into the assoiated bump arenas of its children
|
||||
// those references are stable, even if the component arena moves around in memory, thanks to the bump arenas.
|
||||
// However, there is no way to convey this to rust, so we need to use unsafe to pierce through the lifetime.
|
||||
unsafe {
|
||||
// let p = &mut *(very_unsafe_components);
|
||||
// let p = &mut self.components;
|
||||
let p = &mut *(very_unsafe_components);
|
||||
|
||||
// todo, hook up the parent/child indexes properly
|
||||
let idx = self.components.insert_with(|f| Scope::new(caller, f, None));
|
||||
let c = self.components.get_mut(idx).unwrap();
|
||||
// let idx = p.insert_with(|f| Scope::new(caller, f, None));
|
||||
// let c = p.get_mut(idx).unwrap();
|
||||
c.run_scope();
|
||||
// diff_machine.diff_node(c.old_frame(), c.new_frame());
|
||||
let idx = p.insert_with(|f| Scope::new(caller, f, None));
|
||||
let c = p.get_mut(idx).unwrap();
|
||||
|
||||
let real_scope = scope.upgrade().unwrap();
|
||||
*real_scope.as_ref().borrow_mut() = Some(idx);
|
||||
c.run_scope()?;
|
||||
|
||||
diff_machine.change_list.load_known_root(id);
|
||||
|
||||
diff_machine.diff_node(c.old_frame(), c.new_frame());
|
||||
}
|
||||
}
|
||||
LifeCycleEvent::PropsChanged => {
|
||||
//
|
||||
LifeCycleEvent::PropsChanged { caller, id, scope } => {
|
||||
let idx = scope.upgrade().unwrap().as_ref().borrow().unwrap();
|
||||
|
||||
// We're modifying the component arena while holding onto references into the assoiated bump arenas of its children
|
||||
// those references are stable, even if the component arena moves around in memory, thanks to the bump arenas.
|
||||
// However, there is no way to convey this to rust, so we need to use unsafe to pierce through the lifetime.
|
||||
unsafe {
|
||||
let p = &mut *(very_unsafe_components);
|
||||
// todo, hook up the parent/child indexes properly
|
||||
// let idx = p.insert_with(|f| Scope::new(caller, f, None));
|
||||
let c = p.get_mut(idx).unwrap();
|
||||
c.run_scope()?;
|
||||
|
||||
diff_machine.change_list.load_known_root(id);
|
||||
|
||||
diff_machine.diff_node(c.old_frame(), c.new_frame());
|
||||
}
|
||||
// break 'render;
|
||||
}
|
||||
LifeCycleEvent::SameProps => {
|
||||
LifeCycleEvent::SameProps { caller, id, scope } => {
|
||||
//
|
||||
// break 'render;
|
||||
}
|
||||
@@ -134,6 +148,7 @@ impl VirtualDom {
|
||||
//
|
||||
// break 'render;
|
||||
}
|
||||
LifeCycleEvent::Replace { caller, id, .. } => {}
|
||||
}
|
||||
|
||||
// } else {
|
||||
@@ -176,13 +191,14 @@ impl VirtualDom {
|
||||
.expect("Borrowing should not fail");
|
||||
|
||||
component.call_listener(event);
|
||||
component.run_scope();
|
||||
component.run_scope()?;
|
||||
|
||||
let mut diff_machine = DiffMachine::new();
|
||||
// let mut diff_machine = DiffMachine::new(&self.diff_bump);
|
||||
|
||||
diff_machine.diff_node(component.old_frame(), component.new_frame());
|
||||
// diff_machine.diff_node(component.old_frame(), component.new_frame());
|
||||
|
||||
Ok(diff_machine.consume())
|
||||
// Ok(diff_machine.consume())
|
||||
self.rebuild()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user