Skip to main content

Store

Struct Store 

Source
pub struct Store<T = StoreEntry> { /* private fields */ }
Expand description

A keyed collection of entries shared across the pipeline lifecycle.

The store is the single source of truth for pipeline state. It holds draft-time variables, resolved step parameters, per-step global outputs, and the values produced by return blocks. The generic parameter T is the entry type — most stores hold StoreEntry values, but Store<Parameters> is used in draft/ready phases to hold the unresolved parameter bindings for each step.

Keys are flat dotted strings; nesting is modelled by the StoreEntry::Array and StoreEntry::Map variants, not by the store itself. Insertion is append-only through insert (errors on duplicate) or replacement-allowed through insert_or_replace.

Implementations§

Source§

impl<T> Store<T>

Source

pub fn new() -> Self

Constructs an empty store.

Examples found in repository?
examples/extend_store_scalars.rs (line 11)
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11    let mut store = Store::new();
12
13    // define_var accepts any V: Into<Value>.
14    // From impls exist for &str, String, bool, i64, f64, so you can pass
15    // these directly without calling .into().
16    store.define_var("name", "Alice")?;
17    store.define_var("age", 30i64)?;
18    store.define_var("active", true)?;
19    store.define_var("score", 9.5f64)?;
20    store.define_var("empty", Value::Null)?;
21
22    // Reading back: Store::get returns &StoreEntry.
23    // get_value() extracts the &Value from a Var entry.
24    let name = store.get("name")?.get_value()?;
25    println!("name = {name:?}");
26
27    // as_var() returns (&Value, &Type) — useful when you need to inspect both.
28    let (val, ty) = store.get("age")?.as_var()?;
29    println!("age = {val:?} (type: {ty:?})");
30
31    // Type is inferred from the value at define time.
32    assert_eq!(store.get("active")?.as_var()?.1, &Type::Boolean);
33    assert_eq!(store.get("score")?.as_var()?.1, &Type::Float);
34    assert_eq!(store.get("empty")?.as_var()?.1, &Type::Null);
35
36    // Duplicate names are rejected with StoreError::EntryAlreadyExists.
37    let err = store.define_var("name", "Bob");
38    println!("duplicate define_var: {err:?}");
39    assert!(err.is_err());
40
41    println!("store_scalars: ok");
42    Ok(())
43}
More examples
Hide additional examples
examples/extend_store_nested.rs (line 91)
90fn main() -> Result<(), Box<dyn std::error::Error>> {
91    let mut store = Store::new();
92
93    // An Operation would call these to populate its output Store.
94    write_query_results(&mut store)?;
95    write_grouped_data(&mut store)?;
96    write_nested_config(&mut store)?;
97
98    // --- Reading results back via chained accessors ---
99
100    // Query rows: array -> index -> key -> value
101    let bob_status = store
102        .get("rows")?
103        .get_index(1)?
104        .get_key("status")?
105        .get_value()?;
106    println!("rows[1].status = {bob_status:?}");
107    assert_eq!(bob_status, &Value::Text("Failure".into()));
108
109    let alice_attempts = store
110        .get("rows")?
111        .get_index(0)?
112        .get_key("attempts")?
113        .get_value()?;
114    println!("rows[0].attempts = {alice_attempts:?}");
115    assert_eq!(alice_attempts, &Value::Integer(1));
116
117    // Grouped data: map -> key -> index -> value
118    let high_count = store.get("by_severity")?.get_key("high")?.as_array()?.len();
119    println!("by_severity.high: {high_count} incidents");
120    assert_eq!(high_count, 2);
121
122    let first_low = store
123        .get("by_severity")?
124        .get_key("low")?
125        .get_index(0)?
126        .get_value()?;
127    println!("by_severity.low[0] = {first_low:?}");
128
129    // Nested config: map -> key -> key -> key -> value
130    let timeout = store
131        .get("pipeline_config")?
132        .get_key("source")?
133        .get_key("options")?
134        .get_key("timeout_secs")?
135        .get_value()?;
136    println!("pipeline_config.source.options.timeout_secs = {timeout:?}");
137    assert_eq!(timeout, &Value::Integer(30));
138
139    // Config outputs array: map -> key -> index -> key -> value
140    let second_format = store
141        .get("pipeline_config")?
142        .get_key("outputs")?
143        .get_index(1)?
144        .get_key("format")?
145        .get_value()?;
146    println!("pipeline_config.outputs[1].format = {second_format:?}");
147    assert_eq!(second_format, &Value::Text("csv".into()));
148
149    println!("store_nested: ok");
150    Ok(())
151}
examples/extend_store_collections.rs (line 10)
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 get<N: AsRef<str>>(&self, name: N) -> Result<&T, StoreError>

