Skip to main content

iter_map/
iter_map.rs

1//! Iterating a map with `iter_map`.
2//!
3//! The body closure is handed the current `key` and `value` binding names —
4//! feed them to `Param::reference` to read each entry. Parent variables
5//! remain accessible inside the body, and steps after the loop see the
6//! final iteration's outputs in the parent store.
7
8use panopticon_core::{params, prelude::*};
9use std::time::Duration;
10
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12    // ── Basic iter_map: iterate over key-value pairs ──
13    println!("=== Basic iter_map ===");
14    {
15        let mut pipe = Pipeline::default();
16        pipe.map("config")?
17            .insert("host", "localhost")?
18            .insert("port", "8080")?
19            .insert("protocol", "https")?;
20
21        pipe.iter_map(
22            "read_config",
23            IterSource::map("config"),
24            |key, value, body| {
25                body.step::<SetVar>(
26                    "capture_key",
27                    params!(
28                        "name" => "current_key",
29                        "value" => Param::reference(key),
30                    ),
31                )?;
32                body.step::<SetVar>(
33                    "capture_value",
34                    params!(
35                        "name" => "current_value",
36                        "value" => Param::reference(value),
37                    ),
38                )?;
39                Ok(())
40            },
41        )?;
42
43        pipe.hook(Logger::new().writer(std::io::stdout()));
44        pipe.hook(Timeout::new(Duration::from_secs(5)));
45
46        let complete = pipe.compile()?.run().wait()?;
47        complete.debug();
48    }
49
50    // ── iter_map with parent variable references ──
51    println!("\n=== iter_map referencing parent vars ===");
52    {
53        let mut pipe = Pipeline::default();
54        pipe.var("env", "production")?;
55        pipe.map("settings")?
56            .insert("db_host", "db.example.com")?
57            .insert("cache_host", "cache.example.com")?;
58
59        pipe.iter_map(
60            "apply_env",
61            IterSource::map("settings"),
62            |key, value, body| {
63                body.step::<SetVar>(
64                    "label",
65                    params!(
66                        "name" => "entry",
67                        "value" => Param::template(vec![
68                            Param::reference("env"),
69                            Param::literal("."),
70                            Param::reference(key),
71                            Param::literal("="),
72                            Param::reference(value),
73                        ]),
74                    ),
75                )?;
76                Ok(())
77            },
78        )?;
79
80        let complete = pipe.compile()?.run().wait()?;
81        complete.debug();
82    }
83
84    // ── iter_map followed by regular steps ──
85    println!("\n=== iter_map then regular steps ===");
86    {
87        let mut pipe = Pipeline::default();
88        pipe.var("status", "ready")?;
89        pipe.map("headers")?
90            .insert("content-type", "application/json")?
91            .insert("accept", "text/html")?;
92
93        pipe.iter_map(
94            "scan_headers",
95            IterSource::map("headers"),
96            |_key, value, body| {
97                body.step::<SetVar>(
98                    "save",
99                    params!(
100                        "name" => "last_header",
101                        "value" => Param::reference(value),
102                    ),
103                )?;
104                Ok(())
105            },
106        )?;
107
108        // Regular step after the iteration
109        pipe.step::<SetVar>(
110            "finalize",
111            params!(
112                "name" => "done",
113                "value" => Param::reference("status"),
114            ),
115        )?;
116
117        pipe.returns(
118            "result",
119            params!(
120                "status" => Param::reference("done"),
121            ),
122        )?;
123
124        let complete = pipe.compile()?.run().wait()?;
125        complete.debug();
126    }
127
128    // ── Error: iter_map with unresolved source ──
129    println!("\n=== iter_map unresolved source ===");
130    {
131        let mut pipe = Pipeline::default();
132
133        pipe.iter_map("loop", IterSource::map("missing"), |_, _, _| Ok(()))?;
134
135        match pipe.compile() {
136            Err(e) => println!("  Caught: {}", e),
137            Ok(_) => println!("  ERROR: should have failed!"),
138        }
139    }
140
141    // ── Error: iter_map body references unknown variable ──
142    println!("\n=== iter_map unresolved body reference ===");
143    {
144        let mut pipe = Pipeline::default();
145        pipe.map("data")?.insert("k", "v")?;
146
147        pipe.iter_map("loop", IterSource::map("data"), |_, _, body| {
148            body.step::<SetVar>(
149                "bad",
150                params!(
151                    "name" => "out",
152                    "value" => Param::reference("phantom"),
153                ),
154            )?;
155            Ok(())
156        })?;
157
158        match pipe.compile() {
159            Err(e) => println!("  Caught: {}", e),
160            Ok(_) => println!("  ERROR: should have failed!"),
161        }
162    }
163
164    Ok(())
165}