1use super::{Address, GeoLocation, JobMode, OpMode, Operator, TextID, TextName, ID, R32};
2use chrono::{DateTime, FixedOffset};
3use indexmap::IndexMap;
4use serde::{Deserialize, Serialize};
5use std::borrow::Cow;
6use std::convert::TryInto;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct Controller<'a> {
13 pub controller_id: ID,
15 pub display_name: TextName<'a>,
18 pub controller_type: TextID<'a>,
28 pub version: TextID<'a>,
31 pub model: TextID<'a>,
34 #[serde(rename = "IP")]
41 pub address: Address<'a>,
42 #[serde(skip_serializing_if = "Option::is_none")]
45 #[serde(flatten)]
46 pub geo_location: Option<GeoLocation>,
47 pub op_mode: OpMode,
50 pub job_mode: JobMode,
53 #[serde(skip_serializing_if = "IndexMap::is_empty")]
56 #[serde(default)]
57 pub last_cycle_data: IndexMap<TextID<'a>, R32>,
58 #[serde(skip_serializing_if = "IndexMap::is_empty")]
61 #[serde(default)]
62 pub variables: IndexMap<TextID<'a>, R32>,
63 #[serde(skip_serializing_if = "Option::is_none")]
66 pub last_connection_time: Option<DateTime<FixedOffset>>,
67 #[serde(flatten)]
70 #[serde(skip_serializing_if = "Option::is_none")]
71 pub operator: Option<Operator<'a>>,
72 #[serde(skip_serializing_if = "Option::is_none")]
75 #[serde(borrow)]
76 pub job_card_id: Option<Box<Cow<'a, str>>>,
77 #[serde(skip_serializing_if = "Option::is_none")]
80 #[serde(borrow)]
81 pub mold_id: Option<Box<Cow<'a, str>>>,
82}
83
84impl Default for Controller<'_> {
85 fn default() -> Self {
91 Controller {
92 controller_id: ID::from_u32(1),
93 display_name: "Unknown".try_into().unwrap(),
94 controller_type: "Unknown".try_into().unwrap(),
95 version: "Unknown".try_into().unwrap(),
96 model: "Unknown".try_into().unwrap(),
97 address: Address::Unknown,
98 geo_location: None,
99 op_mode: OpMode::Unknown,
100 job_mode: JobMode::Unknown,
101 job_card_id: None,
102 last_cycle_data: Default::default(),
103 variables: Default::default(),
104 last_connection_time: None,
105 operator: None,
106 mold_id: None,
107 }
108 }
109}
110
111#[cfg(test)]
114mod test {
115 use super::*;
116 use std::result::Result;
117
118 #[test]
119 fn test_controller_to_json() -> Result<(), String> {
120 let c = Controller {
121 op_mode: OpMode::Automatic,
122 job_mode: JobMode::ID02,
123 operator: Some(Operator::try_new_with_name(ID::from_u32(123), "John")?),
124 geo_location: Some(GeoLocation::new(88.0, 123.0)?),
125 ..Default::default()
126 };
127 let serialized = serde_json::to_string(&c).map_err(|x| x.to_string())?;
128
129 assert_eq!(
130 r#"{"controllerId":1,"displayName":"Unknown","controllerType":"Unknown","version":"Unknown","model":"Unknown","IP":"0.0.0.0:0","geoLatitude":88.0,"geoLongitude":123.0,"opMode":"Automatic","jobMode":"ID02","operatorId":123,"operatorName":"John"}"#,
131 serialized
132 );
133
134 Ok(())
135 }
136
137 #[test]
138 fn test_controller_from_json() -> Result<(), String> {
139 let c: Controller = serde_json::from_str(r#"{"controllerId":1,"geoLatitude":88,"geoLongitude":-123,"displayName":"Hello","controllerType":"Unknown","version":"Unknown","model":"Unknown","IP":"127.0.0.1:123","opMode":"Automatic","jobMode":"ID02","operatorId":123,"operatorName":"John"}"#).map_err(|x| x.to_string())?;
140
141 assert_eq!(
142 r#"Controller { controller_id: 1, display_name: "Hello", controller_type: "Unknown", version: "Unknown", model: "Unknown", address: IPv4(127.0.0.1, 123), geo_location: Some((88,-123)), op_mode: Automatic, job_mode: ID02, last_cycle_data: {}, variables: {}, last_connection_time: None, operator: Some(Operator { operator_id: 123, operator_name: Some("John") }), job_card_id: None, mold_id: None }"#,
143 format!("{:?}", &c)
144 );
145
146 Ok(())
147 }
148}