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    fn command_id_static() -> &'static str {
25        Self::COMMAND_ID
26    }
27}
28
29/// Result type for a command
30pub trait CommandResultType {
31    type Result: Serialize + DeserializeOwned + Clone + Send + Sync + 'static;
32}
33
34/// Type-erased command trait for dynamic dispatch.
35/// All commands implement this via the `#[myko_command]` macro.
36pub trait AnyCommand: WithTransaction + CommandId + Debug + Send + Sync + 'static {
37    /// Serialize this command to a JSON Value.
38    fn to_value(&self) -> Value;
39}
40
41// A command that can be sent; implementors provide a response type via the macro.
42pub trait MykoCommand<T: DeserializeOwned + Clone + Send + Sync + 'static> {
43    fn handle(
44        &self,
45        client: &MykoClient,
46    ) -> hyphae::Cell<Option<Result<T, String>>, hyphae::CellImmutable>;
47}
48
49// ─────────────────────────────────────────────────────────────────────────────
50// CommandParams - Marker trait for command parameter structs (inner type)
51// ─────────────────────────────────────────────────────────────────────────────
52
53/// Marker trait for command parameter structs.
54///
55/// This is implemented by the user-defined command struct (e.g., `CreateTarget`).
56/// It combines identity traits without requiring transaction metadata.
57///
58/// The full `Command` trait is implemented on `CommandRequest<C>` where `C: CommandParams`.
59pub trait CommandParams:
60    Serialize
61    + DeserializeOwned
62    + Clone
63    + Send
64    + Sync
65    + CommandId
66    + CommandIdStatic
67    + CommandResultType
68    + Debug
69    + 'static
70{
71}
72
73// Blanket impl for any type that satisfies the bounds
74impl<T> CommandParams for T where
75    T: Serialize
76        + DeserializeOwned
77        + Clone
78        + Send
79        + Sync
80        + CommandId
81        + CommandIdStatic
82        + CommandResultType
83        + Debug
84        + 'static
85{
86}
87
88// ─────────────────────────────────────────────────────────────────────────────
89// Conversions
90// ─────────────────────────────────────────────────────────────────────────────
91
92// Conversion from Arc<dyn AnyCommand> to WrappedCommand
93impl From<&dyn AnyCommand> for WrappedCommand {
94    fn from(command: &dyn AnyCommand) -> Self {
95        WrappedCommand {
96            command: command.to_value(),
97            command_id: command.command_id().to_string(),
98        }
99    }
100}
101
102impl From<Arc<dyn AnyCommand>> for WrappedCommand {
103    fn from(command: Arc<dyn AnyCommand>) -> Self {
104        WrappedCommand::from(command.as_ref())
105    }
106}
107
108impl From<&Arc<dyn AnyCommand>> for WrappedCommand {
109    fn from(command: &Arc<dyn AnyCommand>) -> Self {
110        WrappedCommand::from(command.as_ref())
111    }
112}