Skip to main content

myko/core/command/
traits.rs

1//! Command trait definitions.
2
3use std::{fmt::Debug, sync::Arc};
4
5use serde::{Serialize, de::DeserializeOwned};
6use serde_json::Value;
7
8use crate::{client::MykoClient, common::with_transaction::WithTransaction, wire::WrappedCommand};
9
10// ─────────────────────────────────────────────────────────────────────────────
11// Core Command Traits
12// ─────────────────────────────────────────────────────────────────────────────
13
14pub trait CommandId {
15    fn command_id(&self) -> Arc<str>;
16}
17
18/// Static command ID for registration
19pub trait CommandIdStatic {
20    /// The command ID as a const string (usable in static contexts)
21    const COMMAND_ID: &'static str;
22
23    /// Get the command ID (convenience method, defaults to `COMMAND_ID`)
24    #[must_use]
25    fn command_id_static() -> &'static str {
26        Self::COMMAND_ID
27    }
28}
29
30/// Result type for a command
31pub trait CommandResultType {
32    type Result: Serialize + DeserializeOwned + Clone + Send + Sync + 'static;
33}
34
35/// Type-erased command trait for dynamic dispatch.
36/// All commands implement this via the `#[myko_command]` macro.
37pub trait AnyCommand: WithTransaction + CommandId + Debug + Send + Sync + 'static {
38    /// Serialize this command to a JSON Value.
39    fn to_value(&self) -> Value;
40}
41
42// A command that can be sent; implementors provide a response type via the macro.
43pub trait MykoCommand<T: DeserializeOwned + Clone + Send + Sync + 'static> {
44    fn handle(
45        &self,
46        client: &MykoClient,
47    ) -> hyphae::Cell<Option<Result<T, String>>, hyphae::CellImmutable>;
48}
49
50// ─────────────────────────────────────────────────────────────────────────────
51// CommandParams - Marker trait for command parameter structs (inner type)
52// ─────────────────────────────────────────────────────────────────────────────
53
54/// Marker trait for command parameter structs.
55///
56/// This is implemented by the user-defined command struct (e.g., `CreateTarget`).
57/// It combines identity traits without requiring transaction metadata.
58///
59/// The full `Command` trait is implemented on `CommandRequest<C>` where `C: CommandParams`.
60pub trait CommandParams:
61    Serialize
62    + DeserializeOwned
63    + Clone
64    + Send
65    + Sync
66    + CommandId
67    + CommandIdStatic
68    + CommandResultType
69    + Debug
70    + 'static
71{
72}
73
74// Blanket impl for any type that satisfies the bounds
75impl<T> CommandParams for T where
76    T: Serialize
77        + DeserializeOwned
78        + Clone
79        + Send
80        + Sync
81        + CommandId
82        + CommandIdStatic
83        + CommandResultType
84        + Debug
85        + 'static
86{
87}
88
89// ─────────────────────────────────────────────────────────────────────────────
90// Conversions
91// ─────────────────────────────────────────────────────────────────────────────
92
93// Conversion from Arc<dyn AnyCommand> to WrappedCommand
94impl From<&dyn AnyCommand> for WrappedCommand {
95    fn from(command: &dyn AnyCommand) -> Self {
96        Self {
97            command: command.to_value(),
98            command_id: command.command_id().to_string(),
99        }
100    }
101}
102
103impl From<Arc<dyn AnyCommand>> for WrappedCommand {
104    fn from(command: Arc<dyn AnyCommand>) -> Self {
105        Self::from(command.as_ref())
106    }
107}
108
109impl From<&Arc<dyn AnyCommand>> for WrappedCommand {
110    fn from(command: &Arc<dyn AnyCommand>) -> Self {
111        Self::from(command.as_ref())
112    }
113}