Feat: solve some issues regarding listeners
This commit is contained in:
1 parent
6084fbcd11
commit
dfaf5adee1
22 files changed
+192
-168
No files matched your search
@@ -13,10 +13,10 @@ use slab::Slab;
|
||||
// #[cfg(feature = "serialize", serde::Serialize)]
|
||||
// #[cfg(feature = "serialize", serde::Serialize)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct ScopeId(usize);
|
||||
pub struct ScopeId(pub usize);
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct ElementId(usize);
|
||||
pub struct ElementId(pub usize);
|
||||
|
||||
impl ElementId {
|
||||
pub fn as_u64(self) -> u64 {
|
||||
|
||||
@@ -34,12 +34,16 @@
|
||||
//! For all components, we employ some basic heuristics to speed up allocations and pre-size bump arenas. The heuristics are
|
||||
//! currently very rough, but will get better as time goes on. For FFI, we recommend using a bloom filter to cache strings.
|
||||
//!
|
||||
//!
|
||||
//! ## Garbage Collection
|
||||
//! ---------------------
|
||||
//! Dioxus uses a passive garbage collection system to clean up old nodes once the work has been completed. This garabge
|
||||
//! collection is done internally once the main diffing work is complete. After the "garbage" is collected, Dioxus will then
|
||||
//! start to re-use old keys for new nodes. This results in a passive memory management system that is very efficient.
|
||||
//!
|
||||
//! The IDs used by the key/map are just an index into a vec. This means that Dioxus will drive the key allocation strategy
|
||||
//! so the client only needs to maintain a simple list of nodes. By default, Dioxus will not manually clean up old nodes
|
||||
//! for the client. As new nodes are created, old nodes will be over-written.
|
||||
//!
|
||||
//! Further Reading and Thoughts
|
||||
//! ----------------------------
|
||||
@@ -53,10 +57,9 @@ use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use std::{any::Any, borrow::Borrow};
|
||||
|
||||
/// Instead of having handles directly over nodes, Dioxus uses simple u64s as node IDs.
|
||||
/// The expectation is that the underlying renderer will mainain their Nodes in something like slotmap or an ECS memory
|
||||
/// where indexing is very fast. For reference, the slotmap in the WebSys renderer takes about 3ns to randomly access any
|
||||
/// node.
|
||||
/// Instead of having handles directly over nodes, Dioxus uses simple u32 as node IDs.
|
||||
/// The expectation is that the underlying renderer will mainain their Nodes in vec where the ids are the index. This allows
|
||||
/// for a form of passive garbage collection where nodes aren't immedately cleaned up.
|
||||
///
|
||||
/// The "RealDom" abstracts over the... real dom. The RealDom trait assumes that the renderer maintains a stack of real
|
||||
/// nodes as the diffing algorithm descenes through the tree. This means that whatever is on top of the stack will receive
|
||||
@@ -531,7 +534,7 @@ impl<'a, 'bump> DiffMachine<'a, 'bump> {
|
||||
// [... node]
|
||||
//
|
||||
// The change list stack is left unchanged.
|
||||
fn diff_listeners(&mut self, old: &[&mut Listener<'_>], new: &[&mut Listener<'_>]) {
|
||||
fn diff_listeners(&mut self, old: &[Listener<'_>], new: &[Listener<'_>]) {
|
||||
if !old.is_empty() || !new.is_empty() {
|
||||
// self.edits.commit_traversal();
|
||||
}
|
||||
@@ -721,7 +724,6 @@ impl<'a, 'bump> DiffMachine<'a, 'bump> {
|
||||
//
|
||||
// Upon exiting, the change list stack is in the same state.
|
||||
fn diff_keyed_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
|
||||
// todo!();
|
||||
if cfg!(debug_assertions) {
|
||||
let mut keys = fxhash::FxHashSet::default();
|
||||
let mut assert_unique_keys = |children: &'bump [VNode<'bump>]| {
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
//! 3rd party renderers are responsible for converting their native events into these virtual event types. Events might
|
||||
//! be heavy or need to interact through FFI, so the events themselves are designed to be lazy.
|
||||
|
||||
use std::{cell::Cell, rc::Rc};
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use crate::innerlude::{ElementId, HeightMarker, ScopeId};
|
||||
|
||||
@@ -135,7 +138,7 @@ pub mod on {
|
||||
//!
|
||||
|
||||
#![allow(unused)]
|
||||
use std::{fmt::Debug, ops::Deref, rc::Rc};
|
||||
use std::{cell::RefCell, fmt::Debug, ops::Deref, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
innerlude::NodeFactory,
|
||||
@@ -183,10 +186,10 @@ pub mod on {
|
||||
event: stringify!($name),
|
||||
mounted_node: Cell::new(None),
|
||||
scope: c.scope.our_arena_idx,
|
||||
callback: bump.alloc(move |evt: VirtualEvent| match evt {
|
||||
callback: RefCell::new(bump.alloc(move |evt: VirtualEvent| match evt {
|
||||
VirtualEvent::$wrapper(event) => callback(event),
|
||||
_ => unreachable!("Downcasted VirtualEvent to wrong event type - this is an internal bug!")
|
||||
}),
|
||||
})),
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
+37
-19
@@ -8,7 +8,7 @@ use crate::{
|
||||
innerlude::{empty_cell, Context, DomTree, ElementId, Properties, Scope, ScopeId, FC},
|
||||
};
|
||||
use std::{
|
||||
cell::Cell,
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Arguments, Debug, Formatter},
|
||||
marker::PhantomData,
|
||||
rc::Rc,
|
||||
@@ -77,7 +77,7 @@ pub struct VElement<'a> {
|
||||
pub namespace: Option<&'static str>,
|
||||
|
||||
pub static_listeners: bool,
|
||||
pub listeners: &'a [&'a mut Listener<'a>],
|
||||
pub listeners: &'a [Listener<'a>],
|
||||
|
||||
pub static_attrs: bool,
|
||||
pub attributes: &'a [Attribute<'a>],
|
||||
@@ -112,7 +112,7 @@ pub struct Listener<'bump> {
|
||||
|
||||
pub mounted_node: Cell<Option<ElementId>>,
|
||||
|
||||
pub(crate) callback: &'bump mut dyn FnMut(VirtualEvent),
|
||||
pub(crate) callback: RefCell<&'bump mut dyn FnMut(VirtualEvent)>,
|
||||
}
|
||||
|
||||
/// Virtual Components for custom user-defined components
|
||||
@@ -200,14 +200,19 @@ impl<'a> NodeFactory<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn element(
|
||||
pub fn element<L, A, V>(
|
||||
&self,
|
||||
el: impl DioxusElement,
|
||||
listeners: &'a mut [&'a mut Listener<'a>],
|
||||
attributes: &'a [Attribute<'a>],
|
||||
children: &'a [VNode<'a>],
|
||||
listeners: L,
|
||||
attributes: A,
|
||||
children: V,
|
||||
key: Option<&'a str>,
|
||||
) -> VNode<'a> {
|
||||
) -> VNode<'a>
|
||||
where
|
||||
L: 'a + AsRef<[Listener<'a>]>,
|
||||
A: 'a + AsRef<[Attribute<'a>]>,
|
||||
V: 'a + AsRef<[VNode<'a>]>,
|
||||
{
|
||||
self.raw_element(
|
||||
el.tag_name(),
|
||||
el.namespace(),
|
||||
@@ -218,26 +223,39 @@ impl<'a> NodeFactory<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn raw_element(
|
||||
pub fn raw_element<L, A, V>(
|
||||
&self,
|
||||
tag: &'static str,
|
||||
namespace: Option<&'static str>,
|
||||
listeners: &'a mut [&'a mut Listener<'a>],
|
||||
attributes: &'a [Attribute],
|
||||
children: &'a [VNode<'a>],
|
||||
listeners: L,
|
||||
attributes: A,
|
||||
children: V,
|
||||
key: Option<&'a str>,
|
||||
) -> VNode<'a> {
|
||||
) -> VNode<'a>
|
||||
where
|
||||
L: 'a + AsRef<[Listener<'a>]>,
|
||||
A: 'a + AsRef<[Attribute<'a>]>,
|
||||
V: 'a + AsRef<[VNode<'a>]>,
|
||||
{
|
||||
let listeners: &'a L = self.bump().alloc(listeners);
|
||||
let listeners = listeners.as_ref();
|
||||
|
||||
let attributes: &'a A = self.bump().alloc(attributes);
|
||||
let attributes = attributes.as_ref();
|
||||
|
||||
let children: &'a V = self.bump().alloc(children);
|
||||
let children = children.as_ref();
|
||||
|
||||
// We take the references directly from the bump arena
|
||||
//
|
||||
//
|
||||
// TODO: this code shouldn't necessarily be here of all places
|
||||
// It would make more sense to do this in diffing
|
||||
|
||||
let mut queue = self.scope.listeners.borrow_mut();
|
||||
for listener in listeners.iter_mut() {
|
||||
let raw_listener = &mut **listener;
|
||||
|
||||
let long_listener: &mut Listener<'static> =
|
||||
unsafe { std::mem::transmute(raw_listener) };
|
||||
queue.push(long_listener as *mut _)
|
||||
for listener in listeners.iter() {
|
||||
let long_listener: &Listener<'static> = unsafe { std::mem::transmute(listener) };
|
||||
queue.push(long_listener as *const _)
|
||||
}
|
||||
|
||||
VNode {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::innerlude::*;
|
||||
use bumpalo::boxed::Box as BumpBox;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
cell::{Cell, RefCell},
|
||||
@@ -31,7 +32,7 @@ pub struct Scope {
|
||||
pub(crate) child_nodes: &'static [VNode<'static>],
|
||||
|
||||
// Listeners
|
||||
pub(crate) listeners: RefCell<Vec<*mut Listener<'static>>>,
|
||||
pub(crate) listeners: RefCell<Vec<*const Listener<'static>>>,
|
||||
pub(crate) listener_idx: Cell<usize>,
|
||||
|
||||
// State
|
||||
@@ -154,7 +155,7 @@ impl Scope {
|
||||
let listners = self.listeners.borrow_mut();
|
||||
|
||||
let raw_listener = listners.iter().find(|lis| {
|
||||
let search = unsafe { &mut ***lis };
|
||||
let search = unsafe { &***lis };
|
||||
let search_id = search.mounted_node.get();
|
||||
log::info!("searching listener {:#?}", search_id);
|
||||
|
||||
@@ -165,8 +166,9 @@ impl Scope {
|
||||
});
|
||||
|
||||
if let Some(raw_listener) = raw_listener {
|
||||
let listener = unsafe { &mut **raw_listener };
|
||||
(listener.callback)(event);
|
||||
let listener = unsafe { &**raw_listener };
|
||||
let mut cb = listener.callback.borrow_mut();
|
||||
(cb)(event);
|
||||
} else {
|
||||
log::warn!("An event was triggered but there was no listener to handle it");
|
||||
}
|
||||
|
||||
@@ -181,8 +181,8 @@ impl VirtualDom {
|
||||
/// The diff machine expects the RealDom's stack to be the root of the application
|
||||
pub fn rebuild<'s>(
|
||||
&'s mut self,
|
||||
realdom: &'s mut dyn RealDom<'s>,
|
||||
edits: &'s mut Vec<DomEdit<'s>>,
|
||||
realdom: &'_ mut dyn RealDom<'s>,
|
||||
edits: &'_ mut Vec<DomEdit<'s>>,
|
||||
) -> Result<()> {
|
||||
let mut diff_machine = DiffMachine::new(edits, realdom, self.base_scope, &self.shared);
|
||||
|
||||
@@ -355,6 +355,10 @@ impl VirtualDom {
|
||||
pub fn base_scope(&self) -> &Scope {
|
||||
unsafe { self.shared.get_scope(self.base_scope).unwrap() }
|
||||
}
|
||||
|
||||
pub fn get_scope(&self, id: ScopeId) -> Option<&Scope> {
|
||||
unsafe { self.shared.get_scope(id) }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO!
|
||||
|
||||
Reference in new issue
Block a user