pub struct Context<T = Value>{ /* private fields */ }Expand description
A context that holds data for pipeline execution.
The context is a type-safe, serializable container that flows through your pipeline, allowing tasks to share data. It supports JSON serialization and provides key-value access patterns with comprehensive error handling.
§Type Parameter
T: The type of values stored in the context. Must implementSerialize,Deserialize, andDebug.
§Examples
use cloacina_workflow::Context;
use serde_json::Value;
// Create a context for JSON values
let mut context = Context::<Value>::new();
// Insert and retrieve data
context.insert("user_id", serde_json::json!(123)).unwrap();
let user_id = context.get("user_id").unwrap();Implementations§
Source§impl<T> Context<T>
impl<T> Context<T>
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new empty context.
§Examples
use cloacina_workflow::Context;
let context = Context::<i32>::new();
assert!(context.get("any_key").is_none());Sourcepub fn clone_data(&self) -> Selfwhere
T: Clone,
pub fn clone_data(&self) -> Selfwhere
T: Clone,
Creates a clone of this context’s data.
§Performance
- Time complexity: O(n) where n is the number of key-value pairs
- Space complexity: O(n) for the cloned data
Sourcepub fn insert(
&mut self,
key: impl Into<String>,
value: T,
) -> Result<(), ContextError>
pub fn insert( &mut self, key: impl Into<String>, value: T, ) -> Result<(), ContextError>
Inserts a value into the context.
§Arguments
key- The key to insert (can be any type that converts to String)value- The value to store
§Returns
Ok(())- If the insertion was successfulErr(ContextError::KeyExists)- If the key already exists
§Examples
use cloacina_workflow::{Context, ContextError};
let mut context = Context::<i32>::new();
// First insertion succeeds
assert!(context.insert("count", 42).is_ok());
// Duplicate insertion fails
assert!(matches!(context.insert("count", 43), Err(ContextError::KeyExists(_))));Sourcepub fn update(
&mut self,
key: impl Into<String>,
value: T,
) -> Result<(), ContextError>
pub fn update( &mut self, key: impl Into<String>, value: T, ) -> Result<(), ContextError>
Updates an existing value in the context.
§Arguments
key- The key to updatevalue- The new value
§Returns
Ok(())- If the update was successfulErr(ContextError::KeyNotFound)- If the key doesn’t exist
§Examples
use cloacina_workflow::{Context, ContextError};
let mut context = Context::<i32>::new();
context.insert("count", 42).unwrap();
// Update existing key
assert!(context.update("count", 100).is_ok());
assert_eq!(context.get("count"), Some(&100));
// Update non-existent key fails
assert!(matches!(context.update("missing", 1), Err(ContextError::KeyNotFound(_))));Sourcepub fn get(&self, key: &str) -> Option<&T>
pub fn get(&self, key: &str) -> Option<&T>
Gets a reference to a value from the context.
§Arguments
key- The key to look up
§Returns
Some(&T)- If the key existsNone- If the key doesn’t exist
§Examples
use cloacina_workflow::Context;
let mut context = Context::<String>::new();
context.insert("message", "Hello".to_string()).unwrap();
assert_eq!(context.get("message"), Some(&"Hello".to_string()));
assert_eq!(context.get("missing"), None);Sourcepub fn remove(&mut self, key: &str) -> Option<T>
pub fn remove(&mut self, key: &str) -> Option<T>
Removes and returns a value from the context.
§Arguments
key- The key to remove
§Returns
Some(T)- If the key existed and was removedNone- If the key didn’t exist
§Examples
use cloacina_workflow::Context;
let mut context = Context::<i32>::new();
context.insert("temp", 42).unwrap();
assert_eq!(context.remove("temp"), Some(42));
assert_eq!(context.get("temp"), None);
assert_eq!(context.remove("missing"), None);Sourcepub fn data(&self) -> &HashMap<String, T>
pub fn data(&self) -> &HashMap<String, T>
Gets a reference to the underlying data HashMap.
This method provides direct access to the internal data structure for advanced use cases that need to iterate over all key-value pairs.
§Returns
A reference to the HashMap containing all context data
§Examples
use cloacina_workflow::Context;
let mut context = Context::<i32>::new();
context.insert("a", 1).unwrap();
context.insert("b", 2).unwrap();
for (key, value) in context.data() {
println!("{}: {}", key, value);
}Sourcepub fn into_data(self) -> HashMap<String, T>
pub fn into_data(self) -> HashMap<String, T>
Consumes the context and returns the underlying data HashMap.
§Returns
The HashMap containing all context data
Sourcepub fn to_json(&self) -> Result<String, ContextError>
pub fn to_json(&self) -> Result<String, ContextError>
Serializes the context to a JSON string.
§Returns
Ok(String)- The JSON representation of the contextErr(ContextError)- If serialization fails
Sourcepub fn from_json(json: String) -> Result<Self, ContextError>
pub fn from_json(json: String) -> Result<Self, ContextError>
Sourcepub fn with_secret_resolver(self, resolver: Arc<dyn SecretResolver>) -> Self
pub fn with_secret_resolver(self, resolver: Arc<dyn SecretResolver>) -> Self
Attach a secret resolver, builder-style.
The resolver is a runtime-only side channel: it is NEVER serialized (see
Context::to_json, which writes only data), which is what keeps a
resolved secret structurally out of the durable context.
Sourcepub fn set_secret_resolver(&mut self, resolver: Arc<dyn SecretResolver>)
pub fn set_secret_resolver(&mut self, resolver: Arc<dyn SecretResolver>)
Attach (or replace) the secret resolver on this scope.
Sourcepub fn has_secret_resolver(&self) -> bool
pub fn has_secret_resolver(&self) -> bool
Whether a secret resolver is configured on this execution scope.
Sourcepub async fn secret(
&self,
name: &str,
) -> Result<BTreeMap<String, String>, SecretAccessError>
pub async fn secret( &self, name: &str, ) -> Result<BTreeMap<String, String>, SecretAccessError>
Resolve a named secret into its decrypted {field: value} map.
name may be either the concrete secret name OR a declared local
binding name that an instance mapped to a secret via a
{"$secret": "..."} reference (CLOACI-I-0133 / T-0859). When the
context carries a {"$secret"} alias map (under
secret::SECRET_REFS_KEY) and name
appears as a local binding there, the mapped secret name is resolved
instead — so a task can read either the declared name it authored against
or the concrete secret the instance chose.
The returned map is handed to the task and is NEVER inserted into the
context’s serialized data. Errors clearly when no resolver is
configured (SecretAccessError::NotConfigured) or the name is absent
(SecretAccessError::NotFound).
Sourcepub async fn secret_field(
&self,
name: &str,
field: &str,
) -> Result<String, SecretAccessError>
pub async fn secret_field( &self, name: &str, field: &str, ) -> Result<String, SecretAccessError>
Resolve one field of a named secret.
Convenience over Context::secret; errors with
SecretAccessError::FieldNotFound when the secret exists but lacks the
requested field.
Source§impl Context<Value>
Typed accessors for the task context (Context<serde_json::Value>).
impl Context<Value>
Typed accessors for the task context (Context<serde_json::Value>).
Task bodies operate on a Context<serde_json::Value>, so reading an input
otherwise means get(...).and_then(|v| v.as_*()).ok_or_else(...)? plus a
serde_json::from_value round-trip, and writing means wrapping every value
in serde_json::json!(...). These helpers fold that boilerplate and return
a [TaskError] so they compose with ? in a task body (CLOACI-T-0733).
This mirrors the ergonomics Python authors already get from
context.get(key, default) / context.set(key, value).
Sourcepub fn get_as<V>(&self, key: &str) -> Result<Option<V>, TaskError>where
V: DeserializeOwned,
pub fn get_as<V>(&self, key: &str) -> Result<Option<V>, TaskError>where
V: DeserializeOwned,
Get a value by key and deserialize it into V.
Returns Ok(None) when the key is absent, Ok(Some(value)) when it is
present and deserializes cleanly, and Err(TaskError::ValidationFailed)
when the stored JSON does not match V (the message names the key and
target type).
§Examples
use cloacina_workflow::Context;
let mut ctx = Context::new();
ctx.insert("count", serde_json::json!(7)).unwrap();
let n: Option<i64> = ctx.get_as("count").unwrap();
assert_eq!(n, Some(7));
assert_eq!(ctx.get_as::<i64>("missing").unwrap(), None);Sourcepub fn get_required<V>(&self, key: &str) -> Result<V, TaskError>where
V: DeserializeOwned,
pub fn get_required<V>(&self, key: &str) -> Result<V, TaskError>where
V: DeserializeOwned,
Get a value by key, deserialize it into V, and error if the key is
missing.
Err(TaskError::ValidationFailed) when the key is absent or the stored
JSON does not match V.
§Examples
use cloacina_workflow::Context;
let mut ctx = Context::new();
ctx.insert("name", serde_json::json!("ada")).unwrap();
let name: String = ctx.get_required("name").unwrap();
assert_eq!(name, "ada");
assert!(ctx.get_required::<String>("missing").is_err());Sourcepub fn insert_as<V>(
&mut self,
key: impl Into<String>,
value: V,
) -> Result<(), TaskError>where
V: Serialize,
pub fn insert_as<V>(
&mut self,
key: impl Into<String>,
value: V,
) -> Result<(), TaskError>where
V: Serialize,
Serialize a value and write it under key, upserting (insert or
overwrite).
Folds the serde_json::json!(...) / to_value wrapping — and the
“exists? update : insert” dance — that every context write otherwise
repeats. Upsert semantics mirror Python’s context.set(key, value)
(unlike the lower-level Context::insert, which errors on an existing
key). Errors with TaskError::ValidationFailed only if the value cannot
be serialized.
§Examples
use cloacina_workflow::Context;
let mut ctx = Context::new();
ctx.insert_as("total", 42u32).unwrap();
assert_eq!(ctx.get_as::<u32>("total").unwrap(), Some(42));
// Upserts — overwriting an existing key is fine.
ctx.insert_as("total", 100u32).unwrap();
assert_eq!(ctx.get_as::<u32>("total").unwrap(), Some(100));