ExecutionResult

Struct ExecutionResult 

Source
pub struct ExecutionResult {
    pub context: ExecutionContext,
    pub node_outputs: HashMap<NodeId, HashMap<String, String>>,
    pub branch_outputs: HashMap<usize, HashMap<String, String>>,
}
Expand description

Execution result that tracks outputs per node and per branch

Fields§

§context: ExecutionContext

Global execution context (all variables accessible by broadcast name)

§node_outputs: HashMap<NodeId, HashMap<String, String>>

Outputs per node (node_id -> HashMap of output variables)

§branch_outputs: HashMap<usize, HashMap<String, String>>

Outputs per branch (branch_id -> HashMap of output variables)

Implementations§

Source§

impl ExecutionResult

Source

pub fn new() -> Self

Create a new empty execution result

Source

pub fn get(&self, key: &str) -> Option<&String>

Get a value from the global context

Examples found in repository?
examples/per_node_output_access.rs (line 285)
225fn demo_variant_per_node_access() {
226    println!("─────────────────────────────────────────────────────────");
227    println!("Demo 3: Variant Outputs with Per-Node Tracking");
228    println!("─────────────────────────────────────────────────────────\n");
229    
230    let mut graph = Graph::new();
231    
232    // Source node
233    graph.add(
234        |_: &HashMap<String, String>, _| {
235            let mut result = HashMap::new();
236            result.insert("base_value".to_string(), "10".to_string());
237            result
238        },
239        Some("Source"),
240        None,
241        Some(vec![("base_value", "data")])
242    );
243    
244    // Variant factory for scaling
245    fn make_scaler(factor: f64) -> impl Fn(&HashMap<String, String>, &HashMap<String, String>) -> HashMap<String, String> {
246        move |inputs: &HashMap<String, String>, _| {
247            let value = inputs.get("input_data").unwrap().parse::<f64>().unwrap();
248            let mut result = HashMap::new();
249            result.insert("scaled_value".to_string(), (value * factor).to_string());
250            result
251        }
252    }
253    
254    // Create variants with unique output names to preserve all results
255    graph.variant(
256        make_scaler,
257        vec![2.0, 3.0, 5.0],
258        Some("Scale"),
259        Some(vec![("data", "input_data")]),
260        Some(vec![("scaled_value", "result")])  // Note: will overwrite in global context
261    );
262    
263    let dag = graph.build();
264    let result = dag.execute_detailed(false, None);
265    
266    println!("🌍 Global Context (note: 'result' contains last variant's output):");
267    for (key, value) in &result.context {
268        println!("  {} = {}", key, value);
269    }
270    
271    println!("\n📦 Per-Node Outputs (each variant tracked separately):");
272    
273    // Node 0 is the source
274    // Nodes 1, 2, 3 are the variant nodes (2x, 3x, 5x scalers)
275    for node_id in 1..=3 {
276        println!("\nNode {} (Variant Scaler) outputs:", node_id);
277        if let Some(outputs) = result.get_node_outputs(node_id) {
278            for (key, value) in outputs {
279                println!("  {} = {}", key, value);
280            }
281        }
282    }
283    
284    println!("\n💡 Key Insight:");
285    println!("  - Global context has 'result' = {} (last variant overwrites)", result.get("result").unwrap());
286    println!("  - But per-node outputs preserve ALL variant results:");
287    println!("    Node 1 (2x): result = {}", result.get_from_node(1, "result").unwrap());
288    println!("    Node 2 (3x): result = {}", result.get_from_node(2, "result").unwrap());
289    println!("    Node 3 (5x): result = {}", result.get_from_node(3, "result").unwrap());
290    
291    println!();
292}
Source

pub fn get_node_outputs( &self, node_id: NodeId, ) -> Option<&HashMap<String, String>>

Get all outputs from a specific node

