use crate::graph::FleetGraph;
use std::collections::{HashMap, HashSet, VecDeque};
pub struct ConstraintRouter<'a> {
graph: &'a FleetGraph,
}
impl<'a> ConstraintRouter<'a> {
pub fn new(graph: &'a FleetGraph) -> Self {
ConstraintRouter { graph }
}
pub fn route(&self, from: &str, to: &str) -> Option<Route> {
let constraint_adj: HashMap<&str, Vec<(&str, u64)>> = self
.graph
.edges()
.iter()
.filter(|e| e.constraint_flow)
.fold(HashMap::new(), |mut acc, e| {
acc.entry(&e.from)
.or_default()
.push((&e.to, e.latency_us));
acc.entry(&e.to)
.or_default()
.push((&e.from, e.latency_us));
acc
});
let mut queue = VecDeque::new();
let mut parent: HashMap<String, Option<(String, u64)>> = HashMap::new();
queue.push_back(from.to_string());
parent.insert(from.to_string(), None);
while let Some(current) = queue.pop_front() {
if current == to {
let mut path = Vec::new();
let mut total_latency = 0u64;
let mut node = Some(to.to_string());
while let Some(n) = node {
let latency = parent
.get(&n)
.and_then(|p| p.as_ref().map(|(_, l)| *l))
.unwrap_or(0);
total_latency += latency;
path.push(n.clone());
node = parent.get(&n).and_then(|p| p.as_ref().map(|(p, _)| p.clone()));
}
path.reverse();
return Some(Route {
hops: path.len().saturating_sub(1),
path,
total_latency_us: total_latency,
});
}
if let Some(neighbors) = constraint_adj.get(current.as_str()) {
for &(neighbor, latency) in neighbors {
let n = neighbor.to_string();
if !parent.contains_key(&n) {
parent.insert(
n.clone(),
Some((current.clone(), latency)),
);
queue.push_back(n);
}
}
}
}
None
}
pub fn constraint_neighborhood(&self, device: &str) -> Vec<String> {
let constraint_adj: HashMap<&str, Vec<&str>> = self
.graph
.edges()
.iter()
.filter(|e| e.constraint_flow)
.fold(HashMap::new(), |mut acc, e| {
acc.entry(&e.from).or_default().push(&e.to);
acc.entry(&e.to).or_default().push(&e.from);
acc
});
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
let mut result = Vec::new();
queue.push_back(device);
visited.insert(device);
while let Some(current) = queue.pop_front() {
result.push(current.to_string());
if let Some(neighbors) = constraint_adj.get(current) {
for &next in neighbors {
if !visited.contains(next) {
visited.insert(next);
queue.push_back(next);
}
}
}
}
result
}
}
pub struct Route {
pub path: Vec<String>,
pub total_latency_us: u64,
pub hops: usize,
}