wip: move everything over to a stack dst
This commit is contained in:
1 parent
12a9758c3c
commit
0e9d5fc530
36 files changed
+224
-185
No files matched your search
@@ -5,7 +5,10 @@
|
||||
//! if the type supports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder
|
||||
//! that ensures compile-time required and optional fields on cx.
|
||||
|
||||
use crate::innerlude::{Context, DomTree, LazyNodes, FC};
|
||||
use crate::{
|
||||
innerlude::{Context, Element, LazyNodes, FC},
|
||||
VNode,
|
||||
};
|
||||
|
||||
/// A component is a wrapper around a Context and some Props that share a lifetime
|
||||
///
|
||||
@@ -63,8 +66,8 @@ pub type Component<'a, T> = (Context<'a>, &'a T);
|
||||
/// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it.
|
||||
///
|
||||
#[allow(non_upper_case_globals, non_snake_case)]
|
||||
pub fn Fragment((cx, _): Component<()>) -> DomTree {
|
||||
cx.render(LazyNodes::new(|f| f.fragment_from_iter(cx.children())))
|
||||
pub fn Fragment((cx, _): Component<()>) -> Element {
|
||||
Some(LazyNodes::new(|f| f.fragment_from_iter(cx.children())))
|
||||
}
|
||||
|
||||
/// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus
|
||||
|
||||
@@ -137,10 +137,7 @@ impl<'src> Context<'src> {
|
||||
/// cx.render(lazy_tree)
|
||||
/// }
|
||||
///```
|
||||
pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
||||
self,
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> DomTree<'src> {
|
||||
pub fn render(self, lazy_nodes: LazyNodes<'src>) -> Option<VNode<'src>> {
|
||||
let bump = &self.scope.frames.wip_frame().bump;
|
||||
Some(lazy_nodes.into_vnode(NodeFactory { bump }))
|
||||
}
|
||||
|
||||
@@ -93,11 +93,11 @@ pub fn use_suspense<'src, Out, Fut, Cb>(
|
||||
cx: Context<'src>,
|
||||
task_initializer: impl FnOnce() -> Fut,
|
||||
user_callback: Cb,
|
||||
) -> DomTree<'src>
|
||||
) -> Element<'src>
|
||||
where
|
||||
Fut: Future<Output = Out> + 'static,
|
||||
Out: 'static,
|
||||
Cb: for<'a> Fn(SuspendedContext<'a>, &Out) -> DomTree<'a> + 'static,
|
||||
Cb: for<'a> Fn(SuspendedContext<'a>, &Out) -> Element<'a> + 'static,
|
||||
{
|
||||
/*
|
||||
General strategy:
|
||||
@@ -135,12 +135,12 @@ where
|
||||
None => {
|
||||
let value = hook.value.clone();
|
||||
|
||||
cx.render(LazyNodes::new(|f| {
|
||||
Some(LazyNodes::new(|f| {
|
||||
let bump = f.bump();
|
||||
|
||||
use bumpalo::boxed::Box as BumpBox;
|
||||
|
||||
let f: &mut dyn FnMut(SuspendedContext<'src>) -> DomTree<'src> =
|
||||
let f: &mut dyn FnMut(SuspendedContext<'src>) -> Element<'src> =
|
||||
bump.alloc(move |sus| {
|
||||
let val = value.borrow();
|
||||
|
||||
@@ -177,12 +177,14 @@ pub struct SuspendedContext<'a> {
|
||||
}
|
||||
|
||||
impl<'src> SuspendedContext<'src> {
|
||||
pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
||||
pub fn render(
|
||||
// pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
||||
self,
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> DomTree<'src> {
|
||||
lazy_nodes: LazyNodes<'src>,
|
||||
) -> Element<'src> {
|
||||
let bump = &self.inner.scope.frames.wip_frame().bump;
|
||||
Some(lazy_nodes.into_vnode(NodeFactory { bump }))
|
||||
todo!("suspense")
|
||||
// Some(lazy_nodes.into_vnode(NodeFactory { bump }))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,12 +56,13 @@ pub(crate) mod innerlude {
|
||||
pub use crate::util::*;
|
||||
pub use crate::virtual_dom::*;
|
||||
|
||||
pub type DomTree<'a> = Option<VNode<'a>>;
|
||||
pub type FC<P> = for<'a> fn(Component<'a, P>) -> DomTree<'a>;
|
||||
// pub type Element<'a> = Option<VNode<'a>>;
|
||||
pub type Element<'a> = Option<LazyNodes<'a>>;
|
||||
pub type FC<P> = for<'a> fn(Component<'a, P>) -> Element<'a>;
|
||||
}
|
||||
|
||||
pub use crate::innerlude::{
|
||||
Context, DioxusElement, DomEdit, DomTree, ElementId, EventPriority, LazyNodes, MountType,
|
||||
Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, LazyNodes, MountType,
|
||||
Mutations, NodeFactory, Properties, SchedulerMsg, ScopeId, SuspendedContext, TaskHandle,
|
||||
TestDom, ThreadsafeVirtualDom, UserEvent, VNode, VirtualDom, FC,
|
||||
};
|
||||
@@ -70,7 +71,7 @@ pub mod prelude {
|
||||
pub use crate::component::{fc_to_builder, Component, Fragment, Properties};
|
||||
pub use crate::context::Context;
|
||||
pub use crate::hooks::*;
|
||||
pub use crate::innerlude::{DioxusElement, DomTree, LazyNodes, Mutations, NodeFactory, FC};
|
||||
pub use crate::innerlude::{DioxusElement, Element, LazyNodes, Mutations, NodeFactory, FC};
|
||||
pub use crate::nodes::VNode;
|
||||
pub use crate::VirtualDom;
|
||||
}
|
||||
|
||||
+47
-30
@@ -4,7 +4,7 @@
|
||||
//! cheap and *very* fast to construct - building a full tree should be quick.
|
||||
|
||||
use crate::innerlude::{
|
||||
empty_cell, Context, DomTree, ElementId, Properties, Scope, ScopeId, SuspendedContext, FC,
|
||||
empty_cell, Context, Element, ElementId, Properties, Scope, ScopeId, SuspendedContext, FC,
|
||||
};
|
||||
use bumpalo::{boxed::Box as BumpBox, Bump};
|
||||
use std::{
|
||||
@@ -13,6 +13,10 @@ use std::{
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
||||
use stack_dst::Value as StackDST;
|
||||
|
||||
pub type LazyNodeFactory<'a> = StackDST<dyn FnOnce(NodeFactory<'a>) -> VNode<'a>>;
|
||||
|
||||
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
|
||||
///
|
||||
/// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
|
||||
@@ -287,7 +291,7 @@ pub struct VComponent<'src> {
|
||||
// Function pointer to the FC that was used to generate this component
|
||||
pub user_fc: *const (),
|
||||
|
||||
pub(crate) caller: &'src dyn for<'b> Fn(&'b Scope) -> DomTree<'b>,
|
||||
pub(crate) caller: &'src dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
||||
|
||||
pub(crate) children: &'src [VNode<'src>],
|
||||
|
||||
@@ -306,7 +310,7 @@ pub struct VSuspended<'a> {
|
||||
pub dom_id: Cell<Option<ElementId>>,
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub callback: RefCell<Option<BumpBox<'a, dyn FnMut(SuspendedContext<'a>) -> DomTree<'a>>>>,
|
||||
pub callback: RefCell<Option<BumpBox<'a, dyn FnMut(SuspendedContext<'a>) -> Element<'a>>>>,
|
||||
}
|
||||
|
||||
/// This struct provides an ergonomic API to quickly build VNodes.
|
||||
@@ -328,9 +332,10 @@ impl<'a> NodeFactory<'a> {
|
||||
self.bump
|
||||
}
|
||||
|
||||
pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a, F>) -> DomTree<'a>
|
||||
where
|
||||
F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a>) -> Option<VNode<'a>>
|
||||
// pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a, F>) -> Element<'a>
|
||||
// where
|
||||
// F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
Some(lazy_nodes.into_vnode(NodeFactory { bump: self.bump }))
|
||||
}
|
||||
@@ -526,11 +531,11 @@ impl<'a> NodeFactory<'a> {
|
||||
|
||||
let key = key.map(|f| self.raw_text(f).0);
|
||||
|
||||
let caller: &'a mut dyn for<'b> Fn(&'b Scope) -> DomTree<'b> =
|
||||
bump.alloc(move |scope: &Scope| -> DomTree {
|
||||
let caller: &'a mut dyn for<'b> Fn(&'b Scope) -> Element<'b> =
|
||||
bump.alloc(move |scope: &Scope| -> Element {
|
||||
log::debug!("calling component renderr {:?}", scope.our_arena_idx);
|
||||
let props: &'_ P = unsafe { &*(raw_props as *const P) };
|
||||
let res = component((Context { scope }, props));
|
||||
let res: Element = component((Context { scope }, props));
|
||||
unsafe { std::mem::transmute(res) }
|
||||
});
|
||||
|
||||
@@ -691,40 +696,43 @@ impl<'a> IntoVNode<'a> for VNode<'a> {
|
||||
/// ```rust
|
||||
/// LazyNodes::new(|f| f.element("div", [], [], [] None))
|
||||
/// ```
|
||||
pub struct LazyNodes<'a, G>
|
||||
where
|
||||
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
inner: G,
|
||||
_p: PhantomData<&'a ()>,
|
||||
pub struct LazyNodes<'a> {
|
||||
inner: LazyNodeFactory<'a>,
|
||||
}
|
||||
// where
|
||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
|
||||
impl<'a, G> LazyNodes<'a, G>
|
||||
where
|
||||
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
impl<'a> LazyNodes<'a>
|
||||
// where
|
||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
pub fn new(f: G) -> Self {
|
||||
Self {
|
||||
inner: f,
|
||||
_p: PhantomData {},
|
||||
}
|
||||
pub fn new(f: impl FnOnce(NodeFactory<'a>) -> VNode<'a>) -> Self {
|
||||
todo!()
|
||||
// pub fn new<G: FnOnce(NodeFactory<'a>) -> VNode<'a>>(f: G) -> Self {
|
||||
// let inner = LazyNodeFactory::new(f);
|
||||
// Self { inner: f }
|
||||
}
|
||||
}
|
||||
|
||||
// Our blanket impl
|
||||
impl<'a, G> IntoVNode<'a> for LazyNodes<'a, G>
|
||||
where
|
||||
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
impl<'a> IntoVNode<'a> for LazyNodes<'a>
|
||||
// where
|
||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||
(self.inner)(cx)
|
||||
// let f = self.inner;
|
||||
todo!("manually drop here")
|
||||
// (self.inner)(cx)
|
||||
}
|
||||
}
|
||||
|
||||
// Our blanket impl
|
||||
impl<'a, G> IntoIterator for LazyNodes<'a, G>
|
||||
where
|
||||
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
impl<'a> IntoIterator for LazyNodes<'a>
|
||||
// where
|
||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
// impl<'a, G> IntoIterator for LazyNodes<'a, G>
|
||||
// where
|
||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
type Item = Self;
|
||||
type IntoIter = std::iter::Once<Self::Item>;
|
||||
@@ -756,6 +764,15 @@ impl<'a> IntoVNode<'a> for Option<VNode<'a>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoVNode<'a> for Option<LazyNodes<'a>> {
|
||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||
match self {
|
||||
Some(n) => n.into_vnode(cx),
|
||||
None => cx.fragment_from_iter(None as Option<VNode>),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoVNode<'_> for &'static str {
|
||||
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
||||
cx.static_text(self)
|
||||
|
||||
+19
-14
@@ -28,7 +28,7 @@ pub struct Scope {
|
||||
|
||||
// Nodes
|
||||
pub(crate) frames: ActiveFrame,
|
||||
pub(crate) caller: *const dyn for<'b> Fn(&'b Scope) -> DomTree<'b>,
|
||||
pub(crate) caller: *const dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
||||
pub(crate) child_nodes: ScopeChildren<'static>,
|
||||
|
||||
/*
|
||||
@@ -176,7 +176,7 @@ impl Scope {
|
||||
// Scopes cannot be made anywhere else except for this file
|
||||
// Therefore, their lifetimes are connected exclusively to the virtual dom
|
||||
pub(crate) fn new(
|
||||
caller: &dyn for<'b> Fn(&'b Scope) -> DomTree<'b>,
|
||||
caller: &dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
||||
our_arena_idx: ScopeId,
|
||||
parent_idx: Option<ScopeId>,
|
||||
height: u32,
|
||||
@@ -217,7 +217,7 @@ impl Scope {
|
||||
|
||||
pub(crate) fn update_scope_dependencies<'creator_node>(
|
||||
&mut self,
|
||||
caller: &'creator_node dyn for<'b> Fn(&'b Scope) -> DomTree<'b>,
|
||||
caller: &'creator_node dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
||||
child_nodes: ScopeChildren,
|
||||
) {
|
||||
log::debug!("Updating scope dependencies {:?}", self.our_arena_idx);
|
||||
@@ -317,7 +317,7 @@ impl Scope {
|
||||
|
||||
let mut cb = sus.callback.borrow_mut().take().unwrap();
|
||||
|
||||
let new_node: DomTree<'a> = (cb)(cx);
|
||||
let new_node: Element<'a> = (cb)(cx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,20 +350,25 @@ impl Scope {
|
||||
log::debug!("Borrowed stuff is successfully cleared");
|
||||
|
||||
// Cast the caller ptr from static to one with our own reference
|
||||
let render: &dyn for<'b> Fn(&'b Scope) -> DomTree<'b> = unsafe { &*self.caller };
|
||||
let render: &dyn for<'b> Fn(&'b Scope) -> Element<'b> = unsafe { &*self.caller };
|
||||
|
||||
// Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders.
|
||||
if let Some(new_head) = render(self) {
|
||||
log::debug!("Render is successful");
|
||||
//
|
||||
todo!()
|
||||
// if let Some(builder) = render(self) {
|
||||
// let new_head = builder.into_vnode(NodeFactory {
|
||||
// bump: &self.frames.wip_frame().bump,
|
||||
// });
|
||||
// log::debug!("Render is successful");
|
||||
|
||||
// the user's component succeeded. We can safely cycle to the next frame
|
||||
self.frames.wip_frame_mut().head_node = unsafe { std::mem::transmute(new_head) };
|
||||
self.frames.cycle_frame();
|
||||
// // the user's component succeeded. We can safely cycle to the next frame
|
||||
// self.frames.wip_frame_mut().head_node = unsafe { std::mem::transmute(new_head) };
|
||||
// self.frames.cycle_frame();
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
// true
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,16 +21,16 @@ impl TestDom {
|
||||
NodeFactory::new(&self.bump)
|
||||
}
|
||||
|
||||
pub fn render_direct<'a, F>(&'a self, lazy_nodes: LazyNodes<'a, F>) -> VNode<'a>
|
||||
where
|
||||
F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
pub fn render_direct<'a>(&'a self, lazy_nodes: Element<'a>) -> VNode<'a>
|
||||
// where
|
||||
// F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
lazy_nodes.into_vnode(NodeFactory::new(&self.bump))
|
||||
}
|
||||
|
||||
pub fn render<'a, F>(&'a self, lazy_nodes: LazyNodes<'a, F>) -> &'a VNode<'a>
|
||||
where
|
||||
F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
pub fn render<'a>(&'a self, lazy_nodes: Element<'a>) -> &'a VNode<'a>
|
||||
// where
|
||||
// F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
self.bump
|
||||
.alloc(lazy_nodes.into_vnode(NodeFactory::new(&self.bump)))
|
||||
@@ -43,9 +43,10 @@ impl TestDom {
|
||||
machine.mutations
|
||||
}
|
||||
|
||||
pub fn create<'a, F1>(&'a self, left: LazyNodes<'a, F1>) -> Mutations<'a>
|
||||
where
|
||||
F1: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
pub fn create<'a>(&'a self, left: Element<'a>) -> Mutations<'a>
|
||||
// pub fn create<'a, F1>(&'a self, left: LazyNodes<'a, F1>) -> Mutations<'a>
|
||||
// where
|
||||
// F1: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
let old = self.bump.alloc(self.render_direct(left));
|
||||
|
||||
@@ -58,14 +59,16 @@ impl TestDom {
|
||||
machine.mutations
|
||||
}
|
||||
|
||||
pub fn lazy_diff<'a, F1, F2>(
|
||||
pub fn lazy_diff<'a>(
|
||||
&'a self,
|
||||
left: LazyNodes<'a, F1>,
|
||||
right: LazyNodes<'a, F2>,
|
||||
left: Element<'a>,
|
||||
right: Element<'a>,
|
||||
// left: LazyNodes<'a, F1>,
|
||||
// right: LazyNodes<'a, F2>,
|
||||
) -> (Mutations<'a>, Mutations<'a>)
|
||||
where
|
||||
F1: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
F2: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
// where
|
||||
// F1: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
// F2: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
let (old, new) = (self.render(left), self.render(right));
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ impl VirtualDom {
|
||||
|
||||
let _p = root_props.clone();
|
||||
// Safety: this callback is only valid for the lifetime of the root props
|
||||
let root_caller: Rc<dyn Fn(&Scope) -> DomTree> = Rc::new(move |scope: &Scope| unsafe {
|
||||
let root_caller: Rc<dyn Fn(&Scope) -> Element> = Rc::new(move |scope: &Scope| unsafe {
|
||||
let props = _p.downcast_ref::<P>().unwrap();
|
||||
std::mem::transmute(root((Context { scope }, props)))
|
||||
});
|
||||
@@ -219,7 +219,7 @@ impl VirtualDom {
|
||||
|
||||
let root = *self.root_fc.downcast_ref::<FC<P>>().unwrap();
|
||||
|
||||
let root_caller: Box<dyn Fn(&Scope) -> DomTree> =
|
||||
let root_caller: Box<dyn Fn(&Scope) -> Element> =
|
||||
Box::new(move |scope: &Scope| unsafe {
|
||||
let props: &'_ P = &*(props_ptr as *const P);
|
||||
std::mem::transmute(root((Context { scope }, props)))
|
||||
@@ -368,22 +368,24 @@ impl VirtualDom {
|
||||
use futures_util::StreamExt;
|
||||
|
||||
// Wait for any new events if we have nothing to do
|
||||
futures_util::select! {
|
||||
_ = self.scheduler.async_tasks.next() => {}
|
||||
msg = self.scheduler.receiver.next() => {
|
||||
match msg.unwrap() {
|
||||
SchedulerMsg::Task(t) => {
|
||||
self.scheduler.handle_task(t);
|
||||
},
|
||||
SchedulerMsg::Immediate(im) => {
|
||||
self.scheduler.dirty_scopes.insert(im);
|
||||
}
|
||||
SchedulerMsg::UiEvent(evt) => {
|
||||
self.scheduler.ui_events.push_back(evt);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
todo!("wait for work without select macro")
|
||||
|
||||
// futures_util::select! {
|
||||
// _ = self.scheduler.async_tasks.next() => {}
|
||||
// msg = self.scheduler.receiver.next() => {
|
||||
// match msg.unwrap() {
|
||||
// SchedulerMsg::Task(t) => {
|
||||
// self.scheduler.handle_task(t);
|
||||
// },
|
||||
// SchedulerMsg::Immediate(im) => {
|
||||
// self.scheduler.dirty_scopes.insert(im);
|
||||
// }
|
||||
// SchedulerMsg::UiEvent(evt) => {
|
||||
// self.scheduler.ui_events.push_back(evt);
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,4 +410,4 @@ impl std::fmt::Display for VirtualDom {
|
||||
}
|
||||
|
||||
// we never actually use the contents of this root caller
|
||||
struct RootCaller(Rc<dyn for<'b> Fn(&'b Scope) -> DomTree<'b> + 'static>);
|
||||
struct RootCaller(Rc<dyn for<'b> Fn(&'b Scope) -> Element<'b> + 'static>);
|
||||
Reference in new issue
Block a user