use crate::{Bytes, Decoder, Encoder, Result, Sri};
use alloc::string::String;
use core::marker::PhantomData;
use myrmic_common::cells::Command;
pub trait Handler {
const NAME: &'static str;
type Arg;
}
pub struct Callback<T> {
command: Command,
_payload: PhantomData<T>,
}
impl<T> Callback<T> {
pub fn of<H: Handler<Arg = T>>() -> Self {
Self {
command: Command::new(H::NAME.into()).expect("handler name is validated by #[cmd]"),
_payload: PhantomData,
}
}
pub fn to(name: impl Into<String>) -> Result<Self> {
Ok(Self {
command: Command::new(name.into())?,
_payload: PhantomData,
})
}
}
impl<T: Encoder> Callback<T> {
pub fn invoke(self, sri: Sri, value: &T) -> Result<()> {
crate::send(sri, self, value)
}
}
impl<T> From<Callback<T>> for Command {
fn from(value: Callback<T>) -> Self {
value.command
}
}
impl<T> Encoder for Callback<T> {
fn to_bytes(&self) -> Result<Bytes> {
Ok(self.command.as_ref().as_bytes().to_vec())
}
}
impl<T> Decoder for Callback<T> {
fn from_bytes(bytes: Bytes) -> Result<Self> {
let name = core::str::from_utf8(&bytes).map_err(|_| "callback name is not valid utf-8")?;
Self::to(name)
}
}
impl<T> core::fmt::Debug for Callback<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Callback").field(&self.command).finish()
}
}
mod serde_json {
use crate::{Bytes, Decoder, Encoder, Result};
use alloc::string::String;
use serde_json::{Map, Number, Value};
macro_rules! json_codec {
($ty:ty, $noun:literal) => {
impl Decoder for $ty {
fn from_bytes(bytes: Bytes) -> Result<Self> {
serde_json::from_slice(&bytes)
.map_err(|_| concat!("payload is not a valid json ", $noun))
}
}
impl Encoder for $ty {
fn to_bytes(&self) -> Result<Bytes> {
serde_json::to_vec(self)
.map_err(|_| concat!("unable to serialise json ", $noun))
}
}
};
}
json_codec!(Value, "value");
json_codec!(Number, "number");
json_codec!(Map<String, Value>, "object");
}