use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use serde_repr::{Deserialize_repr, Serialize_repr}; pub type Payload = Map; #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Message { pub src: String, pub dest: String, pub body: Body, } #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Body { #[serde(rename = "type")] pub typ: String, #[serde(default, skip_serializing_if = "u64_zero_by_ref")] pub msg_id: u64, #[serde(default, skip_serializing_if = "u64_zero_by_ref")] pub in_reply_to: u64, #[serde(flatten)] pub payload: Payload, } impl Body { pub fn from_type(typ: &str) -> Self { Body { typ: typ.to_string(), ..Default::default() } } pub fn with_msg_id(self, msg_id: u64) -> Self { let mut b = self; b.msg_id = msg_id; b } pub fn with_in_reply_to(self, in_reply_to: u64) -> Self { let mut b = self; b.in_reply_to = in_reply_to; b } pub fn with_payload(self, payload: Payload) -> Self { let mut b = self; b.payload = payload; b } } pub fn init_ok(msg_id: u64, in_reply_to: u64) -> Body { Body::from_type("init_ok") .with_msg_id(msg_id) .with_in_reply_to(in_reply_to) } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum ErrorCode { Definite(DefiniteError), Indefinite(IndefiniteError), } #[derive(Debug, Clone, Serialize_repr, Deserialize_repr)] #[repr(u64)] pub enum DefiniteError { NodeNotFound = 2, NotSupported = 10, TemporarilyUnavailable = 11, MalformedRequest = 12, Abort = 14, KeyNotFound = 20, KeyAlreadyExists = 21, PreconditionFailed = 22, TxnConflict = 30, } #[derive(Debug, Clone, Serialize_repr, Deserialize_repr)] #[repr(u64)] pub enum IndefiniteError { Timeout = 0, Crash = 13, } pub fn error(msg_id: u64, in_reply_to: u64, code: ErrorCode, text: Option<&str>) -> Body { Body { typ: "error".to_string(), msg_id, in_reply_to, payload: [ ("code".to_string(), serde_json::to_value(code).unwrap()), ("text".to_string(), serde_json::to_value(text).unwrap()), ] .into_iter() .collect(), } } #[allow(clippy::trivially_copy_pass_by_ref)] fn u64_zero_by_ref(num: &u64) -> bool { *num == 0 } #[cfg(test)] mod test { use super::*; #[test] fn error_codes() { let ec = ErrorCode::Definite(DefiniteError::Abort); let e = serde_json::to_string(&ec).unwrap(); assert_eq!(&e, "14"); } }