use std::thread::JoinHandle; use crate::block::GraphableBlock; #[macro_export] macro_rules! flowgraph { ($($x:ident),* $(,)?) => { { let mut flowgraph = FlowGraph::new(); $( flowgraph.add_block($x); )* flowgraph } } } pub struct FlowGraph { blocks: Vec>, } impl FlowGraph { pub fn new() -> Self { FlowGraph { blocks: vec![] } } pub fn add_block(&mut self, block: T) { block.set_index(self.blocks.len()); self.blocks.push(Box::new(block)); } pub fn run(mut self) -> JoinHandle<()> { self.populate_edges(); std::thread::spawn(move || { 'outer: loop { for x in self.blocks.iter_mut() { match x.work() { crate::block::BlockResult::Ok => {} crate::block::BlockResult::Terminated => { //break 'outer; } crate::block::BlockResult::Exit => { println!("KILLING GRAPH"); break 'outer; } } } } }) } fn populate_edges(&mut self) { for block_index in 0..self.blocks.len() { let successors = self.blocks[block_index].get_successors(); for (output_index, succ_id) in successors.iter().enumerate() { let (tx, rx) = self.blocks[block_index].create_anonymous_stream_for(output_index, 4096); self.blocks[block_index].set_anonymous_out_stream(output_index, tx); self.blocks[succ_id.block_index].set_anonymous_in_stream(succ_id.port_index, rx); } } } pub fn get_dot(&self) -> String { let mut node_string = String::new(); for (i, block) in self.blocks.iter().enumerate() { // Block name // Input strings let mut input_string = String::new(); let inputs = block.get_input_names(); let len = inputs.len(); if !inputs.is_empty() { input_string.push('{'); for (j, input) in inputs.iter().enumerate() { input_string.push_str(&format!(" {}", j, input)); if j != len - 1 { input_string.push('|'); } } input_string.push_str("}|"); } // Output strings let mut output_string = String::new(); let outputs = block.get_output_names(); let len = outputs.len(); if !outputs.is_empty() { output_string.push_str("|{"); for (j, output) in outputs.iter().enumerate() { output_string.push_str(&format!(" {}", j, output)); if j != len - 1 { output_string.push('|'); } } output_string.push('}'); } node_string.push_str(&format!( "{}_{} [label=\"{{ {} {} {} }}\"];\n", block.get_block_name(), i, input_string, block.get_block_name(), output_string, )); } let mut edges_string = String::new(); for (i, block) in self.blocks.iter().enumerate() { let outputs = block.get_successors(); let output_types = block.get_output_type_names(); let block_name = block.get_block_name(); for (j, (output, output_type)) in outputs.iter().zip(output_types.iter()).enumerate() { let destination_block = output.block_index; let destination_block_name = self.blocks[destination_block].get_block_name(); edges_string.push_str(&format!( "{}_{}:o{} -> {}_{}:i{} [label=\"{}\"];\n", block_name, i, j, destination_block_name, destination_block, output.port_index, output_type )); } } format!( " digraph G {{ node [shape=record]; rankdir=TB; {} {} }} ", node_string, edges_string ) } } impl Default for FlowGraph { fn default() -> Self { Self::new() } }