Feat: WIP ctx
This commit is contained in:
1 parent
b3e6886351
commit
7a6aabe4f3
18 files changed
+430
-99
No files matched your search
+164
-29
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user