Skip to main content

Param

Enum Param 

Source
pub enum Param {
    Literal(Value),
    Ref(String),
    Template(Vec<Param>),
    Array(Vec<Param>),
    Map(HashMap<String, Param>),
}
Expand description

A parameter value supplied to an operation input at draft time.

Operations declare their inputs in OperationMetadata; callers bind each declared input to a Param through the params! macro when adding a step with Pipeline::step. A Param is either a literal (resolved immediately from the embedded Value) or a reference that looks up state from the runtime Store when the step runs.

Most code constructs Params through the params! macro rather than the variants directly — the macro picks the right variant from the Rust literal or reference syntax it is given.

use panopticon_core::prelude::*;

let mut pipe = Pipeline::default();
pipe.var("target", "world")?;
pipe.step::<SetVar>(
    "greet",
    params!(
        "name" => "greeting",
        "value" => Param::template(vec![
            Param::literal("hello, "),
            Param::reference("target"),
        ]),
    ),
)?;

Variants§

§

Literal(Value)

A scalar value supplied directly, with no store lookup.

§

Ref(String)

A reference to a store entry by dotted path (e.g. "var_name" or "step_name.output_name"). Resolved against the runtime store when the step executes.

§

Template(Vec<Param>)

A string template whose parts (literals or references) are resolved and concatenated into a single Text value at runtime. Every part must resolve to a scalar — nested arrays or maps produce OperationError::InvalidTemplatePart.

§

Array(Vec<Param>)

An array of parameters. Each element is resolved independently and the result is wrapped in a StoreEntry::Array.

§

Map(HashMap<String, Param>)

A map of parameters keyed by name. Each value is resolved independently and the result is wrapped in a StoreEntry::Map.

Implementations§

Source§

impl Param

Source

pub fn literal(value: impl Into<Value>) -> Self

Constructs a Param::Literal from anything convertible into a Value.

