wip: move everything over to a stack dst

This commit is contained in:
Jonathan Kelley committed 2021-10-29 17:12:30 -04:00
1 parent 12a9758c3c
commit 0e9d5fc530
36 files changed
+224 -185

No files matched your search

+6 -3
View File
@@ -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
+1 -4
View File
@@ -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 }))
}
+10 -8
View File
@@ -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 }))
}
}
+5 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
// }
}
}
+18 -15
View File
@@ -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));
+21 -19
View File
@@ -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>);