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 fn present<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Option<Value>, D::Error> {
68 Value::deserialize(deserializer).map(Some)
69 }
70
71 #[derive(Deserialize)]
72 struct Res {
73 id: Id,
74 #[serde(default, deserialize_with = "present")]
75 result: Option<Value>,
76 error: Option<Err>,
77 }
78
79 let res = Res::deserialize(deserializer)?;
80 if let Some(result) = res.result {
81 if res.error.is_some() {
82 Err(Error::duplicate_field("error"))?
83 }
84 Ok(Response::Ok(res.id, result))
85 } else if let Some(error) = res.error {
86 if res.result.is_some() {
87 Err(Error::duplicate_field("result"))?
88 }
89 Ok(Response::Err(res.id, error.code.into(), error.message, error.data))
90 } else {
91 Err(Error::missing_field("result"))?
92 }
93 }
94}
95
96impl Response {
97 pub fn new_ok<T>(id: Id, result: T) -> Response
98 where
99 T: Serialize,
100 {
101 Response::Ok(id, to_value(result).unwrap())
102 }
103
104 pub fn new_err<T>(id: Id, error_code: ErrorCode, message: String, value: T) -> Response
105 where
106 T: Serialize,
107 {
108 Response::Err(id, error_code, message, to_value(value).unwrap())
109 }
110}
111
112#[derive(Debug, Clone, PartialEq, Eq)]
114pub struct ResponseError {
115 pub code: ErrorCode,
116 pub message: String,
117}
118
119impl ResponseError {
120 pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
121 Self { code, message: message.into() }
122 }
123}
124
125impl From<ErrorCode> for ResponseError {
126 fn from(code: ErrorCode) -> Self {
128 Self { code, message: format!("{code:?}") }
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use serde_json::{from_str, json, to_string};
135
136 use super::*;
137
138 #[test]
139 fn test_response_serialize_ok_omits_error() {
140 let response = Response::Ok(1.into(), json!({"capabilities": {}}));
141 let serialized = to_string(&response).unwrap();
142 assert!(serialized.contains("\"result\""), "should contain result");
143 assert!(!serialized.contains("\"error\""), "should not contain error key");
144 assert_eq!(serialized, r#"{"id":1,"result":{"capabilities":{}}}"#);
145 }
146
147 #[test]
148 fn test_response_serialize_err_omits_result() {
149 let response = Response::Err(1.into(), ErrorCode::ParseError, "Parse error".into(), Value::Null);
150 let serialized = to_string(&response).unwrap();
151 assert!(serialized.contains("\"error\""), "should contain error");
152 assert!(!serialized.contains("\"result\""), "should not contain result key");
153 }
154
155 #[test]
156 fn test_response_deserialize() {
157 assert_eq!(from_str::<Response>(r#"{"id":3, "result":7}"#).unwrap(), Response::Ok(3.into(), json!(7)));
158 assert_eq!(
159 from_str::<Response>(r#"{"id":4, "result":["a", "b"]}"#).unwrap(),
160 Response::Ok(4.into(), json!(["a", "b"]))
161 );
162 assert_eq!(from_str::<Response>(r#"{"id":5, "result":null}"#).unwrap(), Response::Ok(5.into(), Value::Null));
163 assert_eq!(
164 from_str::<Response>(r#"{"id":"a", "error":{"code": -32700, "message": "Parse error"}}"#).unwrap(),
165 Response::Err("a".into(), ErrorCode::ParseError, "Parse error".into(), Value::Null)
166 );
167 assert_eq!(
168 from_str::<Response>(
169 r#"{"id":"foo", "error":{"code": -32600, "message": "Invalid Request", "data": ["foo"]}}"#
170 )
171 .unwrap(),
172 Response::Err("foo".into(), ErrorCode::InvalidRequest, "Invalid Request".into(), json!(["foo"]))
173 );
174 }
175
176 #[test]
177 fn test_response_deserialize_error() {
178 assert!(from_str::<Response>(r#"{"id":3}"#).is_err());
180
181 assert!(from_str::<Response>(r#"{"id":3, "error":{}}"#).is_err());
183
184 assert!(from_str::<Response>(r#"{"id":3, "error":{"code":0}}"#).is_err());
186
187 assert!(from_str::<Response>(r#"{"id":3, "error":{"message":""}}"#).is_err());
189
190 assert!(from_str::<Response>(r#"{"id":3, "error":{"code":0, "message": ""}, "result":7}"#).is_err());
192 assert!(from_str::<Response>(r#"{"id":3, "result":7, "error":{"code":0, "message": ""}}"#).is_err());
193 }
194}