Feat: remove generic paramter on VDOM
This makes storage of VDoms easier, and removes static dispatch on any function that relies on VDOMs.
This commit is contained in:
1 parent
4bbc5af6e1
commit
4c291a0efd
8 files changed
+113
-75
No files matched your search
@@ -19,7 +19,7 @@
|
||||
//!
|
||||
//!
|
||||
|
||||
use crate::innerlude::Listener;
|
||||
use crate::innerlude::{Listener, VirtualDom};
|
||||
|
||||
/// Renderers need to implement the interpreter trait
|
||||
///
|
||||
@@ -60,6 +60,7 @@ pub struct ChangeList<'src> {
|
||||
next_temporary: u32,
|
||||
forcing_new_listeners: bool,
|
||||
emitter: &'src mut dyn Inrerpreter,
|
||||
domlock: &'src VirtualDom,
|
||||
}
|
||||
|
||||
/// Traversal methods.
|
||||
@@ -158,19 +159,19 @@ impl ChangeList<'_> {
|
||||
temp_base
|
||||
}
|
||||
|
||||
pub fn push_temporary(&self, temp: u32) {
|
||||
pub fn push_temporary(&mut self, temp: u32) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: push_temporary({})", temp);
|
||||
self.emitter.push_temporary(temp);
|
||||
}
|
||||
|
||||
pub fn remove_child(&self, child: usize) {
|
||||
pub fn remove_child(&mut self, child: usize) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: remove_child({})", child);
|
||||
self.emitter.remove_child(child as u32);
|
||||
}
|
||||
|
||||
pub fn insert_before(&self) {
|
||||
pub fn insert_before(&mut self) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: insert_before()");
|
||||
self.emitter.insert_before();
|
||||
@@ -181,20 +182,20 @@ impl ChangeList<'_> {
|
||||
// self.strings.ensure_string(string, &self.emitter)
|
||||
}
|
||||
|
||||
pub fn set_text(&self, text: &str) {
|
||||
pub fn set_text(&mut self, text: &str) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: set_text({:?})", text);
|
||||
self.emitter.set_text(text);
|
||||
// .set_text(text.as_ptr() as u32, text.len() as u32);
|
||||
}
|
||||
|
||||
pub fn remove_self_and_next_siblings(&self) {
|
||||
pub fn remove_self_and_next_siblings(&mut self) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: remove_self_and_next_siblings()");
|
||||
self.emitter.remove_self_and_next_siblings();
|
||||
}
|
||||
|
||||
pub fn replace_with(&self) {
|
||||
pub fn replace_with(&mut self) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: replace_with()");
|
||||
self.emitter.replace_with();
|
||||
@@ -218,38 +219,42 @@ impl ChangeList<'_> {
|
||||
}
|
||||
|
||||
pub fn remove_attribute(&mut self, name: &str) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: remove_attribute({:?})", name);
|
||||
let name_id = self.ensure_string(name);
|
||||
self.emitter.remove_attribute(name_id.into());
|
||||
// todo!("figure out how to get this working with ensure string");
|
||||
self.emitter.remove_attribute(name);
|
||||
// debug_assert!(self.traversal_is_committed());
|
||||
// // debug!("emit: remove_attribute({:?})", name);
|
||||
// let name_id = self.ensure_string(name);
|
||||
// self.emitter.remove_attribute(name_id.into());
|
||||
}
|
||||
|
||||
pub fn append_child(&self) {
|
||||
pub fn append_child(&mut self) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: append_child()");
|
||||
self.emitter.append_child();
|
||||
}
|
||||
|
||||
pub fn create_text_node(&self, text: &str) {
|
||||
pub fn create_text_node(&mut self, text: &str) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: create_text_node({:?})", text);
|
||||
self.emitter.create_text_node(text);
|
||||
}
|
||||
|
||||
pub fn create_element(&mut self, tag_name: &str) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: create_element({:?})", tag_name);
|
||||
let tag_name_id = self.ensure_string(tag_name);
|
||||
self.emitter.create_element(tag_name_id.into());
|
||||
// let tag_name_id = self.ensure_string(tag_name);
|
||||
self.emitter.create_element(tag_name);
|
||||
// self.emitter.create_element(tag_name_id.into());
|
||||
}
|
||||
|
||||
pub fn create_element_ns(&mut self, tag_name: &str, ns: &str) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: create_element_ns({:?}, {:?})", tag_name, ns);
|
||||
let tag_name_id = self.ensure_string(tag_name);
|
||||
let ns_id = self.ensure_string(ns);
|
||||
self.emitter
|
||||
.create_element_ns(tag_name_id.into(), ns_id.into());
|
||||
// let tag_name_id = self.ensure_string(tag_name);
|
||||
// let ns_id = self.ensure_string(ns);
|
||||
self.emitter.create_element_ns(tag_name, ns);
|
||||
// self.emitter
|
||||
// .create_element_ns(tag_name_id.into(), ns_id.into());
|
||||
}
|
||||
|
||||
pub fn push_force_new_listeners(&mut self) -> bool {
|
||||
@@ -265,11 +270,12 @@ impl ChangeList<'_> {
|
||||
|
||||
pub fn new_event_listener(&mut self, listener: &Listener) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
todo!("Event listener not wired up yet");
|
||||
// debug!("emit: new_event_listener({:?})", listener);
|
||||
let (a, b) = listener.get_callback_parts();
|
||||
debug_assert!(a != 0);
|
||||
let event_id = self.ensure_string(listener.event);
|
||||
self.emitter.new_event_listener(event_id.into(), a, b);
|
||||
// let (a, b) = listener.get_callback_parts();
|
||||
// debug_assert!(a != 0);
|
||||
// let event_id = self.ensure_string(listener.event);
|
||||
// self.emitter.new_event_listener(event_id.into(), a, b);
|
||||
}
|
||||
|
||||
pub fn update_event_listener(&mut self, listener: &Listener) {
|
||||
@@ -281,17 +287,19 @@ impl ChangeList<'_> {
|
||||
}
|
||||
|
||||
// debug!("emit: update_event_listener({:?})", listener);
|
||||
let (a, b) = listener.get_callback_parts();
|
||||
debug_assert!(a != 0);
|
||||
todo!("Event listener not wired up yet");
|
||||
// let (a, b) = listener.get_callback_parts();
|
||||
// debug_assert!(a != 0);
|
||||
let event_id = self.ensure_string(listener.event);
|
||||
self.emitter.update_event_listener(event_id.into(), a, b);
|
||||
// self.emitter.update_event_listener(event_id.into(), a, b);
|
||||
}
|
||||
|
||||
pub fn remove_event_listener(&mut self, event: &str) {
|
||||
debug_assert!(self.traversal_is_committed());
|
||||
// debug!("emit: remove_event_listener({:?})", event);
|
||||
let event_id = self.ensure_string(event);
|
||||
self.emitter.remove_event_listener(event_id.into());
|
||||
todo!("Event listener not wired up yet");
|
||||
// self.emitter.remove_event_listener(event_id.into());
|
||||
}
|
||||
|
||||
// #[inline]
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
use crate::prelude::{Properties, VirtualDom};
|
||||
|
||||
pub struct DebugRenderer<'a, P: Properties> {
|
||||
vdom: &'a mut VirtualDom<P>,
|
||||
pub struct DebugRenderer {
|
||||
vdom: VirtualDom,
|
||||
}
|
||||
|
||||
impl<'a, P: Properties> DebugRenderer<'a, P> {
|
||||
pub fn new(vdom: &'a mut VirtualDom<P>) -> Self {
|
||||
impl DebugRenderer {
|
||||
pub fn new(vdom: VirtualDom) -> Self {
|
||||
Self { vdom }
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ pub enum Error {
|
||||
#[error("No event to progress")]
|
||||
NoEvent,
|
||||
|
||||
#[error("Wrong Properties Type")]
|
||||
WrongProps,
|
||||
|
||||
// #[error("Out of compute credits")]
|
||||
// OutOfCredits,
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::nodes::VNode;
|
||||
use crate::{changelist::ChangeList, nodes::VNode};
|
||||
use crate::{events::EventTrigger, innerlude::*};
|
||||
use any::Any;
|
||||
use bumpalo::Bump;
|
||||
@@ -14,7 +14,8 @@ use std::{
|
||||
|
||||
/// An integrated virtual node system that progresses events and diffs UI trees.
|
||||
/// Differences are converted into patches which a renderer can use to draw the UI.
|
||||
pub struct VirtualDom<P: Properties> {
|
||||
pub struct VirtualDom {
|
||||
// pub struct VirtualDom<P: Properties> {
|
||||
/// All mounted components are arena allocated to make additions, removals, and references easy to work with
|
||||
/// A generational arean is used to re-use slots of deleted scopes without having to resize the underlying arena.
|
||||
pub(crate) components: Arena<Scope>,
|
||||
@@ -28,11 +29,15 @@ pub struct VirtualDom<P: Properties> {
|
||||
///
|
||||
event_queue: Rc<RefCell<Vec<LifecycleEvent>>>,
|
||||
|
||||
#[doc(hidden)] // mark the root props with P, even though they're held by the root component
|
||||
_root_props: PhantomData<P>,
|
||||
// Mark the root props with P, even though they're held by the root component
|
||||
// This is done so we don't have a "generic" vdom, making it easier to hold references to it, especially when the holders
|
||||
// don't care about the generic props type
|
||||
// Most implementations that use the VirtualDom won't care about the root props anyways.
|
||||
#[doc(hidden)]
|
||||
_root_prop_type: std::any::TypeId,
|
||||
}
|
||||
|
||||
impl VirtualDom<()> {
|
||||
impl VirtualDom {
|
||||
/// Create a new instance of the Dioxus Virtual Dom with no properties for the root component.
|
||||
///
|
||||
/// This means that the root component must either consumes its own context, or statics are used to generate the page.
|
||||
@@ -42,13 +47,14 @@ impl VirtualDom<()> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Properties + 'static> VirtualDom<P> {
|
||||
impl VirtualDom {
|
||||
// impl<P: Properties + 'static> VirtualDom<P> {
|
||||
/// Start a new VirtualDom instance with a dependent props.
|
||||
/// Later, the props can be updated by calling "update" with a new set of props, causing a set of re-renders.
|
||||
///
|
||||
/// This is useful when a component tree can be driven by external state (IE SSR) but it would be too expensive
|
||||
/// to toss out the entire tree.
|
||||
pub fn new_with_props(root: FC<P>, root_props: P) -> Self {
|
||||
pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
|
||||
// 1. Create the component arena
|
||||
// 2. Create the base scope (can never be removed)
|
||||
// 3. Create the lifecycle queue
|
||||
@@ -67,28 +73,41 @@ impl<P: Properties + 'static> VirtualDom<P> {
|
||||
// Create an event queue with a mount for the base scope
|
||||
let event_queue = Rc::new(RefCell::new(vec![first_event]));
|
||||
|
||||
let _root_prop_type = TypeId::of::<P>();
|
||||
|
||||
Self {
|
||||
components,
|
||||
base_scope,
|
||||
event_queue,
|
||||
_root_props: PhantomData {},
|
||||
_root_prop_type,
|
||||
}
|
||||
}
|
||||
|
||||
/// With access to the virtual dom, schedule an update to the Root component's props
|
||||
pub fn update_props(&mut self, new_props: P) {
|
||||
pub fn update_props<P: Properties + 'static>(&mut self, new_props: P) -> Result<()> {
|
||||
// Ensure the props match
|
||||
if TypeId::of::<P>() != self._root_prop_type {
|
||||
return Err(Error::WrongProps);
|
||||
}
|
||||
|
||||
self.event_queue.borrow_mut().push(LifecycleEvent {
|
||||
event_type: LifecycleType::PropsChanged {
|
||||
props: Box::new(new_props),
|
||||
},
|
||||
index: self.base_scope,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Schedule a future update for a component from outside the vdom!
|
||||
///
|
||||
/// This lets services external to the virtual dom interact directly with the component and event system.
|
||||
pub fn queue_update() {}
|
||||
|
||||
/// Pop an event off the event queue and process it
|
||||
/// Update the root props, and progress
|
||||
/// Takes a bump arena to allocate into, making the diff phase as fast as possible
|
||||
///
|
||||
pub fn progress(&mut self) -> Result<()> {
|
||||
let event = self.event_queue.borrow_mut().pop().ok_or(Error::NoEvent)?;
|
||||
process_event(&mut self.components, event)
|
||||
@@ -109,7 +128,7 @@ impl<P: Properties + 'static> VirtualDom<P> {
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
pub async fn progress_with_event(&mut self, evt: EventTrigger) -> Result<()> {
|
||||
pub async fn progress_with_event(&mut self, evt: EventTrigger) -> Result<ChangeList<'_>> {
|
||||
let EventTrigger {
|
||||
component_id,
|
||||
listener_id,
|
||||
@@ -144,7 +163,8 @@ impl<P: Properties + 'static> VirtualDom<P> {
|
||||
process_event(&mut self.components, event)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
todo!()
|
||||
// Ok(())
|
||||
}
|
||||
|
||||
pub async fn progress_completely(&mut self) -> Result<()> {
|
||||
|
||||
Reference in new issue
Block a user