use rustc_hash::FxHashMap;
use crate::graph::ValueMap;
use crate::value::{Value, ValueOrView, ValueView};
use super::{Graph, Node, NodeId};
#[derive(Clone)]
pub struct CaptureEnv<'a> {
parent: Option<&'a CaptureEnv<'a>>,
graph: Option<&'a Graph>,
inputs: Option<&'a FxHashMap<NodeId, ValueOrView<'a>>>,
temp_values_by_ref: Option<&'a ValueMap>,
temp_values: Option<FxHashMap<NodeId, Value>>,
}
impl<'a> CaptureEnv<'a> {
pub fn new(
parent: Option<&'a CaptureEnv<'a>>,
graph: &'a Graph,
inputs: Option<&'a FxHashMap<NodeId, ValueOrView<'a>>>,
temp_values_by_ref: Option<&'a ValueMap>,
temp_values: Option<FxHashMap<NodeId, Value>>,
) -> CaptureEnv<'a> {
CaptureEnv {
parent,
graph: Some(graph),
inputs,
temp_values_by_ref,
temp_values,
}
}
#[allow(unused)]
pub fn empty() -> Self {
CaptureEnv {
parent: None,
graph: None,
inputs: None,
temp_values_by_ref: None,
temp_values: None,
}
}
#[cfg(test)]
pub fn top_level_static(graph: &'a Graph) -> Self {
CaptureEnv {
parent: None,
graph: Some(graph),
inputs: None,
temp_values_by_ref: None,
temp_values: None,
}
}
pub fn child(&self) -> CaptureEnv<'_> {
CaptureEnv {
parent: Some(self),
graph: None,
inputs: None,
temp_values_by_ref: None,
temp_values: None,
}
}
pub fn get_node(&self, name: &str) -> Option<&'a Node> {
if let Some(graph) = self.graph
&& let Some(node_id) = graph.get_node_id(name)
{
if !graph.captures().contains(&node_id) {
return graph.get_node(node_id);
}
}
self.parent.and_then(|parent| parent.get_node(name))
}
pub fn get_input(&self, name: &str) -> Option<ValueView<'_>> {
if let Some(graph) = self.graph &&
let Some(node_id) = graph.get_node_id(name) &&
!graph.captures().contains(&node_id)
{
return match graph.get_node(node_id) {
Some(Node::Constant(c)) => Some(c.as_view()),
Some(Node::Value(_)) => self
.temp_values_by_ref
.and_then(|tv| tv.get(node_id))
.map(|i| i.as_view())
.or_else(|| {
self.temp_values
.as_ref()
.and_then(|tv| tv.get(&node_id))
.map(|o| o.as_view())
})
.or_else(|| {
self.inputs
.and_then(|i| i.get(&node_id))
.map(|i| i.as_view())
}),
_ => None,
};
}
self.parent.and_then(|parent| parent.get_input(name))
}
pub fn take_input(&mut self, name: &str) -> Option<Value> {
let node_id = self.graph.and_then(|g| g.get_node_id(name))?;
self.temp_values.as_mut()?.remove(&node_id)
}
pub fn take_all_inputs(&mut self) -> Option<FxHashMap<NodeId, Value>> {
self.temp_values.take()
}
}