Feat: notes on safety, and inline listeners

This commit is contained in:
Jonathan Kelley committed 2021-03-04 13:49:18 -05:00
1 parent c70652a3c9
commit bdd6be309e
5 files changed
+133 -103

No files matched your search

+62 -60
View File
@@ -3,18 +3,12 @@ use crate::context::hooks::Hook;
use crate::innerlude::*;
use crate::nodes::VNode;
use bumpalo::Bump;
// use generational_arena::ScopeIdx;
use std::{
any::TypeId,
borrow::{Borrow, BorrowMut},
cell::{RefCell, UnsafeCell},
future::Future,
any::{Any, TypeId},
cell::RefCell,
marker::PhantomData,
ops::{Deref, DerefMut},
sync::atomic::AtomicUsize,
sync::atomic::Ordering,
todo,
ops::Deref,
};
/// Every component in Dioxus is represented by a `Scope`.
@@ -24,31 +18,35 @@ use std::{
/// Scopes are allocated in a generational arena. As components are mounted/unmounted, they will replace slots of dead components.
/// The actual contents of the hooks, though, will be allocated with the standard allocator. These should not allocate as frequently.
pub struct Scope {
// pub(crate) struct Scope {
// TODO @Jon
// These hooks are actually references into the hook arena
// These two could be combined with "OwningRef" to remove unsafe usage
// could also use ourborous
pub hooks: RefCell<Vec<*mut Hook>>,
pub hook_arena: typed_arena::Arena<Hook>,
// Map to the parent
pub parent: Option<ScopeIdx>,
pub frames: ActiveFrame,
// List of listeners generated when CTX is evaluated
pub listeners: Vec<*const dyn Fn(crate::events::VirtualEvent)>,
// pub listeners: Vec<*const dyn Fn(crate::events::VirtualEvent)>,
// pub listeners: Vec<Box<dyn Fn(crate::events::VirtualEvent)>>,
// lying, cheating reference >:(
pub props: Box<dyn std::any::Any>,
// our own index
pub myidx: ScopeIdx,
// pub props_type: TypeId,
// ==========================
// slightly unsafe stuff
// ==========================
// an internal, highly efficient storage of vnodes
pub frames: ActiveFrame,
// These hooks are actually references into the hook arena
// These two could be combined with "OwningRef" to remove unsafe usage
// could also use ourborous
pub hooks: RefCell<Vec<*mut Hook>>,
pub hook_arena: typed_arena::Arena<Hook>,
// Unsafety:
// - is self-refenrential and therefore needs to point into the bump
//
// Stores references into the listeners attached to the vnodes
pub listeners: RefCell<Vec<*const dyn Fn(crate::events::VirtualEvent)>>,
// Unsafety
// - is a raw ptr because we need to compare
pub caller: *const (),
}
@@ -66,8 +64,7 @@ impl Scope {
// Capture the caller
let caller = f as *const ();
let listeners = vec![];
// let listeners: Vec<Box<dyn Fn(crate::events::VirtualEvent)>> = vec![];
let listeners = Default::default();
let old_frame = BumpFrame {
bump: Bump::new(),
@@ -97,7 +94,21 @@ impl Scope {
props,
}
}
}
pub struct RawComponent {
// used as a memoization strategy
comparator: *const Box<dyn Fn(&Box<dyn Any>) -> bool>,
// used to actually run the component
// encapsulates props
runner: *const Box<dyn Fn(Context) -> DomTree>,
// the actual FC<T>
raw: *const (),
}
impl Scope {
/// Create a new context and run the component with references from the Virtual Dom
/// This function downcasts the function pointer based on the stored props_type
///
@@ -106,11 +117,11 @@ impl Scope {
let frame = {
let frame = self.frames.next();
frame.bump.reset();
log::debug!("Rednering into frame {:?}", frame as *const _);
frame
};
let node_slot = std::rc::Rc::new(RefCell::new(None));
let ctx: Context<'bump> = Context {
arena: &self.hook_arena,
hooks: &self.hooks,
@@ -119,6 +130,7 @@ impl Scope {
_p: PhantomData {},
final_nodes: node_slot.clone(),
scope: self.myidx,
listeners: &self.listeners,
};
unsafe {
@@ -139,7 +151,7 @@ impl Scope {
let props = self.props.downcast_ref::<PLocked>().unwrap();
// Note that the actual modification of the vnode head element occurs during this call
let _nodes: DomTree = caller(ctx, props);
let _: DomTree = caller(ctx, props);
/*
SAFETY ALERT
@@ -158,32 +170,8 @@ impl Scope {
.borrow_mut()
.take()
.expect("Viewing did not happen");
// todo:
// make this so we dont have to iterate through the vnodes to get its listener
let mut listeners = vec![];
retrieve_listeners(&frame.head_node, &mut listeners);
self.listeners = listeners
.into_iter()
.map(|f| {
let g = f.callback;
g as *const _
})
.collect();
// consume the listeners from the head_node into a list of boxed ref listeners
}
}
/// Accessor to get the root node and its children (safely)\
/// Scope is self-referntial, so we are forced to use the 'static lifetime to cheat
pub fn new_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
self.frames.current_head_node()
}
pub fn old_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
self.frames.prev_head_node()
}
}
fn retrieve_listeners(node: &VNode<'static>, listeners: &mut Vec<&Listener>) {
@@ -198,6 +186,21 @@ fn retrieve_listeners(node: &VNode<'static>, listeners: &mut Vec<&Listener>) {
}
}
// ==========================
// Active-frame related code
// ==========================
impl Scope {
/// Accessor to get the root node and its children (safely)\
/// Scope is self-referntial, so we are forced to use the 'static lifetime to cheat
pub fn new_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
self.frames.current_head_node()
}
pub fn old_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
self.frames.prev_head_node()
}
}
// todo, do better with the active frame stuff
// somehow build this vnode with a lifetime tied to self
// This root node has "static" lifetime, but it's really not static.
@@ -205,7 +208,7 @@ fn retrieve_listeners(node: &VNode<'static>, listeners: &mut Vec<&Listener>) {
// Use this node as if it were static is unsafe, and needs to be fixed with ourborous or owning ref
// ! do not copy this reference are things WILL break !
pub struct ActiveFrame {
pub idx: AtomicUsize,
pub idx: RefCell<usize>,
pub frames: [BumpFrame; 2],
}
@@ -223,7 +226,7 @@ impl ActiveFrame {
}
fn current_head_node<'b>(&'b self) -> &'b VNode<'b> {
let raw_node = match self.idx.borrow().load(Ordering::Relaxed) & 1 == 0 {
let raw_node = match *self.idx.borrow() & 1 == 0 {
true => &self.frames[0],
false => &self.frames[1],
};
@@ -237,7 +240,7 @@ impl ActiveFrame {
}
fn prev_head_node<'b>(&'b self) -> &'b VNode<'b> {
let raw_node = match self.idx.borrow().load(Ordering::Relaxed) & 1 != 0 {
let raw_node = match *self.idx.borrow() & 1 != 0 {
true => &self.frames[0],
false => &self.frames[1],
};
@@ -251,10 +254,9 @@ impl ActiveFrame {
}
fn next(&mut self) -> &mut BumpFrame {
self.idx.fetch_add(1, Ordering::Relaxed);
let cur = self.idx.borrow().load(Ordering::Relaxed);
*self.idx.borrow_mut() += 1;
if cur % 2 == 0 {
if *self.idx.borrow() % 2 == 0 {
&mut self.frames[0]
} else {
&mut self.frames[1]
@@ -262,7 +264,7 @@ impl ActiveFrame {
}
}
// #[cfg(test)]
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;