csskit_lsp/jsonrpc/
response.rs

1use serde::{Deserialize, Deserializer, Serialize, de::Error};
2use serde_json::{Value, json, to_value};
3
4use super::{ErrorCode, Id};
5
6/// A Response Message sent as a result of a request
7///
8/// As defined in [JSON-RPC](https://www.jsonrpc.org/specification#response_object) and [LSP](https://microsoft.github.io/language-server-protocol/specifications/specification-3-16/#responseMessage).
9///
10/// Can either be [`Ok`] (the response had a `result`, and did not have attached `error` information),
11/// or as [`Err`] (the response had no `result`, instead having attached `error` information).
12///
13/// Both [`Ok`] and [`Err`] have an [`Id`] which matches the [`Id`] of the [`super::Request`] object.
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub enum Response {
16	/// [`Ok`]s also have an optional payload (serialised as a serde [`Value`]) which may contain more data about the
17	/// response, such as computed values.
18	Ok(Id, Value),
19	/// [`Err`]s also have an [`ErrorCode`] to determine which error occurred, an informatinal [`String`], and may contain
20	/// additional data (serialised as serde [`Value`]).
21	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			result: Option<&'a Value>,
33			error: Option<Value>,
34		}
35		if let Response::Ok(id, value) = self {
36			Res { id, result: Some(value), error: None }.serialize(serializer)
37		} else if let Response::Err(id, code, message, value) = self {
38			Res {
39				id,
40				result: None,
41				error: Some(json!({
42					"code": code, "message": message, "data": value
43				})),
44			}
45			.serialize(serializer)
46		} else {
47			unreachable!()
48		}
49	}
50}
51
52impl<'de> Deserialize<'de> for Response {
53	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
54	where
55		D: Deserializer<'de>,
56	{
57		#[derive(Deserialize)]
58		struct Err {
59			code: i32,
60			message: String,
61			#[serde(default = "serde_json::Value::default")]
62			data: Value,
63		}
64
65		#[derive(Deserialize)]
66		struct Res {
67			id: Id,
68			result: Option<Value>,
69			error: Option<Err>,
70		}
71
72		let res = Res::deserialize(deserializer)?;
73		if let Some(result) = res.result {
74			if res.error.is_some() {
75				Err(Error::duplicate_field("error"))?
76			}
77			Ok(Response::Ok(res.id, result))
78		} else if let Some(error) = res.error {
79			if res.result.is_some() {
80				Err(Error::duplicate_field("result"))?
81			}
82			Ok(Response::Err(res.id, error.code.into(), error.message, error.data))
83		} else {
84			Err(Error::missing_field("result"))?
85		}
86	}
87}
88
89impl Response {
90	pub fn new_ok<T>(id: Id, result: T) -> Response
91	where
92		T: Serialize,
93	{
94		Response::Ok(id, to_value(result).unwrap())
95	}
96
97	pub fn new_err<T>(id: Id, error_code: ErrorCode, message: String, value: T) -> Response
98	where
99		T: Serialize,
100	{
101		Response::Err(id, error_code, message, to_value(value).unwrap())
102	}
103}
104
105#[cfg(test)]
106mod tests {
107	use serde_json::{from_str, json};
108
109	use super::*;
110
111	#[test]
112	fn test_response_deserialize() {
113		assert_eq!(from_str::<Response>(r#"{"id":3, "result":7}"#).unwrap(), Response::Ok(3.into(), json!(7)));
114		assert_eq!(
115			from_str::<Response>(r#"{"id":4, "result":["a", "b"]}"#).unwrap(),
116			Response::Ok(4.into(), json!(["a", "b"]))
117		);
118		assert_eq!(
119			from_str::<Response>(r#"{"id":"a", "error":{"code": -32700, "message": "Parse error"}}"#).unwrap(),
120			Response::Err("a".into(), ErrorCode::ParseError, "Parse error".into(), Value::Null)
121		);
122		assert_eq!(
123			from_str::<Response>(
124				r#"{"id":"foo", "error":{"code": -32600, "message": "Invalid Request", "data": ["foo"]}}"#
125			)
126			.unwrap(),
127			Response::Err("foo".into(), ErrorCode::InvalidRequest, "Invalid Request".into(), json!(["foo"]))
128		);
129	}
130
131	#[test]
132	fn test_response_deserialize_error() {
133		// Missing result/error
134		assert!(from_str::<Response>(r#"{"id":3}"#).is_err());
135
136		// Missing error Code/Message
137		assert!(from_str::<Response>(r#"{"id":3, "error":{}}"#).is_err());
138
139		// Missing error Message
140		assert!(from_str::<Response>(r#"{"id":3, "error":{"code":0}}"#).is_err());
141
142		// Missing error Code
143		assert!(from_str::<Response>(r#"{"id":3, "error":{"message":""}}"#).is_err());
144
145		// Both error/result present
146		assert!(from_str::<Response>(r#"{"id":3, "error":{"code":0, "message": ""}, "result":7}"#).is_err());
147		assert!(from_str::<Response>(r#"{"id":3, "result":7, "error":{"code":0, "message": ""}}"#).is_err());
148	}
149}