1use num::{BigInt, FromPrimitive};
2use serde::{de, Deserialize, Deserializer, Serialize};
3use serde_json::Number;
4
5use crate::displayed_item;
6
7#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
13#[serde(transparent)]
14pub struct DisplayedItemRef(pub usize);
15
16impl From<&displayed_item::DisplayedItemRef> for crate::DisplayedItemRef {
17 fn from(value: &displayed_item::DisplayedItemRef) -> Self {
18 crate::DisplayedItemRef(value.0)
19 }
20}
21
22impl From<&DisplayedItemRef> for crate::DisplayedItemRef {
23 fn from(value: &DisplayedItemRef) -> Self {
24 crate::DisplayedItemRef(value.0)
25 }
26}
27impl From<DisplayedItemRef> for crate::DisplayedItemRef {
28 fn from(value: DisplayedItemRef) -> Self {
29 crate::DisplayedItemRef(value.0)
30 }
31}
32impl From<&crate::DisplayedItemRef> for DisplayedItemRef {
33 fn from(value: &crate::DisplayedItemRef) -> Self {
34 DisplayedItemRef(value.0)
35 }
36}
37impl From<crate::DisplayedItemRef> for DisplayedItemRef {
38 fn from(value: crate::DisplayedItemRef) -> Self {
39 DisplayedItemRef(value.0)
40 }
41}
42
43#[derive(Serialize, Deserialize, Debug, PartialEq)]
44pub struct ItemInfo {
45 pub name: String,
46 #[serde(rename = "type")]
47 pub t: String,
48 pub id: DisplayedItemRef,
49}
50
51#[derive(Serialize, Deserialize, Debug, PartialEq)]
52#[serde(tag = "command")]
53#[allow(non_camel_case_types)]
54pub enum WcpResponse {
55 get_item_list { ids: Vec<DisplayedItemRef> },
56 get_item_info { results: Vec<ItemInfo> },
57 add_variables { ids: Vec<DisplayedItemRef> },
58 add_scope { ids: Vec<DisplayedItemRef> },
59 ack,
60}
61
62#[derive(Serialize, Deserialize, Debug, PartialEq)]
63#[serde(tag = "event")]
64#[allow(non_camel_case_types)]
65pub enum WcpEvent {
66 waveforms_loaded { source: String },
67 goto_declaration { variable: String },
68 add_drivers { variable: String },
69 add_loads { variable: String },
70}
71
72#[derive(Serialize, Deserialize, Debug, PartialEq)]
73#[serde(tag = "type")]
74#[allow(non_camel_case_types)]
75pub enum WcpSCMessage {
76 greeting {
77 version: String,
78 commands: Vec<String>,
79 },
80 response(WcpResponse),
81 error {
82 error: String,
83 arguments: Vec<String>,
84 message: String,
85 },
86 event(WcpEvent),
87}
88
89impl WcpSCMessage {
90 pub fn create_greeting(version: usize, commands: Vec<String>) -> Self {
91 Self::greeting {
92 version: version.to_string(),
93 commands,
94 }
95 }
96
97 pub fn create_error(error: String, arguments: Vec<String>, message: String) -> Self {
98 Self::error {
99 error,
100 arguments,
101 message,
102 }
103 }
104}
105
106#[derive(Serialize, Deserialize, Debug, PartialEq)]
107#[serde(tag = "command")]
108#[allow(non_camel_case_types)]
109pub enum WcpCommand {
110 get_item_list,
113 get_item_info { ids: Vec<DisplayedItemRef> },
118 set_item_color { id: DisplayedItemRef, color: String },
122 add_variables { variables: Vec<String> },
127 add_scope {
133 scope: String,
134 #[serde(default)]
135 recursive: bool,
136 },
137 reload,
142 set_viewport_to {
146 #[serde(deserialize_with = "deserialize_timestamp")]
147 timestamp: BigInt,
148 },
149 remove_items { ids: Vec<DisplayedItemRef> },
153 focus_item { id: DisplayedItemRef },
160 clear,
163 load { source: String },
167 zoom_to_fit { viewport_idx: usize },
170 shutdowmn,
173}
174
175#[derive(Serialize, Deserialize, Debug, PartialEq)]
176#[serde(tag = "type")]
177#[allow(non_camel_case_types)]
178pub enum WcpCSMessage {
179 #[serde(rename = "greeting")]
180 greeting {
181 version: String,
182 commands: Vec<String>,
183 },
184 command(WcpCommand),
185}
186
187impl WcpCSMessage {
188 pub fn create_greeting(version: usize, commands: Vec<String>) -> Self {
189 Self::greeting {
190 version: version.to_string(),
191 commands,
192 }
193 }
194}
195
196fn deserialize_timestamp<'de, D>(deserializer: D) -> Result<BigInt, D::Error>
197where
198 D: Deserializer<'de>,
199{
200 let num = Number::deserialize(deserializer)?;
201 if let Some(timestamp) = num.as_u128() {
202 Ok(BigInt::from(timestamp))
203 } else if let Some(timestamp) = num.as_i128() {
204 Ok(BigInt::from(timestamp))
205 } else if let Some(timestamp) = num.as_f64() {
206 BigInt::from_f64(timestamp).ok_or_else(|| {
207 <D::Error as serde::de::Error>::invalid_value(
208 serde::de::Unexpected::Float(timestamp),
209 &"a finite value",
210 )
211 })
212 } else {
213 Err(de::Error::custom(
214 "Error durian deserialization of timestamp value {num}",
215 ))
216 }
217}