Examples found in repository?
examples/guard.rs (line 102)
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12    // ── Basic guard: Compare produces true, body executes ──
13    println!("=== Guard (true) ===");
14    {
15        let mut pipe = Pipeline::default();
16        pipe.var("status_code", 200i64)?;
17
18        pipe.step::<Compare>(
19            "is_ok",
20            params!(
21                "left" => Param::reference("status_code"),
22                "op" => "eq",
23                "right" => 200i64,
24                "name" => "should_run",
25            ),
26        )?;
27
28        pipe.guard("check", GuardSource::boolean("is_ok.should_run"), |body| {
29            body.step::<SetVar>(
30                "produce",
31                params!("name" => "result", "value" => "guard body executed"),
32            )?;
33            Ok(())
34        })?;
35
36        pipe.hook(Logger::new().writer(std::io::stdout()));
37        pipe.hook(Timeout::new(Duration::from_secs(5)));
38
39        let complete = pipe.compile()?.run().wait()?;
40        complete.debug();
41    }
42
43    // ── Guard skipped: Compare produces false ──
44    println!("\n=== Guard (false) ===");
45    {
46        let mut pipe = Pipeline::default();
47        pipe.var("status_code", 404i64)?;
48
49        pipe.step::<Compare>(
50            "is_ok",
51            params!(
52                "left" => Param::reference("status_code"),
53                "op" => "eq",
54                "right" => 200i64,
55                "name" => "should_run",
56            ),
57        )?;
58
59        pipe.guard("check", GuardSource::boolean("is_ok.should_run"), |body| {
60            body.step::<SetVar>(
61                "produce",
62                params!("name" => "result", "value" => "should not appear"),
63            )?;
64            Ok(())
65        })?;
66
67        pipe.hook(Logger::new().writer(std::io::stdout()));
68
69        let complete = pipe.compile()?.run().wait()?;
70        complete.debug();
71    }
72
73    // ── Guard output used by downstream step ──
74    println!("\n=== Guard output used downstream ===");
75    {
76        let mut pipe = Pipeline::default();
77        pipe.var("count", 5i64)?;
78
79        pipe.step::<Compare>(
80            "has_results",
81            params!(
82                "left" => Param::reference("count"),
83                "op" => "gt",
84                "right" => 0i64,
85                "name" => "flag",
86            ),
87        )?;
88
89        pipe.guard("gate", GuardSource::boolean("has_results.flag"), |body| {
90            body.step::<SetVar>(
91                "create",
92                params!("name" => "message", "value" => "from inside guard"),
93            )?;
94            Ok(())
95        })?;
96
97        pipe.step::<SetVar>(
98            "consume",
99            params!(
100                "name" => "final_output",
101                "value" => Param::template(vec![
102                    Param::literal("received: "),
103                    Param::reference("message"),
104                ]),
105            ),
106        )?;
107
108        pipe.hook(Logger::new().writer(std::io::stdout()));
109
110        let complete = pipe.compile()?.run().wait()?;
111        complete.debug();
112    }
113
114    // ── Error: unresolved guard reference ──
115    println!("\n=== Guard unresolved reference ===");
116    {
117        let mut pipe = Pipeline::default();
118
119        pipe.guard("check", GuardSource::boolean("nonexistent"), |_body| Ok(()))?;
120
121        match pipe.compile() {
122            Err(e) => println!("  Caught: {}", e),
123            Ok(_) => println!("  ERROR: should have failed!"),
124        }
125    }
126
127    Ok(())
128}
More examples
Hide additional examples
examples/iter_array.rs (line 92)
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13    // ── Basic iter_array: iterate over items and capture each ──
14    println!("=== Basic iter_array ===");
15    {
16        let mut pipe = Pipeline::default();
17        pipe.array("numbers")?.push(10)?.push(20)?.push(30)?;
18
19        pipe.iter_array(
20            "process",
21            IterSource::array("numbers"),
22            |_index, item, body| {
23                body.step::<SetVar>(
24                    "capture",
25                    params!(
26                        "name" => "doubled",
27                        "value" => Param::reference(item),
28                    ),
29                )?;
30                Ok(())
31            },
32        )?;
33
34        pipe.hook(Logger::new().writer(std::io::stdout()));
35        pipe.hook(Timeout::new(Duration::from_secs(5)));
36
37        let complete = pipe.compile()?.run().wait()?;
38        complete.debug();
39    }
40
41    // ── iter_array with parent variable references ──
42    println!("\n=== iter_array referencing parent vars ===");
43    {
44        let mut pipe = Pipeline::default();
45        pipe.var("prefix", "item_")?;
46        pipe.array("items")?
47            .push("alpha")?
48            .push("beta")?
49            .push("gamma")?;
50
51        pipe.iter_array("loop", IterSource::array("items"), |_index, item, body| {
52            body.step::<SetVar>(
53                "combine",
54                params!(
55                    "name" => "label",
56                    "value" => Param::template(vec![
57                        Param::reference("prefix"),
58                        Param::reference(item),
59                    ]),
60                ),
61            )?;
62            Ok(())
63        })?;
64
65        let complete = pipe.compile()?.run().wait()?;
66        complete.debug();
67    }
68
69    // ── iter_array with multiple body steps ──
70    println!("\n=== iter_array with multi-step body ===");
71    {
72        let mut pipe = Pipeline::default();
73        pipe.var("suffix", "_processed")?;
74        pipe.array("words")?.push("hello")?.push("world")?;
75
76        pipe.iter_array("each", IterSource::array("words"), |_index, item, body| {
77            body.step::<SetVar>(
78                "tag",
79                params!(
80                    "name" => "tagged",
81                    "value" => Param::template(vec![
82                        Param::reference(item),
83                        Param::reference("suffix"),
84                    ]),
85                ),
86            )?;
87            body.step::<SetVar>(
88                "wrap",
89                params!(
90                    "name" => "wrapped",
91                    "value" => Param::template(vec![
92                        Param::literal("["),
93                        Param::reference("tagged"),
94                        Param::literal("]"),
95                    ]),
96                ),
97            )?;
98            Ok(())
99        })?;
100
101        let complete = pipe.compile()?.run().wait()?;
102        complete.debug();
103    }
104
105    // ── Error: iter_array with unresolved source ──
106    println!("\n=== iter_array unresolved source ===");
107    {
108        let mut pipe = Pipeline::default();
109
110        pipe.iter_array("loop", IterSource::array("nonexistent"), |_, _, _| Ok(()))?;
111
112        match pipe.compile() {
113            Err(e) => println!("  Caught: {}", e),
114            Ok(_) => println!("  ERROR: should have failed!"),
115        }
116    }
117
118    // ── Error: iter_array body references unknown variable ──
119    println!("\n=== iter_array unresolved body reference ===");
120    {
121        let mut pipe = Pipeline::default();
122        pipe.array("items")?.push(1)?;
123
124        pipe.iter_array("loop", IterSource::array("items"), |_, _, body| {
125            body.step::<SetVar>(
126                "bad",
127                params!(
128                    "name" => "out",
129                    "value" => Param::reference("ghost"),
130                ),
131            )?;
132            Ok(())
133        })?;
134
135        match pipe.compile() {
136            Err(e) => println!("  Caught: {}", e),
137            Ok(_) => println!("  ERROR: should have failed!"),
138        }
139    }
140
141    Ok(())
142}
examples/iter_map.rs (line 69)
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}
examples/pipeline.rs (line 57)
13fn main() -> Result<(), Box<dyn std::error::Error>> {
14    // ── Happy path: derived outputs resolved at compile time ──
15    println!("=== Valid pipeline ===");
16    {
17        let mut pipe = Pipeline::default();
18
19        pipe.var("number", 1)?;
20        pipe.var("string", "example")?;
21        pipe.array("array")?.push(1)?.push(2)?.push(3)?;
22
23        // Derived output name from a variable ref: "string" → "example"
24        pipe.step::<SetVar>(
25            "set_var_1",
26            params!(
27                "name" => Param::reference("string"),
28                "value" => Param::reference("number"),
29            ),
30        )?;
31
32        // Derived output name from a literal: "greeting"
33        pipe.step::<SetVar>(
34            "set_var_2",
35            params!(
36                "name" => "greeting",
37                "value" => "hello world",
38            ),
39        )?;
40
41        // Chained: use derived output "greeting" from set_var_2 as a variable reference
42        pipe.step::<SetVar>(
43            "set_var_3",
44            params!(
45                "name" => "farewell",
46                "value" => Param::reference("greeting"),
47            ),
48        )?;
49
50        // Template referencing a derived output
51        pipe.step::<SetVar>(
52            "set_var_4",
53            params!(
54                "name" => "message",
55                "value" => Param::template(vec![
56                    Param::reference("greeting"),
57                    Param::literal(" and goodbye"),
58                ]),
59            ),
60        )?;
61
62        pipe.returns(
63            "summary",
64            params!(
65                "original_number" => Param::reference("number"),
66                "original_string" => Param::reference("string"),
67                "the_array" => Param::reference("array"),
68                "greeting" => Param::reference("greeting"),
69                "derived_from_ref" => Param::reference("example"),
70                "farewell" => Param::reference("farewell"),
71                "message" => Param::reference("message"),
72            ),
73        )?;
74
75        // Logger: writes each event to stdout
76        pipe.hook(Logger::new().writer(std::io::stdout()));
77
78        // Profiler: tracks per-step wall-clock duration
79        let profiler = Profiler::new().writer(std::io::stdout());
80        let timings = profiler.timings();
81        pipe.hook(profiler);
82
83        // EventLog: collects structured event records for post-mortem inspection
84        let event_log = EventLog::new();
85        let log = event_log.log();
86        pipe.hook(event_log);
87
88        // Timeout: aborts if pipeline exceeds 5 seconds
89        pipe.hook(Timeout::new(Duration::from_secs(5)));
90
91        // StoreValidator: assert "greeting" exists as Text after set_var_2
92        pipe.hook(
93            StoreValidator::new()
94                .after_step("set_var_2")
95                .expect("greeting", Type::Text),
96        );
97
98        let complete = pipe.compile()?.run().wait()?;
99        complete.debug();
100
101        // Read profiler timings programmatically
102        println!("\nProgrammatic timings:");
103        for (name, dur) in timings.lock().unwrap().iter() {
104            println!("  {} took {:.3}ms", name, dur.as_secs_f64() * 1000.0);
105        }
106
107        // Read event log
108        println!("\nEvent log ({} events):", log.lock().unwrap().len());
109        for record in log.lock().unwrap().iter() {
110            println!(
111                "  [{:.3}ms] {:?}{}",
112                record.elapsed.as_secs_f64() * 1000.0,
113                record.kind,
114                record
115                    .step_name
116                    .as_deref()
117                    .map(|s| format!(" ({})", s))
118                    .unwrap_or_default(),
119            );
120        }
121    }
122
123    // ── Error: step references a variable that doesn't exist ──
124    println!("\n=== Unresolved step reference ===");
125    {
126        let mut pipe = Pipeline::default();
127        pipe.var("number", 1)?;
128
129        pipe.step::<SetVar>(
130            "bad_step",
131            params!(
132                "name" => "output",
133                "value" => Param::reference("does_not_exist"),
134            ),
135        )?;
136
137        match pipe.compile() {
138            Err(e) => println!("  Caught: {}", e),
139            Ok(_) => println!("  ERROR: should have failed!"),
140        }
141    }
142
143    // ── Error: return references something that was never produced ──
144    println!("\n=== Unresolved return reference ===");
145    {
146        let mut pipe = Pipeline::default();
147        pipe.var("number", 1)?;
148
149        pipe.step::<SetVar>(
150            "ok_step",
151            params!(
152                "name" => "output",
153                "value" => Param::reference("number"),
154            ),
155        )?;
156
157        pipe.returns(
158            "result",
159            params!(
160                "good" => Param::reference("output"),
161                "bad" => Param::reference("never_created"),
162            ),
163        )?;
164
165        match pipe.compile() {
166            Err(e) => println!("  Caught: {}", e),
167            Ok(_) => println!("  ERROR: should have failed!"),
168        }
169    }
170
171    // ── Error: step references a later step's output (ordering) ──
172    println!("\n=== Forward reference (wrong order) ===");
173    {
174        let mut pipe = Pipeline::default();
175        pipe.var("base", "start")?;
176
177        // This step tries to reference "later_output" which doesn't exist yet
178        pipe.step::<SetVar>(
179            "step_1",
180            params!(
181                "name" => "early",
182                "value" => Param::reference("later_output"),
183            ),
184        )?;
185
186        pipe.step::<SetVar>(
187            "step_2",
188            params!(
189                "name" => "later_output",
190                "value" => Param::reference("base"),
191            ),
192        )?;
193
194        match pipe.compile() {
195            Err(e) => println!("  Caught: {}", e),
196            Ok(_) => println!("  ERROR: should have failed!"),
197        }
198    }
199
200    // ── Error: duplicate variable name ──
201    println!("\n=== Duplicate variable ===");
202    {
203        let mut pipe = Pipeline::default();
204        pipe.var("x", 1)?;
205        match pipe.var("x", 2) {
206            Err(e) => println!("  Caught: {}", e),
207            Ok(_) => println!("  ERROR: should have failed!"),
208        }
209    }
210
211    // ── Error: duplicate step name ──
212    println!("\n=== Duplicate step ===");
213    {
214        let mut pipe = Pipeline::default();
215        pipe.var("v", "val")?;
216
217        pipe.step::<SetVar>("same_name", params!("name" => "a", "value" => "b"))?;
218        match pipe.step::<SetVar>("same_name", params!("name" => "c", "value" => "d")) {
219            Err(e) => println!("  Caught: {}", e),
220            Ok(_) => println!("  ERROR: should have failed!"),
221        }
222    }
223
224    // ── StepFilter: deny a step from executing ──
225    println!("\n=== StepFilter deny ===");
226    {
227        let mut pipe = Pipeline::default();
228        pipe.var("x", 1)?;
229
230        pipe.step::<SetVar>("allowed_step", params!("name" => "a", "value" => "ok"))?;
231        pipe.step::<SetVar>(
232            "blocked_step",
233            params!("name" => "b", "value" => Param::reference("a")),
234        )?;
235
236        pipe.returns("result", params!("a" => Param::reference("a")))?;
237
238        pipe.hook(StepFilter::deny(["blocked_step"]));
239
240        match pipe.compile()?.run().wait() {
241            Err(e) => println!("  Caught: {}", e),
242            Ok(_) => println!("  ERROR: should have been denied!"),
243        }
244    }
245
246    Ok(())
247}
Source

