Structure packets better

This commit is contained in:
Joscha 2022-02-08 00:16:33 +01:00
parent 5cf0f76477
commit 73ffae3898
3 changed files with 78 additions and 18 deletions

View file

@ -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,
pub enum Packet {
Cmd {
id: u64,
#[serde(flatten)]
pub data: Data,
cmd: Cmd,
},
Rpl {
id: u64,
#[serde(flatten)]
rpl: Rpl,
},
}

43
cove-core/src/macros.rs Normal file
View file

@ -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<Cmd> for $cmd {
type Error = ();
fn try_from(cmd: Cmd) -> Result<Self, Self::Error> {
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<Rpl> for $rpl {
type Error = ();
fn try_from(rpl: Rpl) -> Result<Self, Self::Error> {
match rpl {
Rpl::$name(val) => Ok(val),
_ => Err(()),
}
}
}
)*
};
}
// Make macro importable from elsewhere
// See https://stackoverflow.com/a/31749071
pub(crate) use packets;

View file

@ -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());
}