1use crate::{Bytes, Decoder, Encoder, Result, Sri};
2
3use alloc::string::String;
4use core::marker::PhantomData;
5use myrmic_common::cells::Command;
6
7pub trait Handler {
15 const NAME: &'static str;
17 type Arg;
19}
20
21pub struct Callback<T> {
28 command: Command,
29 _payload: PhantomData<T>,
30}
31
32impl<T> Callback<T> {
33 pub fn of<H: Handler<Arg = T>>() -> Self {
38 Self {
41 command: Command::new(H::NAME.into()).expect("handler name is validated by #[cmd]"),
42 _payload: PhantomData,
43 }
44 }
45
46 pub fn to(name: impl Into<String>) -> Result<Self> {
49 Ok(Self {
50 command: Command::new(name.into())?,
51 _payload: PhantomData,
52 })
53 }
54}
55
56impl<T: Encoder> Callback<T> {
57 pub fn invoke(self, sri: Sri, value: &T) -> Result<()> {
59 crate::send(sri, self, value)
60 }
61}
62
63impl<T> From<Callback<T>> for Command {
64 fn from(value: Callback<T>) -> Self {
65 value.command
66 }
67}
68
69impl<T> Encoder for Callback<T> {
70 fn to_bytes(&self) -> Result<Bytes> {
71 Ok(self.command.as_ref().as_bytes().to_vec())
72 }
73}
74
75impl<T> Decoder for Callback<T> {
76 fn from_bytes(bytes: Bytes) -> Result<Self> {
77 let name = core::str::from_utf8(&bytes).map_err(|_| "callback name is not valid utf-8")?;
78
79 Self::to(name)
80 }
81}
82
83impl<T> core::fmt::Debug for Callback<T> {
84 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
85 f.debug_tuple("Callback").field(&self.command).finish()
86 }
87}
88
89mod serde_json {
90 use crate::{Bytes, Decoder, Encoder, Result};
91 use alloc::string::String;
92 use serde_json::{Map, Number, Value};
93
94 macro_rules! json_codec {
95 ($ty:ty, $noun:literal) => {
96 impl Decoder for $ty {
97 fn from_bytes(bytes: Bytes) -> Result<Self> {
98 serde_json::from_slice(&bytes)
99 .map_err(|_| concat!("payload is not a valid json ", $noun))
100 }
101 }
102
103 impl Encoder for $ty {
104 fn to_bytes(&self) -> Result<Bytes> {
105 serde_json::to_vec(self)
106 .map_err(|_| concat!("unable to serialise json ", $noun))
107 }
108 }
109 };
110 }
111
112 json_codec!(Value, "value");
113 json_codec!(Number, "number");
114 json_codec!(Map<String, Value>, "object");
115}