Examples found in repository?
examples/per_node_output_access.rs (line 80)
24fn demo_per_node_access() {
25    println!("─────────────────────────────────────────────────────────");
26    println!("Demo 1: Per-Node Output Access");
27    println!("─────────────────────────────────────────────────────────\n");
28    
29    let mut graph = Graph::new();
30    
31    // Node 0: Source
32    graph.add(
33        |_: &HashMap<String, String>, _| {
34            let mut result = HashMap::new();
35            result.insert("value".to_string(), "10".to_string());
36            result
37        },
38        Some("Source"),
39        None,
40        Some(vec![("value", "initial_data")])
41    );
42    
43    // Node 1: Double
44    graph.add(
45        |inputs: &HashMap<String, String>, _| {
46            let value = inputs.get("in").unwrap().parse::<i32>().unwrap();
47            let mut result = HashMap::new();
48            result.insert("doubled".to_string(), (value * 2).to_string());
49            result
50        },
51        Some("Double"),
52        Some(vec![("initial_data", "in")]),
53        Some(vec![("doubled", "doubled_data")])
54    );
55    
56    // Node 2: Add Ten
57    graph.add(
58        |inputs: &HashMap<String, String>, _| {
59            let value = inputs.get("in").unwrap().parse::<i32>().unwrap();
60            let mut result = HashMap::new();
61            result.insert("added".to_string(), (value + 10).to_string());
62            result
63        },
64        Some("AddTen"),
65        Some(vec![("doubled_data", "in")]),
66        Some(vec![("added", "final_result")])
67    );
68    
69    // Execute and get detailed results
70    let dag = graph.build();
71    let result = dag.execute_detailed(false, None);
72    
73    println!("🌍 Global Context (all variables):");
74    for (key, value) in &result.context {
75        println!("  {} = {}", key, value);
76    }
77    
78    println!("\n📦 Per-Node Outputs:");
79    println!("\nNode 0 (Source) outputs:");
80    if let Some(outputs) = result.get_node_outputs(0) {
81        for (key, value) in outputs {
82            println!("  {} = {}", key, value);
83        }
84    }
85    
86    println!("\nNode 1 (Double) outputs:");
87    if let Some(outputs) = result.get_node_outputs(1) {
88        for (key, value) in outputs {
89            println!("  {} = {}", key, value);
90        }
91    }
92    
93    println!("\nNode 2 (AddTen) outputs:");
94    if let Some(outputs) = result.get_node_outputs(2) {
95        for (key, value) in outputs {
96            println!("  {} = {}", key, value);
97        }
98    }
99    
100    println!("\n🎯 Accessing specific node outputs:");
101    if let Some(value) = result.get_from_node(0, "initial_data") {
102        println!("  Node 0 'initial_data': {}", value);
103    }
104    if let Some(value) = result.get_from_node(1, "doubled_data") {
105        println!("  Node 1 'doubled_data': {}", value);
106    }
107    if let Some(value) = result.get_from_node(2, "final_result") {
108        println!("  Node 2 'final_result': {}", value);
109    }
110    
111    println!();
112}
113
114fn demo_per_branch_access() {
115    println!("─────────────────────────────────────────────────────────");
116    println!("Demo 2: Per-Branch Output Access");
117    println!("─────────────────────────────────────────────────────────\n");
118    
119    let mut graph = Graph::new();
120    
121    // Main graph: Source node
122    graph.add(
123        |_: &HashMap<String, String>, _| {
124            let mut result = HashMap::new();
125            result.insert("dataset".to_string(), "100".to_string());
126            result
127        },
128        Some("Source"),
129        None,
130        Some(vec![("dataset", "data")])
131    );
132    
133    // Branch A: Statistics
134    let mut branch_a = Graph::new();
135    branch_a.add(
136        |inputs: &HashMap<String, String>, _| {
137            let value = inputs.get("input").unwrap();
138            let mut result = HashMap::new();
139            result.insert("stat_result".to_string(), format!("Mean of {}", value));
140            result
141        },
142        Some("Statistics"),
143        Some(vec![("data", "input")]),
144        Some(vec![("stat_result", "statistics")])
145    );
146    
147    // Branch B: Model Training
148    let mut branch_b = Graph::new();
149    branch_b.add(
150        |inputs: &HashMap<String, String>, _| {
151            let value = inputs.get("input").unwrap();
152            let mut result = HashMap::new();
153            result.insert("model_result".to_string(), format!("Model trained on {}", value));
154            result
155        },
156        Some("ModelTraining"),
157        Some(vec![("data", "input")]),
158        Some(vec![("model_result", "trained_model")])
159    );
160    
161    // Branch C: Visualization
162    let mut branch_c = Graph::new();
163    branch_c.add(
164        |inputs: &HashMap<String, String>, _| {
165            let value = inputs.get("input").unwrap();
166            let mut result = HashMap::new();
167            result.insert("viz_result".to_string(), format!("Plot of {}", value));
168            result
169        },
170        Some("Visualization"),
171        Some(vec![("data", "input")]),
172        Some(vec![("viz_result", "plot")])
173    );
174    
175    let branch_a_id = graph.branch(branch_a);
176    let branch_b_id = graph.branch(branch_b);
177    let branch_c_id = graph.branch(branch_c);
178    
179    // Execute and get detailed results
180    let dag = graph.build();
181    let result = dag.execute_detailed(false, None);
182    
183    println!("🌍 Global Context:");
184    for (key, value) in &result.context {
185        println!("  {} = {}", key, value);
186    }
187    
188    println!("\n🌿 Per-Branch Outputs:");
189    
190    println!("\nBranch {} (Statistics) outputs:", branch_a_id);
191    if let Some(outputs) = result.get_branch_outputs(branch_a_id) {
192        for (key, value) in outputs {
193            println!("  {} = {}", key, value);
194        }
195    }
196    
197    println!("\nBranch {} (Model Training) outputs:", branch_b_id);
198    if let Some(outputs) = result.get_branch_outputs(branch_b_id) {
199        for (key, value) in outputs {
200            println!("  {} = {}", key, value);
201        }
202    }
203    
204    println!("\nBranch {} (Visualization) outputs:", branch_c_id);
205    if let Some(outputs) = result.get_branch_outputs(branch_c_id) {
206        for (key, value) in outputs {
207            println!("  {} = {}", key, value);
208        }
209    }
210    
211    println!("\n🎯 Accessing specific branch outputs:");
212    if let Some(value) = result.get_from_branch(branch_a_id, "statistics") {
213        println!("  Branch {} 'statistics': {}", branch_a_id, value);
214    }
215    if let Some(value) = result.get_from_branch(branch_b_id, "trained_model") {
216        println!("  Branch {} 'trained_model': {}", branch_b_id, value);
217    }
218    if let Some(value) = result.get_from_branch(branch_c_id, "plot") {
219        println!("  Branch {} 'plot': {}", branch_c_id, value);
220    }
221    
222    println!();
223}
224
225fn demo_variant_per_node_access() {
226    println!("─────────────────────────────────────────────────────────");
227    println!("Demo 3: Variant Outputs with Per-Node Tracking");
228    println!("─────────────────────────────────────────────────────────\n");
229    
230    let mut graph = Graph::new();
231    
232    // Source node
233    graph.add(
234        |_: &HashMap<String, String>, _| {
235            let mut result = HashMap::new();
236            result.insert("base_value".to_string(), "10".to_string());
237            result
238        },
239        Some("Source"),
240        None,
241        Some(vec![("base_value", "data")])
242    );
243    
244    // Variant factory for scaling
245    fn make_scaler(factor: f64) -> impl Fn(&HashMap<String, String>, &HashMap<String, String>) -> HashMap<String, String> {
246        move |inputs: &HashMap<String, String>, _| {
247            let value = inputs.get("input_data").unwrap().parse::<f64>().unwrap();
248            let mut result = HashMap::new();
249            result.insert("scaled_value".to_string(), (value * factor).to_string());
250            result
251        }
252    }
253    
254    // Create variants with unique output names to preserve all results
255    graph.variant(
256        make_scaler,
257        vec![2.0, 3.0, 5.0],
258        Some("Scale"),
259        Some(vec![("data", "input_data")]),
260        Some(vec![("scaled_value", "result")])  // Note: will overwrite in global context
261    );
262    
263    let dag = graph.build();
264    let result = dag.execute_detailed(false, None);
265    
266    println!("🌍 Global Context (note: 'result' contains last variant's output):");
267    for (key, value) in &result.context {
268        println!("  {} = {}", key, value);
269    }
270    
271    println!("\n📦 Per-Node Outputs (each variant tracked separately):");
272    
273    // Node 0 is the source
274    // Nodes 1, 2, 3 are the variant nodes (2x, 3x, 5x scalers)
275    for node_id in 1..=3 {
276        println!("\nNode {} (Variant Scaler) outputs:", node_id);
277        if let Some(outputs) = result.get_node_outputs(node_id) {
278            for (key, value) in outputs {
279                println!("  {} = {}", key, value);
280            }
281        }
282    }
283    
284    println!("\n💡 Key Insight:");
285    println!("  - Global context has 'result' = {} (last variant overwrites)", result.get("result").unwrap());
286    println!("  - But per-node outputs preserve ALL variant results:");
287    println!("    Node 1 (2x): result = {}", result.get_from_node(1, "result").unwrap());
288    println!("    Node 2 (3x): result = {}", result.get_from_node(2, "result").unwrap());
289    println!("    Node 3 (5x): result = {}", result.get_from_node(3, "result").unwrap());
290    
291    println!();
292}
Source

