use crate::innerlude::Effect;
use crate::ScopeId;
use crate::Task;
use crate::VirtualDom;
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::hash::Hash;
#[derive(Debug, Clone, Copy, Eq)]
pub struct ScopeOrder {
pub(crate) height: u32,
pub(crate) id: ScopeId,
}
impl ScopeOrder {
pub fn new(height: u32, id: ScopeId) -> Self {
Self { height, id }
}
}
impl PartialEq for ScopeOrder {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl PartialOrd for ScopeOrder {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ScopeOrder {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.height.cmp(&other.height).then(self.id.cmp(&other.id))
}
}
impl Hash for ScopeOrder {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl VirtualDom {
pub(crate) fn queue_task(&mut self, task: Task, order: ScopeOrder) {
let mut dirty_tasks = self.runtime.dirty_tasks.borrow_mut();
match dirty_tasks.get(&order) {
Some(scope) => scope.queue_task(task),
None => {
let scope = DirtyTasks::from(order);
scope.queue_task(task);
dirty_tasks.insert(scope);
}
}
}
pub(crate) fn queue_scope(&mut self, order: ScopeOrder) {
self.dirty_scopes.insert(order);
}
pub(crate) fn has_dirty_scopes(&self) -> bool {
!self.dirty_scopes.is_empty()
}
pub(crate) fn pop_task(&mut self) -> Option<Task> {
let mut dirty_tasks = self.runtime.dirty_tasks.borrow_mut();
let tasks = dirty_tasks.first()?;
debug_assert!(self.scopes.contains(tasks.order.id.0));
let mut tasks = tasks.tasks_queued.borrow_mut();
let task = tasks.pop_front()?;
if tasks.is_empty() {
drop(tasks);
dirty_tasks.pop_first();
}
Some(task)
}
pub(crate) fn pop_effect(&mut self) -> Option<Effect> {
let mut pending_effects = self.runtime.pending_effects.borrow_mut();
let effect = pending_effects.pop_first()?;
debug_assert!(self.scopes.contains(effect.order.id.0));
Some(effect)
}
pub(crate) fn pop_work(&mut self) -> Option<Work> {
let dirty_scope = self.dirty_scopes.first();
#[cfg(debug_assertions)]
if let Some(scope) = dirty_scope {
assert!(self.scopes.contains(scope.id.0));
}
let dirty_task = {
let mut dirty_tasks = self.runtime.dirty_tasks.borrow_mut();
let mut dirty_task = dirty_tasks.first();
while let Some(task) = dirty_task {
if task.tasks_queued.borrow().is_empty() {
dirty_tasks.pop_first();
dirty_task = dirty_tasks.first()
} else {
break;
}
}
dirty_task.map(|task| task.order)
};
match (dirty_scope, dirty_task) {
(Some(scope), Some(task)) => {
let tasks_order = task.borrow();
match scope.cmp(tasks_order) {
std::cmp::Ordering::Less => {
let scope = self.dirty_scopes.pop_first().unwrap();
Some(Work::RerunScope(scope))
}
std::cmp::Ordering::Equal | std::cmp::Ordering::Greater => {
Some(Work::PollTask(self.pop_task().unwrap()))
}
}
}
(Some(_), None) => {
let scope = self.dirty_scopes.pop_first().unwrap();
Some(Work::RerunScope(scope))
}
(None, Some(_)) => Some(Work::PollTask(self.pop_task().unwrap())),
(None, None) => None,
}
}
}
#[derive(Debug)]
pub enum Work {
RerunScope(ScopeOrder),
PollTask(Task),
}
#[derive(Debug, Clone, Eq)]
pub(crate) struct DirtyTasks {
pub order: ScopeOrder,
pub tasks_queued: RefCell<VecDeque<Task>>,
}
impl From<ScopeOrder> for DirtyTasks {
fn from(order: ScopeOrder) -> Self {
Self {
order,
tasks_queued: VecDeque::new().into(),
}
}
}
impl DirtyTasks {
pub fn queue_task(&self, task: Task) {
let mut borrow_mut = self.tasks_queued.borrow_mut();
if borrow_mut.contains(&task) {
return;
}
borrow_mut.push_back(task);
}
pub(crate) fn remove(&self, id: Task) {
self.tasks_queued.borrow_mut().retain(|task| *task != id);
}
}
impl Borrow<ScopeOrder> for DirtyTasks {
fn borrow(&self) -> &ScopeOrder {
&self.order
}
}
impl Ord for DirtyTasks {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.order.cmp(&other.order)
}
}
impl PartialOrd for DirtyTasks {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for DirtyTasks {
fn eq(&self, other: &Self) -> bool {
self.order == other.order
}
}
impl Hash for DirtyTasks {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.order.hash(state);
}
}