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
use std::result::Result as StdResult;

#[derive(Debug, Deserialize, PartialEq)]
pub struct RpcError {
    pub code: i32,
    pub message: String,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct RpcResponse<R> {
    pub id: String,
    pub result: Option<R>,
    pub error: Option<RpcError>,
}

impl<R> Into<StdResult<R, RpcError>> for RpcResponse<R> {
    fn into(self) -> Result<R, RpcError> {
        match self {
            RpcResponse {
                result: Some(result),
                error: None,
                ..
            } => Ok(result),
            RpcResponse {
                result: None,
                error: Some(rpc_error),
                ..
            } => Err(rpc_error),
            _ => panic!("Response must contain either result or error."),
        }
    }
}

impl<R> RpcResponse<R> {
    pub fn into_result(self) -> StdResult<R, RpcError> {
        self.into()
    }

    pub fn id(&self) -> &str {
        &self.id
    }
}

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

    #[test]
    fn can_deserialize_successful_response_into_generic_type() {
        let result = r#"{
            "jsonrpc": "1.0",
            "id": "test",
            "result": 519521,
            "error": null
        }"#;

        let deserialized_response: RpcResponse<i32> = from_str(result).unwrap();

        assert_eq!(deserialized_response.into_result(), Ok(519521));
    }

    #[test]
    fn can_deserialize_successful_btc_rsponse() {
        let result = r#"{
                "id": "curltest",
                "result": 1,
                "error": null
            }"#;

        let result: RpcResponse<i32> = from_str(result).unwrap();

        assert_eq!(result.into_result(), Ok(1))
    }

    #[test]
    fn can_deserialize_error_response() {
        let result = r#"{
            "id": "test",
            "jsonrpc": "1.0",
            "result": null,
            "error": {
                "code": -123,
                "message": "Something went wrong"
            }
        }"#;

        let deserialized_response: RpcResponse<i32> = from_str(result).unwrap();

        assert_eq!(
            deserialized_response.into_result(),
            Err(RpcError {
                code: -123,
                message: "Something went wrong".to_string(),
            })
        )
    }
}