use graph_sp::core::{Graph, Node, NodeConfig, Port, PortData};
use graph_sp::executor::Executor;
use graph_sp::inspector::Inspector;
use std::collections::HashMap;
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Graph-SP Example: Implicit Edge Mapping ===\n");
println!("Example 1: Simple Pipeline (auto-connected)");
println!("{}", "-".repeat(50));
let mut graph = Graph::new();
let source = NodeConfig::new(
"source",
"Data Source",
vec![],
vec![Port::simple("data")],
Arc::new(|_: &HashMap<String, PortData>| {
println!("[source] Generating data...");
Ok(HashMap::from([(
"data".to_string(),
PortData::List(vec![
PortData::Int(1),
PortData::Int(2),
PortData::Int(3),
PortData::Int(4),
PortData::Int(5),
]),
)]))
}),
);
let processor = NodeConfig::new(
"processor",
"Data Processor",
vec![Port::simple("data")],
vec![Port::simple("result")],
Arc::new(|inputs: &HashMap<String, PortData>| {
println!("[processor] Processing data...");
if let Some(PortData::List(data)) = inputs.get("data") {
let doubled: Vec<PortData> = data
.iter()
.map(|item| {
if let PortData::Int(val) = item {
PortData::Int(val * 2)
} else {
item.clone()
}
})
.collect();
Ok(HashMap::from([(
"result".to_string(),
PortData::List(doubled),
)]))
} else {
Ok(HashMap::new())
}
}),
);
let sink = NodeConfig::new(
"sink",
"Result Sink",
vec![Port::simple("result")],
vec![],
Arc::new(|inputs: &HashMap<String, PortData>| {
println!("[sink] Receiving result...");
if let Some(result) = inputs.get("result") {
println!("[sink] Final result: {}", result);
}
Ok(HashMap::new())
}),
);
graph.add(Node::new(source))?;
graph.add(Node::new(processor))?;
graph.add(Node::new(sink))?;
let edges_created = graph.auto_connect()?;
println!(
"✓ Auto-connected {} edges based on port name matching!\n",
edges_created
);
println!("Validating graph...");
graph.validate()?;
println!("✓ Graph is valid (no cycles detected)\n");
println!("=== Graph Analysis ===");
let analysis = Inspector::analyze(&graph);
println!("Nodes: {}", analysis.node_count);
println!("Edges: {}", analysis.edge_count);
println!("Depth: {}", analysis.depth);
println!("Summary: {}\n", analysis.summary());
println!("=== Mermaid Diagram ===");
let mermaid = Inspector::to_mermaid(&graph)?;
println!("{}", mermaid);
println!("=== Executing Graph ===");
let executor = Executor::new();
let _result = executor.execute(&mut graph).await?;
println!("✓ Execution completed!\n");
println!("\nExample 2: Parallel Branches (auto-connected)");
println!("{}", "-".repeat(50));
let mut graph2 = Graph::new();
let source2 = NodeConfig::new(
"source",
"Value Source",
vec![],
vec![Port::simple("value")],
Arc::new(|_: &HashMap<String, PortData>| {
println!("[source] Generating value...");
Ok(HashMap::from([("value".to_string(), PortData::Int(100))]))
}),
);
let branch_a = NodeConfig::new(
"branch_a",
"Branch A\\n(×2)", vec![Port::simple("value")],
vec![Port::simple("branch_a_out")],
Arc::new(|inputs: &HashMap<String, PortData>| {
println!("[branch_a] Processing...");
if let Some(PortData::Int(val)) = inputs.get("value") {
Ok(HashMap::from([(
"branch_a_out".to_string(),
PortData::Int(val * 2),
)]))
} else {
Ok(HashMap::new())
}
}),
);
let branch_b = NodeConfig::new(
"branch_b",
"Branch B\\n(+50)", vec![Port::simple("value")],
vec![Port::simple("branch_b_out")],
Arc::new(|inputs: &HashMap<String, PortData>| {
println!("[branch_b] Processing...");
if let Some(PortData::Int(val)) = inputs.get("value") {
Ok(HashMap::from([(
"branch_b_out".to_string(),
PortData::Int(val + 50),
)]))
} else {
Ok(HashMap::new())
}
}),
);
let merger = NodeConfig::new(
"merger",
"Result Merger",
vec![Port::simple("branch_a_out"), Port::simple("branch_b_out")],
vec![Port::simple("final")],
Arc::new(|inputs: &HashMap<String, PortData>| {
println!("[merger] Merging...");
let a = if let Some(PortData::Int(val)) = inputs.get("branch_a_out") {
*val
} else {
0
};
let b = if let Some(PortData::Int(val)) = inputs.get("branch_b_out") {
*val
} else {
0
};
Ok(HashMap::from([("final".to_string(), PortData::Int(a + b))]))
}),
);
let collector = NodeConfig::new(
"collector",
"Result Collector",
vec![Port::simple("final")],
vec![],
Arc::new(|inputs: &HashMap<String, PortData>| {
if let Some(PortData::Int(val)) = inputs.get("final") {
println!("[collector] Final result: {}", val);
}
Ok(HashMap::new())
}),
);
graph2.add(Node::new(source2))?;
graph2.add(Node::new(branch_a))?;
graph2.add(Node::new(branch_b))?;
graph2.add(Node::new(merger))?;
graph2.add(Node::new(collector))?;
let edges_created2 = graph2.auto_connect()?;
println!("✓ Auto-connected {} edges!\n", edges_created2);
graph2.validate()?;
println!("✓ Graph is valid!\n");
println!("=== Mermaid Diagram (with parallel groups & multi-line labels) ===");
let mermaid2 = Inspector::to_mermaid(&graph2)?;
println!("{}", mermaid2);
println!("=== Executing Graph ===");
let _result2 = executor.execute(&mut graph2).await?;
println!("✓ Execution completed!\n");
println!("=== Example Complete ===");
println!("\nKey Features Demonstrated:");
println!(" ✓ Implicit edge mapping (no add_edge() needed)");
println!(" ✓ Port name matching for automatic connections");
println!(" ✓ Multi-line labels in Mermaid (\\n → <br/>)");
println!(" ✓ Parallel group detection and visualization");
println!(" ✓ Fan-out/fan-in patterns auto-detected");
Ok(())
}