use serde::{de::DeserializeOwned, Serialize};
use std::fmt::Debug;
pub trait GraphState: Clone + Send + Sync + Debug + 'static {}
impl<T> GraphState for T where T: Clone + Send + Sync + Debug + 'static {}
#[derive(Debug, Clone)]
pub struct GraphRunContext<State, Deps = ()> {
pub state: State,
pub deps: Deps,
pub step: u32,
pub run_id: String,
pub max_steps: u32,
}
impl<State, Deps> GraphRunContext<State, Deps> {
pub fn new(state: State, deps: Deps, run_id: impl Into<String>) -> Self {
Self {
state,
deps,
step: 0,
run_id: run_id.into(),
max_steps: 100,
}
}
pub fn with_max_steps(mut self, max: u32) -> Self {
self.max_steps = max;
self
}
pub fn increment_step(&mut self) {
self.step += 1;
}
pub fn is_max_steps_reached(&self) -> bool {
self.step >= self.max_steps
}
}
impl<State: Default, Deps: Default> Default for GraphRunContext<State, Deps> {
fn default() -> Self {
Self {
state: State::default(),
deps: Deps::default(),
step: 0,
run_id: generate_run_id(),
max_steps: 100,
}
}
}
#[derive(Debug, Clone)]
pub struct GraphRunResult<State, End = ()> {
pub result: End,
pub state: State,
pub steps: u32,
pub history: Vec<String>,
pub run_id: String,
}
impl<State, End> GraphRunResult<State, End> {
pub fn new(result: End, state: State, steps: u32, run_id: impl Into<String>) -> Self {
Self {
result,
state,
steps,
history: Vec::new(),
run_id: run_id.into(),
}
}
pub fn with_history(mut self, history: Vec<String>) -> Self {
self.history = history;
self
}
}
pub fn generate_run_id() -> String {
use std::time::SystemTime;
let timestamp = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos();
format!("run-{:x}", timestamp)
}
pub trait PersistableState: GraphState + Serialize + DeserializeOwned {}
impl<T> PersistableState for T where T: GraphState + Serialize + DeserializeOwned {}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, Default)]
struct TestState {
value: i32,
}
#[test]
fn test_graph_state_trait() {
let state = TestState { value: 42 };
let cloned = state.clone();
assert_eq!(cloned.value, 42);
}
#[test]
fn test_run_context() {
let mut ctx = GraphRunContext::new(TestState { value: 0 }, (), "test-run");
assert_eq!(ctx.step, 0);
ctx.increment_step();
assert_eq!(ctx.step, 1);
}
#[test]
fn test_max_steps() {
let ctx = GraphRunContext::new(TestState::default(), (), "test").with_max_steps(5);
assert_eq!(ctx.max_steps, 5);
}
#[test]
fn test_generate_run_id() {
let id1 = generate_run_id();
let id2 = generate_run_id();
assert!(id1.starts_with("run-"));
assert!(!id1.is_empty());
assert!(!id2.is_empty());
}
}