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