use std::{
collections::{HashMap, VecDeque},
hash::Hash,
};
#[derive(Debug)]
pub enum Edge<T, L> {
Empty,
Pred(L, T),
}
#[derive(Debug)]
pub struct LabeledQueue<T, L> {
queue: VecDeque<T>,
map: HashMap<T, Edge<T, L>>,
}
#[derive(Debug)]
struct EdgeIterator<'a, T, L> {
queue: &'a LabeledQueue<T, L>,
last_edge: &'a Edge<T, L>,
}
impl<'a, T: Eq + Hash + Clone, L: Clone> Iterator for EdgeIterator<'a, T, L> {
type Item = (&'a T, &'a L);
fn next(&mut self) -> Option<Self::Item> {
match self.last_edge {
Edge::Empty => None,
Edge::Pred(label, node) => {
self.last_edge = self.queue.map.get(node).unwrap();
Some((node, label))
}
}
}
}
#[allow(dead_code)]
impl<T: Eq + Hash + Clone, L: Clone> LabeledQueue<T, L> {
pub fn new(root: T) -> Self {
let mut queue = VecDeque::new();
let mut map = HashMap::new();
queue.push_back(root.clone());
map.insert(root, Edge::Empty);
LabeledQueue { queue, map }
}
pub fn push(&mut self, pre: T, label: L, suc: T) -> bool {
match self.map.get(&suc) {
Some(..) => false,
None => {
self.queue.push_back(suc.clone());
self.map.insert(suc, Edge::Pred(label, pre));
true
}
}
}
pub fn push_all(&mut self, pre: T, iter: impl Iterator<Item = (L, T)>) {
for (label, successor) in iter {
self.push(pre.clone(), label, successor);
}
}
pub fn is_empty(&self) -> bool {
self.queue.is_empty()
}
pub fn pop(&mut self) -> Option<T> {
self.queue.pop_front()
}
pub fn visited(&self, node: &T) -> bool {
self.map.contains_key(node)
}
fn edge_iter<'a>(&'a self, e: &'a Edge<T, L>) -> EdgeIterator<'a, T, L> {
EdgeIterator {
queue: self,
last_edge: e,
}
}
fn labels_on_path(&self, e: &Edge<T, L>) -> Vec<L> {
let mut result: Vec<L> = self
.edge_iter(e)
.map(|(_node, label)| label.clone())
.collect();
result.reverse();
result
}
fn make_path(&self, e: &Edge<T, L>) -> Vec<(T, L)> {
let mut result: Vec<(T, L)> = self
.edge_iter(e)
.map(|(node, label)| (node.clone(), label.clone()))
.collect();
result.reverse();
result
}
pub fn path(&self, node: &T) -> Option<Vec<L>> {
self.map.get(node).map(|e| self.labels_on_path(e))
}
pub fn path_unchecked(&self, node: &T) -> Vec<L> {
let e = self.map.get(node).unwrap();
self.labels_on_path(e)
}
pub fn full_path(&self, destination: &T) -> Option<Vec<(T, L)>> {
self.map.get(destination).map(|e| self.make_path(e))
}
pub fn full_path_unchecked(&self, destination: &T) -> Vec<(T, L)> {
let e = self.map.get(destination).unwrap();
self.make_path(e)
}
}
#[cfg(test)]
mod test {
use std::fmt::Display;
use super::*;
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
struct Node(u32);
impl Display for Node {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "n{}", self.0)
}
}
#[derive(Debug, Clone, Copy)]
struct Label(char);
impl Display for Label {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
fn graph() -> Vec<(u32, char, u32)> {
vec![
(0, 'a', 0),
(0, 'b', 1),
(0, 'c', 2),
(1, 'a', 3),
(1, 'c', 2),
(2, 'b', 3),
(2, 'c', 3),
(3, 'a', 0),
(3, 'b', 1),
(3, 'c', 3),
]
}
fn cycle() -> Vec<(u32, char, u32)> {
vec![
(0, 'a', 1),
(1, 'b', 2),
(2, 'c', 3),
(3, 'd', 4),
(4, 'e', 5),
(5, 'f', 0),
]
}
fn successors(node: u32, graph: &[(u32, char, u32)]) -> impl Iterator<Item = (char, u32)> + '_ {
graph
.iter()
.filter(move |(x, _, _)| *x == node)
.map(|x| (x.1, x.2))
}
fn explore_graph(num_nodes: u32, graph: &[(u32, char, u32)]) {
for i in 0..num_nodes {
let root = Node(i);
let mut queue: LabeledQueue<Node, Label> = LabeledQueue::new(root);
while !queue.is_empty() {
let n = queue.pop().unwrap();
for (l, s) in successors(n.0, graph) {
queue.push(n, Label(l), Node(s));
}
}
println!("Paths from root n{}", i);
for j in 0..num_nodes {
match queue.path(&Node(j)) {
None => {
println!("n{} is not reachable", j);
}
Some(p) => {
print!("n{} is reachable via path (", j);
for l in &p {
print!("{}", l);
}
println!(")");
let full = queue.full_path_unchecked(&Node(j));
print!(" ");
for (n, l) in &full {
print!("{}--{}--", n, l);
}
println!("{}", Node(j));
}
}
}
println!()
}
}
#[test]
fn test() {
println!("\nTest graph");
explore_graph(5, &graph());
println!("\nCycle of 6 nodes");
explore_graph(6, &cycle());
}
}