Skip to main content

myrmic_sdk/host_functions/cell/
commands.rs

1use core::ffi::c_int;
2
3use myrmic_common::cells::{
4    CommandRequest, ERR_CELL_CMD_CELL_ERROR, ERR_CELL_CMD_CELL_NOT_PRESENT,
5    ERR_CELL_CMD_COMMAND_NOT_PRESENT, ERR_CELL_CMD_INTERNAL, ERR_CELL_CMD_SMALL_BUFFER,
6    ERR_CELL_CMD_TIMEOUT,
7};
8
9mod c_functions {
10    use core::ffi::c_int;
11
12    #[link(wasm_import_module = "cell")]
13    unsafe extern "C" {
14
15        /// Sending a command. The function is used to send a command to a cell, both specified via the payload
16        /// which can be deserialized into a `CommandRequest`.
17        ///
18        /// # Arguments:
19        /// - buffer: pointer to the memory where the module has the command request
20        /// - length: length of the serialized command request
21        ///
22        /// # Returns:
23        /// - [`crate::SUCCESS`] on success
24        /// - [`crate::GENERIC_ERROR`] on failure
25        pub(super) fn send_command(buffer: *const u8, length: c_int) -> c_int;
26    }
27}
28
29pub fn send_command(req: &CommandRequest) -> Result<(), CommandError> {
30    crate::host_functions::call(req, c_functions::send_command).map_err(Into::into)
31}
32
33/// Why sending a command to a cell failed.
34#[derive(Copy, Clone)]
35pub enum CommandError {
36    /// No response received within the timeout
37    Timeout,
38    /// The indicated cell is not present in the system (TODO we need some kind of cell registry for this)
39    CellNotPresent,
40    /// The cell exists, but either does not have the specified command or the provided arguments are invalid (e.g., arguments were provided to a cell not expecting input or vice versa)
41    ApiError,
42    /// The receiving cell crashed/errored out while processing the query
43    CellError,
44    /// Internal errors within the framework
45    Internal,
46    /// The provided buffer was too small for the response
47    SmallBuffer,
48    /// Catchall for other error codes (should not be used)
49    Other(i32),
50}
51
52impl CommandError {
53    /// A short human-readable description of the error (also its
54    /// [`Display`](core::fmt::Display) output).
55    pub fn describe(&self) -> &'static str {
56        match self {
57            CommandError::Timeout => "Command timed out",
58            CommandError::CellNotPresent => "Target cell not present",
59            CommandError::ApiError => "Command not present",
60            CommandError::CellError => "Cell error",
61            CommandError::Internal => "Internal error",
62            CommandError::SmallBuffer => "Buffer too small",
63            CommandError::Other(_) => "Other(_)",
64        }
65    }
66}
67
68impl From<c_int> for CommandError {
69    fn from(value: c_int) -> Self {
70        match value {
71            ERR_CELL_CMD_TIMEOUT => Self::Timeout,
72            ERR_CELL_CMD_CELL_NOT_PRESENT => Self::CellNotPresent,
73            ERR_CELL_CMD_COMMAND_NOT_PRESENT => Self::ApiError,
74            ERR_CELL_CMD_CELL_ERROR => Self::CellError,
75            ERR_CELL_CMD_INTERNAL => Self::Internal,
76            ERR_CELL_CMD_SMALL_BUFFER => Self::SmallBuffer,
77            n => Self::Other(n),
78        }
79    }
80}
81
82impl core::fmt::Display for CommandError {
83    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
84        f.write_str(self.describe())
85    }
86}