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
// ref https://developer.apple.com/documentation/appstorereceipts/status

use std::fmt;
use std::result;

use serde::{de, Deserialize, Deserializer};

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Status {
    Success,
    Error21000,
    Error21001,
    Error21002,
    Error21003,
    Error21004,
    Error21005,
    Error21006,
    Error21007,
    Error21008,
    Error21009,
    Error21010,
    InternalDataAccessError(u16),
}

impl<'de> Deserialize<'de> for Status {
    fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let v = u16::deserialize(deserializer)?;
        match v {
            0 => Ok(Self::Success),
            21000 => Ok(Self::Error21000),
            21001 => Ok(Self::Error21001),
            21002 => Ok(Self::Error21002),
            21003 => Ok(Self::Error21003),
            21004 => Ok(Self::Error21004),
            21005 => Ok(Self::Error21005),
            21006 => Ok(Self::Error21006),
            21007 => Ok(Self::Error21007),
            21008 => Ok(Self::Error21008),
            21009 => Ok(Self::Error21009),
            21010 => Ok(Self::Error21010),
            21100..=21199 => Ok(Self::InternalDataAccessError(v)),
            _ => Err(de::Error::custom(format!("unknown status value [{}]", v))),
        }
    }
}

impl fmt::Display for Status {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Success => write!(f, "[0] the receipt is valid"),
            Self::Error21000 => write!(
                f,
                "[21000] The request to the App Store was not made using the HTTP POST request method."
            ),
            Self::Error21001 => write!(f, "[21001] This status code is no longer sent by the App Store."),
            Self::Error21002 => write!(f, "[21002] The data in the receipt-data property was malformed or the service experienced a temporary issue. Try again."),
            Self::Error21003 => write!(f, "[21003] The receipt could not be authenticated."),
            Self::Error21004 => write!(f, "[21004] The shared secret you provided does not match the shared secret on file for your account."),
            Self::Error21005 => write!(f, "[21005] The receipt server was temporarily unable to provide the receipt. Try again."),
            Self::Error21006 => write!(f, "[21006] This receipt is valid but the subscription has expired."),
            Self::Error21007 => write!(f, "[21007] This receipt is from the test environment, but it was sent to the production environment for verification."),
            Self::Error21008 => write!(f, "[21008] This receipt is from the production environment, but it was sent to the test environment for verification."),
            Self::Error21009 => write!(f, "[21009] Internal data access error. Try again later."),
            Self::Error21010 => write!(f, "[21010] The user account cannot be found or has been deleted."),
            Self::InternalDataAccessError(v) => write!(f, "[{}] internal data access errors.", v),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::io;

    use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};

    #[derive(Deserialize, Debug, PartialEq, Eq)]
    struct Foo {
        status: Status,
    }

    #[test]
    fn simple() -> io::Result<()> {
        for (v, status) in vec![
            (0, Status::Success),
            (21000, Status::Error21000),
            (21001, Status::Error21001),
            (21002, Status::Error21002),
            (21003, Status::Error21003),
            (21004, Status::Error21004),
            (21005, Status::Error21005),
            (21006, Status::Error21006),
            (21007, Status::Error21007),
            (21008, Status::Error21008),
            (21009, Status::Error21009),
            (21010, Status::Error21010),
            (21100, Status::InternalDataAccessError(21100)),
            (21101, Status::InternalDataAccessError(21101)),
            (21199, Status::InternalDataAccessError(21199)),
        ] {
            assert_de_tokens(
                &Foo { status },
                &[
                    Token::Struct {
                        name: "Foo",
                        len: 1,
                    },
                    Token::Str("status"),
                    Token::U16(v),
                    Token::StructEnd,
                ],
            );
        }

        assert_de_tokens_error::<Foo>(
            &[
                Token::Struct {
                    name: "Foo",
                    len: 1,
                },
                Token::Str("status"),
                Token::U16(1),
                Token::StructEnd,
            ],
            "unknown status value [1]",
        );

        Ok(())
    }
}