#[macro_export]
macro_rules! protocol_enum {
{$(#[$attr:meta])* enum $name:ident: $carrier:ty {
$($(#[$iattr:meta])* $item:ident = $val:expr),+
}} => (
$crate::protocol_enum! {
$(#[$attr])*
__private $name: $carrier {
$($(#[$iattr])* $item = $val),+
}
}
impl<'de> ::serde::de::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where D: ::serde::de::Deserializer<'de> {
let value: $carrier = ::serde::de::Deserialize::deserialize(deserializer)?;
match value {
$($val => Ok($name::$item)),+,
other => {
use ::serde::de::Error;
let err = format!("Unexpected {}: {}", stringify!($name), other);
Err(D::Error::custom(err))
}
}
}
}
impl ::serde::ser::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
where S: ::serde::ser::Serializer {
<$carrier>::from(*self).serialize(serializer)
}
}
);
{$(#[$attr:meta])* enum $name:ident: $carrier:ty = $default:ident {
$($(#[$iattr:meta])* $item:ident = $val:expr),+
}} => (
$crate::protocol_enum! {
$(#[$attr])*
__private $name: $carrier {
$($(#[$iattr])* $item = $val),+
}
}
impl Default for $name {
fn default() -> $name {
$name::$default
}
}
impl<'de> ::serde::de::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where D: ::serde::de::Deserializer<'de> {
let value: $carrier = ::serde::de::Deserialize::deserialize(deserializer)?;
Ok(match value {
$($val => $name::$item),+,
_ => Default::default()
})
}
}
impl ::serde::ser::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
where S: ::serde::ser::Serializer {
<$carrier>::from(*self).serialize(serializer)
}
}
);
{$(#[$attr:meta])* enum $name:ident {
$($(#[$iattr:meta])* $item:ident = $val:expr),+
}} => (
$crate::protocol_enum! {
$(#[$attr])*
__private $name: String {
$($(#[$iattr])* $item = $val),+
}
}
impl<'de> ::serde::de::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where D: ::serde::de::Deserializer<'de> {
match String::deserialize(deserializer)?.as_ref() {
$($val => Ok($name::$item)),+,
other => {
use ::serde::de::Error;
let err = format!("Unexpected {}: {}",
stringify!($name), other);
Err(D::Error::custom(err))
}
}
}
}
impl ::serde::ser::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
where S: ::serde::ser::Serializer {
serializer.serialize_str(
match *self {
$($name::$item => $val),+,
}
)
}
}
);
{$(#[$attr:meta])* enum $name:ident = $default:ident {
$($(#[$iattr:meta])* $item:ident = $val:expr),+
}} => (
$crate::protocol_enum! {
$(#[$attr])*
__private $name: String {
$($(#[$iattr])* $item = $val),+
}
}
impl Default for $name {
fn default() -> $name {
$name::$default
}
}
impl<'de> ::serde::de::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where D: ::serde::de::Deserializer<'de> {
Ok(match String::deserialize(deserializer)?.as_ref() {
$($val => $name::$item),+,
_ => Default::default()
})
}
}
impl ::serde::ser::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
where S: ::serde::ser::Serializer {
serializer.serialize_str(
match *self {
$($name::$item => $val),+,
}
)
}
}
);
{$(#[$attr:meta])* __private $name:ident: $carrier:ty {
$($(#[$iattr:meta])* $item:ident = $val:expr),+
}} => (
$(#[$attr])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum $name {
$($(#[$iattr])* $item),+,
}
impl From<$name> for $carrier {
fn from(value: $name) -> $carrier {
match value {
$($name::$item => $val.into()),+,
}
}
}
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
<$carrier>::from(*self).fmt(f)
}
}
);
}
#[cfg(test)]
pub mod test {
use serde_json;
use crate::protocol_enum;
protocol_enum! {
enum ImageStatus {
Queued = "queued",
Saving = "saving",
Active = "active",
Killed = "killed",
Deleted = "deleted",
Deactivated = "deactivated"
}
}
#[test]
fn test_string() {
assert_eq!("active", &String::from(ImageStatus::Active));
assert_eq!("active", ImageStatus::Active.to_string());
assert_eq!(
ImageStatus::Active,
serde_json::from_str("\"active\"").unwrap()
);
assert_eq!(
"\"active\"",
serde_json::to_string(&ImageStatus::Active).unwrap()
);
assert!(serde_json::from_str::<ImageStatus>("\"banana\"").is_err());
assert!(serde_json::from_str::<ImageStatus>("42").is_err());
assert_eq!(ImageStatus::Active, ImageStatus::Active);
assert!(!(ImageStatus::Queued == ImageStatus::Active));
}
protocol_enum! {
enum ServerPowerState: u8 {
NoState = 0,
Running = 1,
Paused = 3,
Shutdown = 4,
Crashed = 6,
Suspended = 7
}
}
#[test]
fn test_carrier() {
assert_eq!(1, u8::from(ServerPowerState::Running));
assert_eq!("1", ServerPowerState::Running.to_string());
assert_eq!(
ServerPowerState::Running,
serde_json::from_str("1").unwrap()
);
assert_eq!(
"1",
serde_json::to_string(&ServerPowerState::Running).unwrap()
);
assert!(serde_json::from_str::<ServerPowerState>("\"banana\"").is_err());
assert!(serde_json::from_str::<ServerPowerState>("42").is_err());
assert_eq!(ServerPowerState::Running, ServerPowerState::Running);
assert!(!(ServerPowerState::NoState == ServerPowerState::Running));
}
protocol_enum! {
#[non_exhaustive]
enum ImageStatusWithDefault = Unknown {
Queued = "queued",
Saving = "saving",
Active = "active",
Killed = "killed",
Deleted = "deleted",
Deactivated = "deactivated",
Unknown = "unknown"
}
}
#[test]
fn test_string_with_default() {
assert_eq!("active", &String::from(ImageStatusWithDefault::Active));
assert_eq!("active", ImageStatusWithDefault::Active.to_string());
assert_eq!(
ImageStatusWithDefault::Active,
serde_json::from_str("\"active\"").unwrap()
);
assert_eq!(
"\"active\"",
serde_json::to_string(&ImageStatusWithDefault::Active).unwrap()
);
assert_eq!(
ImageStatusWithDefault::Unknown,
ImageStatusWithDefault::default()
);
assert_eq!(
ImageStatusWithDefault::Unknown,
serde_json::from_str("\"banana\"").unwrap()
);
assert!(serde_json::from_str::<ImageStatusWithDefault>("42").is_err());
}
protocol_enum! {
#[non_exhaustive]
enum ServerPowerStateWithDefault: u8 = NoState {
NoState = 0,
Running = 1,
Paused = 3,
Shutdown = 4,
Crashed = 6,
Suspended = 7
}
}
#[test]
fn test_carrier_with_default() {
assert_eq!(1, u8::from(ServerPowerStateWithDefault::Running));
assert_eq!("1", ServerPowerStateWithDefault::Running.to_string());
assert_eq!(
ServerPowerStateWithDefault::Running,
serde_json::from_str("1").unwrap()
);
assert_eq!(
"1",
serde_json::to_string(&ServerPowerStateWithDefault::Running).unwrap()
);
assert_eq!(
ServerPowerStateWithDefault::NoState,
ServerPowerStateWithDefault::default()
);
assert_eq!(
ServerPowerStateWithDefault::NoState,
serde_json::from_str("42").unwrap()
);
assert!(serde_json::from_str::<ServerPowerStateWithDefault>("\"banana\"").is_err());
}
}