pub fn get_branch_outputs( &self, branch_id: usize, ) -> Option<&HashMap<String, String>>

Get all outputs from a specific branch

Examples found in repository?
examples/per_node_output_access.rs (line 191)
114fn demo_per_branch_access() {
115    println!("─────────────────────────────────────────────────────────");
116    println!("Demo 2: Per-Branch Output Access");
117    println!("─────────────────────────────────────────────────────────\n");
118    
119    let mut graph = Graph::new();
120    
121    // Main graph: Source node
122    graph.add(
123        |_: &HashMap<String, String>, _| {
124            let mut result = HashMap::new();
125            result.insert("dataset".to_string(), "100".to_string());
126            result
127        },
128        Some("Source"),
129        None,
130        Some(vec![("dataset", "data")])
131    );
132    
133    // Branch A: Statistics
134    let mut branch_a = Graph::new();
135    branch_a.add(
136        |inputs: &HashMap<String, String>, _| {
137            let value = inputs.get("input").unwrap();
138            let mut result = HashMap::new();
139            result.insert("stat_result".to_string(), format!("Mean of {}", value));
140            result
141        },
142        Some("Statistics"),
143        Some(vec![("data", "input")]),
144        Some(vec![("stat_result", "statistics")])
145    );
146    
147    // Branch B: Model Training
148    let mut branch_b = Graph::new();
149    branch_b.add(
150        |inputs: &HashMap<String, String>, _| {
151            let value = inputs.get("input").unwrap();
152            let mut result = HashMap::new();
153            result.insert("model_result".to_string(), format!("Model trained on {}", value));
154            result
155        },
156        Some("ModelTraining"),
157        Some(vec![("data", "input")]),
158        Some(vec![("model_result", "trained_model")])
159    );
160    
161    // Branch C: Visualization
162    let mut branch_c = Graph::new();
163    branch_c.add(
164        |inputs: &HashMap<String, String>, _| {
165            let value = inputs.get("input").unwrap();
166            let mut result = HashMap::new();
167            result.insert("viz_result".to_string(), format!("Plot of {}", value));
168            result
169        },
170        Some("Visualization"),
171        Some(vec![("data", "input")]),
172        Some(vec![("viz_result", "plot")])
173    );
174    
175    let branch_a_id = graph.branch(branch_a);
176    let branch_b_id = graph.branch(branch_b);
177    let branch_c_id = graph.branch(branch_c);
178    
179    // Execute and get detailed results
180    let dag = graph.build();
181    let result = dag.execute_detailed(false, None);
182    
183    println!("🌍 Global Context:");
184    for (key, value) in &result.context {
185        println!("  {} = {}", key, value);
186    }
187    
188    println!("\n🌿 Per-Branch Outputs:");
189    
190    println!("\nBranch {} (Statistics) outputs:", branch_a_id);
191    if let Some(outputs) = result.get_branch_outputs(branch_a_id) {
192        for (key, value) in outputs {
193            println!("  {} = {}", key, value);
194        }
195    }
196    
197    println!("\nBranch {} (Model Training) outputs:", branch_b_id);
198    if let Some(outputs) = result.get_branch_outputs(branch_b_id) {
199        for (key, value) in outputs {
200            println!("  {} = {}", key, value);
201        }
202    }
203    
204    println!("\nBranch {} (Visualization) outputs:", branch_c_id);
205    if let Some(outputs) = result.get_branch_outputs(branch_c_id) {
206        for (key, value) in outputs {
207            println!("  {} = {}", key, value);
208        }
209    }
210    
211    println!("\n🎯 Accessing specific branch outputs:");
212    if let Some(value) = result.get_from_branch(branch_a_id, "statistics") {
213        println!("  Branch {} 'statistics': {}", branch_a_id, value);
214    }
215    if let Some(value) = result.get_from_branch(branch_b_id, "trained_model") {
216        println!("  Branch {} 'trained_model': {}", branch_b_id, value);
217    }
218    if let Some(value) = result.get_from_branch(branch_c_id, "plot") {
219        println!("  Branch {} 'plot': {}", branch_c_id, value);
220    }
221    
222    println!();
223}
Source

