From 374584c5fc21ae3ff7cf1c0bc5a1fe59d5d45f86 Mon Sep 17 00:00:00 2001 From: Georgy Moshkin <gmoshkin@picodata.io> Date: Thu, 8 Sep 2022 18:09:06 +0300 Subject: [PATCH] refactor: extract define_str_enum macro --- src/traft/event.rs | 63 +++++++++++++--------------------------------- src/util.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 46 deletions(-) diff --git a/src/traft/event.rs b/src/traft/event.rs index fed643694a..c56f68a379 100644 --- a/src/traft/event.rs +++ b/src/traft/event.rs @@ -9,6 +9,7 @@ use ::tarantool::fiber::{mutex::MutexGuard, Cond, Mutex}; use ::tarantool::proc; use ::tarantool::unwrap_or; +use crate::define_str_enum; use crate::tlog; use crate::traft::error::Error; use crate::unwrap_ok_or; @@ -17,54 +18,24 @@ use thiserror::Error; pub type BoxResult<T> = std::result::Result<T, Box<dyn std::error::Error>>; #[derive(Error, Debug)] -#[error("unknown event")] -pub struct EventFromStrError; - -macro_rules! define_events { - ($($event:tt, $str:literal;)+) => { - //////////////////////////////////////////////////////////////////////// - /// An enumeration of builtin events - #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)] - pub enum Event { - $( $event, )+ - } - - impl Event { - pub const fn as_str(&self) -> &str { - match self { - $( Self::$event => $str, )+ - } - } - } - - impl std::fmt::Display for Event { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str(self.as_str()) - } - } - - impl FromStr for Event { - type Err = EventFromStrError; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - match s { - $( $str => Ok(Self::$event), )+ - _ => Err(EventFromStrError), - } - } - } +#[error("unknown event {0}")] +pub struct EventFromStrError(pub String); + +define_str_enum! { + //////////////////////////////////////////////////////////////////////////// + /// An enumeration of builtin events + pub enum Event { + Demoted = "raft.demoted", + JointStateEnter = "raft.joint-state-enter", + JointStateLeave = "raft.joint-state-leave", + JointStateDrop = "raft.joint-state-drop", + StatusChanged = "raft.status-changed", + TopologyChanged = "raft.topology-changed", + RaftLoopNeeded = "raft.loop-needed", + RaftEntryApplied = "raft.entry-applied", } -} -define_events! { - Demoted, "raft.demoted"; - JointStateEnter, "raft.joint-state-enter"; - JointStateLeave, "raft.joint-state-leave"; - JointStateDrop, "raft.joint-state-drop"; - StatusChanged, "raft.status-changed"; - TopologyChanged, "raft.topology-changed"; - RaftLoopNeeded, "raft.loop-needed"; - RaftEntryApplied, "raft.entry-applied"; + FromStr::Err = EventFromStrError; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/util.rs b/src/util.rs index abb407246c..4bda629fcc 100644 --- a/src/util.rs +++ b/src/util.rs @@ -33,6 +33,68 @@ macro_rules! stringify_debug { }}; } +#[macro_export] +macro_rules! define_str_enum { + ( + $(#[$meta:meta])* + pub enum $enum:ident { $($space:tt = $str:literal,)+ } + FromStr::Err = $err:ident; + ) => { + $(#[$meta])* + #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)] + pub enum $enum { + $( #[doc = $str] $space, )+ + } + + impl $enum { + pub const fn as_str(&self) -> &str { + match self { + $( Self::$space => $str, )+ + } + } + } + + impl std::str::FromStr for $enum { + type Err = $err; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + $( $str => Ok(Self::$space), )+ + _ => Err($err(s.into())), + } + } + } + + impl std::fmt::Display for $enum { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str(self.as_str()) + } + } + + impl serde::Serialize for $enum { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + serializer.serialize_str(self.as_str()) + } + } + + impl<'de> serde::Deserialize<'de> for $enum { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + use serde::de::Error; + let tmp = <&str>::deserialize(deserializer)?; + let res = tmp.parse().map_err(|e| D::Error::custom(e))?; + Ok(res) + } + } + } +} + //////////////////////////////////////////////////////////////////////////////// /// A wrapper around `String` that garantees the string is uppercase by /// converting it to uppercase (if needed) on construction. -- GitLab