Looks up an entry by name. Returns StoreError::EntryNotFound if the name is not in the store.

Examples found in repository?
examples/extend_store_scalars.rs (line 24)
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11    let mut store = Store::new();
12
13    // define_var accepts any V: Into<Value>.
14    // From impls exist for &str, String, bool, i64, f64, so you can pass
15    // these directly without calling .into().
16    store.define_var("name", "Alice")?;
17    store.define_var("age", 30i64)?;
18    store.define_var("active", true)?;
19    store.define_var("score", 9.5f64)?;
20    store.define_var("empty", Value::Null)?;
21
22    // Reading back: Store::get returns &StoreEntry.
23    // get_value() extracts the &Value from a Var entry.
24    let name = store.get("name")?.get_value()?;
25    println!("name = {name:?}");
26
27    // as_var() returns (&Value, &Type) — useful when you need to inspect both.
28    let (val, ty) = store.get("age")?.as_var()?;
29    println!("age = {val:?} (type: {ty:?})");
30
31    // Type is inferred from the value at define time.
32    assert_eq!(store.get("active")?.as_var()?.1, &Type::Boolean);
33    assert_eq!(store.get("score")?.as_var()?.1, &Type::Float);
34    assert_eq!(store.get("empty")?.as_var()?.1, &Type::Null);
35
36    // Duplicate names are rejected with StoreError::EntryAlreadyExists.
37    let err = store.define_var("name", "Bob");
38    println!("duplicate define_var: {err:?}");
39    assert!(err.is_err());
40
41    println!("store_scalars: ok");
42    Ok(())
43}
More examples
Hide additional examples
examples/extend_store_nested.rs (line 102)
90fn main() -> Result<(), Box<dyn std::error::Error>> {
91    let mut store = Store::new();
92
93    // An Operation would call these to populate its output Store.
94    write_query_results(&mut store)?;
95    write_grouped_data(&mut store)?;
96    write_nested_config(&mut store)?;
97
98    // --- Reading results back via chained accessors ---
99
100    // Query rows: array -> index -> key -> value
101    let bob_status = store
102        .get("rows")?
103        .get_index(1)?
104        .get_key("status")?
105        .get_value()?;
106    println!("rows[1].status = {bob_status:?}");
107    assert_eq!(bob_status, &Value::Text("Failure".into()));
108
109    let alice_attempts = store
110        .get("rows")?
111        .get_index(0)?
112        .get_key("attempts")?
113        .get_value()?;
114    println!("rows[0].attempts = {alice_attempts:?}");
115    assert_eq!(alice_attempts, &Value::Integer(1));
116
117    // Grouped data: map -> key -> index -> value
118    let high_count = store.get("by_severity")?.get_key("high")?.as_array()?.len();
119    println!("by_severity.high: {high_count} incidents");
120    assert_eq!(high_count, 2);
121
122    let first_low = store
123        .get("by_severity")?
124        .get_key("low")?
125        .get_index(0)?
126        .get_value()?;
127    println!("by_severity.low[0] = {first_low:?}");
128
129    // Nested config: map -> key -> key -> key -> value
130    let timeout = store
131        .get("pipeline_config")?
132        .get_key("source")?
133        .get_key("options")?
134        .get_key("timeout_secs")?
135        .get_value()?;
136    println!("pipeline_config.source.options.timeout_secs = {timeout:?}");
137    assert_eq!(timeout, &Value::Integer(30));
138
139    // Config outputs array: map -> key -> index -> key -> value
140    let second_format = store
141        .get("pipeline_config")?
142        .get_key("outputs")?
143        .get_index(1)?
144        .get_key("format")?
145        .get_value()?;
146    println!("pipeline_config.outputs[1].format = {second_format:?}");
147    assert_eq!(second_format, &Value::Text("csv".into()));
148
149    println!("store_nested: ok");
150    Ok(())
151}
examples/extend_store_collections.rs (line 17)
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 insert<N: Into<String>>( &mut self, name: N, entry: T, ) -> Result<(), StoreError>

Inserts an entry under name. Returns StoreError::EntryAlreadyExists if the name is already in use.

Source

pub fn insert_or_replace<N: Into<String>>(&mut self, name: N, entry: T)

Inserts an entry under name, overwriting any existing entry with the same name. Used by the runtime when an operation rewrites its own outputs.

Source

pub fn merge( &mut self, prefix_opt: Option<&str>, other: Store<T>, ) -> Result<(), StoreError>

