use core::any::Any;
use crate::collections::HashMap;
use crate::graph::NodeId;
use alloc::boxed::Box;
pub(crate) type StateContent = Box<dyn Any + Send>;
#[derive(Debug)]
pub(crate) enum State {
Recompute { n_required: usize },
Computed {
state_content: StateContent,
n_required: usize,
},
}
impl State {
pub(crate) fn to_state_content(&self) -> &StateContent {
match self {
State::Recompute { n_required: _ } => {
unreachable!(
"Can't get state content of recompute state. A child has likely been accessed before its parents."
)
}
State::Computed {
state_content,
n_required: _,
} => state_content,
}
}
pub(crate) fn into_state_content(self) -> StateContent {
match self {
State::Recompute { n_required: _ } => {
unreachable!(
"Can't get state content of recompute state. A child has likely been accessed before its parents."
)
}
State::Computed {
state_content,
n_required: _,
} => state_content,
}
}
pub(crate) fn n_required(&self) -> usize {
match self {
State::Recompute { n_required } => *n_required,
State::Computed {
state_content: _,
n_required,
} => *n_required,
}
}
}
#[derive(new, Default, Debug)]
pub struct BackwardStates {
map: HashMap<NodeId, State>,
}
impl BackwardStates {
pub fn get_state<T>(&mut self, node_id: &NodeId) -> T
where
T: Clone + Send + 'static,
{
let state = self.map.remove(node_id).unwrap();
let remaining_n_required = state.n_required() - 1;
if remaining_n_required > 0 {
let new_stored_state = match state {
State::Recompute { n_required: _ } => unreachable!(),
State::Computed {
state_content,
n_required: _,
} => State::Computed {
state_content,
n_required: remaining_n_required,
},
};
let downcasted = new_stored_state
.to_state_content()
.downcast_ref::<T>()
.unwrap()
.clone();
self.insert_state(*node_id, new_stored_state);
downcasted
} else {
let downcasted = state.into_state_content().downcast::<T>().unwrap();
*downcasted
}
}
pub(crate) fn get_state_ref(&self, node_id: &NodeId) -> Option<&State> {
self.map.get(node_id)
}
pub(crate) fn insert_state(&mut self, node_id: NodeId, state: State) {
self.map.insert(node_id, state);
}
pub fn save<T>(&mut self, node_id: NodeId, saved_output: T)
where
T: Clone + Send + 'static,
{
let n_required = self.get_state_ref(&node_id).unwrap().n_required();
self.insert_state(
node_id,
State::Computed {
state_content: Box::new(saved_output),
n_required,
},
);
}
pub(crate) fn is_empty(&self) -> bool {
self.map.is_empty()
}
}