1use serde::{de::DeserializeOwned, Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct Message {
32 id: String,
33 value: serde_json::Value,
34}
35
36pub trait MessageType: Serialize + DeserializeOwned {
39 fn id() -> &'static str;
41}
42
43#[derive(Debug, thiserror::Error)]
44pub enum MessageValueError {
45 #[error("invalid message type")]
46 InvalidType,
47 #[error("{0}")]
48 Serialization(SerializationError),
49}
50
51#[derive(Debug, thiserror::Error)]
52#[error("serialization error: {0}")]
53pub struct SerializationError(String);
54
55#[derive(Debug, thiserror::Error)]
56pub enum MessageHandleError {
57 #[error("{0}")]
58 Serialization(SerializationError),
59 #[error("handler error: {0}")]
60 Handler(Box<dyn std::error::Error>),
61}
62
63impl Message {
64 pub fn new<T: MessageType>(value: T) -> Self {
66 Self {
67 id: T::id().to_string(),
68 value: serde_json::to_value(value).unwrap(),
69 }
70 }
71
72 pub fn id(&self) -> &str {
74 &self.id
75 }
76
77 pub fn value<T: MessageType>(&self) -> Result<T, MessageValueError> {
79 if self.id != T::id() {
80 return Err(MessageValueError::InvalidType);
81 }
82
83 serde_json::from_value(self.value.clone())
84 .map_err(|e| MessageValueError::Serialization(SerializationError(e.to_string())))
85 }
86
87 pub fn has_type<T: MessageType>(&self) -> bool {
89 self.id == T::id()
90 }
91
92 pub fn handle<T: MessageType>(
97 &self,
98 f: impl FnOnce(T) -> Result<(), Box<dyn std::error::Error>>,
99 ) -> Result<bool, MessageHandleError> {
100 match self.value::<T>() {
101 Ok(v) => f(v).map_err(MessageHandleError::Handler).map(|_| true),
102 Err(MessageValueError::InvalidType) => Ok(false),
103 Err(MessageValueError::Serialization(e)) => Err(MessageHandleError::Serialization(e)),
104 }
105 }
106
107 #[cfg(feature = "ffi")]
109 pub fn send(&self, target: MessageTarget) {
110 let this = lotus_script_sys::FfiObject::new(self);
111 let target = lotus_script_sys::FfiObject::new(&target);
112
113 unsafe { lotus_script_sys::messages::send(target.packed(), this.packed()) }
114 }
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
119pub enum MessageTarget {
120 Myself,
122 ChildByIndex(usize),
124 Broadcast,
126 BroadcastExceptSelf,
128 Parent,
130}
131
132#[cfg(test)]
133mod tests {
134 use serde::Deserialize;
135
136 use super::*;
137
138 #[derive(Debug, Serialize, Deserialize, PartialEq)]
139 struct TestMessage {
140 value: i32,
141 }
142
143 impl MessageType for TestMessage {
144 fn id() -> &'static str {
145 "test_message"
146 }
147 }
148
149 #[test]
150 fn test_message() {
151 let message = Message::new(TestMessage { value: 42 });
152 assert_eq!(message.id(), "test_message");
153
154 let value = message.value::<TestMessage>().unwrap();
155
156 assert_eq!(value, TestMessage { value: 42 });
157
158 message
159 .handle::<TestMessage>(|m| {
160 assert_eq!(m.value, 42);
161 Ok(())
162 })
163 .expect("message handle failed");
164 }
165}