feat: poll async once
This commit is contained in:
1 parent
94601ccd1f
commit
d2ce57ba6e
9 files changed
+150
-67
No files matched your search
@@ -3,20 +3,20 @@ use std::marker::PhantomData;
|
|||||||
use futures_util::Future;
|
use futures_util::Future;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
factory::ReturnType,
|
factory::{ComponentReturn, RenderReturn},
|
||||||
scopes::{Scope, ScopeState},
|
scopes::{Scope, ScopeState},
|
||||||
Element,
|
Element,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait AnyProps<'a> {
|
pub trait AnyProps<'a> {
|
||||||
fn as_ptr(&self) -> *const ();
|
fn as_ptr(&self) -> *const ();
|
||||||
fn render(&'a self, bump: &'a ScopeState) -> Element<'a>;
|
fn render(&'a self, bump: &'a ScopeState) -> RenderReturn<'a>;
|
||||||
unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
|
unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct VComponentProps<'a, P, A, F = Element<'a>>
|
pub(crate) struct VComponentProps<'a, P, A, F = Element<'a>>
|
||||||
where
|
where
|
||||||
F: ReturnType<'a, A>,
|
F: ComponentReturn<'a, A>,
|
||||||
{
|
{
|
||||||
pub render_fn: fn(Scope<'a, P>) -> F,
|
pub render_fn: fn(Scope<'a, P>) -> F,
|
||||||
pub memo: unsafe fn(&P, &P) -> bool,
|
pub memo: unsafe fn(&P, &P) -> bool,
|
||||||
@@ -35,7 +35,7 @@ impl<'a> VComponentProps<'a, (), ()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, P, A, F: ReturnType<'a, A>> VComponentProps<'a, P, A, F> {
|
impl<'a, P, A, F: ComponentReturn<'a, A>> VComponentProps<'a, P, A, F> {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
render_fn: fn(Scope<'a, P>) -> F,
|
render_fn: fn(Scope<'a, P>) -> F,
|
||||||
memo: unsafe fn(&P, &P) -> bool,
|
memo: unsafe fn(&P, &P) -> bool,
|
||||||
@@ -50,7 +50,7 @@ impl<'a, P, A, F: ReturnType<'a, A>> VComponentProps<'a, P, A, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, P, A, F: ReturnType<'a, A>> AnyProps<'a> for VComponentProps<'a, P, A, F> {
|
impl<'a, P, A, F: ComponentReturn<'a, A>> AnyProps<'a> for VComponentProps<'a, P, A, F> {
|
||||||
fn as_ptr(&self) -> *const () {
|
fn as_ptr(&self) -> *const () {
|
||||||
&self.props as *const _ as *const ()
|
&self.props as *const _ as *const ()
|
||||||
}
|
}
|
||||||
@@ -65,25 +65,16 @@ impl<'a, P, A, F: ReturnType<'a, A>> AnyProps<'a> for VComponentProps<'a, P, A,
|
|||||||
(self.memo)(real_us, real_other)
|
(self.memo)(real_us, real_other)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render<'b>(&'b self, scope: &'b ScopeState) -> Element<'b> {
|
fn render(&self, cx: &'a ScopeState) -> RenderReturn<'a> {
|
||||||
// Make sure the scope ptr is not null
|
// Make sure the scope ptr is not null
|
||||||
// self.props.state.set(scope);
|
// self.props.state.set(scope);
|
||||||
|
|
||||||
let scope = Scope {
|
let scope = Scope {
|
||||||
props: unsafe { &*self.props },
|
props: unsafe { &*self.props },
|
||||||
scope,
|
scope: cx,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Call the render function directly
|
// Call the render function directly
|
||||||
// todo: implement async
|
(self.render_fn)(scope).as_return(cx)
|
||||||
// let res = match self.render_fn {
|
|
||||||
// ComponentFn::Sync(f) => {
|
|
||||||
// let f = unsafe { std::mem::transmute(f) };
|
|
||||||
// f(scope)
|
|
||||||
// }
|
|
||||||
// ComponentFn::Async(_) => todo!(),
|
|
||||||
// };
|
|
||||||
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,23 +2,23 @@ use std::cell::Cell;
|
|||||||
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
|
||||||
use crate::nodes::VNode;
|
use crate::factory::RenderReturn;
|
||||||
|
|
||||||
pub struct BumpFrame {
|
pub struct BumpFrame {
|
||||||
pub bump: Bump,
|
pub bump: Bump,
|
||||||
pub node: Cell<*const VNode<'static>>,
|
pub node: Cell<*mut RenderReturn<'static>>,
|
||||||
}
|
}
|
||||||
impl BumpFrame {
|
impl BumpFrame {
|
||||||
pub fn new(capacity: usize) -> Self {
|
pub fn new(capacity: usize) -> Self {
|
||||||
let bump = Bump::with_capacity(capacity);
|
let bump = Bump::with_capacity(capacity);
|
||||||
Self {
|
Self {
|
||||||
bump,
|
bump,
|
||||||
node: Cell::new(std::ptr::null()),
|
node: Cell::new(std::ptr::null_mut()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.bump.reset();
|
self.bump.reset();
|
||||||
self.node.set(std::ptr::null());
|
self.node.set(std::ptr::null_mut());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+56
-11
@@ -1,9 +1,15 @@
|
|||||||
|
use std::task::Context;
|
||||||
|
|
||||||
|
use futures_util::task::noop_waker_ref;
|
||||||
|
use futures_util::{pin_mut, Future};
|
||||||
|
|
||||||
|
use crate::factory::RenderReturn;
|
||||||
use crate::mutations::Mutation;
|
use crate::mutations::Mutation;
|
||||||
use crate::mutations::Mutation::*;
|
use crate::mutations::Mutation::*;
|
||||||
use crate::nodes::VNode;
|
use crate::nodes::VNode;
|
||||||
use crate::nodes::{DynamicNode, TemplateNode};
|
use crate::nodes::{DynamicNode, TemplateNode};
|
||||||
use crate::virtualdom::VirtualDom;
|
use crate::virtualdom::VirtualDom;
|
||||||
use crate::{AttributeValue, ElementId, TemplateAttribute};
|
use crate::{AttributeValue, Element, ElementId, TemplateAttribute};
|
||||||
|
|
||||||
impl VirtualDom {
|
impl VirtualDom {
|
||||||
/// Create this template and write its mutations
|
/// Create this template and write its mutations
|
||||||
@@ -96,10 +102,12 @@ impl VirtualDom {
|
|||||||
while let Some((idx, path)) = dynamic_nodes.next_if(|(_, p)| p[0] == root_idx as u8) {
|
while let Some((idx, path)) = dynamic_nodes.next_if(|(_, p)| p[0] == root_idx as u8) {
|
||||||
let node = &template.dynamic_nodes[idx];
|
let node = &template.dynamic_nodes[idx];
|
||||||
let m = self.create_dynamic_node(mutations, template, node, idx);
|
let m = self.create_dynamic_node(mutations, template, node, idx);
|
||||||
mutations.push(ReplacePlaceholder {
|
if m > 0 {
|
||||||
m,
|
mutations.push(ReplacePlaceholder {
|
||||||
path: &path[1..],
|
m,
|
||||||
});
|
path: &path[1..],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,16 +180,53 @@ impl VirtualDom {
|
|||||||
DynamicNode::Component { props, .. } => {
|
DynamicNode::Component { props, .. } => {
|
||||||
let id = self.new_scope(unsafe { std::mem::transmute(props.get()) });
|
let id = self.new_scope(unsafe { std::mem::transmute(props.get()) });
|
||||||
|
|
||||||
let template = self.run_scope(id);
|
let render_ret = self.run_scope(id);
|
||||||
|
|
||||||
// shut up about lifetimes please, I know what I'm doing
|
// shut up about lifetimes please, I know what I'm doing
|
||||||
let template: &VNode = unsafe { std::mem::transmute(template) };
|
let render_ret: &mut RenderReturn = unsafe { std::mem::transmute(render_ret) };
|
||||||
|
|
||||||
self.scope_stack.push(id);
|
match render_ret {
|
||||||
let created = self.create(mutations, template);
|
RenderReturn::Sync(Some(template)) => {
|
||||||
self.scope_stack.pop();
|
self.scope_stack.push(id);
|
||||||
|
let created = self.create(mutations, template);
|
||||||
|
self.scope_stack.pop();
|
||||||
|
created
|
||||||
|
}
|
||||||
|
RenderReturn::Sync(None) => todo!("nodes that return nothing"),
|
||||||
|
RenderReturn::Async(fut) => {
|
||||||
|
use futures_util::FutureExt;
|
||||||
|
|
||||||
created
|
// Poll the suspense node once to see if we can get any nodes from it
|
||||||
|
let mut cx = Context::from_waker(&noop_waker_ref());
|
||||||
|
let res = fut.poll_unpin(&mut cx);
|
||||||
|
|
||||||
|
match res {
|
||||||
|
std::task::Poll::Ready(Some(val)) => {
|
||||||
|
let scope = self.get_scope(id).unwrap();
|
||||||
|
let ready = &*scope.bump().alloc(val);
|
||||||
|
let ready = unsafe { std::mem::transmute(ready) };
|
||||||
|
|
||||||
|
self.scope_stack.push(id);
|
||||||
|
let created = self.create(mutations, ready);
|
||||||
|
self.scope_stack.pop();
|
||||||
|
created
|
||||||
|
}
|
||||||
|
std::task::Poll::Ready(None) => {
|
||||||
|
todo!("Pending suspense")
|
||||||
|
}
|
||||||
|
std::task::Poll::Pending => {
|
||||||
|
let new_id = self.next_element(template);
|
||||||
|
// id.set(new_id);
|
||||||
|
mutations.push(AssignId {
|
||||||
|
id: new_id,
|
||||||
|
path: &template.template.node_paths[idx][1..],
|
||||||
|
});
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicNode::Fragment(children) => children
|
DynamicNode::Fragment(children) => children
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::{cell::Cell, fmt::Arguments};
|
use std::{cell::Cell, fmt::Arguments, pin::Pin};
|
||||||
|
|
||||||
|
use bumpalo::boxed::Box as BumpBox;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use futures_util::Future;
|
use futures_util::Future;
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ impl ScopeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new [`VNode::Component`]
|
/// Create a new [`VNode::Component`]
|
||||||
pub fn component<'a, P, A, F: ReturnType<'a, A>>(
|
pub fn component<'a, P, A, F: ComponentReturn<'a, A>>(
|
||||||
&'a self,
|
&'a self,
|
||||||
component: fn(Scope<'a, P>) -> F,
|
component: fn(Scope<'a, P>) -> F,
|
||||||
props: P,
|
props: P,
|
||||||
@@ -100,11 +101,27 @@ impl ScopeState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ReturnType<'a, A = ()> {}
|
pub trait ComponentReturn<'a, A = ()> {
|
||||||
impl<'a> ReturnType<'a> for Element<'a> {}
|
fn as_return(self, cx: &'a ScopeState) -> RenderReturn<'a>;
|
||||||
|
}
|
||||||
|
impl<'a> ComponentReturn<'a> for Element<'a> {
|
||||||
|
fn as_return(self, _cx: &ScopeState) -> RenderReturn<'a> {
|
||||||
|
RenderReturn::Sync(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct AsyncMarker;
|
pub struct AsyncMarker;
|
||||||
impl<'a, F> ReturnType<'a, AsyncMarker> for F where F: Future<Output = Element<'a>> + 'a {}
|
impl<'a, F> ComponentReturn<'a, AsyncMarker> for F
|
||||||
|
where
|
||||||
|
F: Future<Output = Element<'a>> + 'a,
|
||||||
|
{
|
||||||
|
fn as_return(self, cx: &'a ScopeState) -> RenderReturn<'a> {
|
||||||
|
let f: &mut dyn Future<Output = Element<'a>> = cx.bump().alloc(self);
|
||||||
|
let boxed = unsafe { BumpBox::from_raw(f) };
|
||||||
|
let pined: Pin<BumpBox<_>> = boxed.into();
|
||||||
|
RenderReturn::Async(pined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn takes_it() {
|
fn takes_it() {
|
||||||
@@ -113,9 +130,9 @@ fn takes_it() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RenderReturn<'a> {
|
pub enum RenderReturn<'a> {
|
||||||
Sync(Element<'a>),
|
Sync(Element<'a>),
|
||||||
Async(*mut dyn Future<Output = Element<'a>>),
|
Async(Pin<BumpBox<'a, dyn Future<Output = Element<'a>> + 'a>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IntoVnode<'a, A = ()> {
|
pub trait IntoVnode<'a, A = ()> {
|
||||||
|
|||||||
@@ -132,19 +132,3 @@ macro_rules! to_owned {
|
|||||||
let mut $es = $es.to_owned();
|
let mut $es = $es.to_owned();
|
||||||
)*}
|
)*}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get the code location of the code that called this function
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! get_line_num {
|
|
||||||
() => {
|
|
||||||
concat!(
|
|
||||||
file!(),
|
|
||||||
":",
|
|
||||||
line!(),
|
|
||||||
":",
|
|
||||||
column!(),
|
|
||||||
":",
|
|
||||||
env!("CARGO_MANIFEST_DIR")
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@ use crate::{
|
|||||||
any_props::AnyProps,
|
any_props::AnyProps,
|
||||||
arena::ElementId,
|
arena::ElementId,
|
||||||
bump_frame::BumpFrame,
|
bump_frame::BumpFrame,
|
||||||
|
factory::RenderReturn,
|
||||||
nodes::VNode,
|
nodes::VNode,
|
||||||
scopes::{ScopeId, ScopeState},
|
scopes::{ScopeId, ScopeState},
|
||||||
virtualdom::VirtualDom,
|
virtualdom::VirtualDom,
|
||||||
@@ -48,15 +49,15 @@ impl VirtualDom {
|
|||||||
.and_then(|id| self.scopes.get_mut(id.0).map(|f| f as *mut ScopeState))
|
.and_then(|id| self.scopes.get_mut(id.0).map(|f| f as *mut ScopeState))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_scope(&mut self, id: ScopeId) -> &VNode {
|
pub fn run_scope(&mut self, id: ScopeId) -> &mut RenderReturn {
|
||||||
let scope = &mut self.scopes[id.0];
|
let scope = &mut self.scopes[id.0];
|
||||||
scope.hook_idx.set(0);
|
scope.hook_idx.set(0);
|
||||||
|
|
||||||
let res = {
|
let res = {
|
||||||
let props = unsafe { &mut *scope.props };
|
let props = unsafe { &mut *scope.props };
|
||||||
let props: &mut dyn AnyProps = unsafe { std::mem::transmute(props) };
|
let props: &mut dyn AnyProps = unsafe { std::mem::transmute(props) };
|
||||||
let res: VNode = props.render(scope).unwrap();
|
let res: RenderReturn = props.render(scope);
|
||||||
let res: VNode<'static> = unsafe { std::mem::transmute(res) };
|
let res: RenderReturn<'static> = unsafe { std::mem::transmute(res) };
|
||||||
res
|
res
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::any_props::VComponentProps;
|
|||||||
use crate::arena::ElementPath;
|
use crate::arena::ElementPath;
|
||||||
use crate::component::Component;
|
use crate::component::Component;
|
||||||
use crate::diff::DirtyScope;
|
use crate::diff::DirtyScope;
|
||||||
|
use crate::factory::RenderReturn;
|
||||||
use crate::future_container::FutureQueue;
|
use crate::future_container::FutureQueue;
|
||||||
use crate::innerlude::SchedulerMsg;
|
use crate::innerlude::SchedulerMsg;
|
||||||
use crate::mutations::Mutation;
|
use crate::mutations::Mutation;
|
||||||
@@ -57,13 +58,17 @@ impl VirtualDom {
|
|||||||
pub fn rebuild<'a>(&'a mut self, mutations: &mut Vec<Mutation<'a>>) {
|
pub fn rebuild<'a>(&'a mut self, mutations: &mut Vec<Mutation<'a>>) {
|
||||||
// let root = self.scopes.get(0).unwrap();
|
// let root = self.scopes.get(0).unwrap();
|
||||||
|
|
||||||
let root_node = unsafe { std::mem::transmute(self.run_scope(ScopeId(0))) };
|
let root_node: &RenderReturn = self.run_scope(ScopeId(0));
|
||||||
|
let root_node: &RenderReturn = unsafe { std::mem::transmute(root_node) };
|
||||||
// let root_node = unsafe { std::mem::transmute(root.root_node()) };
|
match root_node {
|
||||||
|
RenderReturn::Sync(Some(node)) => {
|
||||||
self.scope_stack.push(ScopeId(0));
|
self.scope_stack.push(ScopeId(0));
|
||||||
self.create(mutations, root_node);
|
self.create(mutations, node);
|
||||||
self.scope_stack.pop();
|
self.scope_stack.pop();
|
||||||
|
}
|
||||||
|
RenderReturn::Sync(None) => todo!("Handle empty root node"),
|
||||||
|
RenderReturn::Async(_) => unreachable!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render what you can given the timeline and then move on
|
/// Render what you can given the timeline and then move on
|
||||||
|
|||||||
+12
-1
@@ -110,6 +110,9 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
|
|||||||
None => quote! { None },
|
None => quote! { None },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let spndbg = format!("{:?}", self.roots[0].span());
|
||||||
|
let root_col = spndbg[9..].split("..").next().unwrap();
|
||||||
|
|
||||||
let root_printer = self.roots.iter().enumerate().map(|(idx, root)| {
|
let root_printer = self.roots.iter().enumerate().map(|(idx, root)| {
|
||||||
context.current_path.push(idx as u8);
|
context.current_path.push(idx as u8);
|
||||||
let out = context.render_static_node(root);
|
let out = context.render_static_node(root);
|
||||||
@@ -126,7 +129,15 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
|
|||||||
|
|
||||||
out_tokens.append_all(quote! {
|
out_tokens.append_all(quote! {
|
||||||
static TEMPLATE: ::dioxus::core::Template = ::dioxus::core::Template {
|
static TEMPLATE: ::dioxus::core::Template = ::dioxus::core::Template {
|
||||||
id: ::dioxus::core::get_line_num!(),
|
id: concat!(
|
||||||
|
file!(),
|
||||||
|
":",
|
||||||
|
line!(),
|
||||||
|
":",
|
||||||
|
column!(),
|
||||||
|
":",
|
||||||
|
#root_col
|
||||||
|
),
|
||||||
roots: &[ #roots ],
|
roots: &[ #roots ],
|
||||||
node_paths: &[ #(#node_paths),* ],
|
node_paths: &[ #(#node_paths),* ],
|
||||||
attr_paths: &[ #(#attr_paths),* ],
|
attr_paths: &[ #(#attr_paths),* ],
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ impl SsrRender {
|
|||||||
// todo: escape the text
|
// todo: escape the text
|
||||||
write!(buf, "{}", value)?
|
write!(buf, "{}", value)?
|
||||||
}
|
}
|
||||||
DynamicNode::Fragment { children } => {
|
DynamicNode::Fragment(children) => {
|
||||||
for child in *children {
|
for child in *children {
|
||||||
self.render_template(buf, child)?;
|
self.render_template(buf, child)?;
|
||||||
}
|
}
|
||||||
@@ -140,6 +140,9 @@ impl SsrRender {
|
|||||||
DynamicNode::Component { .. } => {
|
DynamicNode::Component { .. } => {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
DynamicNode::Placeholder(el) => {
|
||||||
|
//
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Segment::PreRendered(text) => buf.push_str(&text),
|
Segment::PreRendered(text) => buf.push_str(&text),
|
||||||
@@ -217,3 +220,29 @@ fn children_processes_properly() {
|
|||||||
dom.rebuild(&mut mutations);
|
dom.rebuild(&mut mutations);
|
||||||
dbg!(mutations);
|
dbg!(mutations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn async_children() {
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
fn app(cx: Scope) -> Element {
|
||||||
|
let d = 123;
|
||||||
|
|
||||||
|
render! {
|
||||||
|
div {
|
||||||
|
async_child {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn async_child(cx: Scope<'_>) -> Element {
|
||||||
|
let d = 123;
|
||||||
|
render! { p { "{d}" "hii" } }
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dom = VirtualDom::new(app);
|
||||||
|
|
||||||
|
let mut mutations = vec![];
|
||||||
|
dom.rebuild(&mut mutations);
|
||||||
|
dbg!(mutations);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user