use std::{
cell::{BorrowError, RefCell},
ops::DerefMut,
rc::Rc,
};
use crate::execution::{
error::ResolveResult, identifiable::next_node_id, Clean, Identifiable, InputState, Named,
NodeRef, NodeState, Resolve, UpdateInput, Visitor,
};
#[derive(Debug)]
pub struct InputNode<T> {
resolve_state: RefCell<InputState>,
value: RefCell<NodeState<T>>,
id: usize,
}
impl<T: Named> Named for InputNode<T> {
fn name() -> &'static str {
T::name()
}
}
impl<T: Named> Identifiable for InputNode<T> {
fn id(&self) -> usize {
self.id
}
}
impl<T> InputNode<T>
where
T: UpdateInput,
{
pub fn new(value: T) -> Rc<Self> {
Self::new_with_id(value, next_node_id())
}
pub fn new_with_id(value: T, id: usize) -> Rc<Self> {
Rc::new(Self {
resolve_state: RefCell::new(InputState::default()),
value: RefCell::new(NodeState::new(value)),
id,
})
}
pub fn update(&self, input: T::Update) -> ResolveResult<()> {
let mut node_state = self.value.try_borrow_mut()?;
let mut resolve_state = self.resolve_state.try_borrow_mut()?;
if *resolve_state == InputState::Resolving {
node_state.clean();
}
*resolve_state = InputState::Updating;
node_state.deref_mut().update_mut(input);
Ok(())
}
pub fn value(&self) -> Result<NodeRef<'_, T>, BorrowError> {
self.value.try_borrow()
}
}
impl<T> Resolve for InputNode<T>
where
T: UpdateInput,
{
type Output<'a>
= NodeRef<'a, T>
where
Self: 'a;
fn resolve(&self, visitor: &mut impl Visitor) -> ResolveResult<Self::Output<'_>> {
visitor.touch(self, None);
if visitor.visit(self) {
let mut node_state = self.value.try_borrow_mut()?;
let mut resolve_state = self.resolve_state.try_borrow_mut()?;
match *resolve_state {
InputState::Updating => *resolve_state = InputState::Resolving,
InputState::Resolving => {
node_state.clean();
*resolve_state = InputState::Resolved
}
InputState::Resolved => {}
}
node_state.update_node_hash(&mut visitor.hasher());
}
visitor.leave(self);
Ok(self.value.try_borrow()?)
}
}