1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// =============================================================================
// #######
// ### ### F: handler.rs
// ## ## ## ## P: AppCore-Runtime
// ## ##
// C: 2026/05/29 20:47:35 by dnettoRaw
// ## ## ## ## U: 2026/06/04 11:51:29 by dnettoRaw
// ########### S: 0.6.0
// =============================================================================
//! Command handler contracts without execution engine concerns.
use crate::context::RuntimeContext;
use crate::envelope::{CommandEnvelope, EventEnvelope};
use crate::error::RuntimeResult;
use crate::ids::CommandName;
/// Structured command handling result.
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct CommandResult {
accepted: bool,
events: Vec<EventEnvelope>,
message: Option<String>,
}
impl CommandResult {
/// Creates an accepted result with emitted fact events.
pub fn accepted(events: Vec<EventEnvelope>) -> Self {
Self {
accepted: true,
events,
message: None,
}
}
/// Creates a controlled rejection without emitted events.
pub fn rejected(message: impl Into<String>) -> Self {
Self {
accepted: false,
events: Vec::new(),
message: Some(message.into()),
}
}
/// Reports whether the command was accepted.
pub fn is_accepted(&self) -> bool {
self.accepted
}
/// Returns events emitted by an accepted command.
pub fn events(&self) -> &[EventEnvelope] {
&self.events
}
/// Returns the controlled rejection message, when present.
pub fn message(&self) -> Option<&str> {
self.message.as_deref()
}
}
/// Command handler contract.
pub trait CommandHandler: Send + Sync {
/// Returns the command name handled by this implementation.
fn command_name(&self) -> CommandName;
/// Handles one validated command in a read-only Runtime context.
fn handle(
&self,
command: &CommandEnvelope,
context: &dyn RuntimeContext,
) -> RuntimeResult<CommandResult>;
}
#[cfg(test)]
#[path = "handler_tests.rs"]
mod tests;