Feat: WIP ctx

This commit is contained in:
Jonathan Kelley committed 2021-02-20 21:59:16 -05:00
1 parent b3e6886351
commit 7a6aabe4f3
18 files changed
+430 -99

No files matched your search

+164 -29
View File
@@ -33,39 +33,39 @@ pub struct Scope {
// Map to the parent
pub parent: Option<Index>,
// 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.
// It's goverened by the oldest of the two frames and is switched every time a new render occurs
// 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 frames: ActiveFrame,
// IE Which listeners need to be woken up?
pub listeners: Vec<Box<dyn Fn()>>,
// lying, cheating reference >:(
pub props: Box<dyn std::any::Any>,
// pub props: Box<dyn Properties>,
//
pub props_type: TypeId,
pub caller: *const i32,
// pub props_type: TypeId,
pub caller: *const (),
}
impl Scope {
// create a new scope from a function
pub fn new<T: 'static>(
// pub(crate) fn new<T: 'static>(
f: FC<T>,
props: impl Properties + 'static,
pub fn new<'a, P1, P2: 'static>(
// pub fn new<'a, P: Properties, PFree: P + 'a, PLocked: P + 'static>(
f: FC<P1>,
props: P1,
parent: Option<Index>,
) -> Self {
) -> Self
// where
// PFree: 'a,
// PLocked: 'static,
{
// Capture the props type
let props_type = TypeId::of::<T>();
// let props_type = TypeId::of::<P>();
let hook_arena = typed_arena::Arena::new();
let hooks = RefCell::new(Vec::new());
// Capture the caller
let caller = f as *const i32;
let caller = f as *const ();
let listeners = Vec::new();
@@ -80,12 +80,20 @@ impl Scope {
};
let frames = ActiveFrame::from_frames(old_frame, new_frame);
// box the props
let props = Box::new(props);
// erase the lifetime
// we'll manage this with dom lifecycle
let props = unsafe { std::mem::transmute::<_, Box<P2>>(props) };
// todo!()
Self {
hook_arena,
hooks,
props_type,
// props_type,
caller,
frames,
listeners,
@@ -94,13 +102,10 @@ impl Scope {
}
}
/// Update this component's props with a new set of props
/// Update this component's props with a new set of props, remotely
///
///
pub(crate) fn update_props<P: Properties + Sized + 'static>(
&mut self,
new_props: Box<P>,
) -> crate::error::Result<()> {
pub(crate) fn update_props<'a, P>(&self, new_props: P) -> crate::error::Result<()> {
Ok(())
}
@@ -108,7 +113,7 @@ impl Scope {
/// This function downcasts the function pointer based on the stored props_type
///
/// Props is ?Sized because we borrow the props and don't need to know the size. P (sized) is used as a marker (unsized)
pub fn run<'bump, P: Properties + Sized + 'static>(&'bump mut self) {
pub fn run<'bump, PLocked: Sized + 'static>(&'bump mut self) {
let frame = {
let frame = self.frames.next();
frame.bump.reset();
@@ -123,6 +128,18 @@ impl Scope {
_p: PhantomData {},
};
unsafe {
// we use plocked to be able to remove the borrowed lifetime
// these lifetimes could be very broken, so we need to dynamically manage them
let caller = std::mem::transmute::<*const (), FC<PLocked>>(self.caller);
let props = self.props.downcast_ref::<PLocked>().unwrap();
let nodes: DomTree = caller(ctx, props);
todo!("absorb domtree into self")
// let nodes: VNode<'bump> = caller(ctx, props);
// let unsafe_node = std::mem::transmute::<VNode<'bump>, VNode<'static>>(nodes);
// frame.head_node = unsafe_node;
}
/*
SAFETY ALERT
@@ -135,9 +152,6 @@ impl Scope {
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 nodes: VNode<'bump> = caller(ctx, self.props.downcast_ref::<P>().unwrap());
/*
SAFETY ALERT
@@ -149,9 +163,6 @@ impl Scope {
- The VNode has a private API and can only be used from accessors.
- Public API cannot drop or destructure VNode
*/
let unsafe_node = unsafe { std::mem::transmute::<VNode<'bump>, VNode<'static>>(nodes) };
frame.head_node = unsafe_node;
}
/// Accessor to get the root node and its children (safely)\
@@ -159,6 +170,7 @@ impl Scope {
pub fn current_root_node<'bump>(&'bump self) -> &'bump VNode<'bump> {
self.frames.current_head_node()
}
pub fn prev_root_node<'bump>(&'bump self) -> &'bump VNode<'bump> {
todo!()
}
@@ -169,6 +181,12 @@ pub struct BumpFrame {
pub head_node: VNode<'static>,
}
// 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.
// It's goverened by the oldest of the two frames and is switched every time a new render occurs
// 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 frames: [BumpFrame; 2],
@@ -183,7 +201,7 @@ impl ActiveFrame {
}
fn current_head_node<'b>(&'b self) -> &'b VNode<'b> {
let cur_idx = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed);
let cur_idx = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed) % 1;
let raw_node = &self.frames[cur_idx];
unsafe {
let unsafe_head = &raw_node.head_node;
@@ -202,3 +220,120 @@ impl ActiveFrame {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scope() {
let example: FC<()> = |ctx, props| {
use crate::builder::*;
ctx.view(|b| div(b).child(text("a")).finish())
};
let props = ();
let parent = None;
let scope = Scope::new::<(), ()>(example, props, parent);
}
#[derive(Debug)]
struct ExampleProps<'src> {
name: &'src String,
}
// impl<'src> Properties<'src> for ExampleProps<'src> {}
#[derive(Debug)]
struct EmptyProps<'src> {
name: &'src String,
}
// impl<'src> Properties<'src> for EmptyProps<'src> {}
use crate::{builder::*, hooks::use_ref};
fn example_fc<'a>(ctx: Context<'a>, props: &'a EmptyProps) -> DomTree {
// fn example_fc<'a>(ctx: Context<'a>, props: &'a EmptyProps<'a>) -> DomTree {
let (content, _): (&'a String, _) = crate::hooks::use_state(&ctx, || "abcd".to_string());
// let (content, _): (&'a String, _) = crate::hooks::use_state(&ctx, || "abcd".to_string());
// let (text, set_val) = crate::hooks::use_state(&ctx, || "abcd".to_string());
let childprops: ExampleProps<'a> = ExampleProps { name: content };
// let childprops: ExampleProps<'a> = ExampleProps { name: content };
ctx.view(move |b: &'a Bump| {
div(b)
.child(text(props.name))
// .child(text(props.name))
.child(virtual_child::<ExampleProps>(b, childprops, child_example))
// .child(virtual_child::<ExampleProps<'a>>(b, childprops, CHILD))
// as for<'scope> fn(Context<'_>, &'scope ExampleProps<'scope>) -> DomTree
// |ctx, pops| todo!(),
// .child(virtual_child::<'a>(
// b,
// child_example,
// ExampleProps { name: text },
// ))
.finish()
})
}
fn child_example(ctx: Context, props: &ExampleProps) -> DomTree {
ctx.view(move |b| {
div(b)
.child(text(props.name))
//
.finish()
})
}
static CHILD: FC<ExampleProps> = |ctx, props: &'_ ExampleProps| {
// todo!()
ctx.view(move |b| {
div(b)
.child(text(props.name))
//
.finish()
})
};
#[test]
fn test_borrowed_scope() {
// use crate::builder::*;
let example: FC<EmptyProps> = |ctx, props| {
// render counter
// let mut val = crate::hooks::use_ref(&ctx, || 0);
// val.modify(|f| {
// *f += 1;
// });
// dbg!(val.current());
// only needs to be valid when ran?
// can only borrow from parent?
// props are boxed in parent's scope?
// passing complex structures down to child?
// stored value
// let (text, set_val) = crate::hooks::use_state(&ctx, || "abcd".to_string());
ctx.view(move |b| {
todo!()
// div(b)
// // .child(text(props.name))
// // .child(virtual_child(b, CHILD, ExampleProps { name: val.as_str() }))
// .child(virtual_child(b, CHILD, ExampleProps { name: }))
// .finish()
})
};
let source_text = "abcd123".to_string();
let props = ExampleProps { name: &source_text };
// let parent = None;
// let mut scope =
// Scope::new::<EmptyProps, EmptyProps>(example, EmptyProps { name: &() }, parent);
// scope.run::<ExampleProps>();
// scope.run::<ExampleProps>();
// scope.run::<ExampleProps>();
// scope.run::<ExampleProps>();
// scope.run::<ExampleProps>();
// let nodes = scope.current_root_node();
// dbg!(nodes);
}
}