feat: wire tasks up
This commit is contained in:
1 parent
9d8c5ca5ab
commit
55e6dd9701
3 files changed
+32
-17
No files matched your search
@@ -40,7 +40,7 @@ impl<const A: bool> FragmentBuilder<A> {
|
|||||||
/// fn App(cx: Context, props: &()) -> Element {
|
/// fn App(cx: Context, props: &()) -> Element {
|
||||||
/// cx.render(rsx!{
|
/// cx.render(rsx!{
|
||||||
/// CustomCard {
|
/// CustomCard {
|
||||||
/// h1 {}
|
/// h1 {}2
|
||||||
/// p {}
|
/// p {}
|
||||||
/// }
|
/// }
|
||||||
/// })
|
/// })
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use futures_channel::mpsc::UnboundedSender;
|
use futures_channel::mpsc::UnboundedSender;
|
||||||
use fxhash::FxHashMap;
|
use fxhash::{FxHashMap, FxHashSet};
|
||||||
use slab::Slab;
|
use slab::Slab;
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
@@ -22,8 +22,9 @@ pub struct Heuristic {
|
|||||||
// has an internal heuristics engine to pre-allocate arenas to the right size
|
// has an internal heuristics engine to pre-allocate arenas to the right size
|
||||||
pub(crate) struct ScopeArena {
|
pub(crate) struct ScopeArena {
|
||||||
bump: Bump,
|
bump: Bump,
|
||||||
|
pub pending_futures: FxHashSet<ScopeId>,
|
||||||
scope_counter: Cell<usize>,
|
scope_counter: Cell<usize>,
|
||||||
scopes: RefCell<FxHashMap<ScopeId, *mut Scope>>,
|
pub scopes: RefCell<FxHashMap<ScopeId, *mut Scope>>,
|
||||||
pub heuristics: RefCell<FxHashMap<FcSlot, Heuristic>>,
|
pub heuristics: RefCell<FxHashMap<FcSlot, Heuristic>>,
|
||||||
free_scopes: RefCell<Vec<*mut Scope>>,
|
free_scopes: RefCell<Vec<*mut Scope>>,
|
||||||
nodes: RefCell<Slab<*const VNode<'static>>>,
|
nodes: RefCell<Slab<*const VNode<'static>>>,
|
||||||
@@ -55,6 +56,7 @@ impl ScopeArena {
|
|||||||
Self {
|
Self {
|
||||||
scope_counter: Cell::new(0),
|
scope_counter: Cell::new(0),
|
||||||
bump,
|
bump,
|
||||||
|
pending_futures: FxHashSet::default(),
|
||||||
scopes: RefCell::new(FxHashMap::default()),
|
scopes: RefCell::new(FxHashMap::default()),
|
||||||
heuristics: RefCell::new(FxHashMap::default()),
|
heuristics: RefCell::new(FxHashMap::default()),
|
||||||
free_scopes: RefCell::new(Vec::new()),
|
free_scopes: RefCell::new(Vec::new()),
|
||||||
@@ -354,7 +356,7 @@ impl ScopeArena {
|
|||||||
debug_assert_eq!(scope.wip_frame().nodes.borrow().len(), 1);
|
debug_assert_eq!(scope.wip_frame().nodes.borrow().len(), 1);
|
||||||
|
|
||||||
if !scope.items.borrow().tasks.is_empty() {
|
if !scope.items.borrow().tasks.is_empty() {
|
||||||
// self.
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
// make the "wip frame" contents the "finished frame"
|
// make the "wip frame" contents the "finished frame"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
|
|||||||
use futures_util::{Future, StreamExt};
|
use futures_util::{Future, StreamExt};
|
||||||
use fxhash::FxHashSet;
|
use fxhash::FxHashSet;
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -116,8 +117,6 @@ pub struct VirtualDom {
|
|||||||
|
|
||||||
sender: UnboundedSender<SchedulerMsg>,
|
sender: UnboundedSender<SchedulerMsg>,
|
||||||
|
|
||||||
pending_futures: FxHashSet<ScopeId>,
|
|
||||||
|
|
||||||
pending_messages: VecDeque<SchedulerMsg>,
|
pending_messages: VecDeque<SchedulerMsg>,
|
||||||
|
|
||||||
dirty_scopes: IndexSet<ScopeId>,
|
dirty_scopes: IndexSet<ScopeId>,
|
||||||
@@ -210,7 +209,6 @@ impl VirtualDom {
|
|||||||
receiver,
|
receiver,
|
||||||
_root_props: caller,
|
_root_props: caller,
|
||||||
pending_messages,
|
pending_messages,
|
||||||
pending_futures: Default::default(),
|
|
||||||
dirty_scopes,
|
dirty_scopes,
|
||||||
sender,
|
sender,
|
||||||
}
|
}
|
||||||
@@ -266,45 +264,61 @@ impl VirtualDom {
|
|||||||
// todo: poll the events once even if there is work to do to prevent starvation
|
// todo: poll the events once even if there is work to do to prevent starvation
|
||||||
|
|
||||||
// if there's no futures in the virtualdom, just wait for a scheduler message and put it into the queue to be processed
|
// if there's no futures in the virtualdom, just wait for a scheduler message and put it into the queue to be processed
|
||||||
if self.pending_futures.is_empty() {
|
if self.scopes.pending_futures.is_empty() {
|
||||||
self.pending_messages
|
self.pending_messages
|
||||||
.push_front(self.receiver.next().await.unwrap());
|
.push_front(self.receiver.next().await.unwrap());
|
||||||
} else {
|
} else {
|
||||||
struct PollTasks<'a> {
|
struct PollTasks<'a> {
|
||||||
pending_futures: &'a FxHashSet<ScopeId>,
|
scopes: &'a mut ScopeArena,
|
||||||
scopes: &'a ScopeArena,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Future for PollTasks<'a> {
|
impl<'a> Future for PollTasks<'a> {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
fn poll(
|
fn poll(
|
||||||
self: Pin<&mut Self>,
|
mut self: Pin<&mut Self>,
|
||||||
cx: &mut std::task::Context<'_>,
|
cx: &mut std::task::Context<'_>,
|
||||||
) -> Poll<Self::Output> {
|
) -> Poll<Self::Output> {
|
||||||
let mut all_pending = true;
|
let mut all_pending = true;
|
||||||
|
|
||||||
|
let mut unfinished_tasks: SmallVec<[_; 10]> = smallvec::smallvec![];
|
||||||
|
let mut scopes_to_clear: SmallVec<[_; 10]> = smallvec::smallvec![];
|
||||||
|
|
||||||
// Poll every scope manually
|
// Poll every scope manually
|
||||||
for fut in self.pending_futures.iter() {
|
for fut in self.scopes.pending_futures.iter() {
|
||||||
let scope = self
|
let scope = self
|
||||||
.scopes
|
.scopes
|
||||||
.get_scope(fut)
|
.get_scope(fut)
|
||||||
.expect("Scope should never be moved");
|
.expect("Scope should never be moved");
|
||||||
|
|
||||||
let mut items = scope.items.borrow_mut();
|
let mut items = scope.items.borrow_mut();
|
||||||
for task in items.tasks.iter_mut() {
|
|
||||||
let task = task.as_mut();
|
|
||||||
|
|
||||||
|
while let Some(mut task) = items.tasks.pop() {
|
||||||
// todo: does this make sense?
|
// todo: does this make sense?
|
||||||
// I don't usually write futures by hand
|
// I don't usually write futures by hand
|
||||||
// I think the futures neeed to be pinned using bumpbox or something
|
// I think the futures neeed to be pinned using bumpbox or something
|
||||||
// right now, they're bump allocated so this shouldn't matter anyway - they're not going to move
|
// right now, they're bump allocated so this shouldn't matter anyway - they're not going to move
|
||||||
let unpinned = unsafe { Pin::new_unchecked(task) };
|
let task_mut = task.as_mut();
|
||||||
|
let unpinned = unsafe { Pin::new_unchecked(task_mut) };
|
||||||
|
|
||||||
if unpinned.poll(cx).is_ready() {
|
if unpinned.poll(cx).is_ready() {
|
||||||
all_pending = false
|
all_pending = false
|
||||||
|
} else {
|
||||||
|
unfinished_tasks.push(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if unfinished_tasks.is_empty() {
|
||||||
|
scopes_to_clear.push(*fut);
|
||||||
|
}
|
||||||
|
|
||||||
|
for task in unfinished_tasks.drain(..) {
|
||||||
|
items.tasks.push(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for scope in scopes_to_clear {
|
||||||
|
self.scopes.pending_futures.remove(&scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the future if any singular task is ready
|
// Resolve the future if any singular task is ready
|
||||||
@@ -320,8 +334,7 @@ impl VirtualDom {
|
|||||||
|
|
||||||
let scheduler_fut = self.receiver.next();
|
let scheduler_fut = self.receiver.next();
|
||||||
let tasks_fut = PollTasks {
|
let tasks_fut = PollTasks {
|
||||||
pending_futures: &self.pending_futures,
|
scopes: &mut self.scopes,
|
||||||
scopes: &self.scopes,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match select(tasks_fut, scheduler_fut).await {
|
match select(tasks_fut, scheduler_fut).await {
|
||||||
|
|||||||
Reference in new issue
Block a user