pub fn reference(path: impl Into<String>) -> Self

Constructs a Param::Ref pointing at a dotted store path.

Examples found in repository?
examples/guard.rs (line 21)
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12    // ── Basic guard: Compare produces true, body executes ──
13    println!("=== Guard (true) ===");
14    {
15        let mut pipe = Pipeline::default();
16        pipe.var("status_code", 200i64)?;
17
18        pipe.step::<Compare>(
19            "is_ok",
20            params!(
21                "left" => Param::reference("status_code"),
22                "op" => "eq",
23                "right" => 200i64,
24                "name" => "should_run",
25            ),
26        )?;
27
28        pipe.guard("check", GuardSource::boolean("is_ok.should_run"), |body| {
29            body.step::<SetVar>(
30                "produce",
31                params!("name" => "result", "value" => "guard body executed"),
32            )?;
33            Ok(())
34        })?;
35
36        pipe.hook(Logger::new().writer(std::io::stdout()));
37        pipe.hook(Timeout::new(Duration::from_secs(5)));
38
39        let complete = pipe.compile()?.run().wait()?;
40        complete.debug();
41    }
42
43    // ── Guard skipped: Compare produces false ──
44    println!("\n=== Guard (false) ===");
45    {
46        let mut pipe = Pipeline::default();
47        pipe.var("status_code", 404i64)?;
48
49        pipe.step::<Compare>(
50            "is_ok",
51            params!(
52                "left" => Param::reference("status_code"),
53                "op" => "eq",
54                "right" => 200i64,
55                "name" => "should_run",
56            ),
57        )?;
58
59        pipe.guard("check", GuardSource::boolean("is_ok.should_run"), |body| {
60            body.step::<SetVar>(
61                "produce",
62                params!("name" => "result", "value" => "should not appear"),
63            )?;
64            Ok(())
65        })?;
66
67        pipe.hook(Logger::new().writer(std::io::stdout()));
68
69        let complete = pipe.compile()?.run().wait()?;
70        complete.debug();
71    }
72
73    // ── Guard output used by downstream step ──
74    println!("\n=== Guard output used downstream ===");
75    {
76        let mut pipe = Pipeline::default();
77        pipe.var("count", 5i64)?;
78
79        pipe.step::<Compare>(
80            "has_results",
81            params!(
82                "left" => Param::reference("count"),
83                "op" => "gt",
84                "right" => 0i64,
85                "name" => "flag",
86            ),
87        )?;
88
89        pipe.guard("gate", GuardSource::boolean("has_results.flag"), |body| {
90            body.step::<SetVar>(
91                "create",
92                params!("name" => "message", "value" => "from inside guard"),
93            )?;
94            Ok(())
95        })?;
96
97        pipe.step::<SetVar>(
98            "consume",
99            params!(
100                "name" => "final_output",
101                "value" => Param::template(vec![
102                    Param::literal("received: "),
103                    Param::reference("message"),
104                ]),
105            ),
106        )?;
107
108        pipe.hook(Logger::new().writer(std::io::stdout()));
109
110        let complete = pipe.compile()?.run().wait()?;
111        complete.debug();
112    }
113
114    // ── Error: unresolved guard reference ──
115    println!("\n=== Guard unresolved reference ===");
116    {
117        let mut pipe = Pipeline::default();
118
119        pipe.guard("check", GuardSource::boolean("nonexistent"), |_body| Ok(()))?;
120
121        match pipe.compile() {
122            Err(e) => println!("  Caught: {}", e),
123            Ok(_) => println!("  ERROR: should have failed!"),
124        }
125    }
126
127    Ok(())
128}
More examples
Hide additional examples
examples/iter_array.rs (line 27)
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13    // ── Basic iter_array: iterate over items and capture each ──
14    println!("=== Basic iter_array ===");
15    {
16        let mut pipe = Pipeline::default();
17        pipe.array("numbers")?.push(10)?.push(20)?.push(30)?;
18
19        pipe.iter_array(
20            "process",
21            IterSource::array("numbers"),
22            |_index, item, body| {
23                body.step::<SetVar>(
24                    "capture",
25                    params!(
26                        "name" => "doubled",
27                        "value" => Param::reference(item),
28                    ),
29                )?;
30                Ok(())
31            },
32        )?;
33
34        pipe.hook(Logger::new().writer(std::io::stdout()));
35        pipe.hook(Timeout::new(Duration::from_secs(5)));
36
37        let complete = pipe.compile()?.run().wait()?;
38        complete.debug();
39    }
40
41    // ── iter_array with parent variable references ──
42    println!("\n=== iter_array referencing parent vars ===");
43    {
44        let mut pipe = Pipeline::default();
45        pipe.var("prefix", "item_")?;
46        pipe.array("items")?
47            .push("alpha")?
48            .push("beta")?
49            .push("gamma")?;
50
51        pipe.iter_array("loop", IterSource::array("items"), |_index, item, body| {
52            body.step::<SetVar>(
53                "combine",
54                params!(
55                    "name" => "label",
56                    "value" => Param::template(vec![
57                        Param::reference("prefix"),
58                        Param::reference(item),
59                    ]),
60                ),
61            )?;
62            Ok(())
63        })?;
64
65        let complete = pipe.compile()?.run().wait()?;
66        complete.debug();
67    }
68
69    // ── iter_array with multiple body steps ──
70    println!("\n=== iter_array with multi-step body ===");
71    {
72        let mut pipe = Pipeline::default();
73        pipe.var("suffix", "_processed")?;
74        pipe.array("words")?.push("hello")?.push("world")?;
75
76        pipe.iter_array("each", IterSource::array("words"), |_index, item, body| {
77            body.step::<SetVar>(
78                "tag",
79                params!(
80                    "name" => "tagged",
81                    "value" => Param::template(vec![
82                        Param::reference(item),
83                        Param::reference("suffix"),
84                    ]),
85                ),
86            )?;
87            body.step::<SetVar>(
88                "wrap",
89                params!(
90                    "name" => "wrapped",
91                    "value" => Param::template(vec![
92                        Param::literal("["),
93                        Param::reference("tagged"),
94                        Param::literal("]"),
95                    ]),
96                ),
97            )?;
98            Ok(())
99        })?;
100
101        let complete = pipe.compile()?.run().wait()?;
102        complete.debug();
103    }
104
105    // ── Error: iter_array with unresolved source ──
106    println!("\n=== iter_array unresolved source ===");
107    {
108        let mut pipe = Pipeline::default();
109
110        pipe.iter_array("loop", IterSource::array("nonexistent"), |_, _, _| Ok(()))?;
111
112        match pipe.compile() {
113            Err(e) => println!("  Caught: {}", e),
114            Ok(_) => println!("  ERROR: should have failed!"),
115        }
116    }
117
118    // ── Error: iter_array body references unknown variable ──
119    println!("\n=== iter_array unresolved body reference ===");
120    {
121        let mut pipe = Pipeline::default();
122        pipe.array("items")?.push(1)?;
123
124        pipe.iter_array("loop", IterSource::array("items"), |_, _, body| {
125            body.step::<SetVar>(
126                "bad",
127                params!(
128                    "name" => "out",
129                    "value" => Param::reference("ghost"),
130                ),
131            )?;
132            Ok(())
133        })?;
134
135        match pipe.compile() {
136            Err(e) => println!("  Caught: {}", e),
137            Ok(_) => println!("  ERROR: should have failed!"),
138        }
139    }
140
141    Ok(())
142}
examples/iter_map.rs (line 29)
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}
examples/pipeline.rs (line 27)
13fn main() -> Result<(), Box<dyn std::error::Error>> {
14    // ── Happy path: derived outputs resolved at compile time ──
15    println!("=== Valid pipeline ===");
16    {
17        let mut pipe = Pipeline::default();
18
19        pipe.var("number", 1)?;
20        pipe.var("string", "example")?;
21        pipe.array("array")?.push(1)?.push(2)?.push(3)?;
22
23        // Derived output name from a variable ref: "string" → "example"
24        pipe.step::<SetVar>(
25            "set_var_1",
26            params!(
27                "name" => Param::reference("string"),
28                "value" => Param::reference("number"),
29            ),
30        )?;
31
32        // Derived output name from a literal: "greeting"
33        pipe.step::<SetVar>(
34            "set_var_2",
35            params!(
36                "name" => "greeting",
37                "value" => "hello world",
38            ),
39        )?;
40
41        // Chained: use derived output "greeting" from set_var_2 as a variable reference
42        pipe.step::<SetVar>(
43            "set_var_3",
44            params!(
45                "name" => "farewell",
46                "value" => Param::reference("greeting"),
47            ),
48        )?;
49
50        // Template referencing a derived output
51        pipe.step::<SetVar>(
52            "set_var_4",
53            params!(
54                "name" => "message",
55                "value" => Param::template(vec![
56                    Param::reference("greeting"),
57                    Param::literal(" and goodbye"),
58                ]),
59            ),
60        )?;
61
62        pipe.returns(
63            "summary",
64            params!(
65                "original_number" => Param::reference("number"),
66                "original_string" => Param::reference("string"),
67                "the_array" => Param::reference("array"),
68                "greeting" => Param::reference("greeting"),
69                "derived_from_ref" => Param::reference("example"),
70                "farewell" => Param::reference("farewell"),
71                "message" => Param::reference("message"),
72            ),
73        )?;
74
75        // Logger: writes each event to stdout
76        pipe.hook(Logger::new().writer(std::io::stdout()));
77
78        // Profiler: tracks per-step wall-clock duration
79        let profiler = Profiler::new().writer(std::io::stdout());
80        let timings = profiler.timings();
81        pipe.hook(profiler);
82
83        // EventLog: collects structured event records for post-mortem inspection
84        let event_log = EventLog::new();
85        let log = event_log.log();
86        pipe.hook(event_log);
87
88        // Timeout: aborts if pipeline exceeds 5 seconds
89        pipe.hook(Timeout::new(Duration::from_secs(5)));
90
91        // StoreValidator: assert "greeting" exists as Text after set_var_2
92        pipe.hook(
93            StoreValidator::new()
94                .after_step("set_var_2")
95                .expect("greeting", Type::Text),
96        );
97
98        let complete = pipe.compile()?.run().wait()?;
99        complete.debug();
100
101        // Read profiler timings programmatically
102        println!("\nProgrammatic timings:");
103        for (name, dur) in timings.lock().unwrap().iter() {
104            println!("  {} took {:.3}ms", name, dur.as_secs_f64() * 1000.0);
105        }
106
107        // Read event log
108        println!("\nEvent log ({} events):", log.lock().unwrap().len());
109        for record in log.lock().unwrap().iter() {
110            println!(
111                "  [{:.3}ms] {:?}{}",
112                record.elapsed.as_secs_f64() * 1000.0,
113                record.kind,
114                record
115                    .step_name
116                    .as_deref()
117                    .map(|s| format!(" ({})", s))
118                    .unwrap_or_default(),
119            );
120        }
121    }
122
123    // ── Error: step references a variable that doesn't exist ──
124    println!("\n=== Unresolved step reference ===");
125    {
126        let mut pipe = Pipeline::default();
127        pipe.var("number", 1)?;
128
129        pipe.step::<SetVar>(
130            "bad_step",
131            params!(
132                "name" => "output",
133                "value" => Param::reference("does_not_exist"),
134            ),
135        )?;
136
137        match pipe.compile() {
138            Err(e) => println!("  Caught: {}", e),
139            Ok(_) => println!("  ERROR: should have failed!"),
140        }
141    }
142
143    // ── Error: return references something that was never produced ──
144    println!("\n=== Unresolved return reference ===");
145    {
146        let mut pipe = Pipeline::default();
147        pipe.var("number", 1)?;
148
149        pipe.step::<SetVar>(
150            "ok_step",
151            params!(
152                "name" => "output",
153                "value" => Param::reference("number"),
154            ),
155        )?;
156
157        pipe.returns(
158            "result",
159            params!(
160                "good" => Param::reference("output"),
161                "bad" => Param::reference("never_created"),
162            ),
163        )?;
164
165        match pipe.compile() {
166            Err(e) => println!("  Caught: {}", e),
167            Ok(_) => println!("  ERROR: should have failed!"),
168        }
169    }
170
171    // ── Error: step references a later step's output (ordering) ──
172    println!("\n=== Forward reference (wrong order) ===");
173    {
174        let mut pipe = Pipeline::default();
175        pipe.var("base", "start")?;
176
177        // This step tries to reference "later_output" which doesn't exist yet
178        pipe.step::<SetVar>(
179            "step_1",
180            params!(
181                "name" => "early",
182                "value" => Param::reference("later_output"),
183            ),
184        )?;
185
186        pipe.step::<SetVar>(
187            "step_2",
188            params!(
189                "name" => "later_output",
190                "value" => Param::reference("base"),
191            ),
192        )?;
193
194        match pipe.compile() {
195            Err(e) => println!("  Caught: {}", e),
196            Ok(_) => println!("  ERROR: should have failed!"),
197        }
198    }
199
200    // ── Error: duplicate variable name ──
201    println!("\n=== Duplicate variable ===");
202    {
203        let mut pipe = Pipeline::default();
204        pipe.var("x", 1)?;
205        match pipe.var("x", 2) {
206            Err(e) => println!("  Caught: {}", e),
207            Ok(_) => println!("  ERROR: should have failed!"),
208        }
209    }
210
211    // ── Error: duplicate step name ──
212    println!("\n=== Duplicate step ===");
213    {
214        let mut pipe = Pipeline::default();
215        pipe.var("v", "val")?;
216
217        pipe.step::<SetVar>("same_name", params!("name" => "a", "value" => "b"))?;
218        match pipe.step::<SetVar>("same_name", params!("name" => "c", "value" => "d")) {
219            Err(e) => println!("  Caught: {}", e),
220            Ok(_) => println!("  ERROR: should have failed!"),
221        }
222    }
223
224    // ── StepFilter: deny a step from executing ──
225    println!("\n=== StepFilter deny ===");
226    {
227        let mut pipe = Pipeline::default();
228        pipe.var("x", 1)?;
229
230        pipe.step::<SetVar>("allowed_step", params!("name" => "a", "value" => "ok"))?;
231        pipe.step::<SetVar>(
232            "blocked_step",
233            params!("name" => "b", "value" => Param::reference("a")),
234        )?;
235
236        pipe.returns("result", params!("a" => Param::reference("a")))?;
237
238        pipe.hook(StepFilter::deny(["blocked_step"]));
239
240        match pipe.compile()?.run().wait() {
241            Err(e) => println!("  Caught: {}", e),
242            Ok(_) => println!("  ERROR: should have been denied!"),
243        }
244    }
245
246    Ok(())
247}
Source

