use std::cell::Cell;
use super::stabilisation_num::StabilisationNum;
use crate::boxes::SmallBox;
use crate::incrsan::not_observer_boxed_trait;
use crate::node::{ErasedNode, Node};
not_observer_boxed_trait! {
pub(crate) type BoxedUpdateFn<T> = SmallBox<dyn (FnMut(NodeUpdate<&T>))>;
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
enum Previously {
NeverBeenUpdated,
Necessary,
Changed,
Invalidated,
Unnecessary,
}
#[derive(Copy, Clone, Debug)]
pub(crate) enum NodeUpdateDelayed {
Necessary,
Changed,
Invalidated,
Unnecessary,
}
#[derive(Debug)]
pub enum NodeUpdate<T> {
Necessary(T),
Changed(T),
Invalidated,
Unnecessary,
}
not_observer_boxed_trait! {
pub(crate) type ErasedOnUpdateHandler = Box<dyn (HandleUpdate)>;
}
pub(crate) trait HandleUpdate {
fn run(&mut self, node: &Node, node_update: NodeUpdateDelayed, now: StabilisationNum);
}
pub(crate) struct OnUpdateHandler<T> {
handler_fn: BoxedUpdateFn<T>,
previous_update_kind: Cell<Previously>,
created_at: StabilisationNum,
}
impl<T: 'static> OnUpdateHandler<T> {
pub(crate) fn new(created_at: StabilisationNum, handler_fn: BoxedUpdateFn<T>) -> Self {
OnUpdateHandler {
handler_fn,
created_at,
previous_update_kind: Previously::NeverBeenUpdated.into(),
}
}
fn really_run_downcast(&mut self, node: &Node, node_update: NodeUpdateDelayed) {
self.previous_update_kind.set(match &node_update {
NodeUpdateDelayed::Changed => Previously::Changed,
NodeUpdateDelayed::Necessary => Previously::Necessary,
NodeUpdateDelayed::Invalidated => Previously::Invalidated,
NodeUpdateDelayed::Unnecessary => Previously::Unnecessary,
});
let value_any = node.value_as_any();
let concrete_update = match node_update {
NodeUpdateDelayed::Changed => {
let value_any = value_any.unwrap();
let v = value_any
.as_any()
.downcast_ref::<T>()
.expect("downcast_ref failed");
return (self.handler_fn)(NodeUpdate::Changed(&*v));
}
NodeUpdateDelayed::Necessary => {
let value_any = value_any.unwrap();
let v = value_any
.as_any()
.downcast_ref::<T>()
.expect("downcast_ref failed");
return (self.handler_fn)(NodeUpdate::Necessary(&*v));
}
NodeUpdateDelayed::Invalidated => NodeUpdate::Invalidated,
NodeUpdateDelayed::Unnecessary => NodeUpdate::Unnecessary,
};
(self.handler_fn)(concrete_update);
}
}
impl<T: 'static> HandleUpdate for OnUpdateHandler<T> {
fn run(&mut self, node: &Node, node_update: NodeUpdateDelayed, now: StabilisationNum) {
if self.created_at < now {
match (self.previous_update_kind.get(), node_update) {
(Previously::Invalidated, _) => (),
(Previously::Changed, NodeUpdateDelayed::Necessary)
| (Previously::Necessary, NodeUpdateDelayed::Necessary)
| (Previously::Unnecessary, NodeUpdateDelayed::Unnecessary) => (),
(
Previously::NeverBeenUpdated | Previously::Unnecessary,
NodeUpdateDelayed::Changed,
) => self.really_run_downcast(node, NodeUpdateDelayed::Necessary),
(_, node_update) => self.really_run_downcast(node, node_update),
}
}
}
}