use cano::prelude::*;
use std::sync::{Arc, Mutex};
#[derive(Debug, Hash, Eq, PartialEq)]
enum Key {
Store,
Counter,
Params,
}
struct CounterResource {
setup_count: Arc<Mutex<u32>>,
}
impl CounterResource {
fn new() -> Self {
Self {
setup_count: Arc::new(Mutex::new(0)),
}
}
fn get_setup_count(&self) -> u32 {
*self.setup_count.lock().unwrap()
}
}
#[resource]
impl Resource for CounterResource {
async fn setup(&self) -> Result<(), CanoError> {
*self.setup_count.lock().unwrap() += 1;
println!("CounterResource: setup called");
Ok(())
}
async fn teardown(&self) -> Result<(), CanoError> {
println!("CounterResource: teardown called");
Ok(())
}
}
struct WorkflowParams {
multiplier: u32,
}
impl Resource for WorkflowParams {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum Step {
Init,
Process,
Done,
}
struct InitTask;
#[task(state = Step, key = Key)]
impl InitTask {
async fn run(&self, res: &Resources<Key>) -> Result<TaskResult<Step>, CanoError> {
let store = res.get::<MemoryStore, Key>(&Key::Store)?;
let params = res.get::<WorkflowParams, Key>(&Key::Params)?;
let value = 10u32 * params.multiplier;
store.put("value", value)?;
println!("InitTask: stored value = {value}");
Ok(TaskResult::Single(Step::Process))
}
}
struct ProcessTask;
#[task(state = Step, key = Key)]
impl ProcessTask {
async fn run(&self, res: &Resources<Key>) -> Result<TaskResult<Step>, CanoError> {
let store = res.get::<MemoryStore, Key>(&Key::Store)?;
let counter = res.get::<CounterResource, Key>(&Key::Counter)?;
let value: u32 = store.get("value")?;
let result = value + counter.get_setup_count();
store.put("result", result)?;
println!("ProcessTask: result = {result}");
Ok(TaskResult::Single(Step::Done))
}
}
#[tokio::main]
async fn main() -> Result<(), CanoError> {
println!("Workflow Resources Example");
println!("==========================");
println!();
let store = MemoryStore::new();
let counter = CounterResource::new();
let counter_clone = CounterResource {
setup_count: Arc::clone(&counter.setup_count),
};
let resources = Resources::<Key>::new()
.insert(Key::Store, store.clone())
.insert(Key::Counter, counter)
.insert(Key::Params, WorkflowParams { multiplier: 3 });
let workflow = Workflow::new(resources)
.register(Step::Init, InitTask)
.register(Step::Process, ProcessTask)
.add_exit_state(Step::Done);
println!("Running workflow...");
let final_state = workflow.orchestrate(Step::Init).await?;
assert_eq!(final_state, Step::Done);
let result: u32 = store.get("result")?;
println!("Result: {result}");
assert_eq!(counter_clone.get_setup_count(), 1);
println!(
"CounterResource setup was called {} time(s)",
counter_clone.get_setup_count()
);
println!();
println!("Key concepts demonstrated:");
println!(" - Enum keys for compile-time resource safety");
println!(" - Custom Resource with setup/teardown lifecycle");
println!(" - Plain struct resource (WorkflowParams) with no-op lifecycle");
println!(" - Arc-based sharing for post-workflow inspection");
Ok(())
}