use super::{GlobalNodeId, NodeId, OwnershipPreference, circuit_builder::Node};
use crate::circuit::metadata::OperatorLocation;
use std::{borrow::Cow, fmt, fmt::Display, hash::Hash};
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub enum EdgeKind {
Stream(OwnershipPreference),
Dependency,
}
impl EdgeKind {
pub fn is_stream(&self) -> bool {
matches!(self, Self::Stream(..))
}
}
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub enum CircuitEvent {
PushRegion {
name: Cow<'static, str>,
location: OperatorLocation,
},
PopRegion,
Operator {
node_id: GlobalNodeId,
name: Cow<'static, str>,
location: OperatorLocation,
},
StrictOperatorOutput {
node_id: GlobalNodeId,
name: Cow<'static, str>,
location: OperatorLocation,
},
StrictOperatorInput {
node_id: GlobalNodeId,
output_node_id: NodeId,
},
Subcircuit {
node_id: GlobalNodeId,
iterative: bool,
},
SubcircuitComplete {
node_id: GlobalNodeId,
},
Edge {
kind: EdgeKind,
from: GlobalNodeId,
to: GlobalNodeId,
},
}
impl CircuitEvent {
pub fn push_region_static(name: &'static str, location: OperatorLocation) -> Self {
Self::PushRegion {
name: Cow::Borrowed(name),
location,
}
}
pub fn push_region(name: &str, location: OperatorLocation) -> Self {
Self::PushRegion {
name: Cow::Owned(name.to_string()),
location,
}
}
pub fn pop_region() -> Self {
Self::PopRegion
}
pub fn operator(
node_id: GlobalNodeId,
name: Cow<'static, str>,
location: OperatorLocation,
) -> Self {
Self::Operator {
node_id,
name,
location,
}
}
pub fn strict_operator_output(
node_id: GlobalNodeId,
name: Cow<'static, str>,
location: OperatorLocation,
) -> Self {
Self::StrictOperatorOutput {
node_id,
name,
location,
}
}
pub fn strict_operator_input(node_id: GlobalNodeId, output_node_id: NodeId) -> Self {
Self::StrictOperatorInput {
node_id,
output_node_id,
}
}
pub fn subcircuit(node_id: GlobalNodeId, iterative: bool) -> Self {
Self::Subcircuit { node_id, iterative }
}
pub fn subcircuit_complete(node_id: GlobalNodeId) -> Self {
Self::SubcircuitComplete { node_id }
}
pub fn stream(
from: GlobalNodeId,
to: GlobalNodeId,
ownership_preference: OwnershipPreference,
) -> Self {
Self::Edge {
kind: EdgeKind::Stream(ownership_preference),
from,
to,
}
}
pub fn dependency(from: GlobalNodeId, to: GlobalNodeId) -> Self {
Self::Edge {
kind: EdgeKind::Dependency,
from,
to,
}
}
pub fn is_strict_input_event(&self) -> bool {
matches!(self, Self::StrictOperatorInput { .. })
}
pub fn is_strict_output_event(&self) -> bool {
matches!(self, Self::StrictOperatorOutput { .. })
}
pub fn is_operator_event(&self) -> bool {
matches!(self, Self::Operator { .. })
}
pub fn is_subcircuit_event(&self) -> bool {
matches!(self, Self::Subcircuit { .. })
}
pub fn is_iterative_subcircuit_event(&self) -> bool {
matches!(
self,
Self::Subcircuit {
iterative: true,
..
}
)
}
pub fn is_edge_event(&self) -> bool {
matches!(self, Self::Edge { .. })
}
pub fn is_node_event(&self) -> bool {
matches!(
self,
Self::Operator { .. }
| Self::StrictOperatorOutput { .. }
| Self::StrictOperatorInput { .. }
| Self::Subcircuit { .. }
| Self::SubcircuitComplete { .. }
)
}
pub fn is_new_node_event(&self) -> bool {
matches!(
self,
Self::Operator { .. }
| Self::StrictOperatorOutput { .. }
| Self::StrictOperatorInput { .. }
| Self::Subcircuit { .. }
)
}
pub fn node_id(&self) -> Option<&GlobalNodeId> {
match self {
Self::Operator { node_id, .. }
| Self::StrictOperatorOutput { node_id, .. }
| Self::StrictOperatorInput { node_id, .. }
| Self::Subcircuit { node_id, .. } => Some(node_id),
Self::SubcircuitComplete { node_id } => Some(node_id),
_ => None,
}
}
pub fn node_name(&self) -> Option<&Cow<'static, str>> {
match self {
Self::Operator { name, .. } | Self::StrictOperatorOutput { name, .. } => Some(name),
_ => None,
}
}
pub fn location(&self) -> OperatorLocation {
match *self {
Self::PushRegion { location, .. }
| Self::Operator { location, .. }
| Self::StrictOperatorOutput { location, .. } => location,
_ => None,
}
}
pub fn output_node_id(&self) -> Option<NodeId> {
if let Self::StrictOperatorInput { output_node_id, .. } = self {
Some(*output_node_id)
} else {
None
}
}
pub fn from(&self) -> Option<&GlobalNodeId> {
if let Self::Edge { from, .. } = self {
Some(from)
} else {
None
}
}
pub fn to(&self) -> Option<&GlobalNodeId> {
if let Self::Edge { to, .. } = self {
Some(to)
} else {
None
}
}
pub fn edge_kind(&self) -> Option<&EdgeKind> {
if let Self::Edge { kind, .. } = self {
Some(kind)
} else {
None
}
}
}
impl Display for CircuitEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::PushRegion { name, location } => {
write!(f, "PushRegion(\"{name}\"")?;
if let Some(location) = location {
write!(
f,
" @ {}:{}:{}",
location.file(),
location.line(),
location.column()
)?;
}
write!(f, ")")
}
Self::PopRegion => f.write_str("PopRegion"),
Self::Operator {
node_id,
name,
location,
} => {
write!(f, "Operator(\"{name}\", {node_id}")?;
if let Some(location) = location {
write!(
f,
" @ {}:{}:{}",
location.file(),
location.line(),
location.column()
)?;
}
write!(f, ")")
}
Self::StrictOperatorOutput {
node_id,
name,
location,
} => {
write!(f, "StrictOperatorOutput(\"{name}\", {node_id}")?;
if let Some(location) = location {
write!(
f,
" @ {}:{}:{}",
location.file(),
location.line(),
location.column()
)?;
}
write!(f, ")")
}
Self::StrictOperatorInput {
node_id,
output_node_id,
} => {
write!(f, "StrictOperatorInput({node_id} -> {output_node_id})")
}
Self::Subcircuit { node_id, iterative } => {
write!(
f,
"{}Subcircuit({})",
if *iterative { "Iterative" } else { "" },
node_id,
)
}
Self::SubcircuitComplete { node_id } => {
write!(f, "SubcircuitComplete({node_id})")
}
Self::Edge {
kind: EdgeKind::Stream(preference),
from,
to,
} => {
write!(f, "Stream({from} -> [{preference}]{to})")
}
Self::Edge {
kind: EdgeKind::Dependency,
from,
to,
} => {
write!(f, "Dependency({from} -> {to})")
}
}
}
}
pub enum SchedulerEvent<'a> {
EvalStart { node: &'a dyn Node },
EvalEnd { node: &'a dyn Node },
WaitStart { circuit_id: &'a GlobalNodeId },
WaitEnd { circuit_id: &'a GlobalNodeId },
StepStart { circuit_id: &'a GlobalNodeId },
StepEnd { circuit_id: &'a GlobalNodeId },
ClockStart,
ClockEnd,
}
impl<'a> SchedulerEvent<'a> {
pub fn eval_start(node: &'a dyn Node) -> Self {
Self::EvalStart { node }
}
pub fn eval_end(node: &'a dyn Node) -> Self {
Self::EvalEnd { node }
}
pub fn wait_start(circuit_id: &'a GlobalNodeId) -> Self {
Self::WaitStart { circuit_id }
}
pub fn wait_end(circuit_id: &'a GlobalNodeId) -> Self {
Self::WaitEnd { circuit_id }
}
pub fn step_start(circuit_id: &'a GlobalNodeId) -> Self {
Self::StepStart { circuit_id }
}
pub fn step_end(circuit_id: &'a GlobalNodeId) -> Self {
Self::StepEnd { circuit_id }
}
pub fn clock_start() -> Self {
Self::ClockStart
}
pub fn clock_end() -> Self {
Self::ClockEnd
}
}
impl Display for SchedulerEvent<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::EvalStart { node } => {
write!(f, "EvalStart({})", node.global_id())
}
Self::EvalEnd { node } => {
write!(f, "EvalEnd({})", node.global_id())
}
Self::WaitStart { circuit_id } => {
write!(f, "WaitStart({circuit_id})")
}
Self::WaitEnd { circuit_id } => {
write!(f, "WaitEnd({circuit_id})")
}
Self::StepStart { circuit_id } => {
write!(f, "StepStart({circuit_id})")
}
Self::StepEnd { circuit_id } => {
write!(f, "StepEnd({circuit_id})")
}
Self::ClockStart => f.write_str("ClockStart"),
Self::ClockEnd => f.write_str("ClockEnd"),
}
}
}