use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use super::state::RouteFamily;
pub fn edge_content_key(source_ext_id: &str, target_ext_id: &str, relation: &str) -> String {
format!("{}->{}: {}", source_ext_id, target_ext_id, relation)
}
pub fn normalize_bidi_endpoints<'a>(a: &'a str, b: &'a str) -> (&'a str, &'a str) {
if a <= b {
(a, b)
} else {
(b, a)
}
}
pub fn route_content_id(target_ext_id: &str, family: &RouteFamily) -> String {
let mut hasher = DefaultHasher::new();
target_ext_id.hash(&mut hasher);
family_discriminant(family).hash(&mut hasher);
let hash = hasher.finish();
format!("R_{:06x}", hash & 0x00FF_FFFF)
}
fn family_discriminant(family: &RouteFamily) -> u8 {
match family {
RouteFamily::Structural => 0,
RouteFamily::Semantic => 1,
RouteFamily::Temporal => 2,
RouteFamily::Causal => 3,
RouteFamily::Ghost => 4,
RouteFamily::Hole => 5,
RouteFamily::Resonant => 6,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn edge_key_is_deterministic() {
let k1 = edge_content_key("main.rs", "lib.rs", "imports");
let k2 = edge_content_key("main.rs", "lib.rs", "imports");
assert_eq!(k1, k2);
}
#[test]
fn edge_key_differs_by_relation() {
let k1 = edge_content_key("a", "b", "imports");
let k2 = edge_content_key("a", "b", "calls");
assert_ne!(k1, k2);
}
#[test]
fn bidi_normalization() {
let (lo, hi) = normalize_bidi_endpoints("z_node", "a_node");
assert_eq!(lo, "a_node");
assert_eq!(hi, "z_node");
}
#[test]
fn route_id_format() {
let id = route_content_id("session.rs", &RouteFamily::Structural);
assert!(id.starts_with("R_"));
assert_eq!(id.len(), 8); }
#[test]
fn route_id_is_deterministic() {
let a = route_content_id("foo", &RouteFamily::Ghost);
let b = route_content_id("foo", &RouteFamily::Ghost);
assert_eq!(a, b);
}
#[test]
fn route_id_differs_by_family() {
let a = route_content_id("foo", &RouteFamily::Structural);
let b = route_content_id("foo", &RouteFamily::Semantic);
assert_ne!(a, b);
}
}