1use std::borrow::Cow;
32
33use crate::{
34 params::{Id, TwoPointZero},
35 Params,
36};
37use serde::{Deserialize, Deserializer, Serialize};
38use serde_json::value::RawValue;
39
40#[derive(Serialize, Deserialize, Debug, Clone)]
42pub struct Request<'a> {
43 pub jsonrpc: TwoPointZero,
45 #[serde(borrow)]
47 pub id: Id<'a>,
48 #[serde(borrow)]
50 pub method: Cow<'a, str>,
51 #[serde(borrow, default, deserialize_with = "deserialize_borrowed_params")]
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub params: Option<Cow<'a, RawValue>>,
58}
59
60impl<'a> Request<'a> {
61 pub fn borrowed(method: &'a str, params: Option<&'a RawValue>, id: Id<'a>) -> Self {
63 Self {
64 jsonrpc: TwoPointZero,
65 id,
66 method: Cow::Borrowed(method),
67 params: params.map(Cow::Borrowed),
68 }
69 }
70
71 pub fn owned(method: String, params: Option<Box<RawValue>>, id: Id<'a>) -> Self {
73 Self {
74 jsonrpc: TwoPointZero,
75 id,
76 method: Cow::Owned(method),
77 params: params.map(Cow::Owned),
78 }
79 }
80
81 pub fn id(&self) -> Id<'a> {
83 self.id.clone()
84 }
85
86 pub fn method_name(&self) -> &str {
88 &self.method
89 }
90
91 pub fn params(&self) -> Params<'_> {
93 Params::new(self.params.as_ref().map(|p| RawValue::get(p)))
94 }
95}
96
97#[derive(Deserialize, Debug, PartialEq, Eq, Clone)]
99pub struct InvalidRequest<'a> {
100 #[serde(borrow)]
102 pub id: Id<'a>,
103}
104
105#[derive(Serialize, Deserialize, Debug, Clone)]
108pub struct Notification<'a, T> {
109 pub jsonrpc: TwoPointZero,
111 #[serde(borrow)]
113 pub method: Cow<'a, str>,
114 pub params: T,
116}
117
118impl<'a, T> Notification<'a, T> {
119 pub fn new(method: Cow<'a, str>, params: T) -> Self {
121 Self { jsonrpc: TwoPointZero, method, params }
122 }
123
124 pub fn method_name(&self) -> &str {
126 &self.method
127 }
128
129 pub fn params(&self) -> &T {
131 &self.params
132 }
133}
134
135fn deserialize_borrowed_params<'de, D: Deserializer<'de>>(
138 deserializer: D,
139) -> Result<Option<Cow<'de, RawValue>>, D::Error> {
140 Option::<&'de RawValue>::deserialize(deserializer).map(|params| params.map(Cow::Borrowed))
141}
142
143#[cfg(test)]
144mod test {
145 use super::{Cow, Id, InvalidRequest, Notification, Request, TwoPointZero};
146 use serde_json::value::RawValue;
147
148 fn assert_request<'a>(request: Request<'a>, id: Id<'a>, method: &str, params: Option<&str>) {
149 assert_eq!(request.jsonrpc, TwoPointZero);
150 assert_eq!(request.id, id);
151 assert_eq!(request.method, method);
152 assert_eq!(request.params.as_ref().map(|p| RawValue::get(p)), params);
153 assert!(!matches!(request.params, Some(Cow::Owned(_))));
154 }
155
156 #[test]
158 fn deserialize_call() {
159 let method = "subtract";
160 let params = "[42, 23]";
161
162 let test_vector = vec![
163 (
165 r#"{"jsonrpc":"2.0", "method":"subtract", "params":[42, 23], "id":1}"#,
166 Id::Number(1),
167 Some(params),
168 method,
169 ),
170 (r#"{"jsonrpc":"2.0", "method":"subtract", "id":null}"#, Id::Null, None, method),
172 (r#"{"jsonrpc":"2.0", "method":"\"m", "id":null}"#, Id::Null, None, "\"m"),
174 ];
175
176 for (ser, id, params, method) in test_vector.into_iter() {
177 let request = serde_json::from_str(ser).unwrap();
178 assert_request(request, id, method, params);
179 }
180 }
181
182 #[test]
183 fn deserialize_call_escaped_method_name() {
184 let ser = r#"{"jsonrpc":"2.0","id":1,"method":"\"m\""}"#;
185 let req: Request = serde_json::from_str(ser).unwrap();
186 assert_request(req, Id::Number(1), "\"m\"", None);
187 }
188
189 #[test]
190 fn deserialize_valid_notif_works() {
191 let ser = r#"{"jsonrpc":"2.0","method":"say_hello","params":[]}"#;
192 let dsr: Notification<&RawValue> = serde_json::from_str(ser).unwrap();
193 assert_eq!(dsr.method, "say_hello");
194 assert_eq!(dsr.jsonrpc, TwoPointZero);
195 }
196
197 #[test]
198 fn deserialize_valid_notif_escaped_method() {
199 let ser = r#"{"jsonrpc":"2.0","method":"\"m\"","params":[]}"#;
200 let dsr: Notification<&RawValue> = serde_json::from_str(ser).unwrap();
201 assert_eq!(dsr.method, "\"m\"");
202 assert_eq!(dsr.jsonrpc, TwoPointZero);
203 }
204
205 #[test]
206 fn deserialize_call_bad_id_should_fail() {
207 let ser = r#"{"jsonrpc":"2.0","method":"say_hello","params":[],"id":{}}"#;
208 assert!(serde_json::from_str::<Request>(ser).is_err());
209 }
210
211 #[test]
212 fn deserialize_invalid_request() {
213 let s = r#"{"id":120,"method":"my_method","params":["foo", "bar"],"extra_field":[]}"#;
214 let deserialized: InvalidRequest = serde_json::from_str(s).unwrap();
215 assert_eq!(deserialized, InvalidRequest { id: Id::Number(120) });
216 }
217
218 #[test]
219 fn deserialize_invalid_request_bad_id_should_fail() {
220 let s = r#"{"id":[0,0],"method":"my_method","params":[]}"#;
221 let err = serde_json::from_str::<InvalidRequest>(s).unwrap_err();
222 assert_eq!(
223 err.to_string(),
224 "invalid type: sequence, expected null, an unsigned integer or a string at line 1 column 7"
225 );
226 }
227
228 #[test]
230 fn serialize_call() {
231 let method = "subtract";
232 let id = Id::Number(1);
234 let params = Some(serde_json::value::to_raw_value(&[42, 23]).unwrap());
235
236 let test_vector: &[(&'static str, Option<_>, Option<_>, &'static str)] = &[
237 (
239 r#"{"jsonrpc":"2.0","id":1,"method":"subtract","params":[42,23]}"#,
240 Some(id.clone()),
241 params.clone(),
242 method,
243 ),
244 (r#"{"jsonrpc":"2.0","id":1,"method":"\"m"}"#, Some(id.clone()), None, "\"m"),
246 (
248 r#"{"jsonrpc":"2.0","id":null,"method":"subtract","params":[42,23]}"#,
249 None,
250 params,
251 method,
252 ),
253 (r#"{"jsonrpc":"2.0","id":1,"method":"subtract"}"#, Some(id), None, method),
255 (r#"{"jsonrpc":"2.0","id":null,"method":"subtract"}"#, None, None, method),
257 ];
258
259 for (ser, id, params, method) in test_vector.iter().cloned() {
260 let request = serde_json::to_string(&Request::borrowed(
261 method,
262 params.as_deref(),
263 id.unwrap_or(Id::Null),
264 ))
265 .unwrap();
266
267 assert_eq!(&request, ser);
268 }
269 }
270}