Merges other into this store, optionally prefixing each incoming key with "{prefix}.". Fails on the first key collision with StoreError::EntryAlreadyExists.

Source

pub fn keys(&self) -> impl Iterator<Item = &String>

Iterates over the names of every entry in the store.

Source

pub fn iter(&self) -> impl Iterator<Item = (&String, &T)>

Iterates over (name, entry) pairs.

Source§

impl Store<StoreEntry>

Source

pub fn define_var<N: Into<String>, V: Into<Value>>( &mut self, name: N, value: V, ) -> Result<(), StoreError>

Defines a new variable entry — a StoreEntry::Var wrapping the given Value and its derived Type. Fails with StoreError::EntryAlreadyExists if the name is already in use.

Examples found in repository?
examples/extend_store_scalars.rs (line 16)
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11    let mut store = Store::new();
12
13    // define_var accepts any V: Into<Value>.
14    // From impls exist for &str, String, bool, i64, f64, so you can pass
15    // these directly without calling .into().
16    store.define_var("name", "Alice")?;
17    store.define_var("age", 30i64)?;
18    store.define_var("active", true)?;
19    store.define_var("score", 9.5f64)?;
20    store.define_var("empty", Value::Null)?;
21
22    // Reading back: Store::get returns &StoreEntry.
23    // get_value() extracts the &Value from a Var entry.
24    let name = store.get("name")?.get_value()?;
25    println!("name = {name:?}");
26
27    // as_var() returns (&Value, &Type) — useful when you need to inspect both.
28    let (val, ty) = store.get("age")?.as_var()?;
29    println!("age = {val:?} (type: {ty:?})");
30
31    // Type is inferred from the value at define time.
32    assert_eq!(store.get("active")?.as_var()?.1, &Type::Boolean);
33    assert_eq!(store.get("score")?.as_var()?.1, &Type::Float);
34    assert_eq!(store.get("empty")?.as_var()?.1, &Type::Null);
35
36    // Duplicate names are rejected with StoreError::EntryAlreadyExists.
37    let err = store.define_var("name", "Bob");
38    println!("duplicate define_var: {err:?}");
39    assert!(err.is_err());
40
41    println!("store_scalars: ok");
42    Ok(())
43}
Source

pub fn define_array<N: Into<String>>( &mut self, name: N, ) -> Result<ArrayHandle<'_, StoreEntry>, StoreError>

Defines a new empty array entry and returns an ArrayHandle for populating it.

Examples found in repository?
examples/extend_store_collections.rs (line 15)
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 define_map<N: Into<String>>( &mut self, name: N, ) -> Result<MapHandle<'_, StoreEntry>, StoreError>

Defines a new empty map entry and returns a MapHandle for populating it.

Examples found in repository?
examples/extend_store_collections.rs (line 23)
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_array<N: Into<String>, F>( &mut self, name: N, body: F, ) -> Result<(), StoreError>
where F: FnOnce(&mut ArrayHandle<'_, StoreEntry>) -> Result<(), StoreError>,

Defines a new array entry and passes a handle to a closure for population. Convenience wrapper over define_array when the nested structure would otherwise force awkward temporaries.

Examples found in repository?
examples/extend_store_nested.rs (lines 11-27)
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}
More examples
Hide additional examples
examples/extend_store_collections.rs (lines 33-36)
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<N: Into<String>, F>( &mut self, name: N, body: F, ) -> Result<(), StoreError>
where F: FnOnce(&mut MapHandle<'_, StoreEntry>) -> Result<(), StoreError>,

Defines a new map entry and passes a handle to a closure for population.

Examples found in repository?
examples/extend_store_nested.rs (lines 33-50)
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 41-44)
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}

Trait Implementations§

Source§

impl<T: Clone> Clone for Store<T>

Source§

fn clone(&self) -> Store<T>

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<T: Debug> Debug for Store<T>

Source§

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

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

impl Default for Store<StoreEntry>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<T> IntoIterator for Store<T>

Source§

type Item = (String, T)

The type of the elements being iterated over.
Source§

type IntoIter = IntoIter<String, T>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more

Auto Trait Implementations§

§

impl<T> Freeze for Store<T>

§

impl<T> RefUnwindSafe for Store<T>
where T: RefUnwindSafe,

§

impl<T> Send for Store<T>
where T: Send,

§

impl<T> Sync for Store<T>
where T: Sync,

§

impl<T> Unpin for Store<T>
where T: Unpin,

§

impl<T> UnsafeUnpin for Store<T>

§

impl<T> UnwindSafe for Store<T>
where T: UnwindSafe,

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.