feat: wire tasks up

This commit is contained in:
Jonathan Kelley 2021-11-12 01:36:33 -05:00
parent 9d8c5ca5ab
commit 55e6dd9701
3 changed files with 32 additions and 17 deletions

View file

@ -40,7 +40,7 @@ impl<const A: bool> FragmentBuilder<A> {
/// fn App(cx: Context, props: &()) -> Element {
/// cx.render(rsx!{
/// CustomCard {
/// h1 {}
/// h1 {}2
/// p {}
/// }
/// })

View file

@ -1,6 +1,6 @@
use bumpalo::Bump;
use futures_channel::mpsc::UnboundedSender;
use fxhash::FxHashMap;
use fxhash::{FxHashMap, FxHashSet};
use slab::Slab;
use std::{
borrow::Borrow,
@ -22,8 +22,9 @@ pub struct Heuristic {
// has an internal heuristics engine to pre-allocate arenas to the right size
pub(crate) struct ScopeArena {
bump: Bump,
pub pending_futures: FxHashSet<ScopeId>,
scope_counter: Cell<usize>,
scopes: RefCell<FxHashMap<ScopeId, *mut Scope>>,
pub scopes: RefCell<FxHashMap<ScopeId, *mut Scope>>,
pub heuristics: RefCell<FxHashMap<FcSlot, Heuristic>>,
free_scopes: RefCell<Vec<*mut Scope>>,
nodes: RefCell<Slab<*const VNode<'static>>>,
@ -55,6 +56,7 @@ impl ScopeArena {
Self {
scope_counter: Cell::new(0),
bump,
pending_futures: FxHashSet::default(),
scopes: RefCell::new(FxHashMap::default()),
heuristics: RefCell::new(FxHashMap::default()),
free_scopes: RefCell::new(Vec::new()),
@ -354,7 +356,7 @@ impl ScopeArena {
debug_assert_eq!(scope.wip_frame().nodes.borrow().len(), 1);
if !scope.items.borrow().tasks.is_empty() {
// self.
//
}
// make the "wip frame" contents the "finished frame"

View file

@ -7,6 +7,7 @@ use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
use futures_util::{Future, StreamExt};
use fxhash::FxHashSet;
use indexmap::IndexSet;
use smallvec::SmallVec;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
@ -116,8 +117,6 @@ pub struct VirtualDom {
sender: UnboundedSender<SchedulerMsg>,
pending_futures: FxHashSet<ScopeId>,
pending_messages: VecDeque<SchedulerMsg>,
dirty_scopes: IndexSet<ScopeId>,
@ -210,7 +209,6 @@ impl VirtualDom {
receiver,
_root_props: caller,
pending_messages,
pending_futures: Default::default(),
dirty_scopes,
sender,
}
@ -266,45 +264,61 @@ impl VirtualDom {
// 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 self.pending_futures.is_empty() {
if self.scopes.pending_futures.is_empty() {
self.pending_messages
.push_front(self.receiver.next().await.unwrap());
} else {
struct PollTasks<'a> {
pending_futures: &'a FxHashSet<ScopeId>,
scopes: &'a ScopeArena,
scopes: &'a mut ScopeArena,
}
impl<'a> Future for PollTasks<'a> {
type Output = ();
fn poll(
self: Pin<&mut Self>,
mut self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> Poll<Self::Output> {
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
for fut in self.pending_futures.iter() {
for fut in self.scopes.pending_futures.iter() {
let scope = self
.scopes
.get_scope(fut)
.expect("Scope should never be moved");
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?
// I don't usually write futures by hand
// 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
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() {
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
@ -320,8 +334,7 @@ impl VirtualDom {
let scheduler_fut = self.receiver.next();
let tasks_fut = PollTasks {
pending_futures: &self.pending_futures,
scopes: &self.scopes,
scopes: &mut self.scopes,
};
match select(tasks_fut, scheduler_fut).await {