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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
macro_rules! id {
    ($newtype_name:ident, $prefix:expr) => {
        #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
        pub struct $newtype_name(String);

        impl $newtype_name {
            #[inline]
            pub fn prefix() -> &'static str {
                $prefix
            }
        }

        impl ::std::fmt::Display for $newtype_name {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                self.0.fmt(f)
            }
        }

        impl ::std::str::FromStr for $newtype_name {
            type Err = ParseIdError;

            fn from_str(s: &str) -> Result<Self, Self::Err> {
                if !s.starts_with($prefix) {
                    Err(ParseIdError {
                        typename: stringify!($newtype_name),
                        expected: stringify!(id to start with $prefix),
                    })
                } else {
                    Ok($newtype_name(s.to_owned()))
                }
            }
        }

        impl ::serde::Serialize for $newtype_name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                where S: ::serde::ser::Serializer
            {
                self.to_string().serialize(serializer)
            }
        }

        impl<'de> ::serde::Deserialize<'de> for $newtype_name {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                where D: ::serde::de::Deserializer<'de>
            {
                let s: String = ::serde::Deserialize::deserialize(deserializer)?;
                s.parse::<Self>().map_err(|e| ::serde::de::Error::custom(e))
            }
        }
    };

    ($enum_name:ident { $( $variant_name:ident($($variant_type:tt)*) ),* $(,)* }) => {
        #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
        pub enum $enum_name {$(
            $variant_name($($variant_type)*),
        )*}

        impl ::std::fmt::Display for $enum_name {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                match *self {$(
                    $enum_name::$variant_name(ref id) => id.fmt(f),
                )*}
            }
        }

        impl ::std::str::FromStr for $enum_name {
            type Err = ParseIdError;

            fn from_str(s: &str) -> Result<Self, Self::Err> {
                let prefix = s.find('_')
                    .map(|i| &s[0..i+1])
                    .ok_or_else(|| ParseIdError {
                        typename: stringify!($enum_name),
                        expected: "id to start with a prefix (as in 'prefix_')"
                    })?;

                match prefix {
                    $(_ if prefix == $($variant_type)*::prefix() => {
                        Ok($enum_name::$variant_name(s.parse()?))
                    })*
                    _ => {
                        Err(ParseIdError {
                            typename: stringify!($enum_name),
                            expected: "unknown id prefix",
                        })
                    }
                }
            }
        }

        impl ::serde::Serialize for $enum_name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                where S: ::serde::ser::Serializer
            {
                self.to_string().serialize(serializer)
            }
        }

        impl<'de> ::serde::Deserialize<'de> for $enum_name {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                where D: ::serde::de::Deserializer<'de>
            {
                let s: String = ::serde::Deserialize::deserialize(deserializer)?;
                s.parse::<Self>().map_err(|e| ::serde::de::Error::custom(e))
            }
        }

        $(
            impl From<$($variant_type)*> for $enum_name {
                fn from(id: $($variant_type)*) -> Self {
                    $enum_name::$variant_name(id)
                }
            }
        )*
    };
}

#[derive(Clone, Debug)]
pub struct ParseIdError { typename: &'static str, expected: &'static str }

impl ::std::fmt::Display for ParseIdError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "invalid `{}`, expected {}", self.typename, self.expected)
    }
}

impl ::std::error::Error for ParseIdError {
    fn description(&self) -> &str {
        "error parsing an id"
    }
}

id!(BankAccountId, "ba_");
id!(CardId, "card_");
id!(SourceId, "src_");
id!(TokenId, "tok_");
id!(PaymentSourceId {
    BankAcccount(BankAccountId),
    Card(CardId),
    Source(SourceId),
});