1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! `enum_primitive` crate Serde shims
//!
//! To enable this shim, add it as a dependency:
//!
//! ```toml
//! [dependencies]
//! enum_primitive_serde_shim = "0.2"
//! ```
//!
//! Full example:
//!
//! ```
//! #[macro_use]
//! extern crate serde_derive;
//! extern crate serde_json;
//!
//! #[macro_use]
//! extern crate enum_primitive;
//! #[macro_use] // required for impl_serde_for_enum_primitive
//! extern crate enum_primitive_serde_shim;
//!
//! enum_from_primitive! {
//!     #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
//!     enum Codes {
//!         CodeA = 0,
//!         CodeB = 1,
//!         CodeC = 5,
//!         CodeD = 8,
//!     }
//! }
//!
//! impl_serde_for_enum_primitive!(Codes);
//!
//! fn main() {
//!     let code = Codes::CodeC;
//!
//!     assert_eq!(serde_json::to_string(&code).unwrap(), "5");
//!
//!     assert_eq!(serde_json::from_str::<Codes>("8").unwrap(), Codes::CodeD);
//!
//!     assert!(serde_json::from_str::<Codes>("16").is_err());
//! }
//! ```
#![cfg_attr(not(feature = "std"), no_std)]

#[doc(hidden)]
pub extern crate serde;

#[doc(hidden)]
#[cfg(not(feature = "std"))]
pub use core::{fmt, result::Result};

#[doc(hidden)]
#[cfg(feature = "std")]
pub use std::{result::Result, fmt};

#[doc(hidden)]
pub extern crate enum_primitive;

/// Implements `Serialize` and `Deserialize` for an `enum_from_primitive!` generated enum.
///
/// See the [`enum_primitive`](../enum_primitive_serde_shim/index.html) shim for a full example.
#[macro_export]
macro_rules! impl_serde_for_enum_primitive {
    ($name:ident) => {
        impl $crate::serde::Serialize for $name {
            fn serialize<S>(&self, serializer: S) -> $crate::Result<S::Ok, S::Error>
            where
                S: $crate::serde::Serializer,
            {
                serializer.serialize_u64(*self as u64)
            }
        }

        impl<'de> $crate::serde::Deserialize<'de> for $name {
            fn deserialize<D>(deserializer: D) -> $crate::Result<Self, D::Error>
            where
                D: $crate::serde::Deserializer<'de>,
            {
                struct Visitor;

                impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
                    type Value = $name;

                    fn expecting(&self, formatter: &mut $crate::fmt::Formatter) -> $crate::fmt::Result {
                        formatter.write_str(stringify!(Expected $name as primitive numeric value))
                    }

                    #[cfg(feature = "std")]
                    fn visit_u64<E>(self, value: u64) -> $crate::Result<$name, E>
                    where
                        E: $crate::serde::de::Error,
                    {
                        $crate::enum_primitive::FromPrimitive::from_u64(value)
                            .ok_or_else(|| E::custom(format!(concat!("Invalid primitive value {} for enum ", stringify!($name)), value)))
                    }

                    #[cfg(not(feature = "std"))]
                    fn visit_u64<E>(self, value: u64) -> $crate::Result<$name, E>
                    where
                        E: $crate::serde::de::Error,
                    {
                        $crate::enum_primitive::FromPrimitive::from_u64(value)
                            .ok_or_else(|| E::custom(stringify!(Invalid primitive value for enum $name)))
                    }
                }

                deserializer.deserialize_u64(Visitor)
            }
        }
    };
}