use super::{Color, DeviceSize, DeviceType};
use serde::{de, ser};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
use std::str::FromStr;
use thiserror::Error;
#[derive(Debug, Deserialize, Serialize)]
pub struct RegistrationInfoDevice {
pub id: String,
pub name: Option<String>,
pub size: DeviceSize,
#[serde(rename = "type")]
pub _type: Option<DeviceType>,
}
#[derive(Debug)]
pub enum Language {
English,
French,
German,
Spanish,
Japanese,
Korean,
ChineseChina,
ChineseTaiwan,
Unknown(String),
}
impl<'de> de::Deserialize<'de> for Language {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Language;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string")
}
fn visit_str<E>(self, value: &str) -> Result<Language, E>
where
E: de::Error,
{
Ok(match value {
"en" => Language::English,
"fr" => Language::French,
"de" => Language::German,
"es" => Language::Spanish,
"ja" => Language::Japanese,
"zh_cn" => Language::ChineseChina,
"ko" => Language::Korean,
"zh_CN" => Language::ChineseChina,
"zh_TW" => Language::ChineseTaiwan,
value => Language::Unknown(value.to_string()),
})
}
}
deserializer.deserialize_str(Visitor)
}
}
impl ser::Serialize for Language {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let lang = match self {
Language::English => "en",
Language::French => "fr",
Language::German => "de",
Language::Spanish => "es",
Language::Japanese => "ja",
Language::Korean => "ko",
Language::ChineseChina => "zh_CN",
Language::ChineseTaiwan => "zh_TW",
Language::Unknown(value) => value,
};
serializer.serialize_str(lang)
}
}
#[derive(Debug)]
pub enum Platform {
Mac,
Windows,
Unknown(String),
}
impl ser::Serialize for Platform {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let platform = match self {
Platform::Mac => "mac",
Platform::Windows => "windows",
Platform::Unknown(s) => s,
};
serializer.serialize_str(platform)
}
}
impl<'de> de::Deserialize<'de> for Platform {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Platform;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string")
}
fn visit_str<E>(self, value: &str) -> Result<Platform, E>
where
E: de::Error,
{
Ok(match value {
"mac" => Platform::Mac,
"windows" => Platform::Windows,
value => Platform::Unknown(value.to_string()),
})
}
}
deserializer.deserialize_str(Visitor)
}
}
#[derive(Debug, Deserialize, Serialize)]
pub struct RegistrationInfoApplication {
pub font: String,
pub language: Language,
pub platform: Platform,
#[serde(rename = "platformVersion")]
pub platform_version: String,
pub version: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct RegistrationInfoPlugin {
pub version: String,
pub uuid: String,
}
#[derive(Clone, Deserialize, Serialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct UserColors {
pub button_mouse_over_background_color: Option<Color>,
pub button_pressed_background_color: Option<Color>,
pub button_pressed_border_color: Option<Color>,
pub button_pressed_text_color: Option<Color>,
pub highlight_color: Option<Color>,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RegistrationInfo {
pub application: RegistrationInfoApplication,
pub plugin: RegistrationInfoPlugin,
pub device_pixel_ratio: f64,
pub devices: Vec<RegistrationInfoDevice>,
pub colors: UserColors,
}
#[derive(Deserialize)]
pub struct RegistrationParams {
pub port: u16,
pub uuid: String,
pub event: String,
pub info: RegistrationInfo,
}
#[derive(Debug, Error)]
pub enum RegistrationParamsError {
#[error("port not provided")]
NoPort,
#[error("port could not be parsed")]
BadPort(#[source] std::num::ParseIntError),
#[error("uuid not provided")]
NoUuid,
#[error("event not provided")]
NoEvent,
#[error("info not provided")]
NoInfo,
#[error("info could not be parsed")]
BadInfo(#[from] serde_json::Error),
}
impl RegistrationParams {
pub fn from_args<I: IntoIterator<Item = String>>(
args: I,
) -> Result<RegistrationParams, RegistrationParamsError> {
let mut iter = args.into_iter();
let mut port = None;
let mut uuid = None;
let mut event = None;
let mut info = None;
loop {
match iter.next().as_deref() {
Some("-port") => port = iter.next().map(|a| u16::from_str(&a)),
Some("-pluginUUID") => uuid = iter.next(),
Some("-registerEvent") => event = iter.next(),
Some("-info") => info = iter.next().map(|a| serde_json::from_str(&a)),
Some(_) => {}
None => break,
}
}
let port = port
.ok_or(RegistrationParamsError::NoPort)?
.map_err(RegistrationParamsError::BadPort)?;
let uuid = uuid.ok_or(RegistrationParamsError::NoUuid)?;
let event = event.ok_or(RegistrationParamsError::NoEvent)?;
let info = info
.ok_or(RegistrationParamsError::NoInfo)?
.map_err(RegistrationParamsError::BadInfo)?;
Ok(RegistrationParams {
port,
uuid,
event,
info,
})
}
}