use crate::error::types::SupervisorError;
use crate::id::types::{ChildId, SupervisorPath};
use crate::spec::child::{ChildSpec, TaskKind};
use crate::spec::supervisor::SupervisorSpec;
use std::collections::HashSet;
#[derive(Debug, Clone)]
pub struct SupervisorTreeNode {
pub path: SupervisorPath,
pub child: ChildSpec,
pub declaration_index: usize,
}
#[derive(Debug, Clone)]
pub struct SupervisorTree {
pub root_path: SupervisorPath,
pub nodes: Vec<SupervisorTreeNode>,
}
impl SupervisorTree {
pub fn build(spec: &SupervisorSpec) -> Result<Self, SupervisorError> {
spec.validate()?;
let mut seen = HashSet::new();
let mut nodes = Vec::with_capacity(spec.children.len());
for (index, child) in spec.children.iter().enumerate() {
validate_child_path(&spec.path, &child.id, &mut seen)?;
nodes.push(SupervisorTreeNode {
path: spec.path.join(&child.id.value),
child: child.clone(),
declaration_index: index,
});
}
Ok(Self {
root_path: spec.path.clone(),
nodes,
})
}
pub fn child_path(&self, child_id: &ChildId) -> Option<SupervisorPath> {
self.nodes
.iter()
.find(|node| node.child.id == *child_id)
.map(|node| node.path.clone())
}
pub fn nested_supervisors(&self) -> Vec<&SupervisorTreeNode> {
self.nodes
.iter()
.filter(|node| node.child.kind == TaskKind::Supervisor)
.collect()
}
}
fn validate_child_path(
parent: &SupervisorPath,
child_id: &ChildId,
seen: &mut HashSet<String>,
) -> Result<(), SupervisorError> {
let path = parent.join(&child_id.value).to_string();
if seen.insert(path) {
Ok(())
} else {
Err(SupervisorError::fatal_config(format!(
"duplicate child path for {child_id}"
)))
}
}