tuple_api_demo/
tuple_api_demo.rs1use graph_sp::Graph;
9use std::collections::HashMap;
10
11fn main() {
12 println!("=== Tuple-Based API Demo ===\n");
13
14 let mut graph = Graph::new();
15
16 fn data_source(_inputs: &HashMap<String, String>, _variant: &HashMap<String, String>) -> HashMap<String, String> {
18 let mut outputs = HashMap::new();
19 outputs.insert("raw".to_string(), "Sample Data".to_string());
20 outputs
21 }
22
23 graph.add(
24 data_source,
25 Some("Source"),
26 None, Some(vec![("raw", "dataset")]) );
29
30 println!("✓ Added source node");
31 println!(" Output mapping: function's 'raw' → context's 'dataset'\n");
32
33 fn processor(inputs: &HashMap<String, String>, _variant: &HashMap<String, String>) -> HashMap<String, String> {
35 let default = String::new();
36 let data = inputs.get("input_data").unwrap_or(&default);
37 let mut outputs = HashMap::new();
38 outputs.insert("processed_data".to_string(), format!("Processed: {}", data));
39 outputs
40 }
41
42 graph.add(
43 processor,
44 Some("Process"),
45 Some(vec![("dataset", "input_data")]), Some(vec![("processed_data", "result")]) );
48
49 println!("✓ Added processor node");
50 println!(" Input mapping: context's 'dataset' → function's 'input_data'");
51 println!(" Output mapping: function's 'processed_data' → context's 'result'\n");
52
53 let mut branch_a = Graph::new();
55 fn transform_a(inputs: &HashMap<String, String>, _variant: &HashMap<String, String>) -> HashMap<String, String> {
56 let default = String::new();
57 let data = inputs.get("x").unwrap_or(&default);
58 let mut outputs = HashMap::new();
59 outputs.insert("y".to_string(), format!("{} [Path A]", data));
60 outputs
61 }
62 branch_a.add(
63 transform_a,
64 Some("Transform A"),
65 Some(vec![("result", "x")]), Some(vec![("y", "output")]) );
68
69 let mut branch_b = Graph::new();
70 fn transform_b(inputs: &HashMap<String, String>, _variant: &HashMap<String, String>) -> HashMap<String, String> {
71 let default = String::new();
72 let data = inputs.get("x").unwrap_or(&default);
73 let mut outputs = HashMap::new();
74 outputs.insert("y".to_string(), format!("{} [Path B]", data));
75 outputs
76 }
77 branch_b.add(
78 transform_b,
79 Some("Transform B"),
80 Some(vec![("result", "x")]), Some(vec![("y", "output")]) );
83
84 println!("✓ Created two branches");
85 println!(" Both branches use same internal variable names (x, y)");
86 println!(" Both map 'result' → 'x' and 'y' → 'output'\n");
87
88 let branch_a_id = graph.branch(branch_a);
90 let branch_b_id = graph.branch(branch_b);
91
92 println!("✓ Added branches to graph");
93 println!(" Branch A ID: {}", branch_a_id);
94 println!(" Branch B ID: {}\n", branch_b_id);
95
96 fn combine(inputs: &HashMap<String, String>, _variant: &HashMap<String, String>) -> HashMap<String, String> {
98 let default = String::new();
99 let a = inputs.get("from_a").unwrap_or(&default);
100 let b = inputs.get("from_b").unwrap_or(&default);
101 let mut outputs = HashMap::new();
102 outputs.insert("merged".to_string(), format!("Combined: {} + {}", a, b));
103 outputs
104 }
105
106 graph.merge(
107 combine,
108 Some("Combine"),
109 vec![
110 (branch_a_id, "output", "from_a"), (branch_b_id, "output", "from_b") ],
113 Some(vec![("merged", "final_result")]) );
115
116 println!("✓ Added merge node");
117 println!(" Branch-specific input mapping:");
118 println!(" Branch {} 'output' → merge function's 'from_a'", branch_a_id);
119 println!(" Branch {} 'output' → merge function's 'from_b'", branch_b_id);
120 println!(" Output mapping: merge function's 'merged' → context's 'final_result'\n");
121
122 fn make_multiplier(factor: f64) -> impl Fn(&HashMap<String, String>, &HashMap<String, String>) -> HashMap<String, String> {
124 move |inputs, _variant| {
125 let default = "1.0".to_string();
126 let data = inputs.get("value").unwrap_or(&default);
127 if let Ok(val) = data.parse::<f64>() {
128 let mut outputs = HashMap::new();
129 outputs.insert("scaled".to_string(), (val * factor).to_string());
130 outputs
131 } else {
132 HashMap::new()
133 }
134 }
135 }
136
137 graph.variant(
138 make_multiplier,
139 vec![2.0, 3.0, 5.0],
140 Some("Multiply"),
141 Some(vec![("final_result", "value")]), Some(vec![("scaled", "multiplied")]) );
144
145 println!("✓ Added variant nodes with parameter sweep");
146 println!(" Three variants: factor = 2.0, 3.0, 5.0");
147 println!(" Input mapping: context's 'final_result' → function's 'value'");
148 println!(" Output mapping: function's 'scaled' → context's 'multiplied'\n");
149
150 println!("=== Summary ===");
151 println!("The tuple-based API provides clear separation between:");
152 println!("1. Context variable names (broadcast vars) - shared across the graph");
153 println!("2. Function parameter names (impl vars) - internal to each function");
154 println!("\nThis allows:");
155 println!("- Branches to use consistent internal naming (x, y)");
156 println!("- Merge to distinguish branch outputs using branch IDs");
157 println!("- Clear data flow visualization and debugging");
158}