#![cfg_attr(not(feature = "protocol"), allow(unused))]
macro_rules! impl_str_ser {
($type:ty) => {
impl ::serde::ser::Serialize for $type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ::serde::ser::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
};
}
#[allow(unused_macros)]
macro_rules! impl_str_de {
($type:ty) => {
impl<'de> ::serde::de::Deserialize<'de> for $type {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: ::serde::de::Deserializer<'de>,
{
<::std::borrow::Cow<str>>::deserialize(deserializer)?
.parse()
.map_err(::serde::de::Error::custom)
}
}
};
}
#[allow(unused_macros)]
macro_rules! impl_str_serde {
($type:ty) => {
impl_str_ser!($type);
impl_str_de!($type);
};
}
#[cfg(test)]
mod str_tests {
use std::fmt;
use std::io::Cursor;
use std::str::FromStr;
struct Test;
impl FromStr for Test {
type Err = &'static str;
fn from_str(string: &str) -> Result<Self, Self::Err> {
match string {
"test" => Ok(Test),
_ => Err("failed"),
}
}
}
impl fmt::Display for Test {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "test")
}
}
impl_str_serde!(Test);
#[test]
fn test_serialize_string() {
assert_eq!("\"test\"", serde_json::to_string(&Test).unwrap());
}
#[test]
fn test_deserialize() {
assert!(serde_json::from_str::<Test>("\"test\"").is_ok());
}
#[test]
fn test_deserialize_owned() {
assert!(serde_json::from_reader::<_, Test>(Cursor::new("\"test\"")).is_ok());
}
}
macro_rules! impl_hex_ser {
($type:ident) => {
impl ::std::fmt::Display for $type {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{:#x}", self.0)
}
}
impl ::serde::ser::Serialize for $type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ::serde::ser::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
};
}
macro_rules! impl_hex_de {
($type:ident, $num:ident) => {
impl ::std::str::FromStr for $type {
type Err = ::std::num::ParseIntError;
fn from_str(s: &str) -> Result<$type, ::std::num::ParseIntError> {
if s.starts_with("0x") || s.starts_with("0X") {
$num::from_str_radix(&s[2..], 16).map($type)
} else {
s.parse::<$num>().map($type)
}
}
}
impl<'de> ::serde::de::Deserialize<'de> for $type {
fn deserialize<D>(deserializer: D) -> Result<$type, D::Error>
where
D: ::serde::de::Deserializer<'de>,
{
struct HexVisitor;
impl<'de> ::serde::de::Visitor<'de> for HexVisitor {
type Value = $type;
fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "a number or hex string")
}
fn visit_i64<E: ::serde::de::Error>(self, v: i64) -> Result<Self::Value, E> {
Ok($type(v as $num))
}
fn visit_u64<E: ::serde::de::Error>(self, v: u64) -> Result<Self::Value, E> {
Ok($type(v as $num))
}
fn visit_str<E: ::serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
v.parse().map_err(::serde::de::Error::custom)
}
}
deserializer.deserialize_any(HexVisitor)
}
}
};
}
macro_rules! impl_hex_serde {
($type:ident, $num:ident) => {
impl_hex_ser!($type);
impl_hex_de!($type, $num);
};
}
#[cfg(test)]
mod hex_tests {
use std::io::Cursor;
#[derive(Debug, PartialEq)]
struct Hex(u32);
impl_hex_serde!(Hex, u32);
#[test]
fn test_hex_to_string() {
assert_eq!("0x0", &Hex(0).to_string());
assert_eq!("0x2a", &Hex(42).to_string());
}
#[test]
fn test_hex_serialize() {
assert_eq!("\"0x0\"", serde_json::to_string(&Hex(0)).unwrap());
assert_eq!("\"0x2a\"", serde_json::to_string(&Hex(42)).unwrap());
}
#[test]
fn test_hex_from_string() {
assert_eq!(Hex(0), "0".parse().unwrap());
assert_eq!(Hex(42), "42".parse().unwrap());
assert_eq!(Hex(42), "0x2a".parse().unwrap());
assert_eq!(Hex(42), "0X2A".parse().unwrap());
}
#[test]
fn test_hex_deserialize() {
assert_eq!(Hex(0), serde_json::from_str("\"0\"").unwrap());
assert_eq!(Hex(42), serde_json::from_str("\"42\"").unwrap());
assert_eq!(Hex(42), serde_json::from_str("\"0x2a\"").unwrap());
assert_eq!(Hex(42), serde_json::from_str("\"0X2A\"").unwrap());
}
#[test]
fn test_hex_deserialize_owned() {
assert_eq!(
Hex(0),
serde_json::from_reader(Cursor::new("\"0\"")).unwrap()
);
assert_eq!(
Hex(42),
serde_json::from_reader(Cursor::new("\"42\"")).unwrap()
);
assert_eq!(
Hex(42),
serde_json::from_reader(Cursor::new("\"0x2a\"")).unwrap()
);
assert_eq!(
Hex(42),
serde_json::from_reader(Cursor::new("\"0X2A\"")).unwrap()
);
}
#[test]
fn test_invalid() {
let result = serde_json::from_str::<Hex>("true").unwrap_err();
assert_eq!(
"invalid type: boolean `true`, expected a number or hex string at line 1 column 4",
result.to_string()
);
}
}
macro_rules! indexed_enum {
() => {};
{
$(#[$meta:meta])*
$vis:vis enum $name:ident {
$(
$(#[$variant_meta:meta])*
$variant:ident
),* $(,)?
}
$($rest:tt)*
} => {
$(#[$meta])*
$vis enum $name {
$(
$(#[$variant_meta])*
$variant,
)*
}
impl $crate::IndexedEnum for $name {
indexed_enum!(@impl_body [] [] 0usize; $($variant),*);
}
impl $crate::indexed_enum::private::Sealed for $name {}
indexed_enum! {
$($rest)*
}
};
(@impl_body [$($as_index_arms:tt)*] [$($variants_array:expr),*] $idx:expr;) => {
const VARIANTS: &[Self] = &[$($variants_array),*];
fn as_index(&self) -> usize {
match *self {
$($as_index_arms)*
}
}
};
(@impl_body [$($as_index_arms:tt)*] [$($variants_array:expr),*] $idx:expr; $variant:ident $(, $rest:ident)*) => {
indexed_enum!(
@impl_body
[$($as_index_arms)* Self::$variant => $idx,]
[$($variants_array,)* Self::$variant]
$idx + 1usize;
$($rest),*
);
};
}
#[cfg(test)]
mod tests {
use crate::IndexedEnum;
indexed_enum! {
enum IndexedEnumTest {
V0,
V1,
V2,
V3,
}
}
#[test]
fn variant_count_is_accurate() {
assert_eq!(IndexedEnumTest::VARIANTS.len(), 4);
}
#[test]
fn as_index_returns_unique_index() {
let mut indexes_seen = [false; IndexedEnumTest::VARIANTS.len()];
for variant in [
IndexedEnumTest::V0,
IndexedEnumTest::V1,
IndexedEnumTest::V2,
IndexedEnumTest::V3,
] {
let index = variant.as_index();
assert!(!indexes_seen[index]);
indexes_seen[index] = true;
}
assert!(indexes_seen.into_iter().all(|seen| seen))
}
#[test]
fn variant_iter_is_in_index_order() {
for (index, variant) in IndexedEnumTest::VARIANTS.iter().enumerate() {
assert_eq!(index, variant.as_index())
}
}
}