mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 12:43:08 +00:00
feat: poll async once
This commit is contained in:
parent
94601ccd1f
commit
d2ce57ba6e
9 changed files with 150 additions and 67 deletions
|
@ -3,20 +3,20 @@ use std::marker::PhantomData;
|
|||
use futures_util::Future;
|
||||
|
||||
use crate::{
|
||||
factory::ReturnType,
|
||||
factory::{ComponentReturn, RenderReturn},
|
||||
scopes::{Scope, ScopeState},
|
||||
Element,
|
||||
};
|
||||
|
||||
pub trait AnyProps<'a> {
|
||||
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;
|
||||
}
|
||||
|
||||
pub(crate) struct VComponentProps<'a, P, A, F = Element<'a>>
|
||||
where
|
||||
F: ReturnType<'a, A>,
|
||||
F: ComponentReturn<'a, A>,
|
||||
{
|
||||
pub render_fn: fn(Scope<'a, P>) -> F,
|
||||
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(
|
||||
render_fn: fn(Scope<'a, P>) -> F,
|
||||
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 () {
|
||||
&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)
|
||||
}
|
||||
|
||||
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
|
||||
// self.props.state.set(scope);
|
||||
|
||||
let scope = Scope {
|
||||
props: unsafe { &*self.props },
|
||||
scope,
|
||||
scope: cx,
|
||||
};
|
||||
|
||||
// Call the render function directly
|
||||
// todo: implement async
|
||||
// let res = match self.render_fn {
|
||||
// ComponentFn::Sync(f) => {
|
||||
// let f = unsafe { std::mem::transmute(f) };
|
||||
// f(scope)
|
||||
// }
|
||||
// ComponentFn::Async(_) => todo!(),
|
||||
// };
|
||||
|
||||
todo!()
|
||||
(self.render_fn)(scope).as_return(cx)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,23 +2,23 @@ use std::cell::Cell;
|
|||
|
||||
use bumpalo::Bump;
|
||||
|
||||
use crate::nodes::VNode;
|
||||
use crate::factory::RenderReturn;
|
||||
|
||||
pub struct BumpFrame {
|
||||
pub bump: Bump,
|
||||
pub node: Cell<*const VNode<'static>>,
|
||||
pub node: Cell<*mut RenderReturn<'static>>,
|
||||
}
|
||||
impl BumpFrame {
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
let bump = Bump::with_capacity(capacity);
|
||||
Self {
|
||||
bump,
|
||||
node: Cell::new(std::ptr::null()),
|
||||
node: Cell::new(std::ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.bump.reset();
|
||||
self.node.set(std::ptr::null());
|
||||
self.node.set(std::ptr::null_mut());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::nodes::VNode;
|
||||
use crate::nodes::{DynamicNode, TemplateNode};
|
||||
use crate::virtualdom::VirtualDom;
|
||||
use crate::{AttributeValue, ElementId, TemplateAttribute};
|
||||
use crate::{AttributeValue, Element, ElementId, TemplateAttribute};
|
||||
|
||||
impl VirtualDom {
|
||||
/// 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) {
|
||||
let node = &template.dynamic_nodes[idx];
|
||||
let m = self.create_dynamic_node(mutations, template, node, idx);
|
||||
mutations.push(ReplacePlaceholder {
|
||||
m,
|
||||
path: &path[1..],
|
||||
});
|
||||
if m > 0 {
|
||||
mutations.push(ReplacePlaceholder {
|
||||
m,
|
||||
path: &path[1..],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,16 +180,53 @@ impl VirtualDom {
|
|||
DynamicNode::Component { props, .. } => {
|
||||
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
|
||||
let template: &VNode = unsafe { std::mem::transmute(template) };
|
||||
let render_ret: &mut RenderReturn = unsafe { std::mem::transmute(render_ret) };
|
||||
|
||||
self.scope_stack.push(id);
|
||||
let created = self.create(mutations, template);
|
||||
self.scope_stack.pop();
|
||||
match render_ret {
|
||||
RenderReturn::Sync(Some(template)) => {
|
||||
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
|
||||
|
|
|
@ -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 futures_util::Future;
|
||||
|
||||
|
@ -70,7 +71,7 @@ impl ScopeState {
|
|||
}
|
||||
|
||||
/// 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,
|
||||
component: fn(Scope<'a, P>) -> F,
|
||||
props: P,
|
||||
|
@ -100,11 +101,27 @@ impl ScopeState {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ReturnType<'a, A = ()> {}
|
||||
impl<'a> ReturnType<'a> for Element<'a> {}
|
||||
pub trait ComponentReturn<'a, 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;
|
||||
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]
|
||||
fn takes_it() {
|
||||
|
@ -113,9 +130,9 @@ fn takes_it() {
|
|||
}
|
||||
}
|
||||
|
||||
enum RenderReturn<'a> {
|
||||
pub enum RenderReturn<'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 = ()> {
|
||||
|
|
|
@ -132,19 +132,3 @@ macro_rules! 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,
|
||||
arena::ElementId,
|
||||
bump_frame::BumpFrame,
|
||||
factory::RenderReturn,
|
||||
nodes::VNode,
|
||||
scopes::{ScopeId, ScopeState},
|
||||
virtualdom::VirtualDom,
|
||||
|
@ -48,15 +49,15 @@ impl VirtualDom {
|
|||
.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];
|
||||
scope.hook_idx.set(0);
|
||||
|
||||
let res = {
|
||||
let props = unsafe { &mut *scope.props };
|
||||
let props: &mut dyn AnyProps = unsafe { std::mem::transmute(props) };
|
||||
let res: VNode = props.render(scope).unwrap();
|
||||
let res: VNode<'static> = unsafe { std::mem::transmute(res) };
|
||||
let res: RenderReturn = props.render(scope);
|
||||
let res: RenderReturn<'static> = unsafe { std::mem::transmute(res) };
|
||||
res
|
||||
};
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::any_props::VComponentProps;
|
|||
use crate::arena::ElementPath;
|
||||
use crate::component::Component;
|
||||
use crate::diff::DirtyScope;
|
||||
use crate::factory::RenderReturn;
|
||||
use crate::future_container::FutureQueue;
|
||||
use crate::innerlude::SchedulerMsg;
|
||||
use crate::mutations::Mutation;
|
||||
|
@ -57,13 +58,17 @@ impl VirtualDom {
|
|||
pub fn rebuild<'a>(&'a mut self, mutations: &mut Vec<Mutation<'a>>) {
|
||||
// let root = self.scopes.get(0).unwrap();
|
||||
|
||||
let root_node = unsafe { std::mem::transmute(self.run_scope(ScopeId(0))) };
|
||||
|
||||
// let root_node = unsafe { std::mem::transmute(root.root_node()) };
|
||||
|
||||
self.scope_stack.push(ScopeId(0));
|
||||
self.create(mutations, root_node);
|
||||
self.scope_stack.pop();
|
||||
let root_node: &RenderReturn = self.run_scope(ScopeId(0));
|
||||
let root_node: &RenderReturn = unsafe { std::mem::transmute(root_node) };
|
||||
match root_node {
|
||||
RenderReturn::Sync(Some(node)) => {
|
||||
self.scope_stack.push(ScopeId(0));
|
||||
self.create(mutations, node);
|
||||
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
|
||||
|
|
|
@ -110,6 +110,9 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
|
|||
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)| {
|
||||
context.current_path.push(idx as u8);
|
||||
let out = context.render_static_node(root);
|
||||
|
@ -126,7 +129,15 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
|
|||
|
||||
out_tokens.append_all(quote! {
|
||||
static TEMPLATE: ::dioxus::core::Template = ::dioxus::core::Template {
|
||||
id: ::dioxus::core::get_line_num!(),
|
||||
id: concat!(
|
||||
file!(),
|
||||
":",
|
||||
line!(),
|
||||
":",
|
||||
column!(),
|
||||
":",
|
||||
#root_col
|
||||
),
|
||||
roots: &[ #roots ],
|
||||
node_paths: &[ #(#node_paths),* ],
|
||||
attr_paths: &[ #(#attr_paths),* ],
|
||||
|
|
|
@ -131,7 +131,7 @@ impl SsrRender {
|
|||
// todo: escape the text
|
||||
write!(buf, "{}", value)?
|
||||
}
|
||||
DynamicNode::Fragment { children } => {
|
||||
DynamicNode::Fragment(children) => {
|
||||
for child in *children {
|
||||
self.render_template(buf, child)?;
|
||||
}
|
||||
|
@ -140,6 +140,9 @@ impl SsrRender {
|
|||
DynamicNode::Component { .. } => {
|
||||
//
|
||||
}
|
||||
DynamicNode::Placeholder(el) => {
|
||||
//
|
||||
}
|
||||
},
|
||||
|
||||
Segment::PreRendered(text) => buf.push_str(&text),
|
||||
|
@ -217,3 +220,29 @@ fn children_processes_properly() {
|
|||
dom.rebuild(&mut 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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue