179 lines
4.9 KiB
Rust
179 lines
4.9 KiB
Rust
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<Box<dyn GraphableBlock + Send + 'static>>,
|
|
}
|
|
|
|
impl FlowGraph
|
|
{
|
|
pub fn new() -> Self
|
|
{
|
|
FlowGraph { blocks: vec![] }
|
|
}
|
|
|
|
pub fn add_block<T: GraphableBlock + Send + 'static>(&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!("<i{}> {}", 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!("<o{}> {}", 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()
|
|
}
|
|
}
|