wip: changes to scheduler
This commit is contained in:
1 parent
b32e2611e3
commit
098d3821ed
14 files changed
+151
-282
No files matched your search
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"rust-analyzer.inlayHints.enable": false,
|
"rust-analyzer.inlayHints.enable": true,
|
||||||
"rust-analyzer.cargo.allFeatures": true
|
"rust-analyzer.cargo.allFeatures": true
|
||||||
}
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
fn main() {}
|
|
||||||
@@ -20,5 +20,5 @@ struct SomeProps {
|
|||||||
/// This implementation does not require a "PartialEq" because it does not memoize
|
/// This implementation does not require a "PartialEq" because it does not memoize
|
||||||
#[derive(dioxus_core_macro::Props)]
|
#[derive(dioxus_core_macro::Props)]
|
||||||
struct SomePropsTwo<'a> {
|
struct SomePropsTwo<'a> {
|
||||||
a: &'a str,
|
_a: &'a str,
|
||||||
}
|
}
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
pub mod dioxus {
|
|
||||||
pub mod builder {
|
|
||||||
pub struct Builder;
|
|
||||||
|
|
||||||
struct AttrVal;
|
|
||||||
|
|
||||||
impl Into<AttrVal> for &'static str {
|
|
||||||
fn into(self) -> AttrVal {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<AttrVal> for String {
|
|
||||||
fn into(self) -> AttrVal {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// impl<T> From<T> for AttrVal {
|
|
||||||
// fn from(_: T) -> Self {
|
|
||||||
// todo!()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl Builder {
|
|
||||||
// fn attr<T>(mut self, key: &str, value: impl Into<AttrVal>) -> Self {
|
|
||||||
pub fn attr<T>(self, _key: &str, _value: T) -> Self {
|
|
||||||
Self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn on<T>(self, _key: &str, _value: T) -> Self {
|
|
||||||
Self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish(self) {
|
|
||||||
// Self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Bump;
|
|
||||||
pub fn div(_bump: &Bump) -> Builder {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
pub fn h1(_bump: &Bump) -> Builder {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
pub fn h2(_bump: &Bump) -> Builder {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
// render(rsx! {
|
|
||||||
// div { // we can actually support just a list of nodes too
|
|
||||||
// h1 {"Hello Dioxus"}
|
|
||||||
// p {"This is a beautful app you're building"}
|
|
||||||
// section {
|
|
||||||
// "custom section to the rescue",
|
|
||||||
// class: "abc123"
|
|
||||||
// }
|
|
||||||
// span {
|
|
||||||
// class: "abc123"
|
|
||||||
// "Try backwards too."
|
|
||||||
// "Anything goes!"
|
|
||||||
// "As long as it's within the rules"
|
|
||||||
// {0..10.map(|f| rsx!{
|
|
||||||
// div {
|
|
||||||
// h3 {"totally okay to drop in iterators and expressions"}
|
|
||||||
// p {"however, debug information is lost"}
|
|
||||||
// }
|
|
||||||
// })}
|
|
||||||
// }
|
|
||||||
// span {
|
|
||||||
// "Feel free"
|
|
||||||
// class: "abc123"
|
|
||||||
// "To mix to your heart's content"
|
|
||||||
// }
|
|
||||||
// span { class: "some-very-long-and-tedious-class-name-is-now-separated"
|
|
||||||
// "Very ergonomic"
|
|
||||||
// }
|
|
||||||
// span { "Innovative design 🛠"
|
|
||||||
// class: "some-very-long-and-tedious-class-name-is-now-separated"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
let _g = String::from("asd");
|
|
||||||
|
|
||||||
// let lazy = rsx! {
|
|
||||||
// div {
|
|
||||||
// a: "asd",
|
|
||||||
// a: "asd",
|
|
||||||
// a: "asd",
|
|
||||||
// a: "asd",
|
|
||||||
// a: "asd",
|
|
||||||
// // a: {rsx!{ h1 {"hello world"} }}, // include
|
|
||||||
// a: {&g},
|
|
||||||
// b: {1 + 2},
|
|
||||||
// onclick: {move |e: ()| {
|
|
||||||
// println!("hello world!")
|
|
||||||
// }},
|
|
||||||
// div {
|
|
||||||
// a: "asd"
|
|
||||||
// div {
|
|
||||||
// div {
|
|
||||||
// div {
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// h1 {
|
|
||||||
|
|
||||||
// }
|
|
||||||
// h2 {
|
|
||||||
// "child"
|
|
||||||
// }
|
|
||||||
// "Childnode"
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// render(lazy);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(_f: impl Fn(&dioxus::builder::Bump)) {}
|
|
||||||
@@ -22,7 +22,7 @@ criterion_group!(mbenches, create_rows);
|
|||||||
criterion_main!(mbenches);
|
criterion_main!(mbenches);
|
||||||
|
|
||||||
fn create_rows(c: &mut Criterion) {
|
fn create_rows(c: &mut Criterion) {
|
||||||
static App: FC<()> = |cx, props| {
|
static App: FC<()> = |cx, _| {
|
||||||
let mut rng = SmallRng::from_entropy();
|
let mut rng = SmallRng::from_entropy();
|
||||||
let rows = (0..10_000).map(|f| {
|
let rows = (0..10_000).map(|f| {
|
||||||
let label = Label::new(&mut rng);
|
let label = Label::new(&mut rng);
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
use dioxus_core::prelude::*;
|
use dioxus_core::prelude::*;
|
||||||
|
|
||||||
fn main() {}
|
fn main() {
|
||||||
|
let mut dom = VirtualDom::new(EXAMPLE);
|
||||||
|
dom.rebuild();
|
||||||
|
println!("{}", dom);
|
||||||
|
}
|
||||||
|
|
||||||
pub static Example: FC<()> = |cx, props| {
|
pub static EXAMPLE: FC<()> = |cx, _| {
|
||||||
let list = (0..10).map(|_f| LazyNodes::new(move |_f| todo!()));
|
let list = (0..10).map(|_f| LazyNodes::new(move |_f| todo!()));
|
||||||
|
|
||||||
cx.render(LazyNodes::new(move |cx| {
|
cx.render(LazyNodes::new(move |cx| {
|
||||||
|
|||||||
@@ -1,39 +1,15 @@
|
|||||||
use dioxus_core::prelude::*;
|
use dioxus_core::prelude::*;
|
||||||
|
|
||||||
fn main() {}
|
fn main() {
|
||||||
|
let mut dom = VirtualDom::new(App);
|
||||||
|
dom.rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
const App: FC<()> = |cx, props| {
|
const App: FC<()> = |cx, props| {
|
||||||
// create a new future
|
let id = cx.scope_id();
|
||||||
let _fut = cx.use_hook(
|
cx.submit_task(Box::pin(async move { id }));
|
||||||
|_| {
|
|
||||||
//
|
|
||||||
async { loop {} }
|
|
||||||
// Box::pin(async { loop {} }) as Pin<Box<dyn Future<Output = ()>>>
|
|
||||||
},
|
|
||||||
|f| f,
|
|
||||||
|_| {},
|
|
||||||
);
|
|
||||||
// let g = unsafe { Pin::new_unchecked(fut) };
|
|
||||||
|
|
||||||
// cx.submit_task(fut);
|
let (handle, contents) = use_task(cx, || async { "hello world".to_string() });
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
};
|
};
|
||||||
|
|
||||||
const Task: FC<()> = |cx, props| {
|
|
||||||
let (_task, _res) = use_task(cx, || async { true });
|
|
||||||
// task.pause();
|
|
||||||
// task.restart();
|
|
||||||
// task.stop();
|
|
||||||
// task.drop();
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
let _s = use_task(cx, || async { "hello world".to_string() });
|
|
||||||
|
|
||||||
todo!()
|
|
||||||
};
|
|
||||||
|
|
||||||
fn use_mut<P, T>(_cx: Context, _f: impl FnOnce() -> T) -> &mut T {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
@@ -137,7 +137,7 @@ impl<'a> SavedDiffWork<'a> {
|
|||||||
std::mem::transmute(self)
|
std::mem::transmute(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn promote<'b>(self, vdom: &'b mut ResourcePool) -> DiffMachine<'b> {
|
pub unsafe fn promote<'b>(self, vdom: &'b ResourcePool) -> DiffMachine<'b> {
|
||||||
let extended: SavedDiffWork<'b> = std::mem::transmute(self);
|
let extended: SavedDiffWork<'b> = std::mem::transmute(self);
|
||||||
DiffMachine {
|
DiffMachine {
|
||||||
vdom,
|
vdom,
|
||||||
|
|||||||
@@ -15,9 +15,21 @@ use std::{any::Any, cell::RefCell, future::Future, ops::Deref, rc::Rc};
|
|||||||
|
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
|
/// Returns the handle to the task and the value (if it is ready, else None).
|
||||||
///
|
///
|
||||||
|
/// ```
|
||||||
|
/// static Example: FC<()> = |cx, props| {
|
||||||
|
/// let (task, value) = use_task(|| async {
|
||||||
|
/// timer::sleep(Duration::from_secs(1)).await;
|
||||||
|
/// "Hello World"
|
||||||
|
/// });
|
||||||
///
|
///
|
||||||
///
|
/// match contents {
|
||||||
|
/// Some(contents) => rsx!(cx, div { "{title}" }),
|
||||||
|
/// None => rsx!(cx, div { "Loading..." }),
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
pub fn use_task<'src, Out, Fut, Init>(
|
pub fn use_task<'src, Out, Fut, Init>(
|
||||||
cx: Context<'src>,
|
cx: Context<'src>,
|
||||||
task_initializer: Init,
|
task_initializer: Init,
|
||||||
|
|||||||
+78
-101
@@ -101,6 +101,10 @@ pub enum SchedulerMsg {
|
|||||||
Immediate(ScopeId),
|
Immediate(ScopeId),
|
||||||
|
|
||||||
// tasks
|
// tasks
|
||||||
|
Task(TaskMsg),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum TaskMsg {
|
||||||
SubmitTask(FiberTask, u64),
|
SubmitTask(FiberTask, u64),
|
||||||
ToggleTask(u64),
|
ToggleTask(u64),
|
||||||
PauseTask(u64),
|
PauseTask(u64),
|
||||||
@@ -152,7 +156,9 @@ pub(crate) struct Scheduler {
|
|||||||
|
|
||||||
pub garbage_scopes: HashSet<ScopeId>,
|
pub garbage_scopes: HashSet<ScopeId>,
|
||||||
|
|
||||||
pub lane: PriorityLane,
|
pub dirty_scopes: IndexSet<ScopeId>,
|
||||||
|
pub saved_state: Option<SavedDiffWork<'static>>,
|
||||||
|
pub in_progress: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scheduler {
|
impl Scheduler {
|
||||||
@@ -181,7 +187,9 @@ impl Scheduler {
|
|||||||
let task_id = task_counter.get();
|
let task_id = task_counter.get();
|
||||||
task_counter.set(task_id + 1);
|
task_counter.set(task_id + 1);
|
||||||
sender
|
sender
|
||||||
.unbounded_send(SchedulerMsg::SubmitTask(fiber_task, task_id))
|
.unbounded_send(SchedulerMsg::Task(TaskMsg::SubmitTask(
|
||||||
|
fiber_task, task_id,
|
||||||
|
)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
TaskHandle {
|
TaskHandle {
|
||||||
our_id: task_id,
|
our_id: task_id,
|
||||||
@@ -214,6 +222,12 @@ impl Scheduler {
|
|||||||
|
|
||||||
let async_tasks = FuturesUnordered::new();
|
let async_tasks = FuturesUnordered::new();
|
||||||
|
|
||||||
|
// push a task that would never resolve - prevents us from immediately aborting the scheduler
|
||||||
|
async_tasks.push(Box::pin(async {
|
||||||
|
std::future::pending::<()>().await;
|
||||||
|
ScopeId(0)
|
||||||
|
}) as FiberTask);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
pool,
|
pool,
|
||||||
|
|
||||||
@@ -235,24 +249,9 @@ impl Scheduler {
|
|||||||
|
|
||||||
garbage_scopes: HashSet::new(),
|
garbage_scopes: HashSet::new(),
|
||||||
|
|
||||||
// current_priority: EventPriority::Low,
|
dirty_scopes: Default::default(),
|
||||||
lane: PriorityLane::new(),
|
saved_state: None,
|
||||||
}
|
in_progress: false,
|
||||||
}
|
|
||||||
|
|
||||||
pub fn manually_poll_events(&mut self) {
|
|
||||||
while let Ok(Some(msg)) = self.receiver.try_next() {
|
|
||||||
match msg {
|
|
||||||
SchedulerMsg::UiEvent(event) => self.ui_events.push_front(event),
|
|
||||||
SchedulerMsg::Immediate(im) => self.pending_immediates.push_front(im),
|
|
||||||
|
|
||||||
// task stuff
|
|
||||||
SchedulerMsg::SubmitTask(_, _) => todo!(),
|
|
||||||
SchedulerMsg::ToggleTask(_) => todo!(),
|
|
||||||
SchedulerMsg::PauseTask(_) => todo!(),
|
|
||||||
SchedulerMsg::ResumeTask(_) => todo!(),
|
|
||||||
SchedulerMsg::DropTask(_) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,31 +271,27 @@ impl Scheduler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use EventPriority::*;
|
// use EventPriority::*;
|
||||||
|
|
||||||
match priority {
|
// match priority {
|
||||||
Immediate => todo!(),
|
// Immediate => todo!(),
|
||||||
High => todo!(),
|
// High => todo!(),
|
||||||
Medium => todo!(),
|
// Medium => todo!(),
|
||||||
Low => todo!(),
|
// Low => todo!(),
|
||||||
}
|
// }
|
||||||
|
|
||||||
discrete
|
discrete
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_work(&mut self) {
|
fn prepare_work(&mut self) {
|
||||||
while let Some(trigger) = self.ui_events.pop_back() {
|
// while let Some(trigger) = self.ui_events.pop_back() {
|
||||||
if let Some(scope) = self.pool.get_scope_mut(trigger.scope) {}
|
// if let Some(scope) = self.pool.get_scope_mut(trigger.scope) {}
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// nothing to do, no events on channels, no work
|
// nothing to do, no events on channels, no work
|
||||||
pub fn has_any_work(&self) -> bool {
|
pub fn has_any_work(&self) -> bool {
|
||||||
self.lane.has_work() || self.has_pending_events()
|
!(self.dirty_scopes.is_empty() && self.ui_events.is_empty())
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_pending_events(&self) -> bool {
|
|
||||||
!self.ui_events.is_empty()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// re-balance the work lanes, ensuring high-priority work properly bumps away low priority work
|
/// re-balance the work lanes, ensuring high-priority work properly bumps away low priority work
|
||||||
@@ -304,35 +299,39 @@ impl Scheduler {
|
|||||||
|
|
||||||
fn save_work(&mut self, lane: SavedDiffWork) {
|
fn save_work(&mut self, lane: SavedDiffWork) {
|
||||||
let saved: SavedDiffWork<'static> = unsafe { std::mem::transmute(lane) };
|
let saved: SavedDiffWork<'static> = unsafe { std::mem::transmute(lane) };
|
||||||
self.lane.saved_state = Some(saved);
|
self.saved_state = Some(saved);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_work(&mut self) -> SavedDiffWork<'static> {
|
unsafe fn load_work(&mut self) -> SavedDiffWork<'static> {
|
||||||
// match self.current_priority {
|
self.saved_state.take().unwrap().extend()
|
||||||
// EventPriority::Immediate => todo!(),
|
|
||||||
// EventPriority::High => todo!(),
|
|
||||||
// EventPriority::Medium => todo!(),
|
|
||||||
// EventPriority::Low => todo!(),
|
|
||||||
// }
|
|
||||||
unsafe { self.lane.saved_state.take().unwrap().extend() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_channel_msg(&mut self, msg: SchedulerMsg) {
|
pub fn handle_channel_msg(&mut self, msg: SchedulerMsg) {
|
||||||
match msg {
|
match msg {
|
||||||
|
//
|
||||||
|
SchedulerMsg::Task(msg) => todo!(),
|
||||||
|
|
||||||
SchedulerMsg::Immediate(_) => todo!(),
|
SchedulerMsg::Immediate(_) => todo!(),
|
||||||
|
|
||||||
SchedulerMsg::UiEvent(event) => {
|
SchedulerMsg::UiEvent(event) => {
|
||||||
//
|
//
|
||||||
|
|
||||||
self.handle_ui_event(event);
|
let (discrete, priority) = event_meta(&event);
|
||||||
}
|
|
||||||
|
|
||||||
//
|
if let Some(scope) = self.pool.get_scope_mut(event.scope) {
|
||||||
SchedulerMsg::SubmitTask(_, _) => todo!(),
|
if let Some(element) = event.mounted_dom_id {
|
||||||
SchedulerMsg::ToggleTask(_) => todo!(),
|
// TODO: bubble properly here
|
||||||
SchedulerMsg::PauseTask(_) => todo!(),
|
scope.call_listener(event.event, element);
|
||||||
SchedulerMsg::ResumeTask(_) => todo!(),
|
|
||||||
SchedulerMsg::DropTask(_) => todo!(),
|
while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
|
||||||
|
//
|
||||||
|
// self.add_dirty_scope(dirty_scope, trigger.priority)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
discrete;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,22 +345,22 @@ impl Scheduler {
|
|||||||
) -> bool {
|
) -> bool {
|
||||||
// Work through the current subtree, and commit the results when it finishes
|
// Work through the current subtree, and commit the results when it finishes
|
||||||
// When the deadline expires, give back the work
|
// When the deadline expires, give back the work
|
||||||
let saved_state = self.load_work();
|
let saved_state = unsafe { self.load_work() };
|
||||||
|
|
||||||
// We have to split away some parts of ourself - current lane is borrowed mutably
|
// We have to split away some parts of ourself - current lane is borrowed mutably
|
||||||
let mut shared = self.pool.clone();
|
let shared = self.pool.clone();
|
||||||
let mut machine = unsafe { saved_state.promote(&mut shared) };
|
let mut machine = unsafe { saved_state.promote(&shared) };
|
||||||
|
|
||||||
if machine.stack.is_empty() {
|
if machine.stack.is_empty() {
|
||||||
let shared = self.pool.clone();
|
let shared = self.pool.clone();
|
||||||
|
|
||||||
self.lane.dirty_scopes.sort_by(|a, b| {
|
self.dirty_scopes.sort_by(|a, b| {
|
||||||
let h1 = shared.get_scope(*a).unwrap().height;
|
let h1 = shared.get_scope(*a).unwrap().height;
|
||||||
let h2 = shared.get_scope(*b).unwrap().height;
|
let h2 = shared.get_scope(*b).unwrap().height;
|
||||||
h1.cmp(&h2)
|
h1.cmp(&h2)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(scope) = self.lane.dirty_scopes.pop() {
|
if let Some(scope) = self.dirty_scopes.pop() {
|
||||||
let component = self.pool.get_scope(scope).unwrap();
|
let component = self.pool.get_scope(scope).unwrap();
|
||||||
let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
|
let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
|
||||||
machine.stack.push(DiffInstruction::Diff { new, old });
|
machine.stack.push(DiffInstruction::Diff { new, old });
|
||||||
@@ -378,7 +377,7 @@ impl Scheduler {
|
|||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
for node in saved.seen_scopes.drain() {
|
for node in saved.seen_scopes.drain() {
|
||||||
self.lane.dirty_scopes.remove(&node);
|
self.dirty_scopes.remove(&node);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_mutations = Mutations::new();
|
let mut new_mutations = Mutations::new();
|
||||||
@@ -395,9 +394,9 @@ impl Scheduler {
|
|||||||
/// Uses some fairly complex logic to schedule what work should be produced.
|
/// Uses some fairly complex logic to schedule what work should be produced.
|
||||||
///
|
///
|
||||||
/// Returns a list of successful mutations.
|
/// Returns a list of successful mutations.
|
||||||
pub async fn work_with_deadline<'a>(
|
pub fn work_with_deadline<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
deadline: impl Future<Output = ()>,
|
mut deadline: impl FnMut() -> bool,
|
||||||
) -> Vec<Mutations<'a>> {
|
) -> Vec<Mutations<'a>> {
|
||||||
/*
|
/*
|
||||||
Strategy:
|
Strategy:
|
||||||
@@ -429,33 +428,29 @@ impl Scheduler {
|
|||||||
- but if we received both - then we don't need to diff, do we? run as many as we can and then finally diff?
|
- but if we received both - then we don't need to diff, do we? run as many as we can and then finally diff?
|
||||||
*/
|
*/
|
||||||
let mut committed_mutations = Vec::<Mutations<'static>>::new();
|
let mut committed_mutations = Vec::<Mutations<'static>>::new();
|
||||||
pin_mut!(deadline);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Move work out of the scheduler message receiver and into dedicated message lanes
|
// switch our priority, pop off any work
|
||||||
self.manually_poll_events();
|
for event in self.ui_events.drain(..) {
|
||||||
|
if let Some(scope) = self.pool.get_scope_mut(event.scope) {
|
||||||
|
if let Some(element) = event.mounted_dom_id {
|
||||||
|
// TODO: bubble properly here
|
||||||
|
scope.call_listener(event.event, element);
|
||||||
|
|
||||||
// Wait for any new events if we have nothing to do
|
while let Ok(Some(dirty_scope)) = self.receiver.try_next() {
|
||||||
// todo: poll the events once even if there is work to do to prevent starvation
|
match dirty_scope {
|
||||||
if !self.has_any_work() {
|
SchedulerMsg::Immediate(im) => {
|
||||||
futures_util::select! {
|
self.dirty_scopes.insert(im);
|
||||||
// todo: find a solution for the exhausted queue problem
|
}
|
||||||
// msg = self.async_tasks.next() => {}
|
_ => todo!(),
|
||||||
msg = self.receiver.next() => {
|
}
|
||||||
log::debug!("received work in scheduler");
|
}
|
||||||
self.handle_channel_msg(msg.unwrap())
|
}
|
||||||
},
|
|
||||||
_ = (&mut deadline).fuse() => return committed_mutations,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// switch our priority, pop off any work
|
|
||||||
self.prepare_work();
|
|
||||||
|
|
||||||
let mut deadline_reached = || (&mut deadline).now_or_never().is_some();
|
|
||||||
|
|
||||||
let finished_before_deadline =
|
let finished_before_deadline =
|
||||||
self.work_on_current_lane(&mut deadline_reached, &mut committed_mutations);
|
self.work_on_current_lane(&mut deadline, &mut committed_mutations);
|
||||||
|
|
||||||
if !finished_before_deadline {
|
if !finished_before_deadline {
|
||||||
break;
|
break;
|
||||||
@@ -471,7 +466,9 @@ impl Scheduler {
|
|||||||
pub fn work_sync<'a>(&'a mut self) -> Vec<Mutations<'a>> {
|
pub fn work_sync<'a>(&'a mut self) -> Vec<Mutations<'a>> {
|
||||||
let mut committed_mutations = Vec::new();
|
let mut committed_mutations = Vec::new();
|
||||||
|
|
||||||
self.manually_poll_events();
|
while let Ok(Some(msg)) = self.receiver.try_next() {
|
||||||
|
self.handle_channel_msg(msg);
|
||||||
|
}
|
||||||
|
|
||||||
if !self.has_any_work() {
|
if !self.has_any_work() {
|
||||||
return committed_mutations;
|
return committed_mutations;
|
||||||
@@ -534,23 +531,3 @@ impl Scheduler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PriorityLane {
|
|
||||||
pub dirty_scopes: IndexSet<ScopeId>,
|
|
||||||
pub saved_state: Option<SavedDiffWork<'static>>,
|
|
||||||
pub in_progress: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PriorityLane {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
saved_state: None,
|
|
||||||
dirty_scopes: Default::default(),
|
|
||||||
in_progress: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_work(&self) -> bool {
|
|
||||||
!self.dirty_scopes.is_empty() || self.in_progress
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,28 +12,28 @@ impl TaskHandle {
|
|||||||
/// This method is not synchronous - your task will not stop immediately.
|
/// This method is not synchronous - your task will not stop immediately.
|
||||||
pub fn toggle(&self) {
|
pub fn toggle(&self) {
|
||||||
self.sender
|
self.sender
|
||||||
.unbounded_send(SchedulerMsg::ToggleTask(self.our_id))
|
.unbounded_send(SchedulerMsg::Task(TaskMsg::ToggleTask(self.our_id)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method is not synchronous - your task will not stop immediately.
|
/// This method is not synchronous - your task will not stop immediately.
|
||||||
pub fn resume(&self) {
|
pub fn resume(&self) {
|
||||||
self.sender
|
self.sender
|
||||||
.unbounded_send(SchedulerMsg::ResumeTask(self.our_id))
|
.unbounded_send(SchedulerMsg::Task(TaskMsg::ResumeTask(self.our_id)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method is not synchronous - your task will not stop immediately.
|
/// This method is not synchronous - your task will not stop immediately.
|
||||||
pub fn stop(&self) {
|
pub fn stop(&self) {
|
||||||
self.sender
|
self.sender
|
||||||
.unbounded_send(SchedulerMsg::ToggleTask(self.our_id))
|
.unbounded_send(SchedulerMsg::Task(TaskMsg::ToggleTask(self.our_id)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method is not synchronous - your task will not stop immediately.
|
/// This method is not synchronous - your task will not stop immediately.
|
||||||
pub fn restart(&self) {
|
pub fn restart(&self) {
|
||||||
self.sender
|
self.sender
|
||||||
.unbounded_send(SchedulerMsg::ToggleTask(self.our_id))
|
.unbounded_send(SchedulerMsg::Task(TaskMsg::ToggleTask(self.our_id)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,11 +334,8 @@ impl VirtualDom {
|
|||||||
/// applied the edits.
|
/// applied the edits.
|
||||||
///
|
///
|
||||||
/// Mutations are the only link between the RealDOM and the VirtualDOM.
|
/// Mutations are the only link between the RealDOM and the VirtualDOM.
|
||||||
pub async fn run_with_deadline(
|
pub fn run_with_deadline(&mut self, deadline: impl FnMut() -> bool) -> Vec<Mutations<'_>> {
|
||||||
&mut self,
|
self.scheduler.work_with_deadline(deadline)
|
||||||
deadline: impl Future<Output = ()>,
|
|
||||||
) -> Vec<Mutations<'_>> {
|
|
||||||
self.scheduler.work_with_deadline(deadline).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_event_sender(&self) -> futures_channel::mpsc::UnboundedSender<SchedulerMsg> {
|
pub fn get_event_sender(&self) -> futures_channel::mpsc::UnboundedSender<SchedulerMsg> {
|
||||||
@@ -355,12 +352,38 @@ impl VirtualDom {
|
|||||||
|
|
||||||
log::debug!("No active work.... waiting for some...");
|
log::debug!("No active work.... waiting for some...");
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
|
|
||||||
|
// right now this won't poll events if there is ongoing work
|
||||||
|
// in the future we want to prioritize some events over ongoing work
|
||||||
|
// this is coming in the "priorities" PR
|
||||||
|
|
||||||
|
// Wait for any new events if we have nothing to do
|
||||||
|
// todo: poll the events once even if there is work to do to prevent starvation
|
||||||
futures_util::select! {
|
futures_util::select! {
|
||||||
// // hmm - will this resolve to none if there are no async tasks?
|
_ = self.scheduler.async_tasks.next() => {}
|
||||||
// _ = self.scheduler.async_tasks.next() => {
|
msg = self.scheduler.receiver.next() => {
|
||||||
// log::debug!("async task completed!");
|
match msg.unwrap() {
|
||||||
// }
|
SchedulerMsg::Task(t) => todo!(),
|
||||||
msg = self.scheduler.receiver.next() => self.scheduler.handle_channel_msg(msg.unwrap()),
|
SchedulerMsg::Immediate(im) => {
|
||||||
|
self.scheduler.dirty_scopes.insert(im);
|
||||||
|
}
|
||||||
|
SchedulerMsg::UiEvent(evt) => {
|
||||||
|
self.scheduler.ui_events.push_back(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Ok(Some(msg)) = self.scheduler.receiver.try_next() {
|
||||||
|
match msg {
|
||||||
|
SchedulerMsg::Task(t) => todo!(),
|
||||||
|
SchedulerMsg::Immediate(im) => {
|
||||||
|
self.scheduler.dirty_scopes.insert(im);
|
||||||
|
}
|
||||||
|
SchedulerMsg::UiEvent(evt) => {
|
||||||
|
self.scheduler.ui_events.push_back(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ use dioxus::prelude::Properties;
|
|||||||
use dioxus::virtual_dom::VirtualDom;
|
use dioxus::virtual_dom::VirtualDom;
|
||||||
pub use dioxus_core as dioxus;
|
pub use dioxus_core as dioxus;
|
||||||
use dioxus_core::prelude::FC;
|
use dioxus_core::prelude::FC;
|
||||||
|
use futures_util::FutureExt;
|
||||||
|
|
||||||
mod cache;
|
mod cache;
|
||||||
mod cfg;
|
mod cfg;
|
||||||
@@ -145,10 +146,10 @@ pub async fn run_with_props<T: Properties + 'static>(root: FC<T>, root_props: T,
|
|||||||
dom.wait_for_work().await;
|
dom.wait_for_work().await;
|
||||||
|
|
||||||
// wait for the mainthread to schedule us in
|
// wait for the mainthread to schedule us in
|
||||||
let deadline = work_loop.wait_for_idle_time().await;
|
let mut deadline = work_loop.wait_for_idle_time().await;
|
||||||
|
|
||||||
// run the virtualdom work phase until the frame deadline is reached
|
// run the virtualdom work phase until the frame deadline is reached
|
||||||
let mutations = dom.run_with_deadline(deadline).await;
|
let mutations = dom.run_with_deadline(|| (&mut deadline).now_or_never().is_some());
|
||||||
|
|
||||||
// wait for the animation frame to fire so we can apply our changes
|
// wait for the animation frame to fire so we can apply our changes
|
||||||
work_loop.wait_for_raf().await;
|
work_loop.wait_for_raf().await;
|
||||||
|
|||||||
@@ -33,8 +33,10 @@ impl RafLoop {
|
|||||||
.call0(&JsValue::NULL)
|
.call0(&JsValue::NULL)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let window = web_sys::window().unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
window: web_sys::window().unwrap(),
|
window,
|
||||||
raf_receiver,
|
raf_receiver,
|
||||||
raf_closure,
|
raf_closure,
|
||||||
ric_receiver,
|
ric_receiver,
|
||||||
|
|||||||
Reference in new issue
Block a user