|
@@ -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);
|
|
|
+ }
|
|
|
+}
|