use std::{
collections::HashMap,
ops::{Deref, DerefMut},
};
use serde::{Deserialize, Serialize};
use parse_display::{Display, FromStr};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Command<T> {
pub command: CommandName,
pub data: T,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Data<T: core::fmt::Display>(pub Vec<T>);
#[derive(Debug, Clone, Serialize, Deserialize, Display, FromStr)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[display(style = "SNAKE_CASE")]
pub enum CommandName {
OnSettingsDidChange,
SendMessage,
ChangeSettings,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(
into = "Command<MonitorSettings>",
try_from = "Command<MonitorSettings>"
)]
pub struct MiddlewareCommand(pub MonitorSettings);
impl From<MiddlewareCommand> for Command<MonitorSettings> {
fn from(value: MiddlewareCommand) -> Self {
Self {
command: CommandName::OnSettingsDidChange,
data: value.0,
}
}
}
impl TryFrom<Command<MonitorSettings>> for MiddlewareCommand {
type Error = serde_json::Error;
fn try_from(middleware_command: Command<MonitorSettings>) -> Result<Self, Self::Error> {
match middleware_command.command {
CommandName::OnSettingsDidChange => Ok(MiddlewareCommand(middleware_command.data)),
command_name => Err(serde::de::Error::custom(format!(
"ON_SETTING_DID_CHANGE command expected, got {command_name}"
))),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "command", content = "data", rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ClientCommand {
SendMessage(String),
ChangeSettings(MonitorSettings),
}
impl From<ClientCommand> for Command<serde_json::Value> {
fn from(value: ClientCommand) -> Self {
match value {
ClientCommand::SendMessage(send_message) => Self {
command: CommandName::SendMessage,
data: serde_json::to_value(send_message).unwrap(),
},
ClientCommand::ChangeSettings(monitor_settings) => Self {
command: CommandName::ChangeSettings,
data: serde_json::to_value(monitor_settings).unwrap(),
},
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PluggableMonitorSetting {
pub id: Option<String>,
pub label: Option<String>,
pub r#type: Option<LabelType>,
#[serde(default)]
pub values: Vec<String>,
pub selected_value: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub enum LabelType {
Enum,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(transparent)]
pub struct PluggableMonitorSettings(pub HashMap<String, PluggableMonitorSetting>);
impl Deref for PluggableMonitorSettings {
type Target = HashMap<String, PluggableMonitorSetting>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for PluggableMonitorSettings {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Display, FromStr)]
pub enum EndOfLine {
#[display("")]
#[serde(rename = "")]
NoLineEnding,
#[display("\n")]
#[serde(rename = "\n")]
NewLine,
#[display("\r")]
#[serde(rename = "\r")]
CarriageReturn,
#[display("\r\n")]
#[serde(rename = "\r\n")]
CarriageReturnNewLine,
}
impl EndOfLine {
pub const EOL: &'static [&'static str] = &["", "\n", "\r", "\r\n"];
pub fn contains_eol(string: String) -> bool {
Self::EOL.iter().any(|eol| string.contains(eol))
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MonitorModelState {
#[serde(skip_serializing_if = "Option::is_none")]
pub autoscroll: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timestamp: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub line_ending: Option<EndOfLine>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub interpolate: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub dark_theme: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ws_port: Option<u16>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub serial_port: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub connected: Option<bool>,
#[serde(default)]
pub generate: bool,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MonitorSettings {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pluggable_monitor_settings: Option<PluggableMonitorSettings>,
#[serde(
default,
rename = "monitorUISettings",
skip_serializing_if = "Option::is_none"
)]
pub monitor_ui_settings: Option<MonitorModelState>,
}