pub fn get_from_node(&self, node_id: NodeId, key: &str) -> Option<&String>

Get a specific variable from a node

Examples found in repository?
examples/per_node_output_access.rs (line 101)
24fn demo_per_node_access() {
25    println!("─────────────────────────────────────────────────────────");
26    println!("Demo 1: Per-Node Output Access");
27    println!("─────────────────────────────────────────────────────────\n");
28    
29    let mut graph = Graph::new();
30    
31    // Node 0: Source
32    graph.add(
33        |_: &HashMap<String, String>, _| {
34            let mut result = HashMap::new();
35            result.insert("value".to_string(), "10".to_string());
36            result
37        },
38        Some("Source"),
39        None,
40        Some(vec![("value", "initial_data")])
41    );
42    
43    // Node 1: Double
44    graph.add(
45        |inputs: &HashMap<String, String>, _| {
46            let value = inputs.get("in").unwrap().parse::<i32>().unwrap();
47            let mut result = HashMap::new();
48            result.insert("doubled".to_string(), (value * 2).to_string());
49            result
50        },
51        Some("Double"),
52        Some(vec![("initial_data", "in")]),
53        Some(vec![("doubled", "doubled_data")])
54    );
55    
56    // Node 2: Add Ten
57    graph.add(
58        |inputs: &HashMap<String, String>, _| {
59            let value = inputs.get("in").unwrap().parse::<i32>().unwrap();
60            let mut result = HashMap::new();
61            result.insert("added".to_string(), (value + 10).to_string());
62            result
63        },
64        Some("AddTen"),
65        Some(vec![("doubled_data", "in")]),
66        Some(vec![("added", "final_result")])
67    );
68    
69    // Execute and get detailed results
70    let dag = graph.build();
71    let result = dag.execute_detailed(false, None);
72    
73    println!("🌍 Global Context (all variables):");
74    for (key, value) in &result.context {
75        println!("  {} = {}", key, value);
76    }
77    
78    println!("\n📦 Per-Node Outputs:");
79    println!("\nNode 0 (Source) outputs:");
80    if let Some(outputs) = result.get_node_outputs(0) {
81        for (key, value) in outputs {
82            println!("  {} = {}", key, value);
83        }
84    }
85    
86    println!("\nNode 1 (Double) outputs:");
87    if let Some(outputs) = result.get_node_outputs(1) {
88        for (key, value) in outputs {
89            println!("  {} = {}", key, value);
90        }
91    }
92    
93    println!("\nNode 2 (AddTen) outputs:");
94    if let Some(outputs) = result.get_node_outputs(2) {
95        for (key, value) in outputs {
96            println!("  {} = {}", key, value);
97        }
98    }
99    
100    println!("\n🎯 Accessing specific node outputs:");
101    if let Some(value) = result.get_from_node(0, "initial_data") {
102        println!("  Node 0 'initial_data': {}", value);
103    }
104    if let Some(value) = result.get_from_node(1, "doubled_data") {
105        println!("  Node 1 'doubled_data': {}", value);
106    }
107    if let Some(value) = result.get_from_node(2, "final_result") {
108        println!("  Node 2 'final_result': {}", value);
109    }
110    
111    println!();
112}
113
114fn demo_per_branch_access() {
115    println!("─────────────────────────────────────────────────────────");
116    println!("Demo 2: Per-Branch Output Access");
117    println!("─────────────────────────────────────────────────────────\n");
118    
119    let mut graph = Graph::new();
120    
121    // Main graph: Source node
122    graph.add(
123        |_: &HashMap<String, String>, _| {
124            let mut result = HashMap::new();
125            result.insert("dataset".to_string(), "100".to_string());
126            result
127        },
128        Some("Source"),
129        None,
130        Some(vec![("dataset", "data")])
131    );
132    
133    // Branch A: Statistics
134    let mut branch_a = Graph::new();
135    branch_a.add(
136        |inputs: &HashMap<String, String>, _| {
137            let value = inputs.get("input").unwrap();
138            let mut result = HashMap::new();
139            result.insert("stat_result".to_string(), format!("Mean of {}", value));
140            result
141        },
142        Some("Statistics"),
143        Some(vec![("data", "input")]),
144        Some(vec![("stat_result", "statistics")])
145    );
146    
147    // Branch B: Model Training
148    let mut branch_b = Graph::new();
149    branch_b.add(
150        |inputs: &HashMap<String, String>, _| {
151            let value = inputs.get("input").unwrap();
152            let mut result = HashMap::new();
153            result.insert("model_result".to_string(), format!("Model trained on {}", value));
154            result
155        },
156        Some("ModelTraining"),
157        Some(vec![("data", "input")]),
158        Some(vec![("model_result", "trained_model")])
159    );
160    
161    // Branch C: Visualization
162    let mut branch_c = Graph::new();
163    branch_c.add(
164        |inputs: &HashMap<String, String>, _| {
165            let value = inputs.get("input").unwrap();
166            let mut result = HashMap::new();
167            result.insert("viz_result".to_string(), format!("Plot of {}", value));
168            result
169        },
170        Some("Visualization"),
171        Some(vec![("data", "input")]),
172        Some(vec![("viz_result", "plot")])
173    );
174    
175    let branch_a_id = graph.branch(branch_a);
176    let branch_b_id = graph.branch(branch_b);
177    let branch_c_id = graph.branch(branch_c);
178    
179    // Execute and get detailed results
180    let dag = graph.build();
181    let result = dag.execute_detailed(false, None);
182    
183    println!("🌍 Global Context:");
184    for (key, value) in &result.context {
185        println!("  {} = {}", key, value);
186    }
187    
188    println!("\n🌿 Per-Branch Outputs:");
189    
190    println!("\nBranch {} (Statistics) outputs:", branch_a_id);
191    if let Some(outputs) = result.get_branch_outputs(branch_a_id) {
192        for (key, value) in outputs {
193            println!("  {} = {}", key, value);
194        }
195    }
196    
197    println!("\nBranch {} (Model Training) outputs:", branch_b_id);
198    if let Some(outputs) = result.get_branch_outputs(branch_b_id) {
199        for (key, value) in outputs {
200            println!("  {} = {}", key, value);
201        }
202    }
203    
204    println!("\nBranch {} (Visualization) outputs:", branch_c_id);
205    if let Some(outputs) = result.get_branch_outputs(branch_c_id) {
206        for (key, value) in outputs {
207            println!("  {} = {}", key, value);
208        }
209    }
210    
211    println!("\n🎯 Accessing specific branch outputs:");
212    if let Some(value) = result.get_from_branch(branch_a_id, "statistics") {
213        println!("  Branch {} 'statistics': {}", branch_a_id, value);
214    }
215    if let Some(value) = result.get_from_branch(branch_b_id, "trained_model") {
216        println!("  Branch {} 'trained_model': {}", branch_b_id, value);
217    }
218    if let Some(value) = result.get_from_branch(branch_c_id, "plot") {
219        println!("  Branch {} 'plot': {}", branch_c_id, value);
220    }
221    
222    println!();
223}
224
225fn demo_variant_per_node_access() {
226    println!("─────────────────────────────────────────────────────────");
227    println!("Demo 3: Variant Outputs with Per-Node Tracking");
228    println!("─────────────────────────────────────────────────────────\n");
229    
230    let mut graph = Graph::new();
231    
232    // Source node
233    graph.add(
234        |_: &HashMap<String, String>, _| {
235            let mut result = HashMap::new();
236            result.insert("base_value".to_string(), "10".to_string());
237            result
238        },
239        Some("Source"),
240        None,
241        Some(vec![("base_value", "data")])
242    );
243    
244    // Variant factory for scaling
245    fn make_scaler(factor: f64) -> impl Fn(&HashMap<String, String>, &HashMap<String, String>) -> HashMap<String, String> {
246        move |inputs: &HashMap<String, String>, _| {
247            let value = inputs.get("input_data").unwrap().parse::<f64>().unwrap();
248            let mut result = HashMap::new();
249            result.insert("scaled_value".to_string(), (value * factor).to_string());
250            result
251        }
252    }
253    
254    // Create variants with unique output names to preserve all results
255    graph.variant(
256        make_scaler,
257        vec![2.0, 3.0, 5.0],
258        Some("Scale"),
259        Some(vec![("data", "input_data")]),
260        Some(vec![("scaled_value", "result")])  // Note: will overwrite in global context
261    );
262    
263    let dag = graph.build();
264    let result = dag.execute_detailed(false, None);
265    
266    println!("🌍 Global Context (note: 'result' contains last variant's output):");
267    for (key, value) in &result.context {
268        println!("  {} = {}", key, value);
269    }
270    
271    println!("\n📦 Per-Node Outputs (each variant tracked separately):");
272    
273    // Node 0 is the source
274    // Nodes 1, 2, 3 are the variant nodes (2x, 3x, 5x scalers)
275    for node_id in 1..=3 {
276        println!("\nNode {} (Variant Scaler) outputs:", node_id);
277        if let Some(outputs) = result.get_node_outputs(node_id) {
278            for (key, value) in outputs {
279                println!("  {} = {}", key, value);
280            }
281        }
282    }
283    
284    println!("\n💡 Key Insight:");
285    println!("  - Global context has 'result' = {} (last variant overwrites)", result.get("result").unwrap());
286    println!("  - But per-node outputs preserve ALL variant results:");
287    println!("    Node 1 (2x): result = {}", result.get_from_node(1, "result").unwrap());
288    println!("    Node 2 (3x): result = {}", result.get_from_node(2, "result").unwrap());
289    println!("    Node 3 (5x): result = {}", result.get_from_node(3, "result").unwrap());
290    
291    println!();
292}
293
294fn demo_execution_history_tracking() {
295    println!("─────────────────────────────────────────────────────────");
296    println!("Demo 4: Execution History Tracking");
297    println!("─────────────────────────────────────────────────────────\n");
298    
299    let mut graph = Graph::new();
300    
301    // Multi-stage pipeline
302    graph.add(
303        |_: &HashMap<String, String>, _| {
304            let mut result = HashMap::new();
305            result.insert("raw".to_string(), "5".to_string());
306            result
307        },
308        Some("Load"),
309        None,
310        Some(vec![("raw", "input")])
311    );
312    
313    graph.add(
314        |inputs: &HashMap<String, String>, _| {
315            let value = inputs.get("x").unwrap().parse::<i32>().unwrap();
316            let mut result = HashMap::new();
317            result.insert("cleaned".to_string(), (value + 1).to_string());
318            result
319        },
320        Some("Clean"),
321        Some(vec![("input", "x")]),
322        Some(vec![("cleaned", "clean_data")])
323    );
324    
325    graph.add(
326        |inputs: &HashMap<String, String>, _| {
327            let value = inputs.get("x").unwrap().parse::<i32>().unwrap();
328            let mut result = HashMap::new();
329            result.insert("normalized".to_string(), (value * 10).to_string());
330            result
331        },
332        Some("Normalize"),
333        Some(vec![("clean_data", "x")]),
334        Some(vec![("normalized", "norm_data")])
335    );
336    
337    graph.add(
338        |inputs: &HashMap<String, String>, _| {
339            let value = inputs.get("x").unwrap().parse::<i32>().unwrap();
340            let mut result = HashMap::new();
341            result.insert("transformed".to_string(), format!("FINAL_{}", value));
342            result
343        },
344        Some("Transform"),
345        Some(vec![("norm_data", "x")]),
346        Some(vec![("transformed", "output")])
347    );
348    
349    let dag = graph.build();
350    let result = dag.execute_detailed(false, None);
351    
352    println!("📊 Execution History (Data Flow Tracking):");
353    println!();
354    println!("Step-by-step transformation:");
355    println!("  1. Load:      input = {}", result.get_from_node(0, "input").unwrap());
356    println!("  2. Clean:     clean_data = {}", result.get_from_node(1, "clean_data").unwrap());
357    println!("  3. Normalize: norm_data = {}", result.get_from_node(2, "norm_data").unwrap());
358    println!("  4. Transform: output = {}", result.get_from_node(3, "output").unwrap());
359    
360    println!("\n🔍 Debugging: Inspect any intermediate result:");
361    println!("  Need to debug the normalization step?");
362    println!("  Just check Node 2: {}", result.get_from_node(2, "norm_data").unwrap());
363    
364    println!("\n✅ Benefits of Per-Node Access:");
365    println!("  ✓ Track data transformations step-by-step");
366    println!("  ✓ Debug issues by inspecting intermediate values");
367    println!("  ✓ Validate each processing stage independently");
368    println!("  ✓ Preserve all variant outputs even with name collisions");
369    
370    println!();
371}
Source

