oris_kernel/kernel/
execution_step.rs1use serde::{Deserialize, Serialize};
9use serde_json::Value;
10
11use crate::kernel::state::KernelState;
12use crate::kernel::step::Next;
13use crate::kernel::KernelError;
14
15#[derive(Clone, Debug, Serialize, Deserialize)]
19pub enum ExecutionStepInput {
20 Initial,
22 Resume(Value),
24 Signal { name: String, value: Value },
26}
27
28impl ExecutionStepInput {
29 pub fn validate(&self) -> Result<(), KernelError> {
31 match self {
32 ExecutionStepInput::Initial => Ok(()),
33 ExecutionStepInput::Resume(_) => Ok(()),
34 ExecutionStepInput::Signal { name, .. } => {
35 if name.is_empty() {
36 return Err(KernelError::Driver(
37 "ExecutionStepInput::Signal name must be non-empty".into(),
38 ));
39 }
40 Ok(())
41 }
42 }
43 }
44}
45
46pub type StepResult = Next;
52
53pub trait ExecutionStep<S: KernelState>: Send + Sync {
62 fn execute(&self, state: &S, input: &ExecutionStepInput) -> Result<StepResult, KernelError>;
66}
67
68impl<S, F> ExecutionStep<S> for F
73where
74 S: KernelState,
75 F: crate::kernel::step::StepFn<S>,
76{
77 fn execute(&self, state: &S, _input: &ExecutionStepInput) -> Result<StepResult, KernelError> {
78 self.next(state)
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use crate::kernel::event::Event;
86 use crate::kernel::state::KernelState;
87 use crate::kernel::step::StepFn;
88
89 #[derive(Clone, Debug)]
90 struct TestState(u32);
91 impl KernelState for TestState {
92 fn version(&self) -> u32 {
93 1
94 }
95 }
96
97 #[test]
98 fn execution_step_input_initial_validates() {
99 let input = ExecutionStepInput::Initial;
100 assert!(input.validate().is_ok());
101 }
102
103 #[test]
104 fn execution_step_input_resume_validates() {
105 let input = ExecutionStepInput::Resume(serde_json::json!({"ok": true}));
106 assert!(input.validate().is_ok());
107 }
108
109 #[test]
110 fn execution_step_input_signal_empty_name_invalid() {
111 let input = ExecutionStepInput::Signal {
112 name: String::new(),
113 value: serde_json::json!(null),
114 };
115 assert!(input.validate().is_err());
116 }
117
118 #[test]
119 fn execution_step_input_signal_non_empty_name_validates() {
120 let input = ExecutionStepInput::Signal {
121 name: "evt".to_string(),
122 value: serde_json::json!(1),
123 };
124 assert!(input.validate().is_ok());
125 }
126
127 struct StepThatEmits;
128 impl StepFn<TestState> for StepThatEmits {
129 fn next(&self, state: &TestState) -> Result<Next, KernelError> {
130 Ok(Next::Emit(vec![Event::StateUpdated {
131 step_id: None,
132 payload: serde_json::json!({ "n": state.0 }),
133 }]))
134 }
135 }
136
137 #[test]
138 fn step_fn_impls_execution_step() {
139 let step = StepThatEmits;
140 let state = TestState(42);
141 let input = ExecutionStepInput::Initial;
142 let result = step.execute(&state, &input).unwrap();
143 match result {
144 Next::Emit(evs) => {
145 assert_eq!(evs.len(), 1);
146 }
147 _ => panic!("expected Emit"),
148 }
149 }
150}