hypen_engine/serialize/
remote.rs1use crate::reconcile::Patch;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6#[serde(tag = "type", rename_all = "camelCase")]
7pub enum RemoteMessage {
8 InitialTree(InitialTree),
10
11 Patch(PatchStream),
13
14 DispatchAction {
16 module: String,
17 action: String,
18 payload: Option<serde_json::Value>,
19 },
20
21 StateUpdate {
23 module: String,
24 state: serde_json::Value,
25 },
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct InitialTree {
31 pub module: String,
33
34 pub state: serde_json::Value,
36
37 pub patches: Vec<Patch>,
39
40 pub revision: u64,
42
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub hash: Option<String>,
46}
47
48impl InitialTree {
49 pub fn new(module: String, state: serde_json::Value, patches: Vec<Patch>) -> Self {
50 Self {
51 module,
52 state,
53 patches,
54 revision: 0,
55 hash: None,
56 }
57 }
58
59 pub fn with_hash(mut self, hash: String) -> Self {
60 self.hash = Some(hash);
61 self
62 }
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct PatchStream {
68 pub module: String,
70
71 pub patches: Vec<Patch>,
73
74 pub revision: u64,
76
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub hash: Option<String>,
80}
81
82impl PatchStream {
83 pub fn new(module: String, patches: Vec<Patch>, revision: u64) -> Self {
84 Self {
85 module,
86 patches,
87 revision,
88 hash: None,
89 }
90 }
91
92 pub fn with_hash(mut self, hash: String) -> Self {
93 self.hash = Some(hash);
94 self
95 }
96}
97
98pub fn serialize_message(message: &RemoteMessage) -> Result<String, serde_json::Error> {
100 serde_json::to_string(message)
101}
102
103pub fn deserialize_message(json: &str) -> Result<RemoteMessage, serde_json::Error> {
105 serde_json::from_str(json)
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test_serialize_initial_tree() {
114 let initial = InitialTree::new(
115 "TestModule".to_string(),
116 serde_json::json!({"count": 0}),
117 vec![],
118 );
119
120 let message = RemoteMessage::InitialTree(initial);
121 let json = serialize_message(&message).unwrap();
122
123 assert!(json.contains("initialTree"));
124 assert!(json.contains("TestModule"));
125 }
126
127 #[test]
128 fn test_roundtrip() {
129 let message = RemoteMessage::DispatchAction {
130 module: "Test".to_string(),
131 action: "increment".to_string(),
132 payload: Some(serde_json::json!({"amount": 1})),
133 };
134
135 let json = serialize_message(&message).unwrap();
136 let deserialized = deserialize_message(&json).unwrap();
137
138 match deserialized {
139 RemoteMessage::DispatchAction { module, action, .. } => {
140 assert_eq!(module, "Test");
141 assert_eq!(action, "increment");
142 }
143 _ => panic!("Wrong message type"),
144 }
145 }
146}