Feat: major overhaul, wire up event system
This commit is contained in:
1 parent
f47651b32a
commit
8295ac4b3d
20 files changed
+1418
-188
No files matched your search
+58
-41
@@ -1,6 +1,6 @@
|
||||
use crate::context::hooks::Hook;
|
||||
use crate::inner::*;
|
||||
use crate::nodes::VNode;
|
||||
use crate::{context::hooks::Hook, diff::diff};
|
||||
use bumpalo::Bump;
|
||||
use generational_arena::Index;
|
||||
use std::{
|
||||
@@ -15,22 +15,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 {
|
||||
// TODO @Jon
|
||||
// These hooks are actually references into the hook arena
|
||||
// These two could be combined with "OwningRef" to remove unsafe usage
|
||||
// TODO @Jon
|
||||
// could also use ourborous
|
||||
hooks: RefCell<Vec<*mut Hook>>,
|
||||
hook_arena: typed_arena::Arena<Hook>,
|
||||
|
||||
// Map to the parent
|
||||
parent: Option<Index>,
|
||||
|
||||
// todo, do better with the active frame stuff
|
||||
frames: [Bump; 2],
|
||||
|
||||
// somehow build this vnode with a lifetime tied to self
|
||||
cur_node: *mut VNode<'static>,
|
||||
|
||||
active_frame: u8,
|
||||
|
||||
// IE Which listeners need to be woken up?
|
||||
listeners: Vec<Box<dyn Fn()>>,
|
||||
|
||||
//
|
||||
props_type: TypeId,
|
||||
caller: *const i32,
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
// create a new scope from a function
|
||||
pub fn new<T: 'static>(f: FC<T>, parent: Option<Index>) -> Self {
|
||||
pub(crate) fn new<T: 'static>(f: FC<T>, parent: Option<Index>) -> Self {
|
||||
// Capture the props type
|
||||
let props_type = TypeId::of::<T>();
|
||||
let hook_arena = typed_arena::Arena::new();
|
||||
@@ -38,56 +51,60 @@ impl Scope {
|
||||
|
||||
let caller = f as *const i32;
|
||||
|
||||
let frames = [Bump::new(), Bump::new()];
|
||||
|
||||
let listeners = Vec::new();
|
||||
|
||||
let active_frame = 1;
|
||||
|
||||
let new = frames[0].alloc(VNode::Text(VText::new("")));
|
||||
let cur_node = new as *mut _;
|
||||
|
||||
Self {
|
||||
hook_arena,
|
||||
hooks,
|
||||
props_type,
|
||||
caller,
|
||||
active_frame,
|
||||
listeners,
|
||||
parent,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_context<'a, T: Properties>(
|
||||
&'a mut self,
|
||||
components: &'a generational_arena::Arena<Scope>,
|
||||
props: &'a T,
|
||||
) -> Context {
|
||||
|
||||
//
|
||||
Context {
|
||||
scope: &*self,
|
||||
_p: PhantomData {},
|
||||
arena: &self.hook_arena,
|
||||
hooks: &self.hooks,
|
||||
idx: 0.into(),
|
||||
components,
|
||||
frames,
|
||||
cur_node,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
fn run<T: 'static>(&self, f: FC<T>) {}
|
||||
}
|
||||
///
|
||||
/// Props is ?Sized because we borrow the props
|
||||
pub(crate) fn run<'a, P: Properties + ?Sized>(&self, props: &'a P) {
|
||||
let bump = &self.frames[0];
|
||||
|
||||
mod bad_unsafety {
|
||||
// todo
|
||||
// fn call<'a, T: Properties + 'static>(&'a mut self, val: T) {
|
||||
// if self.props_type == TypeId::of::<T>() {
|
||||
// /*
|
||||
// SAFETY ALERT
|
||||
let ctx = Context {
|
||||
scope: &*self,
|
||||
_p: PhantomData {},
|
||||
arena: &self.hook_arena,
|
||||
hooks: &self.hooks,
|
||||
idx: 0.into(),
|
||||
bump,
|
||||
};
|
||||
|
||||
// This particular usage of transmute is outlined in its docs https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||
// We hide the generic bound on the function item by casting it to raw pointer. When the function is actually called,
|
||||
// we transmute the function back using the props as reference.
|
||||
/*
|
||||
SAFETY ALERT
|
||||
|
||||
// This is safe because we check that the generic type matches before casting.
|
||||
// */
|
||||
// let caller = unsafe { std::mem::transmute::<*const i32, FC<T>>(self.caller) };
|
||||
// // let ctx = self.create_context::<T>();
|
||||
// // // TODO: do something with these nodes
|
||||
// // let nodes = caller(ctx);
|
||||
// } else {
|
||||
// panic!("Do not try to use `call` on Scopes with the wrong props type")
|
||||
// }
|
||||
// }
|
||||
This particular usage of transmute is outlined in its docs https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||
We hide the generic bound on the function item by casting it to raw pointer. When the function is actually called,
|
||||
we transmute the function back using the props as reference.
|
||||
|
||||
we could do a better check to make sure that the TypeID is correct
|
||||
--
|
||||
This is safe because we check that the generic type matches before casting.
|
||||
*/
|
||||
let caller = unsafe { std::mem::transmute::<*const i32, FC<P>>(self.caller) };
|
||||
let new_nodes = caller(ctx, props);
|
||||
let old_nodes: &mut VNode<'static> = unsafe { &mut *self.cur_node };
|
||||
|
||||
// perform the diff, dumping into the change list
|
||||
crate::diff::diff(old_nodes, &new_nodes);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user