Skip to main content

MapHandle

Struct MapHandle 

Source
pub struct MapHandle<'a, T = StoreEntry> { /* private fields */ }
Expand description

A draft-time builder for populating a map entry in the Store.

Returned by Pipeline::map and Store::define_map. Methods are chainable so nested structures can be built in a single expression. Nested arrays and maps are added via insert_array and insert_map and return child handles borrowing from this one.

Implementations§

Source§

impl<'a> MapHandle<'a, StoreEntry>

Source

pub fn insert_array<K: Into<String>>( &mut self, key: K, ) -> Result<ArrayHandle<'_, StoreEntry>, StoreError>

Inserts a new nested array entry under key and returns a child handle borrowing from this one to populate it.

Source

pub fn insert_map<K: Into<String>>( &mut self, key: K, ) -> Result<MapHandle<'_, StoreEntry>, StoreError>

Inserts a new nested map entry under key and returns a child handle borrowing from this one to populate it.

Source

pub fn with_array<K: Into<String>, F: FnOnce(&mut ArrayHandle<'_, StoreEntry>) -> Result<(), StoreError>>( &mut self, key: K, body: F, ) -> Result<(), StoreError>

Inserts a nested array under key and hands it to a closure for population. Useful when the nested structure would otherwise force awkward temporaries.

Examples found in repository?
examples/extend_store_nested.rs (lines 34-37)
32fn write_grouped_data(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
33    store.with_map("by_severity", |groups| {
34        groups.with_array("high", |arr| {
35            arr.push("INC-001")?.push("INC-004")?;
36            Ok(())
37        })?;
38
39        groups.with_array("medium", |arr| {
40            arr.push("INC-002")?;
41            Ok(())
42        })?;
43
44        groups.with_array("low", |arr| {
45            arr.push("INC-003")?.push("INC-005")?.push("INC-006")?;
46            Ok(())
47        })?;
48
49        Ok(())
50    })?;
51
52    Ok(())
53}
54
55fn write_nested_config(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
56    store.with_map("pipeline_config", |cfg| {
57        cfg.insert("name", "signin_analysis")?;
58
59        cfg.with_map("source", |src| {
60            src.insert("type", "kql")?
61                .insert("workspace", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")?;
62
63            src.with_map("options", |opts| {
64                opts.insert("timeout_secs", 30i64)?
65                    .insert("max_rows", 10_000i64)?;
66                Ok(())
67            })?;
68
69            Ok(())
70        })?;
71
72        cfg.with_array("outputs", |outputs| {
73            let mut o = outputs.push_map()?;
74            o.insert("format", "json")?
75                .insert("path", "/tmp/results.json")?;
76
77            let mut o = outputs.push_map()?;
78            o.insert("format", "csv")?
79                .insert("path", "/tmp/results.csv")?;
80
81            Ok(())
82        })?;
83
84        Ok(())
85    })?;
86
87    Ok(())
88}
More examples
Hide additional examples
examples/extend_store_collections.rs (lines 55-58)
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10    let mut store = Store::new();
11
12    // --- Chainable push ---
13    // push() accepts V: Into<StoreEntry>. The blanket impl
14    // `From<T: Into<Value>> for StoreEntry` means primitives work directly.
15    let mut arr = store.define_array("numbers")?.push(1)?.push(2)?.push(3)?;
16
17    let items = store.get("numbers")?.as_array()?;
18    println!("numbers: len={}", items.len());
19    assert_eq!(items.len(), 3);
20
21    // --- Chainable insert ---
22    // insert() accepts K: Into<String> and V: Into<StoreEntry>.
23    let mut map = store.define_map("config")?;
24    map.insert("host", "localhost")?
25        .insert("port", 8080i64)?
26        .insert("debug", true)?;
27
28    let host = store.get("config")?.get_key("host")?.get_value()?;
29    println!("config.host = {host:?}");
30
31    // --- Closure API on Store ---
32    // with_array scopes the handle so you don't need an explicit drop.
33    store.with_array("tags", |arr| {
34        arr.push("rust")?.push("pipeline")?.push("store")?;
35        Ok(())
36    })?;
37
38    let tags = store.get("tags")?.as_array()?;
39    println!("tags: len={}", tags.len());
40
41    store.with_map("metadata", |map| {
42        map.insert("version", "0.1.0")?.insert("stable", false)?;
43        Ok(())
44    })?;
45
46    let version = store.get("metadata")?.get_key("version")?.get_value()?;
47    println!("metadata.version = {version:?}");
48
49    // --- Nested construction via MapHandle closures ---
50    // with_array and with_map on MapHandle let you build nested structures
51    // without manually managing sub-handles.
52    store.with_map("server", |map| {
53        map.insert("name", "prod-01")?;
54
55        map.with_array("ports", |arr| {
56            arr.push(80)?.push(443)?;
57            Ok(())
58        })?;
59
60        map.with_map("tls", |tls| {
61            tls.insert("enabled", true)?
62                .insert("cert_path", "/etc/ssl/cert.pem")?;
63            Ok(())
64        })?;
65
66        Ok(())
67    })?;
68
69    let tls_enabled = store
70        .get("server")?
71        .get_key("tls")?
72        .get_key("enabled")?
73        .get_value()?;
74    println!("server.tls.enabled = {tls_enabled:?}");
75
76    // --- push_map on ArrayHandle ---
77    // Builds an array of maps — the most common pattern for tabular results.
78    let mut arr = store.define_array("users")?;
79    {
80        let mut user = arr.push_map()?;
81        user.insert("name", "Alice")?.insert("role", "admin")?;
82    }
83    {
84        let mut user = arr.push_map()?;
85        user.insert("name", "Bob")?.insert("role", "viewer")?;
86    }
87
88    let bob_role = store
89        .get("users")?
90        .get_index(1)?
91        .get_key("role")?
92        .get_value()?;
93    println!("users[1].role = {bob_role:?}");
94    assert_eq!(bob_role, &Value::Text("viewer".into()));
95
96    println!("store_collections: ok");
97    Ok(())
98}
Source

pub fn with_map<K: Into<String>, F: FnOnce(&mut MapHandle<'_, StoreEntry>) -> Result<(), StoreError>>( &mut self, key: K, body: F, ) -> Result<(), StoreError>

Inserts a nested map under key and hands it to a closure for population.

Examples found in repository?
examples/extend_store_nested.rs (lines 59-70)
55fn write_nested_config(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
56    store.with_map("pipeline_config", |cfg| {
57        cfg.insert("name", "signin_analysis")?;
58
59        cfg.with_map("source", |src| {
60            src.insert("type", "kql")?
61                .insert("workspace", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")?;
62
63            src.with_map("options", |opts| {
64                opts.insert("timeout_secs", 30i64)?
65                    .insert("max_rows", 10_000i64)?;
66                Ok(())
67            })?;
68
69            Ok(())
70        })?;
71
72        cfg.with_array("outputs", |outputs| {
73            let mut o = outputs.push_map()?;
74            o.insert("format", "json")?
75                .insert("path", "/tmp/results.json")?;
76
77            let mut o = outputs.push_map()?;
78            o.insert("format", "csv")?
79                .insert("path", "/tmp/results.csv")?;
80
81            Ok(())
82        })?;
83
84        Ok(())
85    })?;
86
87    Ok(())
88}
More examples
Hide additional examples
examples/extend_store_collections.rs (lines 60-64)
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10    let mut store = Store::new();
11
12    // --- Chainable push ---
13    // push() accepts V: Into<StoreEntry>. The blanket impl
14    // `From<T: Into<Value>> for StoreEntry` means primitives work directly.
15    let mut arr = store.define_array("numbers")?.push(1)?.push(2)?.push(3)?;
16
17    let items = store.get("numbers")?.as_array()?;
18    println!("numbers: len={}", items.len());
19    assert_eq!(items.len(), 3);
20
21    // --- Chainable insert ---
22    // insert() accepts K: Into<String> and V: Into<StoreEntry>.
23    let mut map = store.define_map("config")?;
24    map.insert("host", "localhost")?
25        .insert("port", 8080i64)?
26        .insert("debug", true)?;
27
28    let host = store.get("config")?.get_key("host")?.get_value()?;
29    println!("config.host = {host:?}");
30
31    // --- Closure API on Store ---
32    // with_array scopes the handle so you don't need an explicit drop.
33    store.with_array("tags", |arr| {
34        arr.push("rust")?.push("pipeline")?.push("store")?;
35        Ok(())
36    })?;
37
38    let tags = store.get("tags")?.as_array()?;
39    println!("tags: len={}", tags.len());
40
41    store.with_map("metadata", |map| {
42        map.insert("version", "0.1.0")?.insert("stable", false)?;
43        Ok(())
44    })?;
45
46    let version = store.get("metadata")?.get_key("version")?.get_value()?;
47    println!("metadata.version = {version:?}");
48
49    // --- Nested construction via MapHandle closures ---
50    // with_array and with_map on MapHandle let you build nested structures
51    // without manually managing sub-handles.
52    store.with_map("server", |map| {
53        map.insert("name", "prod-01")?;
54
55        map.with_array("ports", |arr| {
56            arr.push(80)?.push(443)?;
57            Ok(())
58        })?;
59
60        map.with_map("tls", |tls| {
61            tls.insert("enabled", true)?
62                .insert("cert_path", "/etc/ssl/cert.pem")?;
63            Ok(())
64        })?;
65
66        Ok(())
67    })?;
68
69    let tls_enabled = store
70        .get("server")?
71        .get_key("tls")?
72        .get_key("enabled")?
73        .get_value()?;
74    println!("server.tls.enabled = {tls_enabled:?}");
75
76    // --- push_map on ArrayHandle ---
77    // Builds an array of maps — the most common pattern for tabular results.
78    let mut arr = store.define_array("users")?;
79    {
80        let mut user = arr.push_map()?;
81        user.insert("name", "Alice")?.insert("role", "admin")?;
82    }
83    {
84        let mut user = arr.push_map()?;
85        user.insert("name", "Bob")?.insert("role", "viewer")?;
86    }
87
88    let bob_role = store
89        .get("users")?
90        .get_index(1)?
91        .get_key("role")?
92        .get_value()?;
93    println!("users[1].role = {bob_role:?}");
94    assert_eq!(bob_role, &Value::Text("viewer".into()));
95
96    println!("store_collections: ok");
97    Ok(())
98}
Source§

impl<'a, T> MapHandle<'a, Vec<T>>

Source

pub fn insert_array<K: Into<String>>( &mut self, key: K, ) -> Result<ArrayHandle<'_, T>, StoreError>

Inserts a new inner Vec<T> under key and returns a child array handle for populating it.

Source§

impl<'a, T> MapHandle<'a, HashMap<String, T>>

Source

pub fn insert_map<K: Into<String>>( &mut self, key: K, ) -> Result<MapHandle<'_, T>, StoreError>

Inserts a new inner HashMap<String, T> under key and returns a child map handle for populating it.

Source§

impl<'a, T> MapHandle<'a, T>

Source

pub fn new<N: Into<String>>(name: N, data: &'a mut HashMap<String, T>) -> Self

Wraps a mutable map in a handle under the given display name. Intended for extension code; user code obtains handles through Pipeline::map or Store::define_map.

Source

pub fn insert<V: Into<T>, K: Into<String>>( &mut self, key: K, value: V, ) -> Result<&mut Self, StoreError>

Inserts a key/value pair into the map. Returns a mutable reference for chaining. An existing entry under the same key is overwritten.

Examples found in repository?
examples/extend_store_nested.rs (line 14)
10fn write_query_results(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
11    store.with_array("rows", |rows| {
12        // Row 1 — all fields inserted via chaining, no .into() needed.
13        let mut row = rows.push_map()?;
14        row.insert("user", "alice@contoso.com")?
15            .insert("ip", "10.0.0.1")?
16            .insert("status", "Success")?
17            .insert("attempts", 1i64)?;
18
19        // Row 2
20        let mut row = rows.push_map()?;
21        row.insert("user", "bob@contoso.com")?
22            .insert("ip", "192.168.1.50")?
23            .insert("status", "Failure")?
24            .insert("attempts", 3i64)?;
25
26        Ok(())
27    })?;
28
29    Ok(())
30}
31
32fn write_grouped_data(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
33    store.with_map("by_severity", |groups| {
34        groups.with_array("high", |arr| {
35            arr.push("INC-001")?.push("INC-004")?;
36            Ok(())
37        })?;
38
39        groups.with_array("medium", |arr| {
40            arr.push("INC-002")?;
41            Ok(())
42        })?;
43
44        groups.with_array("low", |arr| {
45            arr.push("INC-003")?.push("INC-005")?.push("INC-006")?;
46            Ok(())
47        })?;
48
49        Ok(())
50    })?;
51
52    Ok(())
53}
54
55fn write_nested_config(store: &mut Store) -> Result<(), Box<dyn std::error::Error>> {
56    store.with_map("pipeline_config", |cfg| {
57        cfg.insert("name", "signin_analysis")?;
58
59        cfg.with_map("source", |src| {
60            src.insert("type", "kql")?
61                .insert("workspace", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")?;
62
63            src.with_map("options", |opts| {
64                opts.insert("timeout_secs", 30i64)?
65                    .insert("max_rows", 10_000i64)?;
66                Ok(())
67            })?;
68
69            Ok(())
70        })?;
71
72        cfg.with_array("outputs", |outputs| {
73            let mut o = outputs.push_map()?;
74            o.insert("format", "json")?
75                .insert("path", "/tmp/results.json")?;
76
77            let mut o = outputs.push_map()?;
78            o.insert("format", "csv")?
79                .insert("path", "/tmp/results.csv")?;
80
81            Ok(())
82        })?;
83
84        Ok(())
85    })?;
86
87    Ok(())
88}
More examples
Hide additional examples
examples/extend_store_collections.rs (line 24)
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10    let mut store = Store::new();
11
12    // --- Chainable push ---
13    // push() accepts V: Into<StoreEntry>. The blanket impl
14    // `From<T: Into<Value>> for StoreEntry` means primitives work directly.
15    let mut arr = store.define_array("numbers")?.push(1)?.push(2)?.push(3)?;
16
17    let items = store.get("numbers")?.as_array()?;
18    println!("numbers: len={}", items.len());
19    assert_eq!(items.len(), 3);
20
21    // --- Chainable insert ---
22    // insert() accepts K: Into<String> and V: Into<StoreEntry>.
23    let mut map = store.define_map("config")?;
24    map.insert("host", "localhost")?
25        .insert("port", 8080i64)?
26        .insert("debug", true)?;
27
28    let host = store.get("config")?.get_key("host")?.get_value()?;
29    println!("config.host = {host:?}");
30
31    // --- Closure API on Store ---
32    // with_array scopes the handle so you don't need an explicit drop.
33    store.with_array("tags", |arr| {
34        arr.push("rust")?.push("pipeline")?.push("store")?;
35        Ok(())
36    })?;
37
38    let tags = store.get("tags")?.as_array()?;
39    println!("tags: len={}", tags.len());
40
41    store.with_map("metadata", |map| {
42        map.insert("version", "0.1.0")?.insert("stable", false)?;
43        Ok(())
44    })?;
45
46    let version = store.get("metadata")?.get_key("version")?.get_value()?;
47    println!("metadata.version = {version:?}");
48
49    // --- Nested construction via MapHandle closures ---
50    // with_array and with_map on MapHandle let you build nested structures
51    // without manually managing sub-handles.
52    store.with_map("server", |map| {
53        map.insert("name", "prod-01")?;
54
55        map.with_array("ports", |arr| {
56            arr.push(80)?.push(443)?;
57            Ok(())
58        })?;
59
60        map.with_map("tls", |tls| {
61            tls.insert("enabled", true)?
62                .insert("cert_path", "/etc/ssl/cert.pem")?;
63            Ok(())
64        })?;
65
66        Ok(())
67    })?;
68
69    let tls_enabled = store
70        .get("server")?
71        .get_key("tls")?
72        .get_key("enabled")?
73        .get_value()?;
74    println!("server.tls.enabled = {tls_enabled:?}");
75
76    // --- push_map on ArrayHandle ---
77    // Builds an array of maps — the most common pattern for tabular results.
78    let mut arr = store.define_array("users")?;
79    {
80        let mut user = arr.push_map()?;
81        user.insert("name", "Alice")?.insert("role", "admin")?;
82    }
83    {
84        let mut user = arr.push_map()?;
85        user.insert("name", "Bob")?.insert("role", "viewer")?;
86    }
87
88    let bob_role = store
89        .get("users")?
90        .get_index(1)?
91        .get_key("role")?
92        .get_value()?;
93    println!("users[1].role = {bob_role:?}");
94    assert_eq!(bob_role, &Value::Text("viewer".into()));
95
96    println!("store_collections: ok");
97    Ok(())
98}
examples/iter_map.rs (line 17)
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}

Auto Trait Implementations§

§

impl<'a, T> Freeze for MapHandle<'a, T>

§

impl<'a, T> RefUnwindSafe for MapHandle<'a, T>
where T: RefUnwindSafe,

§

impl<'a, T> Send for MapHandle<'a, T>
where T: Send,

§

impl<'a, T> Sync for MapHandle<'a, T>
where T: Sync,

§

impl<'a, T> Unpin for MapHandle<'a, T>

§

impl<'a, T> UnsafeUnpin for MapHandle<'a, T>

§

impl<'a, T = StoreEntry> !UnwindSafe for MapHandle<'a, T>

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> 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, 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.