From dde70a37b88b1caf99629a58329972aaf15c4f90 Mon Sep 17 00:00:00 2001 From: LucasOe Date: Sat, 7 Jan 2023 21:11:02 +0100 Subject: [PATCH] Refactor code with enums This doesn't work because this PR isn't merged: https://github.com/serde-rs/serde/pull/2056 --- src/api.rs | 429 ++++++++++++++++++++--------------------------------- src/tcp.rs | 87 ++--------- 2 files changed, 172 insertions(+), 344 deletions(-) diff --git a/src/api.rs b/src/api.rs index 80ca82f..d6142bb 100644 --- a/src/api.rs +++ b/src/api.rs @@ -7,58 +7,41 @@ pub use crate::tcp::ExternalEditorApi; use serde::{Deserialize, Serialize}; use serde_json::Value; -use std::any::Any; -use std::fmt::{self, Display}; - -pub trait MessageId { - const MESSAGE_ID: u8; -} - -pub trait JsonMessage: Display { - fn message_id(&self) -> u8; - fn as_any(&self) -> &dyn Any; -} ///////////////////////////////////////////////////////////////////////////// -/// Get a list containing the states for every object. Returns an `AnswerReload` message. -#[derive(Serialize, Debug, PartialEq)] -pub struct MessageGetScripts { - #[serde(rename = "messageID")] - message_id: u8, -} - -impl MessageId for MessageGetScripts { - const MESSAGE_ID: u8 = 0; +#[derive(Serialize, Debug)] +#[serde(tag = "messageID")] +pub enum Message { + #[serde(rename = "0")] + MessageGetScripts(MessageGetScripts), + #[serde(rename = "1")] + MessageReload(MessageReload), + #[serde(rename = "2")] + MessageCustomMessage(MessageCustomMessage), + #[serde(rename = "3")] + MessageExectute(MessageExectute), } -impl JsonMessage for MessageGetScripts { - fn message_id(&self) -> u8 { - self.message_id - } - - fn as_any(&self) -> &dyn Any { - self - } -} +pub struct TryFromMessageError(Message); -impl fmt::Display for MessageGetScripts { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Get Scripts") +/// Get a list containing the states for every object. Returns an `AnswerReload` message. +#[derive(Serialize, Debug)] +pub struct MessageGetScripts {} + +impl TryFrom for MessageGetScripts { + type Error = TryFromMessageError; + fn try_from(message: Message) -> Result { + match message { + Message::MessageGetScripts(message) => Ok(message), + other => Err(TryFromMessageError(other)), + } } } impl MessageGetScripts { pub fn new() -> Self { - Self { - message_id: Self::MESSAGE_ID, - } - } -} - -impl Default for MessageGetScripts { - fn default() -> Self { - MessageGetScripts::new() + Self {} } } @@ -69,40 +52,25 @@ impl Default for MessageGetScripts { /// Any objects mentioned have both their Lua script and their UI XML updated. /// If no value is set for either the "script" or "ui" key then the /// corresponding Lua script or UI XML is deleted. -#[derive(Serialize, Debug, PartialEq)] +#[derive(Serialize, Debug)] pub struct MessageReload { - #[serde(rename = "messageID")] - message_id: u8, #[serde(rename = "scriptStates")] pub script_states: Value, } -impl MessageId for MessageReload { - const MESSAGE_ID: u8 = 1; -} - -impl JsonMessage for MessageReload { - fn message_id(&self) -> u8 { - self.message_id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl fmt::Display for MessageReload { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Reload") +impl TryFrom for MessageReload { + type Error = TryFromMessageError; + fn try_from(message: Message) -> Result { + match message { + Message::MessageReload(message) => Ok(message), + other => Err(TryFromMessageError(other)), + } } } impl MessageReload { pub fn new(script_states: Value) -> Self { - Self { - message_id: Self::MESSAGE_ID, - script_states, - } + Self { script_states } } } @@ -110,49 +78,32 @@ impl MessageReload { /// in the currently loaded game. The value of customMessage must be a table, /// and is passed as a parameter to the event handler. /// If this value is not a table then the event is not triggered. -#[derive(Serialize, Debug, PartialEq)] +#[derive(Serialize, Debug)] pub struct MessageCustomMessage { - #[serde(rename = "messageID")] - message_id: u8, #[serde(rename = "customMessage")] pub custom_message: Value, } -impl MessageId for MessageCustomMessage { - const MESSAGE_ID: u8 = 2; -} - -impl JsonMessage for MessageCustomMessage { - fn message_id(&self) -> u8 { - self.message_id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl fmt::Display for MessageCustomMessage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Custom Message") +impl TryFrom for MessageCustomMessage { + type Error = TryFromMessageError; + fn try_from(message: Message) -> Result { + match message { + Message::MessageCustomMessage(message) => Ok(message), + other => Err(TryFromMessageError(other)), + } } } impl MessageCustomMessage { pub fn new(custom_message: Value) -> Self { - Self { - message_id: Self::MESSAGE_ID, - custom_message, - } + Self { custom_message } } } /// Executes a lua script and returns the value in a `AnswerReturn` message. /// Using a guid of "-1" runs the script globally. -#[derive(Serialize, Debug, PartialEq)] +#[derive(Serialize, Debug)] pub struct MessageExectute { - #[serde(rename = "messageID")] - message_id: u8, #[serde(rename = "returnID")] pub return_id: u8, #[serde(rename = "guid")] @@ -161,30 +112,19 @@ pub struct MessageExectute { pub script: String, } -impl MessageId for MessageExectute { - const MESSAGE_ID: u8 = 3; -} - -impl JsonMessage for MessageExectute { - fn message_id(&self) -> u8 { - self.message_id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl fmt::Display for MessageExectute { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Execute") +impl TryFrom for MessageExectute { + type Error = TryFromMessageError; + fn try_from(message: Message) -> Result { + match message { + Message::MessageExectute(message) => Ok(message), + other => Err(TryFromMessageError(other)), + } } } impl MessageExectute { pub fn new(script: String) -> Self { Self { - message_id: Self::MESSAGE_ID, return_id: 5, guid: String::from("-1"), script, @@ -194,6 +134,29 @@ impl MessageExectute { ///////////////////////////////////////////////////////////////////////////// +#[derive(Deserialize, Debug)] +#[serde(tag = "messageID")] +pub enum Answer { + #[serde(rename = "0")] + AnswerNewObject(AnswerNewObject), + #[serde(rename = "1")] + AnswerReload(AnswerReload), + #[serde(rename = "2")] + AnswerPrint(AnswerPrint), + #[serde(rename = "3")] + AnswerError(AnswerError), + #[serde(rename = "4")] + AnswerCustomMessage(AnswerCustomMessage), + #[serde(rename = "5")] + AnswerReturn(AnswerReturn), + #[serde(rename = "6")] + AnswerGameSaved(AnswerGameSaved), + #[serde(rename = "7")] + AnswerObjectCreated(AnswerObjectCreated), +} + +pub struct TryFromAnswerError(Answer); + /// When clicking on "Scripting Editor" in the right click contextual menu /// in TTS for an object that doesn't have a Lua Script yet, TTS will send /// an `AnswerNewObject` message containing data for the object. @@ -211,31 +174,19 @@ impl MessageExectute { /// ] /// } /// ``` -#[derive(Deserialize, Clone, Debug, PartialEq)] +#[derive(Deserialize, Debug)] pub struct AnswerNewObject { - #[serde(rename = "messageID")] - message_id: u8, #[serde(rename = "scriptStates")] pub script_states: Value, } -impl MessageId for AnswerNewObject { - const MESSAGE_ID: u8 = 0; -} - -impl JsonMessage for AnswerNewObject { - fn message_id(&self) -> u8 { - self.message_id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl fmt::Display for AnswerNewObject { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "New Object") +impl TryFrom for AnswerNewObject { + type Error = TryFromAnswerError; + fn try_from(answer: Answer) -> Result { + match answer { + Answer::AnswerNewObject(message) => Ok(message), + other => Err(TryFromAnswerError(other)), + } } } @@ -263,33 +214,21 @@ impl fmt::Display for AnswerNewObject { /// ] /// } /// ``` -#[derive(Deserialize, Clone, Debug, PartialEq)] +#[derive(Deserialize, Debug)] pub struct AnswerReload { - #[serde(rename = "messageID")] - message_id: u8, #[serde(rename = "savePath")] pub save_path: String, #[serde(rename = "scriptStates")] pub script_states: Value, } -impl MessageId for AnswerReload { - const MESSAGE_ID: u8 = 1; -} - -impl JsonMessage for AnswerReload { - fn message_id(&self) -> u8 { - self.message_id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl fmt::Display for AnswerReload { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Reload") +impl TryFrom for AnswerReload { + type Error = TryFromAnswerError; + fn try_from(answer: Answer) -> Result { + match answer { + Answer::AnswerReload(message) => Ok(message), + other => Err(TryFromAnswerError(other)), + } } } @@ -308,31 +247,19 @@ impl AnswerReload { /// "message": "Hit player! White" /// } /// ``` -#[derive(Deserialize, Clone, Debug, PartialEq)] +#[derive(Deserialize, Debug)] pub struct AnswerPrint { - #[serde(rename = "messageID")] - message_id: u8, #[serde(rename = "message")] pub message: String, } -impl MessageId for AnswerPrint { - const MESSAGE_ID: u8 = 2; -} - -impl JsonMessage for AnswerPrint { - fn message_id(&self) -> u8 { - self.message_id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl fmt::Display for AnswerPrint { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Print") +impl TryFrom for AnswerPrint { + type Error = TryFromAnswerError; + fn try_from(answer: Answer) -> Result { + match answer { + Answer::AnswerPrint(message) => Ok(message), + other => Err(TryFromAnswerError(other)), + } } } @@ -347,10 +274,8 @@ impl fmt::Display for AnswerPrint { /// "errorMessagePrefix": "Error in Global Script: " /// } /// ``` -#[derive(Deserialize, Clone, Debug, PartialEq)] +#[derive(Deserialize, Debug)] pub struct AnswerError { - #[serde(rename = "messageID")] - message_id: u8, #[serde(rename = "error")] pub error: String, #[serde(rename = "guid")] @@ -359,23 +284,13 @@ pub struct AnswerError { pub error_message_prefix: String, } -impl MessageId for AnswerError { - const MESSAGE_ID: u8 = 3; -} - -impl JsonMessage for AnswerError { - fn message_id(&self) -> u8 { - self.message_id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl fmt::Display for AnswerError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Error") +impl TryFrom for AnswerError { + type Error = TryFromAnswerError; + fn try_from(answer: Answer) -> Result { + match answer { + Answer::AnswerError(message) => Ok(message), + other => Err(TryFromAnswerError(other)), + } } } @@ -388,31 +303,19 @@ impl fmt::Display for AnswerError { /// "custom_message": { "foo": "Hello", "bar": "World"} /// } /// ``` -#[derive(Deserialize, Clone, Debug, PartialEq)] +#[derive(Deserialize, Debug)] pub struct AnswerCustomMessage { - #[serde(rename = "messageID")] - message_id: u8, #[serde(rename = "customMessage")] pub custom_message: Value, } -impl MessageId for AnswerCustomMessage { - const MESSAGE_ID: u8 = 4; -} - -impl JsonMessage for AnswerCustomMessage { - fn message_id(&self) -> u8 { - self.message_id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl fmt::Display for AnswerCustomMessage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Custom Message") +impl TryFrom for AnswerCustomMessage { + type Error = TryFromAnswerError; + fn try_from(answer: Answer) -> Result { + match answer { + Answer::AnswerCustomMessage(message) => Ok(message), + other => Err(TryFromAnswerError(other)), + } } } @@ -428,33 +331,21 @@ impl fmt::Display for AnswerCustomMessage { /// "return_value": true /// } /// ``` -#[derive(Deserialize, Clone, Debug, PartialEq)] +#[derive(Deserialize, Debug)] pub struct AnswerReturn { - #[serde(rename = "messageID")] - message_id: u8, #[serde(rename = "returnID")] pub return_id: u8, #[serde(rename = "returnValue")] pub return_value: Option, } -impl MessageId for AnswerReturn { - const MESSAGE_ID: u8 = 5; -} - -impl JsonMessage for AnswerReturn { - fn message_id(&self) -> u8 { - self.message_id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl fmt::Display for AnswerReturn { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Return") +impl TryFrom for AnswerReturn { + type Error = TryFromAnswerError; + fn try_from(answer: Answer) -> Result { + match answer { + Answer::AnswerReturn(message) => Ok(message), + other => Err(TryFromAnswerError(other)), + } } } @@ -466,29 +357,16 @@ impl AnswerReturn { } /// Whenever the player saves the game in TTS, `AnswerGameSaved` is sent as a response. -#[derive(Deserialize, Clone, Debug, PartialEq)] -pub struct AnswerGameSaved { - #[serde(rename = "messageID")] - message_id: u8, -} - -impl MessageId for AnswerGameSaved { - const MESSAGE_ID: u8 = 6; -} - -impl JsonMessage for AnswerGameSaved { - fn message_id(&self) -> u8 { - self.message_id - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl fmt::Display for AnswerGameSaved { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Game Saved") +#[derive(Deserialize, Debug)] +pub struct AnswerGameSaved {} + +impl TryFrom for AnswerGameSaved { + type Error = TryFromAnswerError; + fn try_from(answer: Answer) -> Result { + match answer { + Answer::AnswerGameSaved(message) => Ok(message), + other => Err(TryFromAnswerError(other)), + } } } @@ -501,31 +379,44 @@ impl fmt::Display for AnswerGameSaved { /// "guid": "abcdef" /// } /// ``` -#[derive(Deserialize, Debug, PartialEq)] +#[derive(Deserialize, Debug)] pub struct AnswerObjectCreated { - #[serde(rename = "messageID")] - message_id: u8, #[serde(rename = "guid")] pub guid: String, } -impl MessageId for AnswerObjectCreated { - const MESSAGE_ID: u8 = 7; +impl TryFrom for AnswerObjectCreated { + type Error = TryFromAnswerError; + fn try_from(answer: Answer) -> Result { + match answer { + Answer::AnswerObjectCreated(message) => Ok(message), + other => Err(TryFromAnswerError(other)), + } + } } -impl JsonMessage for AnswerObjectCreated { - fn message_id(&self) -> u8 { - self.message_id +///////////////////////////////////////////////////////////////////////////// + +impl ExternalEditorApi { + pub fn get_scripts(&self) -> AnswerReload { + self.send(Message::MessageGetScripts(MessageGetScripts::new())); + self.wait() } - fn as_any(&self) -> &dyn Any { - self + pub fn reload(&self, script_states: Value) -> AnswerReload { + self.send(Message::MessageReload(MessageReload::new(script_states))); + self.wait() + } + + pub fn custom_message(&self, message: Value) { + self.send(Message::MessageCustomMessage(MessageCustomMessage::new( + message, + ))); } -} -impl fmt::Display for AnswerObjectCreated { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Object Created") + pub fn execute(&self, script: String) -> AnswerReturn { + self.send(Message::MessageExectute(MessageExectute::new(script))); + self.wait() } } @@ -556,8 +447,8 @@ mod tests { fn test_read() { let api = ExternalEditorApi::new(); loop { - let answer = api.read().unwrap(); - println!("{}", answer); + let answer = api.read(); + println!("{:#?}", answer); } } } diff --git a/src/tcp.rs b/src/tcp.rs index cf7be14..adbdd3a 100644 --- a/src/tcp.rs +++ b/src/tcp.rs @@ -1,12 +1,4 @@ -use crate::api::{ - AnswerCustomMessage, AnswerError, AnswerGameSaved, AnswerNewObject, AnswerObjectCreated, - AnswerPrint, AnswerReload, AnswerReturn, MessageId, -}; -use crate::{JsonMessage, MessageCustomMessage, MessageExectute, MessageGetScripts, MessageReload}; -use anyhow::{bail, Result}; -use serde::de::DeserializeOwned; -use serde::Serialize; -use serde_json::Value; +use crate::{Answer, Message}; use std::io::{Read, Write}; use std::net::{TcpListener, TcpStream}; @@ -21,81 +13,26 @@ impl ExternalEditorApi { Self { listener } } - fn send(&self, message: T) - where - T: Serialize, - { - let json_message = serde_json::to_string(&message).unwrap(); + pub fn send(&self, message: Message) { let mut stream = TcpStream::connect("127.0.0.1:39999").unwrap(); + let json_message = serde_json::to_string(&message).unwrap(); stream.write_all(json_message.as_bytes()).unwrap(); stream.flush().unwrap(); } - pub fn read(&self) -> Result> { - let (mut stream, _addr) = self.listener.accept()?; + pub fn read(&self) -> Answer { + let (mut stream, _addr) = self.listener.accept().unwrap(); let mut buffer = String::new(); stream.read_to_string(&mut buffer).unwrap(); - - let message: Value = serde_json::from_str(&buffer)?; - let message_id = get_message_id(&message); - - match message_id { - AnswerNewObject::MESSAGE_ID => helper::(message), - AnswerReload::MESSAGE_ID => helper::(message), - AnswerPrint::MESSAGE_ID => helper::(message), - AnswerError::MESSAGE_ID => helper::(message), - AnswerCustomMessage::MESSAGE_ID => helper::(message), - AnswerReturn::MESSAGE_ID => helper::(message), - AnswerGameSaved::MESSAGE_ID => helper::(message), - AnswerObjectCreated::MESSAGE_ID => helper::(message), - _ => bail!("Can't find id"), - } + println!("{}", buffer); + serde_json::from_str(&buffer).unwrap() } - /// Waits for an answer with the correct id and returns it - pub fn wait(&self) -> T - where - T: MessageId + DeserializeOwned + Clone + 'static, - { - let answer = loop { - let answer = self.read().unwrap(); - let message_id = answer.message_id(); - match message_id { - _ if message_id == T::MESSAGE_ID => break answer, - _ => {} + pub fn wait>(&self) -> T { + loop { + if let Ok(answer) = T::try_from(self.read()) { + return answer; } - }; - let downcast = answer.as_any().downcast_ref::().unwrap(); - downcast.clone() - } - - pub fn get_scripts(&self) -> AnswerReload { - self.send(MessageGetScripts::new()); - self.wait() - } - - pub fn reload(&self, script_states: Value) -> AnswerReload { - self.send(MessageReload::new(script_states)); - self.wait() - } - - pub fn custom_message(&self, message: Value) { - self.send(MessageCustomMessage::new(message)); - } - - pub fn execute(&self, script: String) -> AnswerReturn { - self.send(MessageExectute::new(script)); - self.wait() + } } } - -fn helper(answer: Value) -> Result> -where - T: JsonMessage + DeserializeOwned + 'static, -{ - Ok(Box::new(serde_json::from_value::(answer).unwrap())) -} - -fn get_message_id(message: &Value) -> u8 { - message["messageID"].as_u64().unwrap() as u8 -}