diff --git a/cove-core/src/lib.rs b/cove-core/src/lib.rs index 0e59125..4c7b3cc 100644 --- a/cove-core/src/lib.rs +++ b/cove-core/src/lib.rs @@ -1,25 +1,43 @@ +mod macros; + use serde::{Deserialize, Serialize}; +use self::macros::packets; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Id(pub u128); + #[derive(Debug, Deserialize, Serialize)] pub struct HelloCmd { + pub id: Id, pub name: String, } #[derive(Debug, Deserialize, Serialize)] -pub struct HelloRpl { - pub msg: String, +#[serde(tag = "type")] +pub enum HelloRpl { + Success { id: Id }, + InvalidName { reason: String }, + NameAlreadyUsed, +} + +// Create a Cmd enum for all commands and a Rpl enum for all replies, as well as +// TryFrom impls for the individual command and reply structs. +packets! { + Hello(HelloCmd, HelloRpl), } #[derive(Debug, Deserialize, Serialize)] #[serde(tag = "type")] -pub enum Data { - HelloCmd(HelloCmd), - HelloRpl(HelloRpl), -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct Packet { - pub id: u64, - #[serde(flatten)] - pub data: Data, +pub enum Packet { + Cmd { + id: u64, + #[serde(flatten)] + cmd: Cmd, + }, + Rpl { + id: u64, + #[serde(flatten)] + rpl: Rpl, + }, } diff --git a/cove-core/src/macros.rs b/cove-core/src/macros.rs new file mode 100644 index 0000000..aa9b737 --- /dev/null +++ b/cove-core/src/macros.rs @@ -0,0 +1,43 @@ +macro_rules! packets { + ( $( $name:ident($cmd:ident, $rpl:ident), )* ) => { + #[derive(Debug, Deserialize, Serialize)] + #[serde(tag = "name", content = "data")] + pub enum Cmd { + $( $name($cmd), )* + } + + $( + impl std::convert::TryFrom for $cmd { + type Error = (); + fn try_from(cmd: Cmd) -> Result { + match cmd { + Cmd::$name(val) => Ok(val), + _ => Err(()), + } + } + } + )* + + #[derive(Debug, Deserialize, Serialize)] + #[serde(tag = "name", content = "data")] + pub enum Rpl { + $( $name($rpl), )* + } + + $( + impl std::convert::TryFrom for $rpl { + type Error = (); + fn try_from(rpl: Rpl) -> Result { + match rpl { + Rpl::$name(val) => Ok(val), + _ => Err(()), + } + } + } + )* + }; +} + +// Make macro importable from elsewhere +// See https://stackoverflow.com/a/31749071 +pub(crate) use packets; diff --git a/cove-server/src/main.rs b/cove-server/src/main.rs index f10fa8f..db2845f 100644 --- a/cove-server/src/main.rs +++ b/cove-server/src/main.rs @@ -1,12 +1,11 @@ -use cove_core::{Data, HelloCmd, Packet}; +use cove_core::{HelloCmd, HelloRpl, Id, Packet, Rpl}; fn main() { - println!("Hello, world!"); - let packet = Packet { + let packet = Packet::Rpl { id: 1337, - data: Data::HelloCmd(HelloCmd { - name: "Garmy".to_string(), + rpl: Rpl::Hello(HelloRpl::InvalidName { + reason: "abc".to_string(), }), }; - println!("{}", serde_json::to_string(&packet).unwrap()); + println!("{}", serde_json::to_string_pretty(&packet).unwrap()); }