pub fn get_from_branch(&self, branch_id: usize, key: &str) -> Option<&String>

Get a specific variable from a branch

Examples found in repository?
examples/per_node_output_access.rs (line 212)
114fn demo_per_branch_access() {
115    println!("─────────────────────────────────────────────────────────");
116    println!("Demo 2: Per-Branch Output Access");
117    println!("─────────────────────────────────────────────────────────\n");
118    
119    let mut graph = Graph::new();
120    
121    // Main graph: Source node
122    graph.add(
123        |_: &HashMap<String, String>, _| {
124            let mut result = HashMap::new();
125            result.insert("dataset".to_string(), "100".to_string());
126            result
127        },
128        Some("Source"),
129        None,
130        Some(vec![("dataset", "data")])
131    );
132    
133    // Branch A: Statistics
134    let mut branch_a = Graph::new();
135    branch_a.add(
136        |inputs: &HashMap<String, String>, _| {
137            let value = inputs.get("input").unwrap();
138            let mut result = HashMap::new();
139            result.insert("stat_result".to_string(), format!("Mean of {}", value));
140            result
141        },
142        Some("Statistics"),
143        Some(vec![("data", "input")]),
144        Some(vec![("stat_result", "statistics")])
145    );
146    
147    // Branch B: Model Training
148    let mut branch_b = Graph::new();
149    branch_b.add(
150        |inputs: &HashMap<String, String>, _| {
151            let value = inputs.get("input").unwrap();
152            let mut result = HashMap::new();
153            result.insert("model_result".to_string(), format!("Model trained on {}", value));
154            result
155        },
156        Some("ModelTraining"),
157        Some(vec![("data", "input")]),
158        Some(vec![("model_result", "trained_model")])
159    );
160    
161    // Branch C: Visualization
162    let mut branch_c = Graph::new();
163    branch_c.add(
164        |inputs: &HashMap<String, String>, _| {
165            let value = inputs.get("input").unwrap();
166            let mut result = HashMap::new();
167            result.insert("viz_result".to_string(), format!("Plot of {}", value));
168            result
169        },
170        Some("Visualization"),
171        Some(vec![("data", "input")]),
172        Some(vec![("viz_result", "plot")])
173    );
174    
175    let branch_a_id = graph.branch(branch_a);
176    let branch_b_id = graph.branch(branch_b);
177    let branch_c_id = graph.branch(branch_c);
178    
179    // Execute and get detailed results
180    let dag = graph.build();
181    let result = dag.execute_detailed(false, None);
182    
183    println!("🌍 Global Context:");
184    for (key, value) in &result.context {
185        println!("  {} = {}", key, value);
186    }
187    
188    println!("\n🌿 Per-Branch Outputs:");
189    
190    println!("\nBranch {} (Statistics) outputs:", branch_a_id);
191    if let Some(outputs) = result.get_branch_outputs(branch_a_id) {
192        for (key, value) in outputs {
193            println!("  {} = {}", key, value);
194        }
195    }
196    
197    println!("\nBranch {} (Model Training) outputs:", branch_b_id);
198    if let Some(outputs) = result.get_branch_outputs(branch_b_id) {
199        for (key, value) in outputs {
200            println!("  {} = {}", key, value);
201        }
202    }
203    
204    println!("\nBranch {} (Visualization) outputs:", branch_c_id);
205    if let Some(outputs) = result.get_branch_outputs(branch_c_id) {
206        for (key, value) in outputs {
207            println!("  {} = {}", key, value);
208        }
209    }
210    
211    println!("\n🎯 Accessing specific branch outputs:");
212    if let Some(value) = result.get_from_branch(branch_a_id, "statistics") {
213        println!("  Branch {} 'statistics': {}", branch_a_id, value);
214    }
215    if let Some(value) = result.get_from_branch(branch_b_id, "trained_model") {
216        println!("  Branch {} 'trained_model': {}", branch_b_id, value);
217    }
218    if let Some(value) = result.get_from_branch(branch_c_id, "plot") {
219        println!("  Branch {} 'plot': {}", branch_c_id, value);
220    }
221    
222    println!();
223}
Source

pub fn contains_key(&self, key: &str) -> bool

Check if a variable exists in global context

Trait Implementations§

Source§

impl Clone for ExecutionResult

Source§

fn clone(&self) -> ExecutionResult

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ExecutionResult

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.