Skip to main content

Context

Struct Context 

Source
pub struct Context<T = Value>
where T: Serialize + for<'de> Deserialize<'de> + Debug,
{ /* 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 implement Serialize, Deserialize, and Debug.

§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>
where T: Serialize + for<'de> Deserialize<'de> + Debug,

Source

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());
Source

pub fn clone_data(&self) -> Self
where 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
Source

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 successful
  • Err(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(_))));
Source

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 update
  • value - The new value
§Returns
  • Ok(()) - If the update was successful
  • Err(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(_))));
Source

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 exists
  • None - 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);
Source

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 removed
  • None - 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);
Source

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);
}
Source

pub fn into_data(self) -> HashMap<String, T>

Consumes the context and returns the underlying data HashMap.

§Returns

The HashMap containing all context data

Source

pub fn from_data(data: HashMap<String, T>) -> Self

Creates a Context from a HashMap.

§Arguments
  • data - The HashMap to use as context data
§Returns

A new Context with the provided data

Source

pub fn to_json(&self) -> Result<String, ContextError>

Serializes the context to a JSON string.

§Returns
  • Ok(String) - The JSON representation of the context
  • Err(ContextError) - If serialization fails
Source

pub fn from_json(json: String) -> Result<Self, ContextError>

Deserializes a context from a JSON string.

§Arguments
  • json - The JSON string to deserialize
§Returns
  • Ok(Context<T>) - The deserialized context
  • Err(ContextError) - If deserialization fails
Source

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.

Source

pub fn set_secret_resolver(&mut self, resolver: Arc<dyn SecretResolver>)

Attach (or replace) the secret resolver on this scope.

Source

pub fn has_secret_resolver(&self) -> bool

Whether a secret resolver is configured on this execution scope.

Source

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

Source

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

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

Source

pub fn get_as<V>(&self, key: &str) -> Result<Option<V>, TaskError>

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);
Source

pub fn get_required<V>(&self, key: &str) -> Result<V, TaskError>

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());
Source

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));

Trait Implementations§

Source§

impl<T> Debug for Context<T>
where T: Serialize + for<'de> Deserialize<'de> + Debug,

Source§

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

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

impl<T> Default for Context<T>
where T: Serialize + for<'de> Deserialize<'de> + Debug,

Source§

fn default() -> Self

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

Auto Trait Implementations§

§

impl<T = Value> !RefUnwindSafe for Context<T>

§

impl<T = Value> !UnwindSafe for Context<T>

§

impl<T> Freeze for Context<T>
where HashMap<String, T>: Freeze,

§

impl<T> Send for Context<T>
where HashMap<String, T>: Send,

§

impl<T> Sync for Context<T>
where HashMap<String, T>: Sync,

§

impl<T> Unpin for Context<T>
where HashMap<String, T>: Unpin,

§

impl<T> UnsafeUnpin for Context<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> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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 = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more