use crate::ast::{Protocol, Role};
use std::collections::{HashMap, HashSet};
pub(super) fn has_cycle(graph: &HashMap<Role, HashSet<Role>>) -> bool {
let mut visited = HashSet::new();
let mut rec_stack = HashSet::new();
for node in graph.keys() {
if !visited.contains(node) && dfs_cycle(node, graph, &mut visited, &mut rec_stack) {
return true;
}
}
false
}
fn dfs_cycle(
node: &Role,
graph: &HashMap<Role, HashSet<Role>>,
visited: &mut HashSet<Role>,
rec_stack: &mut HashSet<Role>,
) -> bool {
visited.insert(node.clone());
rec_stack.insert(node.clone());
if let Some(neighbors) = graph.get(node) {
for neighbor in neighbors {
if !visited.contains(neighbor) {
if dfs_cycle(neighbor, graph, visited, rec_stack) {
return true;
}
} else if rec_stack.contains(neighbor) {
return true;
}
}
}
rec_stack.remove(node);
false
}
pub(super) fn has_communication(protocol: &Protocol) -> bool {
match protocol {
Protocol::Send { .. } | Protocol::Broadcast { .. } => true,
Protocol::Choice { branches, .. } => {
branches.iter().any(|b| has_communication(&b.protocol))
}
Protocol::Case { branches, .. } => branches.iter().any(|b| has_communication(&b.protocol)),
Protocol::Timeout {
body,
on_timeout,
on_cancel,
..
} => {
has_communication(body)
|| has_communication(on_timeout)
|| on_cancel.as_deref().is_some_and(has_communication)
}
Protocol::Loop { body, .. } => has_communication(body),
Protocol::Parallel { protocols } => protocols.iter().any(has_communication),
Protocol::Rec { body, .. } => has_communication(body),
Protocol::Var(_) | Protocol::End => false,
Protocol::Begin { continuation, .. }
| Protocol::Await { continuation, .. }
| Protocol::Resolve { continuation, .. }
| Protocol::Invalidate { continuation, .. }
| Protocol::Extension { continuation, .. }
| Protocol::Let { continuation, .. }
| Protocol::Publish { continuation, .. }
| Protocol::PublishAuthority { continuation, .. }
| Protocol::Materialize { continuation, .. }
| Protocol::Handoff { continuation, .. }
| Protocol::DependentWork { continuation, .. } => has_communication(continuation),
}
}