nika_engine/display/
dag.rs1use colored::Colorize;
7
8use crate::display::icons;
9
10pub struct StaticDagTask {
12 pub id: String,
13 pub verb: String,
14 pub layer: usize,
15}
16
17pub struct StaticDagEdge {
19 pub from: String,
20 pub to: String,
21}
22
23pub fn print_static_dag(tasks: &[StaticDagTask], edges: &[StaticDagEdge]) {
40 if tasks.is_empty() {
41 return;
42 }
43
44 let max_layer = tasks.iter().map(|t| t.layer).max().unwrap_or(0);
46 let num_layers = max_layer + 1;
47
48 let tc = tasks.len();
49 let ec = edges.len();
50 let summary = format!(
51 "DAG {} {} \u{00B7} {} {} \u{00B7} {} {}",
52 tc,
53 if tc == 1 { "task" } else { "tasks" },
54 num_layers,
55 if num_layers == 1 { "layer" } else { "layers" },
56 ec,
57 if ec == 1 { "edge" } else { "edges" },
58 );
59 println!(" {}", summary.cyan().bold());
60 println!();
61
62 for layer_idx in 0..=max_layer {
64 let layer_tasks: Vec<&StaticDagTask> =
65 tasks.iter().filter(|t| t.layer == layer_idx).collect();
66
67 let line: Vec<String> = layer_tasks
69 .iter()
70 .map(|t| format!("{} {}", icons::verb_plain(&t.verb), t.id))
71 .collect();
72
73 println!(" {}", line.join(" "));
74
75 if layer_idx < max_layer {
77 let has_outgoing: Vec<bool> = layer_tasks
79 .iter()
80 .map(|t| edges.iter().any(|e| e.from == t.id))
81 .collect();
82
83 if has_outgoing.iter().any(|&b| b) {
84 let mut pipe_line = String::from(" ");
86 let mut arrow_line = String::from(" ");
87
88 for (i, task) in layer_tasks.iter().enumerate() {
89 let task_label_len = task.id.len() + 2; let center = task_label_len / 2;
93
94 if has_outgoing[i] {
95 pipe_line.push_str(&" ".repeat(center));
96 pipe_line.push_str(&format!("{}", "\u{2502}".dimmed())); pipe_line.push_str(&" ".repeat(task_label_len.saturating_sub(center + 1)));
98 } else {
99 pipe_line.push_str(&" ".repeat(task_label_len));
100 }
101
102 if has_outgoing[i] {
103 arrow_line.push_str(&" ".repeat(center));
104 arrow_line.push_str(&format!("{}", "\u{25BE}".dimmed())); arrow_line.push_str(&" ".repeat(task_label_len.saturating_sub(center + 1)));
106 } else {
107 arrow_line.push_str(&" ".repeat(task_label_len));
108 }
109
110 if i < layer_tasks.len() - 1 {
112 pipe_line.push_str(" ");
113 arrow_line.push_str(" ");
114 }
115 }
116
117 println!("{}", pipe_line);
118 println!("{}", arrow_line);
119 }
120 }
121 }
122 println!();
123}