pub fn template(parts: Vec<Param>) -> Self

Constructs a Param::Template from an ordered list of parts.

Examples found in repository?
examples/guard.rs (lines 101-104)
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12    // ── Basic guard: Compare produces true, body executes ──
13    println!("=== Guard (true) ===");
14    {
15        let mut pipe = Pipeline::default();
16        pipe.var("status_code", 200i64)?;
17
18        pipe.step::<Compare>(
19            "is_ok",
20            params!(
21                "left" => Param::reference("status_code"),
22                "op" => "eq",
23                "right" => 200i64,
24                "name" => "should_run",
25            ),
26        )?;
27
28        pipe.guard("check", GuardSource::boolean("is_ok.should_run"), |body| {
29            body.step::<SetVar>(
30                "produce",
31                params!("name" => "result", "value" => "guard body executed"),
32            )?;
33            Ok(())
34        })?;
35
36        pipe.hook(Logger::new().writer(std::io::stdout()));
37        pipe.hook(Timeout::new(Duration::from_secs(5)));
38
39        let complete = pipe.compile()?.run().wait()?;
40        complete.debug();
41    }
42
43    // ── Guard skipped: Compare produces false ──
44    println!("\n=== Guard (false) ===");
45    {
46        let mut pipe = Pipeline::default();
47        pipe.var("status_code", 404i64)?;
48
49        pipe.step::<Compare>(
50            "is_ok",
51            params!(
52                "left" => Param::reference("status_code"),
53                "op" => "eq",
54                "right" => 200i64,
55                "name" => "should_run",
56            ),
57        )?;
58
59        pipe.guard("check", GuardSource::boolean("is_ok.should_run"), |body| {
60            body.step::<SetVar>(
61                "produce",
62                params!("name" => "result", "value" => "should not appear"),
63            )?;
64            Ok(())
65        })?;
66
67        pipe.hook(Logger::new().writer(std::io::stdout()));
68
69        let complete = pipe.compile()?.run().wait()?;
70        complete.debug();
71    }
72
73    // ── Guard output used by downstream step ──
74    println!("\n=== Guard output used downstream ===");
75    {
76        let mut pipe = Pipeline::default();
77        pipe.var("count", 5i64)?;
78
79        pipe.step::<Compare>(
80            "has_results",
81            params!(
82                "left" => Param::reference("count"),
83                "op" => "gt",
84                "right" => 0i64,
85                "name" => "flag",
86            ),
87        )?;
88
89        pipe.guard("gate", GuardSource::boolean("has_results.flag"), |body| {
90            body.step::<SetVar>(
91                "create",
92                params!("name" => "message", "value" => "from inside guard"),
93            )?;
94            Ok(())
95        })?;
96
97        pipe.step::<SetVar>(
98            "consume",
99            params!(
100                "name" => "final_output",
101                "value" => Param::template(vec![
102                    Param::literal("received: "),
103                    Param::reference("message"),
104                ]),
105            ),
106        )?;
107
108        pipe.hook(Logger::new().writer(std::io::stdout()));
109
110        let complete = pipe.compile()?.run().wait()?;
111        complete.debug();
112    }
113
114    // ── Error: unresolved guard reference ──
115    println!("\n=== Guard unresolved reference ===");
116    {
117        let mut pipe = Pipeline::default();
118
119        pipe.guard("check", GuardSource::boolean("nonexistent"), |_body| Ok(()))?;
120
121        match pipe.compile() {
122            Err(e) => println!("  Caught: {}", e),
123            Ok(_) => println!("  ERROR: should have failed!"),
124        }
125    }
126
127    Ok(())
128}
More examples
Hide additional examples
examples/iter_array.rs (lines 56-59)
12fn main() -> Result<(), Box<dyn std::error::Error>> {
13    // ── Basic iter_array: iterate over items and capture each ──
14    println!("=== Basic iter_array ===");
15    {
16        let mut pipe = Pipeline::default();
17        pipe.array("numbers")?.push(10)?.push(20)?.push(30)?;
18
19        pipe.iter_array(
20            "process",
21            IterSource::array("numbers"),
22            |_index, item, body| {
23                body.step::<SetVar>(
24                    "capture",
25                    params!(
26                        "name" => "doubled",
27                        "value" => Param::reference(item),
28                    ),
29                )?;
30                Ok(())
31            },
32        )?;
33
34        pipe.hook(Logger::new().writer(std::io::stdout()));
35        pipe.hook(Timeout::new(Duration::from_secs(5)));
36
37        let complete = pipe.compile()?.run().wait()?;
38        complete.debug();
39    }
40
41    // ── iter_array with parent variable references ──
42    println!("\n=== iter_array referencing parent vars ===");
43    {
44        let mut pipe = Pipeline::default();
45        pipe.var("prefix", "item_")?;
46        pipe.array("items")?
47            .push("alpha")?
48            .push("beta")?
49            .push("gamma")?;
50
51        pipe.iter_array("loop", IterSource::array("items"), |_index, item, body| {
52            body.step::<SetVar>(
53                "combine",
54                params!(
55                    "name" => "label",
56                    "value" => Param::template(vec![
57                        Param::reference("prefix"),
58                        Param::reference(item),
59                    ]),
60                ),
61            )?;
62            Ok(())
63        })?;
64
65        let complete = pipe.compile()?.run().wait()?;
66        complete.debug();
67    }
68
69    // ── iter_array with multiple body steps ──
70    println!("\n=== iter_array with multi-step body ===");
71    {
72        let mut pipe = Pipeline::default();
73        pipe.var("suffix", "_processed")?;
74        pipe.array("words")?.push("hello")?.push("world")?;
75
76        pipe.iter_array("each", IterSource::array("words"), |_index, item, body| {
77            body.step::<SetVar>(
78                "tag",
79                params!(
80                    "name" => "tagged",
81                    "value" => Param::template(vec![
82                        Param::reference(item),
83                        Param::reference("suffix"),
84                    ]),
85                ),
86            )?;
87            body.step::<SetVar>(
88                "wrap",
89                params!(
90                    "name" => "wrapped",
91                    "value" => Param::template(vec![
92                        Param::literal("["),
93                        Param::reference("tagged"),
94                        Param::literal("]"),
95                    ]),
96                ),
97            )?;
98            Ok(())
99        })?;
100
101        let complete = pipe.compile()?.run().wait()?;
102        complete.debug();
103    }
104
105    // ── Error: iter_array with unresolved source ──
106    println!("\n=== iter_array unresolved source ===");
107    {
108        let mut pipe = Pipeline::default();
109
110        pipe.iter_array("loop", IterSource::array("nonexistent"), |_, _, _| Ok(()))?;
111
112        match pipe.compile() {
113            Err(e) => println!("  Caught: {}", e),
114            Ok(_) => println!("  ERROR: should have failed!"),
115        }
116    }
117
118    // ── Error: iter_array body references unknown variable ──
119    println!("\n=== iter_array unresolved body reference ===");
120    {
121        let mut pipe = Pipeline::default();
122        pipe.array("items")?.push(1)?;
123
124        pipe.iter_array("loop", IterSource::array("items"), |_, _, body| {
125            body.step::<SetVar>(
126                "bad",
127                params!(
128                    "name" => "out",
129                    "value" => Param::reference("ghost"),
130                ),
131            )?;
132            Ok(())
133        })?;
134
135        match pipe.compile() {
136            Err(e) => println!("  Caught: {}", e),
137            Ok(_) => println!("  ERROR: should have failed!"),
138        }
139    }
140
141    Ok(())
142}
examples/iter_map.rs (lines 67-73)
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}
examples/pipeline.rs (lines 55-58)
13fn main() -> Result<(), Box<dyn std::error::Error>> {
14    // ── Happy path: derived outputs resolved at compile time ──
15    println!("=== Valid pipeline ===");
16    {
17        let mut pipe = Pipeline::default();
18
19        pipe.var("number", 1)?;
20        pipe.var("string", "example")?;
21        pipe.array("array")?.push(1)?.push(2)?.push(3)?;
22
23        // Derived output name from a variable ref: "string" → "example"
24        pipe.step::<SetVar>(
25            "set_var_1",
26            params!(
27                "name" => Param::reference("string"),
28                "value" => Param::reference("number"),
29            ),
30        )?;
31
32        // Derived output name from a literal: "greeting"
33        pipe.step::<SetVar>(
34            "set_var_2",
35            params!(
36                "name" => "greeting",
37                "value" => "hello world",
38            ),
39        )?;
40
41        // Chained: use derived output "greeting" from set_var_2 as a variable reference
42        pipe.step::<SetVar>(
43            "set_var_3",
44            params!(
45                "name" => "farewell",
46                "value" => Param::reference("greeting"),
47            ),
48        )?;
49
50        // Template referencing a derived output
51        pipe.step::<SetVar>(
52            "set_var_4",
53            params!(
54                "name" => "message",
55                "value" => Param::template(vec![
56                    Param::reference("greeting"),
57                    Param::literal(" and goodbye"),
58                ]),
59            ),
60        )?;
61
62        pipe.returns(
63            "summary",
64            params!(
65                "original_number" => Param::reference("number"),
66                "original_string" => Param::reference("string"),
67                "the_array" => Param::reference("array"),
68                "greeting" => Param::reference("greeting"),
69                "derived_from_ref" => Param::reference("example"),
70                "farewell" => Param::reference("farewell"),
71                "message" => Param::reference("message"),
72            ),
73        )?;
74
75        // Logger: writes each event to stdout
76        pipe.hook(Logger::new().writer(std::io::stdout()));
77
78        // Profiler: tracks per-step wall-clock duration
79        let profiler = Profiler::new().writer(std::io::stdout());
80        let timings = profiler.timings();
81        pipe.hook(profiler);
82
83        // EventLog: collects structured event records for post-mortem inspection
84        let event_log = EventLog::new();
85        let log = event_log.log();
86        pipe.hook(event_log);
87
88        // Timeout: aborts if pipeline exceeds 5 seconds
89        pipe.hook(Timeout::new(Duration::from_secs(5)));
90
91        // StoreValidator: assert "greeting" exists as Text after set_var_2
92        pipe.hook(
93            StoreValidator::new()
94                .after_step("set_var_2")
95                .expect("greeting", Type::Text),
96        );
97
98        let complete = pipe.compile()?.run().wait()?;
99        complete.debug();
100
101        // Read profiler timings programmatically
102        println!("\nProgrammatic timings:");
103        for (name, dur) in timings.lock().unwrap().iter() {
104            println!("  {} took {:.3}ms", name, dur.as_secs_f64() * 1000.0);
105        }
106
107        // Read event log
108        println!("\nEvent log ({} events):", log.lock().unwrap().len());
109        for record in log.lock().unwrap().iter() {
110            println!(
111                "  [{:.3}ms] {:?}{}",
112                record.elapsed.as_secs_f64() * 1000.0,
113                record.kind,
114                record
115                    .step_name
116                    .as_deref()
117                    .map(|s| format!(" ({})", s))
118                    .unwrap_or_default(),
119            );
120        }
121    }
122
123    // ── Error: step references a variable that doesn't exist ──
124    println!("\n=== Unresolved step reference ===");
125    {
126        let mut pipe = Pipeline::default();
127        pipe.var("number", 1)?;
128
129        pipe.step::<SetVar>(
130            "bad_step",
131            params!(
132                "name" => "output",
133                "value" => Param::reference("does_not_exist"),
134            ),
135        )?;
136
137        match pipe.compile() {
138            Err(e) => println!("  Caught: {}", e),
139            Ok(_) => println!("  ERROR: should have failed!"),
140        }
141    }
142
143    // ── Error: return references something that was never produced ──
144    println!("\n=== Unresolved return reference ===");
145    {
146        let mut pipe = Pipeline::default();
147        pipe.var("number", 1)?;
148
149        pipe.step::<SetVar>(
150            "ok_step",
151            params!(
152                "name" => "output",
153                "value" => Param::reference("number"),
154            ),
155        )?;
156
157        pipe.returns(
158            "result",
159            params!(
160                "good" => Param::reference("output"),
161                "bad" => Param::reference("never_created"),
162            ),
163        )?;
164
165        match pipe.compile() {
166            Err(e) => println!("  Caught: {}", e),
167            Ok(_) => println!("  ERROR: should have failed!"),
168        }
169    }
170
171    // ── Error: step references a later step's output (ordering) ──
172    println!("\n=== Forward reference (wrong order) ===");
173    {
174        let mut pipe = Pipeline::default();
175        pipe.var("base", "start")?;
176
177        // This step tries to reference "later_output" which doesn't exist yet
178        pipe.step::<SetVar>(
179            "step_1",
180            params!(
181                "name" => "early",
182                "value" => Param::reference("later_output"),
183            ),
184        )?;
185
186        pipe.step::<SetVar>(
187            "step_2",
188            params!(
189                "name" => "later_output",
190                "value" => Param::reference("base"),
191            ),
192        )?;
193
194        match pipe.compile() {
195            Err(e) => println!("  Caught: {}", e),
196            Ok(_) => println!("  ERROR: should have failed!"),
197        }
198    }
199
200    // ── Error: duplicate variable name ──
201    println!("\n=== Duplicate variable ===");
202    {
203        let mut pipe = Pipeline::default();
204        pipe.var("x", 1)?;
205        match pipe.var("x", 2) {
206            Err(e) => println!("  Caught: {}", e),
207            Ok(_) => println!("  ERROR: should have failed!"),
208        }
209    }
210
211    // ── Error: duplicate step name ──
212    println!("\n=== Duplicate step ===");
213    {
214        let mut pipe = Pipeline::default();
215        pipe.var("v", "val")?;
216
217        pipe.step::<SetVar>("same_name", params!("name" => "a", "value" => "b"))?;
218        match pipe.step::<SetVar>("same_name", params!("name" => "c", "value" => "d")) {
219            Err(e) => println!("  Caught: {}", e),
220            Ok(_) => println!("  ERROR: should have failed!"),
221        }
222    }
223
224    // ── StepFilter: deny a step from executing ──
225    println!("\n=== StepFilter deny ===");
226    {
227        let mut pipe = Pipeline::default();
228        pipe.var("x", 1)?;
229
230        pipe.step::<SetVar>("allowed_step", params!("name" => "a", "value" => "ok"))?;
231        pipe.step::<SetVar>(
232            "blocked_step",
233            params!("name" => "b", "value" => Param::reference("a")),
234        )?;
235
236        pipe.returns("result", params!("a" => Param::reference("a")))?;
237
238        pipe.hook(StepFilter::deny(["blocked_step"]));
239
240        match pipe.compile()?.run().wait() {
241            Err(e) => println!("  Caught: {}", e),
242            Ok(_) => println!("  ERROR: should have been denied!"),
243        }
244    }
245
246    Ok(())
247}
Source

pub fn array(items: Vec<Param>) -> Self

Constructs a Param::Array from an ordered list of parameters.

Source

pub fn map(entries: HashMap<String, Param>) -> Self

Constructs a Param::Map from a map of named parameters.

Source

pub fn get_references(&self) -> Vec<String>

Returns every dotted store path referenced by this parameter, walking into nested templates, arrays, and maps. Used by draft-time validation to catch forward and unresolved references.

Trait Implementations§

Source§

impl Clone for Param

Source§

fn clone(&self) -> Param

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 Param

Source§

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

Formats the value using the given formatter. Read more
Source§

impl<V: Into<Value>> From<V> for Param

Source§

fn from(v: V) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl Freeze for Param

§

impl RefUnwindSafe for Param

§

impl Send for Param

§

impl Sync for Param

§

impl Unpin for Param

§

impl UnsafeUnpin for Param

§

impl UnwindSafe for Param

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.