use crate::utils::ffi::{self, TopologyNode};
use std::collections::HashMap;
pub struct SlaveTopology {
nodes: Vec<TopologyNode>,
children_map: HashMap<u16, Vec<u16>>,
root_slaves: Vec<u16>,
}
impl SlaveTopology {
pub fn build(master_index: u16) -> Self {
let mut buf = vec![TopologyNode {
slave_index: 0, config_addr: 0, parent_index: 0,
entry_port: 0, active_ports: 0, topology: 0, port_type: 0,
}; 512];
let count = unsafe { ffi::TopologyBuild(master_index, buf.as_mut_ptr(), 512) };
let count = count.max(0) as usize;
buf.truncate(count);
let mut children_map: HashMap<u16, Vec<u16>> = HashMap::new();
let mut root_slaves = Vec::new();
for node in &buf {
if node.parent_index == 0 || node.parent_index == node.slave_index {
root_slaves.push(node.slave_index);
} else {
children_map.entry(node.parent_index)
.or_insert_with(Vec::new)
.push(node.slave_index);
}
}
Self {
nodes: buf,
children_map,
root_slaves,
}
}
pub fn nodes(&self) -> &[TopologyNode] {
&self.nodes
}
pub fn count(&self) -> usize {
self.nodes.len()
}
pub fn root_slaves(&self) -> &[u16] {
&self.root_slaves
}
pub fn children(&self, parent_index: u16) -> &[u16] {
self.children_map.get(&parent_index).map(|v| v.as_slice()).unwrap_or(&[])
}
pub fn child_count(&self, parent_index: u16) -> usize {
self.children_map.get(&parent_index).map(|v| v.len()).unwrap_or(0)
}
pub fn get(&self, slave_index: u16) -> Option<&TopologyNode> {
self.nodes.iter().find(|n| n.slave_index == slave_index)
}
pub fn get_by_address(&self, address: &str) -> Option<&TopologyNode> {
let addr = if let Some(hex) = address.strip_prefix("0x").or_else(|| address.strip_prefix("0X")) {
u16::from_str_radix(hex, 16).ok()?
} else {
address.parse::<u16>().ok()?
};
self.nodes.iter().find(|n| n.config_addr == addr)
}
pub fn parent_of(&self, slave_index: u16) -> Option<u16> {
self.get(slave_index).map(|n| n.parent_index)
}
pub fn depth(&self, slave_index: u16) -> u32 {
let mut depth = 0u32;
let mut current = slave_index;
let mut visited = std::collections::HashSet::new();
while let Some(node) = self.get(current) {
if node.parent_index == 0 || node.parent_index == current || visited.contains(¤t) {
break;
}
visited.insert(current);
current = node.parent_index;
depth += 1;
}
depth
}
pub fn walk_dfs<F>(&self, mut visitor: F)
where
F: FnMut(u16, u32), {
for &root in &self.root_slaves {
self.walk_dfs_recursive(root, 0, &mut visitor);
}
}
fn walk_dfs_recursive<F>(&self, slave_index: u16, depth: u32, visitor: &mut F)
where
F: FnMut(u16, u32),
{
visitor(slave_index, depth);
if let Some(children) = self.children_map.get(&slave_index) {
for &child in children {
self.walk_dfs_recursive(child, depth + 1, visitor);
}
}
}
}