1use serde::{Deserialize, Deserializer, Serialize, de::Error};
2use serde_json::{Value, json, to_value};
3
4use super::{ErrorCode, Id};
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub enum Response {
16 Ok(Id, Value),
19 Err(Id, ErrorCode, String, Value),
22}
23
24impl Serialize for Response {
25 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
26 where
27 S: serde::Serializer,
28 {
29 #[derive(Serialize)]
30 struct Res<'a> {
31 id: &'a Id,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 result: Option<&'a Value>,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 error: Option<Value>,
36 }
37 if let Response::Ok(id, value) = self {
38 Res { id, result: Some(value), error: None }.serialize(serializer)
39 } else if let Response::Err(id, code, message, value) = self {
40 Res {
41 id,
42 result: None,
43 error: Some(json!({
44 "code": code, "message": message, "data": value
45 })),
46 }
47 .serialize(serializer)
48 } else {
49 unreachable!()
50 }
51 }
52}
53
54impl<'de> Deserialize<'de> for Response {
55 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
56 where
57 D: Deserializer<'de>,
58 {
59 #[derive(Deserialize)]
60 struct Err {
61 code: i32,
62 message: String,
63 #[serde(default = "serde_json::Value::default")]
64 data: Value,
65 }
66
67 #[derive(Deserialize)]
68 struct Res {
69 id: Id,
70 result: Option<Value>,
71 error: Option<Err>,
72 }
73
74 let res = Res::deserialize(deserializer)?;
75 if let Some(result) = res.result {
76 if res.error.is_some() {
77 Err(Error::duplicate_field("error"))?
78 }
79 Ok(Response::Ok(res.id, result))
80 } else if let Some(error) = res.error {
81 if res.result.is_some() {
82 Err(Error::duplicate_field("result"))?
83 }
84 Ok(Response::Err(res.id, error.code.into(), error.message, error.data))
85 } else {
86 Err(Error::missing_field("result"))?
87 }
88 }
89}
90
91impl Response {
92 pub fn new_ok<T>(id: Id, result: T) -> Response
93 where
94 T: Serialize,
95 {
96 Response::Ok(id, to_value(result).unwrap())
97 }
98
99 pub fn new_err<T>(id: Id, error_code: ErrorCode, message: String, value: T) -> Response
100 where
101 T: Serialize,
102 {
103 Response::Err(id, error_code, message, to_value(value).unwrap())
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use serde_json::{from_str, json, to_string};
110
111 use super::*;
112
113 #[test]
114 fn test_response_serialize_ok_omits_error() {
115 let response = Response::Ok(1.into(), json!({"capabilities": {}}));
116 let serialized = to_string(&response).unwrap();
117 assert!(serialized.contains("\"result\""), "should contain result");
118 assert!(!serialized.contains("\"error\""), "should not contain error key");
119 assert_eq!(serialized, r#"{"id":1,"result":{"capabilities":{}}}"#);
120 }
121
122 #[test]
123 fn test_response_serialize_err_omits_result() {
124 let response = Response::Err(1.into(), ErrorCode::ParseError, "Parse error".into(), Value::Null);
125 let serialized = to_string(&response).unwrap();
126 assert!(serialized.contains("\"error\""), "should contain error");
127 assert!(!serialized.contains("\"result\""), "should not contain result key");
128 }
129
130 #[test]
131 fn test_response_deserialize() {
132 assert_eq!(from_str::<Response>(r#"{"id":3, "result":7}"#).unwrap(), Response::Ok(3.into(), json!(7)));
133 assert_eq!(
134 from_str::<Response>(r#"{"id":4, "result":["a", "b"]}"#).unwrap(),
135 Response::Ok(4.into(), json!(["a", "b"]))
136 );
137 assert_eq!(
138 from_str::<Response>(r#"{"id":"a", "error":{"code": -32700, "message": "Parse error"}}"#).unwrap(),
139 Response::Err("a".into(), ErrorCode::ParseError, "Parse error".into(), Value::Null)
140 );
141 assert_eq!(
142 from_str::<Response>(
143 r#"{"id":"foo", "error":{"code": -32600, "message": "Invalid Request", "data": ["foo"]}}"#
144 )
145 .unwrap(),
146 Response::Err("foo".into(), ErrorCode::InvalidRequest, "Invalid Request".into(), json!(["foo"]))
147 );
148 }
149
150 #[test]
151 fn test_response_deserialize_error() {
152 assert!(from_str::<Response>(r#"{"id":3}"#).is_err());
154
155 assert!(from_str::<Response>(r#"{"id":3, "error":{}}"#).is_err());
157
158 assert!(from_str::<Response>(r#"{"id":3, "error":{"code":0}}"#).is_err());
160
161 assert!(from_str::<Response>(r#"{"id":3, "error":{"message":""}}"#).is_err());
163
164 assert!(from_str::<Response>(r#"{"id":3, "error":{"code":0, "message": ""}, "result":7}"#).is_err());
166 assert!(from_str::<Response>(r#"{"id":3, "result":7, "error":{"code":0, "message": ""}}"#).is_err());
167 }
168}