feat: somewhat working with rc and weak
This commit is contained in:
1 parent
ec801eab16
commit
d4f1ceaffb
10 files changed
+170
-137
No files matched your search
@@ -71,14 +71,9 @@ impl PartialEq for ChildProps<'_> {
|
|||||||
|
|
||||||
impl<'a> Properties for ChildProps<'a> {
|
impl<'a> Properties for ChildProps<'a> {
|
||||||
type Builder = ChildPropsBuilder<'a, ((), ())>;
|
type Builder = ChildPropsBuilder<'a, ((), ())>;
|
||||||
type StaticOutput = ChildProps<'static>;
|
|
||||||
fn builder() -> <Self as Properties>::Builder {
|
fn builder() -> <Self as Properties>::Builder {
|
||||||
ChildProps::builder()
|
ChildProps::builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn into_static(self) -> Self::StaticOutput {
|
|
||||||
unsafe { std::mem::transmute(self) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ChildItem(_ctx: Context, _props: &ChildProps) -> DomTree {
|
fn ChildItem(_ctx: Context, _props: &ChildProps) -> DomTree {
|
||||||
|
|||||||
@@ -27,12 +27,7 @@ fn main() {}
|
|||||||
|
|
||||||
impl Properties for ExampleProps {
|
impl Properties for ExampleProps {
|
||||||
type Builder = ExamplePropsBuilder<((),)>;
|
type Builder = ExamplePropsBuilder<((),)>;
|
||||||
type StaticOutput = ExampleProps;
|
|
||||||
fn builder() -> Self::Builder {
|
fn builder() -> Self::Builder {
|
||||||
ExampleProps::builder()
|
ExampleProps::builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn into_static(self) -> Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -12,12 +12,12 @@ static Header: FC<()> = |ctx, props| {
|
|||||||
|
|
||||||
let handler1 = move || println!("Value is {}", inner.current());
|
let handler1 = move || println!("Value is {}", inner.current());
|
||||||
|
|
||||||
ctx.render(|bump| {
|
ctx.render(|c| {
|
||||||
builder::ElementBuilder::new(bump, "div")
|
builder::ElementBuilder::new(c, "div")
|
||||||
.child(VNode::Component(VComponent::new(
|
.child(VNode::Component(VComponent::new(
|
||||||
Bottom,
|
Bottom,
|
||||||
//
|
//
|
||||||
&mut (),
|
c.bump.alloc(()),
|
||||||
)))
|
)))
|
||||||
.finish()
|
.finish()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -27,12 +27,7 @@ static Example: FC<SomeProps> = |ctx, _props| {
|
|||||||
// toodo: derive this
|
// toodo: derive this
|
||||||
impl Properties for SomeProps {
|
impl Properties for SomeProps {
|
||||||
type Builder = SomePropsBuilder<((),)>;
|
type Builder = SomePropsBuilder<((),)>;
|
||||||
type StaticOutput = SomeProps;
|
|
||||||
fn builder() -> Self::Builder {
|
fn builder() -> Self::Builder {
|
||||||
SomeProps::builder()
|
SomeProps::builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn into_static(self) -> Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
//!
|
//!
|
||||||
//! More info on how to improve this diffing algorithm:
|
//! More info on how to improve this diffing algorithm:
|
||||||
//! - https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/
|
//! - https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/
|
||||||
use crate::{innerlude::*, scope::Scoped};
|
use crate::{innerlude::*, scope::Scope};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use fxhash::{FxHashMap, FxHashSet};
|
use fxhash::{FxHashMap, FxHashSet};
|
||||||
use generational_arena::Arena;
|
use generational_arena::Arena;
|
||||||
@@ -60,12 +60,15 @@ use std::{
|
|||||||
pub struct DiffMachine<'a> {
|
pub struct DiffMachine<'a> {
|
||||||
pub change_list: EditMachine<'a>,
|
pub change_list: EditMachine<'a>,
|
||||||
pub diffed: FxHashSet<ScopeIdx>,
|
pub diffed: FxHashSet<ScopeIdx>,
|
||||||
pub lifecycle_events: VecDeque<LifeCycleEvent>,
|
pub lifecycle_events: VecDeque<LifeCycleEvent<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
// #[derive(Debug)]
|
||||||
pub enum LifeCycleEvent {
|
pub enum LifeCycleEvent<'a> {
|
||||||
Mount { caller: Caller, id: Uuid },
|
Mount {
|
||||||
|
caller: Rc<dyn for<'r> Fn(Context<'r>) -> DomTree + 'a>,
|
||||||
|
id: Uuid,
|
||||||
|
},
|
||||||
PropsChanged,
|
PropsChanged,
|
||||||
SameProps,
|
SameProps,
|
||||||
Remove,
|
Remove,
|
||||||
@@ -260,6 +263,7 @@ impl<'a> DiffMachine<'a> {
|
|||||||
self.change_list
|
self.change_list
|
||||||
.create_text_node("placeholder for vcomponent");
|
.create_text_node("placeholder for vcomponent");
|
||||||
let id = uuid::Uuid::new_v4();
|
let id = uuid::Uuid::new_v4();
|
||||||
|
*component.stable_addr.as_ref().borrow_mut() = Some(id);
|
||||||
self.change_list.save_known_root(id);
|
self.change_list.save_known_root(id);
|
||||||
self.lifecycle_events.push_back(LifeCycleEvent::Mount {
|
self.lifecycle_events.push_back(LifeCycleEvent::Mount {
|
||||||
caller: component.caller.clone(),
|
caller: component.caller.clone(),
|
||||||
|
|||||||
@@ -521,8 +521,9 @@ pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
pub fn virtual_child<'a, T: Properties>(ctx: &NodeCtx<'a>, f: FC<T>, p: T) -> VNode<'a> {
|
pub fn virtual_child<'a, T: Properties + 'a>(ctx: &NodeCtx<'a>, f: FC<T>, p: T) -> VNode<'a> {
|
||||||
VNode::Component(crate::nodes::VComponent::new(f, ctx.bump.alloc(p)))
|
let propsd: &'a mut _ = ctx.bump.alloc(p);
|
||||||
|
VNode::Component(crate::nodes::VComponent::new(f, propsd))
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Bany {
|
trait Bany {
|
||||||
|
|||||||
+56
-47
@@ -264,35 +264,40 @@ impl<'a> VText<'a> {
|
|||||||
|
|
||||||
/// Virtual Components for custom user-defined components
|
/// Virtual Components for custom user-defined components
|
||||||
/// Only supports the functional syntax
|
/// Only supports the functional syntax
|
||||||
pub type StableScopeAddres = Rc<RefCell<Option<usize>>>;
|
pub type StableScopeAddres = Rc<RefCell<Option<uuid::Uuid>>>;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct VComponent<'src> {
|
pub struct VComponent<'src> {
|
||||||
pub stable_addr: StableScopeAddres,
|
pub stable_addr: StableScopeAddres,
|
||||||
pub raw_props: Rc<*mut dyn Any>,
|
|
||||||
// pub comparator: Comparator,
|
pub comparator: Rc<dyn Fn(&VComponent) -> bool + 'src>,
|
||||||
pub caller: Caller,
|
pub caller: Rc<dyn for<'r> Fn(Context<'r>) -> DomTree + 'src>,
|
||||||
pub caller_ref: *const (),
|
|
||||||
|
// a pointer into the bump arena (given by the 'src lifetime)
|
||||||
|
raw_props: *const (),
|
||||||
|
|
||||||
|
// a pointer to the raw fn typ
|
||||||
|
caller_ref: *const (),
|
||||||
_p: PhantomData<&'src ()>,
|
_p: PhantomData<&'src ()>,
|
||||||
}
|
}
|
||||||
pub trait PropsComparator {}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
impl std::fmt::Debug for VComponent<'_> {
|
||||||
// pub struct Comparator(pub Rc<dyn Fn(&dyn PropsComparator) -> bool>);
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
pub struct Comparator(pub Rc<dyn Fn(&dyn Any) -> bool>);
|
todo!()
|
||||||
impl std::fmt::Debug for Comparator {
|
|
||||||
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// pub struct Comparator(pub Rc<dyn Fn(&VComponent) -> bool>);
|
||||||
|
// impl std::fmt::Debug for Comparator {
|
||||||
|
// fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
#[derive(Clone)]
|
// pub struct Caller(pub Rc<dyn Fn(Context) -> DomTree>);
|
||||||
pub struct Caller(pub Rc<dyn Fn(Context) -> DomTree>);
|
// impl std::fmt::Debug for Caller {
|
||||||
impl std::fmt::Debug for Caller {
|
// fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
// Ok(())
|
||||||
Ok(())
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> VComponent<'a> {
|
impl<'a> VComponent<'a> {
|
||||||
// use the type parameter on props creation and move it into a portable context
|
// use the type parameter on props creation and move it into a portable context
|
||||||
@@ -300,36 +305,40 @@ impl<'a> VComponent<'a> {
|
|||||||
// - perform comparisons when diffing (memoization)
|
// - perform comparisons when diffing (memoization)
|
||||||
// TODO: lift the requirement that props need to be static
|
// TODO: lift the requirement that props need to be static
|
||||||
// we want them to borrow references... maybe force implementing a "to_static_unsafe" trait
|
// we want them to borrow references... maybe force implementing a "to_static_unsafe" trait
|
||||||
pub fn new<P: Properties>(caller: FC<P>, props: &mut P) -> Self {
|
pub fn new<P: Properties + 'a>(component: FC<P>, props: &'a P) -> Self {
|
||||||
let caller_ref = caller as *const ();
|
let caller_ref = component as *const ();
|
||||||
|
|
||||||
let props = Rc::new(props);
|
let raw_props = props as *const P as *const ();
|
||||||
|
|
||||||
// used for memoization
|
let props_comparator = move |other: &VComponent| {
|
||||||
let p1 = props.clone();
|
// Safety:
|
||||||
|
// We are guaranteed that the props will be of the same type because
|
||||||
// let props_comparator = move |new_props| -> bool {
|
// there is no way to create a VComponent other than this `new` method.
|
||||||
// false
|
//
|
||||||
// let p = new_props.downcast_ref::<P::StaticOutput>().expect("");
|
// Therefore, if the render functions are identical (by address), then so will be
|
||||||
// let r = unsafe { std::mem::transmute::<_, &P>(p) };
|
// props type paramter (because it is the same render function). Therefore, we can be
|
||||||
// &r == p1.as_ref()
|
// sure
|
||||||
// };
|
if caller_ref == other.caller_ref {
|
||||||
|
let real_other = unsafe { &*(other.raw_props as *const _ as *const P) };
|
||||||
// used for actually rendering the custom component
|
real_other == props
|
||||||
let p2 = props.clone();
|
} else {
|
||||||
let caller = move |ctx: Context| -> DomTree {
|
false
|
||||||
// cast back into the right lifetime
|
}
|
||||||
caller(ctx, p2.as_ref())
|
|
||||||
};
|
};
|
||||||
|
|
||||||
todo!()
|
let caller = move |ctx: Context| -> DomTree {
|
||||||
// Self {
|
// cast back into the right lifetime
|
||||||
// caller_ref,
|
let safe_props: &P = unsafe { &*(raw_props as *const P) };
|
||||||
// raw_props: props,
|
component(ctx, props)
|
||||||
// _p: PhantomData,
|
};
|
||||||
// comparator: Comparator(Rc::new(props_comparator)),
|
|
||||||
// caller: Caller(Rc::new(caller)),
|
Self {
|
||||||
// stable_addr: Rc::new(RefCell::new(None)),
|
caller_ref,
|
||||||
// }
|
raw_props: props as *const P as *const _,
|
||||||
|
_p: PhantomData,
|
||||||
|
caller: Rc::new(caller),
|
||||||
|
comparator: Rc::new(props_comparator),
|
||||||
|
stable_addr: Rc::new(RefCell::new(None)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+83
-44
@@ -1,15 +1,22 @@
|
|||||||
use crate::innerlude::*;
|
use crate::innerlude::*;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
|
||||||
use std::{any::Any, cell::RefCell, collections::HashSet, marker::PhantomData, ops::Deref};
|
use std::{
|
||||||
|
any::Any,
|
||||||
|
cell::RefCell,
|
||||||
|
collections::HashSet,
|
||||||
|
marker::PhantomData,
|
||||||
|
ops::Deref,
|
||||||
|
rc::{Rc, Weak},
|
||||||
|
};
|
||||||
|
|
||||||
pub trait Scoped {
|
// pub trait Scoped {
|
||||||
fn run(&mut self);
|
// fn run(&mut self);
|
||||||
// fn compare_props(&self, new: &dyn std::any::Any) -> bool;
|
// // fn compare_props(&self, new: &dyn std::any::Any) -> bool;
|
||||||
fn call_listener(&mut self, trigger: EventTrigger);
|
// fn call_listener(&mut self, trigger: EventTrigger);
|
||||||
fn new_frame<'bump>(&'bump self) -> &'bump VNode<'bump>;
|
// fn new_frame<'bump>(&'bump self) -> &'bump VNode<'bump>;
|
||||||
fn old_frame<'bump>(&'bump self) -> &'bump VNode<'bump>;
|
// fn old_frame<'bump>(&'bump self) -> &'bump VNode<'bump>;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Every component in Dioxus is represented by a `Scope`.
|
/// Every component in Dioxus is represented by a `Scope`.
|
||||||
///
|
///
|
||||||
@@ -17,7 +24,8 @@ pub trait Scoped {
|
|||||||
///
|
///
|
||||||
/// Scopes are allocated in a generational arena. As components are mounted/unmounted, they will replace slots of dead components.
|
/// 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.
|
/// The actual contents of the hooks, though, will be allocated with the standard allocator. These should not allocate as frequently.
|
||||||
pub struct Scope<P: Properties> {
|
pub struct Scope {
|
||||||
|
// pub struct Scope<P: Properties> {
|
||||||
// Map to the parent
|
// Map to the parent
|
||||||
pub parent: Option<ScopeIdx>,
|
pub parent: Option<ScopeIdx>,
|
||||||
|
|
||||||
@@ -27,12 +35,15 @@ pub struct Scope<P: Properties> {
|
|||||||
//
|
//
|
||||||
pub children: HashSet<ScopeIdx>,
|
pub children: HashSet<ScopeIdx>,
|
||||||
|
|
||||||
|
pub caller: Weak<dyn Fn(Context) -> DomTree + 'static>,
|
||||||
|
|
||||||
// // the props
|
// // the props
|
||||||
// pub props: P,
|
// pub props: P,
|
||||||
|
|
||||||
// and the actual render function
|
// and the actual render function
|
||||||
pub caller: Caller,
|
// pub caller: *const dyn Fn(Context) -> DomTree,
|
||||||
_p: std::marker::PhantomData<P>,
|
// _p: std::marker::PhantomData<P>,
|
||||||
|
// _p: std::marker::PhantomData<P>,
|
||||||
// pub raw_caller: FC<P>,
|
// pub raw_caller: FC<P>,
|
||||||
|
|
||||||
// ==========================
|
// ==========================
|
||||||
@@ -57,35 +68,62 @@ pub struct Scope<P: Properties> {
|
|||||||
|
|
||||||
// instead of having it as a trait method, we use a single function
|
// instead of having it as a trait method, we use a single function
|
||||||
// todo: do the unsafety magic stuff to erase the type of p
|
// todo: do the unsafety magic stuff to erase the type of p
|
||||||
pub fn create_scoped(
|
// pub fn create_scoped(
|
||||||
// raw_f: FC<P>,
|
// // raw_f: FC<P>,
|
||||||
caller: Caller,
|
// // caller: Caller,
|
||||||
|
|
||||||
// props: P,
|
// // props: P,
|
||||||
myidx: ScopeIdx,
|
// myidx: ScopeIdx,
|
||||||
parent: Option<ScopeIdx>,
|
// parent: Option<ScopeIdx>,
|
||||||
) -> Box<dyn Scoped> {
|
// ) -> Box<dyn Scoped> {
|
||||||
Box::new(Scope::<()> {
|
// Box::new(Scope::<()> {
|
||||||
// raw_caller: raw_f,
|
// // raw_caller: raw_f,
|
||||||
_p: Default::default(),
|
// _p: Default::default(),
|
||||||
caller,
|
// // caller,
|
||||||
myidx,
|
// myidx,
|
||||||
hook_arena: typed_arena::Arena::new(),
|
// hook_arena: typed_arena::Arena::new(),
|
||||||
hooks: RefCell::new(Vec::new()),
|
// hooks: RefCell::new(Vec::new()),
|
||||||
frames: ActiveFrame::new(),
|
// frames: ActiveFrame::new(),
|
||||||
children: HashSet::new(),
|
// children: HashSet::new(),
|
||||||
listeners: Default::default(),
|
// listeners: Default::default(),
|
||||||
parent,
|
// parent,
|
||||||
// props,
|
// // props,
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl<P: Properties + 'static> Scoped for Scope<P> {
|
impl Scope {
|
||||||
|
// we are being created in the scope of an existing component (where the creator_node lifetime comes into play)
|
||||||
|
// we are going to break this lifetime by force in order to save it on ourselves.
|
||||||
|
// To make sure that the lifetime isn't truly broken, we receive a Weak RC so we can't keep it around after the parent dies.
|
||||||
|
// This should never happen, but is a good check to keep around
|
||||||
|
pub fn new<'creator_node>(
|
||||||
|
caller: Weak<dyn Fn(Context) -> DomTree + 'creator_node>,
|
||||||
|
myidx: ScopeIdx,
|
||||||
|
parent: Option<ScopeIdx>,
|
||||||
|
) -> Self {
|
||||||
|
// caller has been broken free
|
||||||
|
// however, it's still weak, so if the original Rc gets killed, we can't touch it
|
||||||
|
let broken_caller: Weak<dyn Fn(Context) -> DomTree + 'static> =
|
||||||
|
unsafe { std::mem::transmute(caller) };
|
||||||
|
|
||||||
|
Self {
|
||||||
|
caller: broken_caller,
|
||||||
|
hook_arena: typed_arena::Arena::new(),
|
||||||
|
hooks: RefCell::new(Vec::new()),
|
||||||
|
frames: ActiveFrame::new(),
|
||||||
|
children: HashSet::new(),
|
||||||
|
listeners: Default::default(),
|
||||||
|
parent,
|
||||||
|
myidx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl<P: Properties + 'static> Scoped for Scope<P> {
|
||||||
/// Create a new context and run the component with references from the Virtual Dom
|
/// 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
|
/// 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)
|
/// Props is ?Sized because we borrow the props and don't need to know the size. P (sized) is used as a marker (unsized)
|
||||||
fn run<'bump>(&'bump mut self) {
|
pub fn run<'bump>(&'bump mut self) {
|
||||||
let frame = {
|
let frame = {
|
||||||
let frame = self.frames.next();
|
let frame = self.frames.next();
|
||||||
frame.bump.reset();
|
frame.bump.reset();
|
||||||
@@ -105,8 +143,9 @@ impl<P: Properties + 'static> Scoped for Scope<P> {
|
|||||||
listeners: &self.listeners,
|
listeners: &self.listeners,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
todo!()
|
||||||
// Note that the actual modification of the vnode head element occurs during this call
|
// Note that the actual modification of the vnode head element occurs during this call
|
||||||
let _: DomTree = (self.caller.0.as_ref())(ctx);
|
// let _: DomTree = (self.caller.0.as_ref())(ctx);
|
||||||
// let _: DomTree = (self.raw_caller)(ctx, &self.props);
|
// let _: DomTree = (self.raw_caller)(ctx, &self.props);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -121,14 +160,14 @@ impl<P: Properties + 'static> Scoped for Scope<P> {
|
|||||||
- Public API cannot drop or destructure VNode
|
- Public API cannot drop or destructure VNode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
frame.head_node = node_slot
|
// frame.head_node = node_slot
|
||||||
.deref()
|
// .deref()
|
||||||
.borrow_mut()
|
// .borrow_mut()
|
||||||
.take()
|
// .take()
|
||||||
.expect("Viewing did not happen");
|
// .expect("Viewing did not happen");
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn compare_props(&self, new: &dyn Any) -> bool {
|
// pub fn compare_props(&self, new: &dyn Any) -> bool {
|
||||||
// new.downcast_ref::<P>()
|
// new.downcast_ref::<P>()
|
||||||
// .map(|f| &self.props == f)
|
// .map(|f| &self.props == f)
|
||||||
// .expect("Props should not be of a different type")
|
// .expect("Props should not be of a different type")
|
||||||
@@ -137,7 +176,7 @@ impl<P: Properties + 'static> Scoped for Scope<P> {
|
|||||||
// A safe wrapper around calling listeners
|
// A safe wrapper around calling listeners
|
||||||
// calling listeners will invalidate the list of listeners
|
// calling listeners will invalidate the list of listeners
|
||||||
// The listener list will be completely drained because the next frame will write over previous listeners
|
// The listener list will be completely drained because the next frame will write over previous listeners
|
||||||
fn call_listener(&mut self, trigger: EventTrigger) {
|
pub fn call_listener(&mut self, trigger: EventTrigger) {
|
||||||
let EventTrigger {
|
let EventTrigger {
|
||||||
listener_id,
|
listener_id,
|
||||||
event: source,
|
event: source,
|
||||||
@@ -165,11 +204,11 @@ impl<P: Properties + 'static> Scoped for Scope<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
|
pub fn new_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
|
||||||
self.frames.current_head_node()
|
self.frames.current_head_node()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn old_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
|
pub fn old_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
|
||||||
self.frames.prev_head_node()
|
self.frames.prev_head_node()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
// use crate::{changelist::EditList, nodes::VNode};
|
// use crate::{changelist::EditList, nodes::VNode};
|
||||||
|
|
||||||
use crate::innerlude::*;
|
use crate::innerlude::*;
|
||||||
use crate::{
|
use crate::{patch::Edit, scope::Scope};
|
||||||
patch::Edit,
|
|
||||||
scope::{create_scoped, Scoped},
|
|
||||||
};
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use generational_arena::Arena;
|
use generational_arena::Arena;
|
||||||
use std::{any::TypeId, cell::RefCell, rc::Rc};
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
|
cell::RefCell,
|
||||||
|
rc::{Rc, Weak},
|
||||||
|
};
|
||||||
|
|
||||||
/// An integrated virtual node system that progresses events and diffs UI trees.
|
/// An integrated virtual node system that progresses events and diffs UI trees.
|
||||||
/// Differences are converted into patches which a renderer can use to draw the UI.
|
/// Differences are converted into patches which a renderer can use to draw the UI.
|
||||||
@@ -18,13 +19,15 @@ pub struct VirtualDom {
|
|||||||
/// eventually, come up with a better datastructure that reuses boxes for known P types
|
/// eventually, come up with a better datastructure that reuses boxes for known P types
|
||||||
/// like a generational typemap bump arena
|
/// like a generational typemap bump arena
|
||||||
/// -> IE a cache line for each P type with some heuristics on optimizing layout
|
/// -> IE a cache line for each P type with some heuristics on optimizing layout
|
||||||
pub(crate) components: Arena<Box<dyn Scoped>>,
|
pub(crate) components: Arena<Scope>,
|
||||||
// pub(crate) components: RefCell<Arena<Box<dyn Scoped>>>,
|
// pub(crate) components: RefCell<Arena<Box<dyn Scoped>>>,
|
||||||
// pub(crate) components: Rc<RefCell<Arena<Box<dyn Scoped>>>>,
|
// pub(crate) components: Rc<RefCell<Arena<Box<dyn Scoped>>>>,
|
||||||
/// The index of the root component.
|
/// The index of the root component.
|
||||||
/// Will not be ready if the dom is fresh
|
/// Will not be ready if the dom is fresh
|
||||||
pub(crate) base_scope: ScopeIdx,
|
pub(crate) base_scope: ScopeIdx,
|
||||||
|
|
||||||
|
pub(crate) root_caller: Rc<dyn Fn(Context) -> DomTree + 'static>,
|
||||||
|
|
||||||
// Type of the original props. This is done so VirtualDom does not need to be generic.
|
// Type of the original props. This is done so VirtualDom does not need to be generic.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
_root_prop_type: std::any::TypeId,
|
_root_prop_type: std::any::TypeId,
|
||||||
@@ -55,6 +58,7 @@ impl VirtualDom {
|
|||||||
pub fn new(root: FC<()>) -> Self {
|
pub fn new(root: FC<()>) -> Self {
|
||||||
Self::new_with_props(root, ())
|
Self::new_with_props(root, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start a new VirtualDom instance with a dependent props.
|
/// Start a new VirtualDom instance with a dependent props.
|
||||||
/// Later, the props can be updated by calling "update" with a new set of props, causing a set of re-renders.
|
/// Later, the props can be updated by calling "update" with a new set of props, causing a set of re-renders.
|
||||||
///
|
///
|
||||||
@@ -63,18 +67,15 @@ impl VirtualDom {
|
|||||||
pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
|
pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
|
||||||
let mut components = Arena::new();
|
let mut components = Arena::new();
|
||||||
|
|
||||||
// Create a reference to the component in the arena
|
// the root is kept around
|
||||||
// Note: we are essentially running the "Mount" lifecycle event manually while the vdom doesnt yet exist
|
let root_caller: Rc<dyn Fn(Context) -> DomTree + 'static> =
|
||||||
let caller = Caller(Rc::new(move |ctx| {
|
Rc::new(move |ctx| root(ctx, &root_props));
|
||||||
//
|
let weak_caller: Weak<dyn Fn(Context) -> DomTree + 'static> = Rc::downgrade(&root_caller);
|
||||||
root(ctx, &root_props)
|
let base_scope = components.insert_with(move |id| Scope::new(weak_caller, id, None));
|
||||||
// DomTree {}
|
|
||||||
}));
|
|
||||||
let base_scope = components.insert_with(|id| create_scoped(caller, id, None));
|
|
||||||
// let base_scope = components.insert_with(|id| create_scoped(root, root_props, id, None));
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
components,
|
components,
|
||||||
|
root_caller,
|
||||||
base_scope,
|
base_scope,
|
||||||
diff_bump: Bump::new(),
|
diff_bump: Bump::new(),
|
||||||
_root_prop_type: TypeId::of::<P>(),
|
_root_prop_type: TypeId::of::<P>(),
|
||||||
|
|||||||
@@ -60,13 +60,7 @@ static Example2: FC<ExampleProps> = |ctx, props| {
|
|||||||
|
|
||||||
impl Properties for ExampleProps {
|
impl Properties for ExampleProps {
|
||||||
type Builder = ExamplePropsBuilder<((),)>;
|
type Builder = ExamplePropsBuilder<((),)>;
|
||||||
type StaticOutput = ExampleProps;
|
|
||||||
fn builder() -> Self::Builder {
|
fn builder() -> Self::Builder {
|
||||||
ExampleProps::builder()
|
ExampleProps::builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsafe fn into_static(self) -> Self::StaticOutput {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user