feat: task system works

but I broke the other things :(
This commit is contained in:
Jonathan Kelley committed 2021-07-14 02:04:19 -04:00
1 parent 84c3e9fcb1
commit 3a57b94262
12 files changed
+251 -181

No files matched your search

+17 -17
View File
@@ -23,11 +23,11 @@ default = [
"macro", "macro",
"hooks", "hooks",
"html", "html",
"ssr",
"web",
"desktop",
# "atoms", # "atoms",
# "ssr",
# "router", # "router",
# "web",
# "desktop",
] ]
atoms = [] atoms = []
macro = ["dioxus-core-macro"] macro = ["dioxus-core-macro"]
@@ -43,17 +43,17 @@ core = []
[dev-dependencies] [dev-dependencies]
# futures = "0.3.15" futures = "0.3.15"
# log = "0.4.14" log = "0.4.14"
# num-format = "0.4.0" num-format = "0.4.0"
# separator = "0.4.1" separator = "0.4.1"
# serde = { version = "1.0.126", features = ["derive"] } serde = { version = "1.0.126", features = ["derive"] }
# surf = "2.2.0" surf = "2.2.0"
# env_logger = "*" env_logger = "*"
# async-std = { version = "1.9.0", features = ["attributes"] } async-std = { version = "1.9.0", features = ["attributes"] }
# im-rc = "15.0.0" im-rc = "15.0.0"
# rand = { version = "0.8.4", features = ["small_rng"] } rand = { version = "0.8.4", features = ["small_rng"] }
# fxhash = "0.2.1" fxhash = "0.2.1"
[workspace] [workspace]
@@ -62,9 +62,9 @@ members = [
"packages/core-macro", "packages/core-macro",
"packages/html", "packages/html",
"packages/hooks", "packages/hooks",
# "packages/web", "packages/web",
# "packages/webview", "packages/ssr",
# "packages/ssr", "packages/webview",
# "packages/atoms", # "packages/atoms",
# "packages/docsite", # "packages/docsite",
] ]
+1 -1
View File
@@ -1,3 +1,3 @@
{ {
"rust-analyzer.inlayHints.enable": false "rust-analyzer.inlayHints.enable": true
} }
+25 -18
View File
@@ -36,7 +36,6 @@ use std::{
pub struct Context<'src, T> { pub struct Context<'src, T> {
pub props: &'src T, pub props: &'src T,
pub scope: &'src Scope, pub scope: &'src Scope,
pub tasks: &'src RefCell<Vec<&'src mut dyn Future<Output = ()>>>,
} }
// pub type PinnedTask = Pin<Box<dyn Future<Output = ()>>>; // pub type PinnedTask = Pin<Box<dyn Future<Output = ()>>>;
@@ -46,7 +45,6 @@ impl<'src, T> Clone for Context<'src, T> {
Self { Self {
props: self.props, props: self.props,
scope: self.scope, scope: self.scope,
tasks: self.tasks,
} }
} }
} }
@@ -264,6 +262,9 @@ Any function prefixed with "use" should not be called conditionally.
/// ///
/// This is useful when you have some async task that needs to be progressed. /// This is useful when you have some async task that needs to be progressed.
/// ///
/// This method takes ownership over the task you've provided, and must return (). This means any work that needs to
/// happen must occur within the future or scheduled for after the future completes (through schedule_update )
///
/// ## Explanation /// ## Explanation
/// Dioxus will step its internal event loop if the future returns if the future completes while waiting. /// Dioxus will step its internal event loop if the future returns if the future completes while waiting.
/// ///
@@ -274,7 +275,9 @@ Any function prefixed with "use" should not be called conditionally.
/// ///
/// ///
/// ///
pub fn submit_task(&self, _task: Pin<Box<dyn Future<Output = ()>>>) -> TaskHandle { pub fn submit_task(&self, task: FiberTask) -> TaskHandle {
let r = (self.scope.task_submitter)(task);
// self.scope.submit_task(task);
// let r = task.then(|f| async { // let r = task.then(|f| async {
// // // //
// }); // });
@@ -284,7 +287,6 @@ Any function prefixed with "use" should not be called conditionally.
// t // t
// // () // // ()
// }); // });
todo!();
// let new_fut = task.then(|f| async { // let new_fut = task.then(|f| async {
// // // //
// () // ()
@@ -297,13 +299,12 @@ Any function prefixed with "use" should not be called conditionally.
/// Awaits the given task, forcing the component to re-render when the value is ready. /// Awaits the given task, forcing the component to re-render when the value is ready.
/// ///
/// ///
pub fn use_task<Out, Fut: 'static>( pub fn use_task<Out, Fut, Init>(&self, task_initializer: Init) -> &mut Option<Out>
&self,
task_initializer: impl FnOnce() -> Fut + 'src,
) -> &mut Option<Out>
where where
Out: 'static, Out: 'static,
Fut: Future<Output = Out>, Fut: Future<Output = Out>,
Fut: 'static,
Init: FnOnce() -> Fut + 'src,
{ {
struct TaskHook<T> { struct TaskHook<T> {
task_dump: Rc<RefCell<Option<T>>>, task_dump: Rc<RefCell<Option<T>>>,
@@ -318,9 +319,18 @@ Any function prefixed with "use" should not be called conditionally.
let task_dump = Rc::new(RefCell::new(None)); let task_dump = Rc::new(RefCell::new(None));
let slot = task_dump.clone(); let slot = task_dump.clone();
let update = self.schedule_update();
let originator = self.scope.arena_idx.clone();
self.submit_task(Box::pin(task_fut.then(move |output| async move { self.submit_task(Box::pin(task_fut.then(move |output| async move {
*slot.as_ref().borrow_mut() = Some(output); *slot.as_ref().borrow_mut() = Some(output);
update();
EventTrigger {
event: VirtualEvent::FiberEvent,
originator,
priority: EventPriority::Low,
real_node_id: None,
}
}))); })));
TaskHook { TaskHook {
@@ -340,29 +350,26 @@ Any function prefixed with "use" should not be called conditionally.
/// Asynchronously render new nodes once the given future has completed. /// Asynchronously render new nodes once the given future has completed.
/// ///
///
///
///
/// # Easda /// # Easda
/// ///
/// ///
///
///
/// # Example /// # Example
/// ///
pub fn suspend<Out, Fut: 'static>( ///
pub fn use_suspense<Out, Fut: 'static>(
&'src self, &'src self,
_task_initializer: impl FnOnce() -> Fut + 'src, _task_initializer: impl FnOnce() -> Fut,
_callback: impl FnOnce(SuspendedContext, Out) -> VNode<'src> + 'src, _callback: impl FnOnce(SuspendedContext, Out) -> VNode<'src> + 'src,
) -> VNode<'src> ) -> VNode<'src>
where where
Out: 'src, Out: 'src,
Fut: Future<Output = Out>, Fut: Future<Output = Out>,
{ {
// self.use_hook(|| , runner, cleanup)
todo!() todo!()
// use futures_util::FutureExt;
// match fut.now_or_never() {
// Some(out) => callback(SuspendedContext {}, out),
// None => NodeFactory::suspended(),
// }
} }
} }
+18 -16
View File
@@ -49,7 +49,7 @@
//! - 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::{arena::SharedArena, innerlude::*, tasks::TaskQueue}; use crate::{arena::SharedArena, innerlude::*, tasks::TaskQueue};
use fxhash::{FxHashSet}; use fxhash::FxHashSet;
use std::any::Any; use std::any::Any;
@@ -179,6 +179,7 @@ where
new_node.dom_id.set(root); new_node.dom_id.set(root);
// push it just in case // push it just in case
// TODO: remove this - it clogs up things and is inefficient
self.dom.push(root); self.dom.push(root);
self.diff_listeners(old.listeners, new.listeners); self.diff_listeners(old.listeners, new.listeners);
self.diff_attr(old.attributes, new.attributes, new.namespace); self.diff_attr(old.attributes, new.attributes, new.namespace);
@@ -311,9 +312,9 @@ where
// When we create new nodes, we need to propagate some information back up the call chain. // When we create new nodes, we need to propagate some information back up the call chain.
// This gives the caller some information on how to handle things like insertins, appending, and subtree discarding. // This gives the caller some information on how to handle things like insertins, appending, and subtree discarding.
struct CreateMeta { pub struct CreateMeta {
is_static: bool, pub is_static: bool,
added_to_stack: u32, pub added_to_stack: u32,
} }
impl CreateMeta { impl CreateMeta {
@@ -338,7 +339,7 @@ where
// When this function returns, the new node is on top of the change list stack: // When this function returns, the new node is on top of the change list stack:
// //
// [... node] // [... node]
fn create(&mut self, node: &'bump VNode<'bump>) -> CreateMeta { pub fn create(&mut self, node: &'bump VNode<'bump>) -> CreateMeta {
log::warn!("Creating node! ... {:#?}", node); log::warn!("Creating node! ... {:#?}", node);
match &node.kind { match &node.kind {
VNodeKind::Text(text) => { VNodeKind::Text(text) => {
@@ -373,6 +374,7 @@ where
node.dom_id.set(real_id); node.dom_id.set(real_id);
listeners.iter().enumerate().for_each(|(idx, listener)| { listeners.iter().enumerate().for_each(|(idx, listener)| {
log::info!("setting listener id to {:#?}", real_id);
listener.mounted_node.set(real_id); listener.mounted_node.set(real_id);
self.dom self.dom
.new_event_listener(listener.event, listener.scope, idx, real_id); .new_event_listener(listener.event, listener.scope, idx, real_id);
@@ -396,12 +398,12 @@ where
// Notice: this is a web-specific optimization and may be changed in the future // Notice: this is a web-specific optimization and may be changed in the future
// //
// TODO move over // TODO move over
if children.len() == 1 { // if children.len() == 1 {
if let VNodeKind::Text(text) = &children[0].kind { // if let VNodeKind::Text(text) = &children[0].kind {
self.dom.set_text(text.text); // self.dom.set_text(text.text);
return CreateMeta::new(is_static, 1); // return CreateMeta::new(is_static, 1);
} // }
} // }
for child in *children { for child in *children {
let child_meta = self.create(child); let child_meta = self.create(child);
@@ -411,11 +413,11 @@ where
self.dom.append_children(child_meta.added_to_stack); self.dom.append_children(child_meta.added_to_stack);
} }
if is_static { // if is_static {
log::debug!("created a static node {:#?}", node); // log::debug!("created a static node {:#?}", node);
} else { // } else {
log::debug!("created a dynamic node {:#?}", node); // log::debug!("created a dynamic node {:#?}", node);
} // }
// el_is_static.set(is_static); // el_is_static.set(is_static);
CreateMeta::new(is_static, 1) CreateMeta::new(is_static, 1)
+7 -7
View File
@@ -189,6 +189,13 @@ impl<'a> NodeFactory<'a> {
children: &'a [VNode<'a>], children: &'a [VNode<'a>],
key: Option<&'a str>, key: Option<&'a str>,
) -> VNode<'a> { ) -> VNode<'a> {
let mut queue = self.scope_ref.listeners.borrow_mut();
for listener in listeners {
let mounted = listener.mounted_node as *const _ as *mut _;
let callback = listener.callback as *const _ as *mut _;
queue.push((mounted, callback))
}
VNode { VNode {
dom_id: RealDomNode::empty_cell(), dom_id: RealDomNode::empty_cell(),
key, key,
@@ -285,20 +292,13 @@ impl<'a> NodeFactory<'a> {
let caller: Captured = Rc::new(move |scp: &Scope| -> VNode { let caller: Captured = Rc::new(move |scp: &Scope| -> VNode {
// cast back into the right lifetime // cast back into the right lifetime
let safe_props: &'_ P = unsafe { &*(raw_props as *const P) }; let safe_props: &'_ P = unsafe { &*(raw_props as *const P) };
let tasks = RefCell::new(Vec::new());
let cx: Context<P> = Context { let cx: Context<P> = Context {
props: safe_props, props: safe_props,
scope: scp, scope: scp,
tasks: &tasks,
}; };
let res = component(cx); let res = component(cx);
// submit any async tasks to the scope
for _task in tasks.borrow_mut().drain(..) {
// scp.submit_task(task);
}
let g2 = unsafe { std::mem::transmute(res) }; let g2 = unsafe { std::mem::transmute(res) };
g2 g2
+20 -2
View File
@@ -71,6 +71,8 @@ pub struct Scope {
pub(crate) suspended_tasks: Vec<*mut Pin<Box<dyn Future<Output = VNode<'static>>>>>, pub(crate) suspended_tasks: Vec<*mut Pin<Box<dyn Future<Output = VNode<'static>>>>>,
} }
pub type FiberTask = Pin<Box<dyn Future<Output = EventTrigger>>>;
impl Scope { impl Scope {
// we are being created in the scope of an existing component (where the creator_node lifetime comes into play) // 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. // we are going to break this lifetime by force in order to save it on ourselves.
@@ -148,6 +150,17 @@ impl Scope {
Ok(()) Ok(())
} }
/// Progress a suspended node
pub fn progress_suspended(&mut self) -> Result<()> {
// load the hook
// downcast to our special state
// run just this hook
// create a new vnode
// diff this new vnode with the original suspended vnode
Ok(())
}
// this is its own function so we can preciesly control how lifetimes flow // this is its own function so we can preciesly control how lifetimes flow
unsafe fn call_user_component<'a>(&'a self, caller: &WrappedCaller) -> VNode<'static> { unsafe fn call_user_component<'a>(&'a self, caller: &WrappedCaller) -> VNode<'static> {
let new_head: VNode<'a> = caller(self); let new_head: VNode<'a> = caller(self);
@@ -164,6 +177,11 @@ impl Scope {
.. ..
} = trigger; } = trigger;
if let &VirtualEvent::FiberEvent = &event {
log::info!("arrived a fiber event");
return Ok(());
}
// todo: implement scanning for outdated events // todo: implement scanning for outdated events
// Convert the raw ptr into an actual object // Convert the raw ptr into an actual object
@@ -200,9 +218,9 @@ impl Scope {
Ok(()) Ok(())
} }
pub fn submit_task(&self, task: &mut Pin<Box<dyn Future<Output = ()>>>) { pub fn submit_task(&self, task: FiberTask) {
log::debug!("Task submitted into scope"); log::debug!("Task submitted into scope");
(self.task_submitter)(DTask::new(task, self.arena_idx)); (self.task_submitter)(task);
} }
#[inline] #[inline]
+62 -57
View File
@@ -16,28 +16,28 @@ use std::{
task::{Context, Poll}, task::{Context, Poll},
}; };
use futures_util::{Future, Stream}; use futures_util::{stream::FuturesUnordered, Future, Stream, StreamExt};
use slotmap::{DefaultKey, SlotMap}; use slotmap::{DefaultKey, SlotMap};
use crate::{events::EventTrigger, innerlude::ScopeIdx}; use crate::innerlude::{EventTrigger, FiberTask, ScopeIdx};
pub type TaskSubmitter = Arc<dyn Fn(DTask)>; pub type TaskSubmitter = Arc<dyn Fn(FiberTask)>;
pub struct TaskQueue { pub struct TaskQueue {
slots: Arc<RwLock<SlotMap<DefaultKey, DTask>>>, slots: Arc<RwLock<FuturesUnordered<FiberTask>>>,
// slots: Arc<RwLock<SlotMap<DefaultKey, DTask>>>,
submitter: TaskSubmitter, submitter: TaskSubmitter,
} }
impl TaskQueue { impl TaskQueue {
pub fn new() -> Self { pub fn new() -> Self {
let slots = Arc::new(RwLock::new(SlotMap::new())); let slots = Arc::new(RwLock::new(FuturesUnordered::new()));
let slots2 = slots.clone(); let slots2 = slots.clone();
let submitter = Arc::new(move |task| { let submitter = Arc::new(move |task| {
let mut slots = slots2.write().unwrap(); let mut slots = slots2.write().unwrap();
log::debug!("Task submitted into global task queue"); log::debug!("Task submitted into global task queue");
slots.insert(task); slots.push(task);
}); });
Self { slots, submitter } Self { slots, submitter }
} }
@@ -46,9 +46,9 @@ impl TaskQueue {
self.submitter.clone() self.submitter.clone()
} }
pub fn submit_task(&mut self, task: DTask) -> TaskHandle { pub fn submit_task(&mut self, task: FiberTask) {
let key = self.slots.write().unwrap().insert(task); self.slots.write().unwrap().push(task);
TaskHandle { key } // TaskHandle { key }
} }
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
@@ -57,73 +57,78 @@ impl TaskQueue {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.slots.read().unwrap().len() self.slots.read().unwrap().len()
} }
}
impl Stream for TaskQueue {
type Item = EventTrigger;
/// We can never be finished polling
fn poll_next(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<Self::Item>> {
// let yield_every = self.len();
// let mut polled = 0;
pub async fn next(&mut self) -> Option<EventTrigger> {
let mut slots = self.slots.write().unwrap(); let mut slots = self.slots.write().unwrap();
for (_key, slot) in slots.iter_mut() { slots.next().await
if slot.dead.get() {
continue;
}
let r = slot.fut;
let fut = unsafe { &mut *r };
// use futures::{future::Future, poll, FutureExt};
let f2 = fut.as_mut();
let w = cx.waker();
let mut cx = Context::from_waker(&w);
// Pin::new_unchecked(pointer)
// use std::future::Future;
match f2.poll(&mut cx) {
Poll::Ready(_) => {
let trigger = EventTrigger::new_from_task(slot.originator);
slot.dead.set(true);
return Poll::Ready(Some(trigger));
}
Poll::Pending => continue,
}
}
// we tried polling every active task.
// give up and relinquish controlto the parent
// We have polled a large number of futures in a row without yielding.
// To ensure we do not starve other tasks waiting on the executor,
// we yield here, but immediately wake ourselves up to continue.
// cx.waker().wake_by_ref();
return Poll::Pending;
} }
} }
// impl Stream for TaskQueue {
// type Item = EventTrigger;
// /// We can never be finished polling
// fn poll_next(
// self: Pin<&mut Self>,
// cx: &mut std::task::Context<'_>,
// ) -> std::task::Poll<Option<Self::Item>> {
// // let yield_every = self.len();
// // let mut polled = 0;
// let mut slots = self.slots.write().unwrap();
// for (_key, slot) in slots.iter_mut() {
// if slot.dead.get() {
// continue;
// }
// let r = slot.fut;
// // let fut = unsafe { &mut *r };
// // use futures::{future::Future, poll, FutureExt};
// let f2 = fut.as_mut();
// let w = cx.waker();
// let mut cx = Context::from_waker(&w);
// // Pin::new_unchecked(pointer)
// // use std::future::Future;
// match f2.poll(&mut cx) {
// Poll::Ready(_) => {
// let trigger = EventTrigger::new_from_task(slot.originator);
// slot.dead.set(true);
// return Poll::Ready(Some(trigger));
// }
// Poll::Pending => continue,
// }
// }
// // we tried polling every active task.
// // give up and relinquish controlto the parent
// // We have polled a large number of futures in a row without yielding.
// // To ensure we do not starve other tasks waiting on the executor,
// // we yield here, but immediately wake ourselves up to continue.
// // cx.waker().wake_by_ref();
// return Poll::Pending;
// }
// }
pub struct TaskHandle { pub struct TaskHandle {
key: DefaultKey, key: DefaultKey,
} }
pub struct DTask { pub struct DTask {
fut: *mut Pin<Box<dyn Future<Output = ()>>>, fut: FiberTask,
originator: ScopeIdx, originator: ScopeIdx,
dead: Cell<bool>, dead: Cell<bool>,
} }
impl DTask { impl DTask {
pub fn new(fut: &mut Pin<Box<dyn Future<Output = ()>>>, originator: ScopeIdx) -> Self { pub fn new(fut: FiberTask, originator: ScopeIdx) -> Self {
Self { Self {
fut, fut,
originator, originator,
dead: Cell::new(false), dead: Cell::new(false),
} }
} }
pub fn debug_new(fut: &mut Pin<Box<dyn Future<Output = ()>>>) -> Self { pub fn debug_new(fut: FiberTask) -> Self {
let originator = ScopeIdx::default(); let originator = ScopeIdx::default();
Self { Self {
fut, fut,
+19 -5
View File
@@ -26,8 +26,8 @@ use slotmap::DefaultKey;
use slotmap::SlotMap; use slotmap::SlotMap;
use std::any::Any; use std::any::Any;
use std::any::TypeId;
use std::pin::Pin; use std::pin::Pin;
use std::{any::TypeId};
pub type ScopeIdx = DefaultKey; pub type ScopeIdx = DefaultKey;
@@ -191,7 +191,10 @@ impl VirtualDom {
} }
/// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch /// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch
///
/// Currently this doesn't do what we want it to do /// Currently this doesn't do what we want it to do
///
/// The diff machine expects the RealDom's stack to be the root of the application
pub fn rebuild<'s, Dom: RealDom<'s>>(&'s mut self, realdom: &mut Dom) -> Result<()> { pub fn rebuild<'s, Dom: RealDom<'s>>(&'s mut self, realdom: &mut Dom) -> Result<()> {
let mut diff_machine = DiffMachine::new( let mut diff_machine = DiffMachine::new(
realdom, realdom,
@@ -201,15 +204,26 @@ impl VirtualDom {
&self.tasks, &self.tasks,
); );
let cur_component = self.components.try_get_mut(self.base_scope).unwrap();
cur_component.run_scope()?;
let meta = diff_machine.create(cur_component.next_frame());
log::info!(
"nodes created! appending to body {:#?}",
meta.added_to_stack
);
diff_machine.dom.append_children(meta.added_to_stack);
// Schedule an update and then immediately call it on the root component // Schedule an update and then immediately call it on the root component
// This is akin to a hook being called from a listener and requring a re-render // This is akin to a hook being called from a listener and requring a re-render
// Instead, this is done on top-level component // Instead, this is done on top-level component
let base = self.components.try_get(self.base_scope)?; // let base = self.components.try_get(self.base_scope)?;
let update = &base.event_channel; // let update = &base.event_channel;
update(); // update();
self.progress_completely(&mut diff_machine)?; // self.progress_completely(&mut diff_machine)?;
Ok(()) Ok(())
} }
+7 -2
View File
@@ -57,7 +57,7 @@ pub fn use_state<'a, 'c, T: 'static, F: FnOnce() -> T, P>(
move || UseStateInner { move || UseStateInner {
current_val: initial_state_fn(), current_val: initial_state_fn(),
callback: cx.schedule_update(), callback: cx.schedule_update(),
wip: RefCell::new(None), wip: Rc::new(RefCell::new(None)),
update_scheuled: Cell::new(false), update_scheuled: Cell::new(false),
}, },
move |hook| { move |hook| {
@@ -76,7 +76,7 @@ struct UseStateInner<T: 'static> {
current_val: T, current_val: T,
update_scheuled: Cell<bool>, update_scheuled: Cell<bool>,
callback: Rc<dyn Fn()>, callback: Rc<dyn Fn()>,
wip: RefCell<Option<T>>, wip: Rc<RefCell<Option<T>>>,
} }
pub struct UseState<'a, T: 'static> { pub struct UseState<'a, T: 'static> {
@@ -118,6 +118,11 @@ impl<'a, T: 'static> UseState<'a, T> {
pub fn classic(self) -> (&'a T, &'a Rc<dyn Fn(T)>) { pub fn classic(self) -> (&'a T, &'a Rc<dyn Fn(T)>) {
todo!() todo!()
} }
pub fn setter(&self) -> Rc<dyn Fn(T)> {
let slot = self.inner.wip.clone();
Rc::new(move |new| *slot.borrow_mut() = Some(new))
}
} }
impl<'a, T: 'static + ToOwned<Owned = T>> UseState<'a, T> { impl<'a, T: 'static + ToOwned<Owned = T>> UseState<'a, T> {
pub fn get_mut(self) -> RefMut<'a, T> { pub fn get_mut(self) -> RefMut<'a, T> {
+19 -18
View File
@@ -26,25 +26,26 @@ fn main() {
static App: FC<()> = |cx| { static App: FC<()> = |cx| {
// let mut count = use_state(cx, || 0); // let mut count = use_state(cx, || 0);
let fut = cx.use_hook(
move || {
Box::pin(async {
let mut tick: i32 = 0;
log::debug!("yeet!");
loop {
gloo_timers::future::TimeoutFuture::new(250).await;
log::debug!("ticking forward... {}", tick);
tick += 1;
}
}) as Pin<Box<dyn Future<Output = ()> + 'static>>
},
|h| h,
|_| {},
);
cx.submit_task(fut);
let state = use_state(cx, || 0); let state = use_state(cx, || 0);
let set_val = state.setter();
let g = cx.use_task(|| async move {
let mut tick: i32 = 0;
log::debug!("yeet!");
loop {
gloo_timers::future::TimeoutFuture::new(250).await;
log::debug!("ticking forward... {}", tick);
tick += 1;
if tick > 10 {
break;
}
}
set_val(10);
String::from("Huzza!")
});
log::debug!("Value from component was {:#?}", g);
cx.render(rsx! { cx.render(rsx! {
div { div {
section { class: "py-12 px-4 text-center" section { class: "py-12 px-4 text-center"
+47 -34
View File
@@ -62,20 +62,27 @@ impl WebsysRenderer {
} }
pub async fn run(&mut self) -> dioxus_core::error::Result<()> { pub async fn run(&mut self) -> dioxus_core::error::Result<()> {
let body_element = prepare_websys_dom(); use wasm_bindgen::JsCast;
let root_node = body_element.first_child().unwrap(); let root = prepare_websys_dom();
let root_node = root.clone().dyn_into::<Node>().unwrap();
let mut websys_dom = crate::new::WebsysDom::new(body_element.clone()); let mut websys_dom = crate::new::WebsysDom::new(root.clone());
websys_dom.stack.push(root_node.clone());
websys_dom.stack.push(root_node); websys_dom.stack.push(root_node);
self.internal_dom.rebuild(&mut websys_dom)?; self.internal_dom.rebuild(&mut websys_dom)?;
log::info!("Going into event loop"); log::info!("Going into event loop");
loop { // loop {
let trigger = { let trigger = {
let real_queue = websys_dom.wait_for_event(); let real_queue = websys_dom.wait_for_event();
if self.internal_dom.tasks.is_empty() {
log::info!("tasks is empty, waiting for dom event to trigger soemthing");
real_queue.await
} else {
log::info!("tasks is not empty, waiting for either tasks or event system");
let task_queue = (&mut self.internal_dom.tasks).next(); let task_queue = (&mut self.internal_dom.tasks).next();
pin_mut!(real_queue); pin_mut!(real_queue);
@@ -85,26 +92,30 @@ impl WebsysRenderer {
futures_util::future::Either::Left((trigger, _)) => trigger, futures_util::future::Either::Left((trigger, _)) => trigger,
futures_util::future::Either::Right((trigger, _)) => trigger, futures_util::future::Either::Right((trigger, _)) => trigger,
} }
}; }
};
if let Some(real_trigger) = trigger {
log::info!("event received"); log::info!("event received");
let root_node = body_element.first_child().unwrap(); // let root_node = body_element.first_child().unwrap();
websys_dom.stack.push(root_node.clone()); // websys_dom.stack.push(root_node.clone());
self.internal_dom
.progress_with_event(&mut websys_dom, trigger.unwrap())?;
// let t2 = self.internal_dom.tasks.next(); self.internal_dom
// futures::select! { .progress_with_event(&mut websys_dom, real_trigger)?;
// trigger = t1 => {
// log::info!("event received");
// let root_node = body_element.first_child().unwrap();
// websys_dom.stack.push(root_node.clone());
// self.internal_dom
// .progress_with_event(&mut websys_dom, trigger)?;
// },
// () = t2 => {}
// };
} }
// let t2 = self.internal_dom.tasks.next();
// futures::select! {
// trigger = t1 => {
// log::info!("event received");
// let root_node = body_element.first_child().unwrap();
// websys_dom.stack.push(root_node.clone());
// self.internal_dom
// .progress_with_event(&mut websys_dom, trigger)?;
// },
// () = t2 => {}
// };
// }
// while let Some(trigger) = websys_dom.wait_for_event().await { // while let Some(trigger) = websys_dom.wait_for_event().await {
// } // }
@@ -119,21 +130,23 @@ fn prepare_websys_dom() -> Element {
let document = window let document = window
.document() .document()
.expect("should have access to the Document"); .expect("should have access to the Document");
let body = document.body().unwrap();
// let body = document.body().unwrap();
let el = document.get_element_by_id("dioxusroot").unwrap();
// Build a dummy div // Build a dummy div
let container: &Element = body.as_ref(); // let container: &Element = body.as_ref();
// container.set_inner_html(""); // container.set_inner_html("");
container // container
.append_child( // .append_child(
document // document
.create_element("div") // .create_element("div")
.expect("should create element OK") // .expect("should create element OK")
.as_ref(), // .as_ref(),
) // )
.expect("should append child OK"); // .expect("should append child OK");
el
container.clone() // container.clone()
} }
// Progress the mount of the root component // Progress the mount of the root component
+9 -4
View File
@@ -52,6 +52,7 @@ impl WebsysDom {
let mut nodes = slotmap::SlotMap::with_capacity(1000); let mut nodes = slotmap::SlotMap::with_capacity(1000);
let root_id = nodes.insert(root.clone().dyn_into::<Node>().unwrap()); let root_id = nodes.insert(root.clone().dyn_into::<Node>().unwrap());
Self { Self {
stack: Stack::with_capacity(10), stack: Stack::with_capacity(10),
nodes, nodes,
@@ -72,9 +73,13 @@ impl WebsysDom {
impl<'a> dioxus_core::diff::RealDom<'a> for WebsysDom { impl<'a> dioxus_core::diff::RealDom<'a> for WebsysDom {
fn push(&mut self, root: RealDomNode) { fn push(&mut self, root: RealDomNode) {
log::debug!("Called [push_root] {:?}", root); log::debug!("Called [push_root] {:#?}", root);
let key: DefaultKey = KeyData::from_ffi(root.0).into(); let key: DefaultKey = KeyData::from_ffi(root.0).into();
let domnode = self.nodes.get(key).expect("Failed to pop know root"); let domnode = self
.nodes
.get(key)
.expect(&format!("Failed to pop know root: {:#?}", key));
self.stack.push(domnode.clone()); self.stack.push(domnode.clone());
} }
// drop the node off the stack // drop the node off the stack
@@ -85,10 +90,10 @@ impl<'a> dioxus_core::diff::RealDom<'a> for WebsysDom {
fn append_children(&mut self, many: u32) { fn append_children(&mut self, many: u32) {
log::debug!("Called [`append_child`]"); log::debug!("Called [`append_child`]");
let mut root: Node = self let root: Node = self
.stack .stack
.list .list
.get(self.stack.list.len() - many as usize) .get(self.stack.list.len() - (1 + many as usize))
.unwrap() .unwrap()
.clone(); .clone();