1use std::borrow::Cow;
31
32use crate::{
33 params::{Id, TwoPointZero},
34 Params,
35};
36use http::Extensions;
37use serde::{Deserialize, 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)]
53 pub params: Option<Cow<'a, RawValue>>,
54 #[serde(skip)]
56 pub extensions: Extensions,
57}
58
59impl<'a> Request<'a> {
60 pub fn new(method: Cow<'a, str>, params: Option<&'a RawValue>, id: Id<'a>) -> Self {
62 Self { jsonrpc: TwoPointZero, id, method, params: params.map(Cow::Borrowed), extensions: Extensions::new() }
63 }
64
65 pub fn id(&self) -> Id<'a> {
67 self.id.clone()
68 }
69
70 pub fn method_name(&self) -> &str {
72 &self.method
73 }
74
75 pub fn params(&self) -> Params {
77 Params::new(self.params.as_ref().map(|p| RawValue::get(p)))
78 }
79
80 pub fn extensions(&self) -> &Extensions {
82 &self.extensions
83 }
84
85 pub fn extensions_mut(&mut self) -> &mut Extensions {
87 &mut self.extensions
88 }
89}
90
91#[derive(Deserialize, Debug, PartialEq, Eq)]
93pub struct InvalidRequest<'a> {
94 #[serde(borrow)]
96 pub id: Id<'a>,
97}
98
99#[derive(Serialize, Deserialize, Debug, Clone)]
102pub struct Notification<'a, T> {
103 pub jsonrpc: TwoPointZero,
105 #[serde(borrow)]
107 pub method: Cow<'a, str>,
108 pub params: T,
110}
111
112impl<'a, T> Notification<'a, T> {
113 pub fn new(method: Cow<'a, str>, params: T) -> Self {
115 Self { jsonrpc: TwoPointZero, method, params }
116 }
117}
118
119#[derive(Serialize, Debug, Clone)]
121pub struct RequestSer<'a> {
122 pub jsonrpc: TwoPointZero,
124 pub id: Id<'a>,
126 pub method: Cow<'a, str>,
129 #[serde(skip_serializing_if = "Option::is_none")]
131 pub params: Option<Cow<'a, RawValue>>,
132}
133
134impl<'a> RequestSer<'a> {
135 pub fn borrowed(id: &'a Id<'a>, method: &'a impl AsRef<str>, params: Option<&'a RawValue>) -> Self {
137 Self {
138 jsonrpc: TwoPointZero,
139 id: id.clone(),
140 method: method.as_ref().into(),
141 params: params.map(Cow::Borrowed),
142 }
143 }
144
145 pub fn owned(id: Id<'a>, method: impl Into<String>, params: Option<Box<RawValue>>) -> Self {
147 Self { jsonrpc: TwoPointZero, id, method: method.into().into(), params: params.map(Cow::Owned) }
148 }
149}
150
151#[derive(Serialize, Debug, Clone)]
153pub struct NotificationSer<'a> {
154 pub jsonrpc: TwoPointZero,
156 pub method: Cow<'a, str>,
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub params: Option<Cow<'a, RawValue>>,
162}
163
164impl<'a> NotificationSer<'a> {
165 pub fn borrowed(method: &'a impl AsRef<str>, params: Option<&'a RawValue>) -> Self {
167 Self { jsonrpc: TwoPointZero, method: method.as_ref().into(), params: params.map(Cow::Borrowed) }
168 }
169
170 pub fn owned(method: impl Into<String>, params: Option<Box<RawValue>>) -> Self {
172 Self { jsonrpc: TwoPointZero, method: method.into().into(), params: params.map(Cow::Owned) }
173 }
174}
175
176#[cfg(test)]
177mod test {
178 use super::{Cow, Id, InvalidRequest, Notification, NotificationSer, Request, RequestSer, TwoPointZero};
179 use serde_json::value::RawValue;
180
181 fn assert_request<'a>(request: Request<'a>, id: Id<'a>, method: &str, params: Option<&str>) {
182 assert_eq!(request.jsonrpc, TwoPointZero);
183 assert_eq!(request.id, id);
184 assert_eq!(request.method, method);
185 assert_eq!(request.params.as_ref().map(|p| RawValue::get(p)), params);
186 }
187
188 #[test]
190 fn deserialize_call() {
191 let method = "subtract";
192 let params = "[42, 23]";
193
194 let test_vector = vec![
195 (
197 r#"{"jsonrpc":"2.0", "method":"subtract", "params":[42, 23], "id":1}"#,
198 Id::Number(1),
199 Some(params),
200 method,
201 ),
202 (r#"{"jsonrpc":"2.0", "method":"subtract", "id":null}"#, Id::Null, None, method),
204 (r#"{"jsonrpc":"2.0", "method":"\"m", "id":null}"#, Id::Null, None, "\"m"),
206 ];
207
208 for (ser, id, params, method) in test_vector.into_iter() {
209 let request = serde_json::from_str(ser).unwrap();
210 assert_request(request, id, method, params);
211 }
212 }
213
214 #[test]
215 fn deserialize_call_escaped_method_name() {
216 let ser = r#"{"jsonrpc":"2.0","id":1,"method":"\"m\""}"#;
217 let req: Request = serde_json::from_str(ser).unwrap();
218 assert_request(req, Id::Number(1), "\"m\"", None);
219 }
220
221 #[test]
222 fn deserialize_valid_notif_works() {
223 let ser = r#"{"jsonrpc":"2.0","method":"say_hello","params":[]}"#;
224 let dsr: Notification<&RawValue> = serde_json::from_str(ser).unwrap();
225 assert_eq!(dsr.method, "say_hello");
226 assert_eq!(dsr.jsonrpc, TwoPointZero);
227 }
228
229 #[test]
230 fn deserialize_valid_notif_escaped_method() {
231 let ser = r#"{"jsonrpc":"2.0","method":"\"m\"","params":[]}"#;
232 let dsr: Notification<&RawValue> = serde_json::from_str(ser).unwrap();
233 assert_eq!(dsr.method, "\"m\"");
234 assert_eq!(dsr.jsonrpc, TwoPointZero);
235 }
236
237 #[test]
238 fn deserialize_call_bad_id_should_fail() {
239 let ser = r#"{"jsonrpc":"2.0","method":"say_hello","params":[],"id":{}}"#;
240 assert!(serde_json::from_str::<Request>(ser).is_err());
241 }
242
243 #[test]
244 fn deserialize_invalid_request() {
245 let s = r#"{"id":120,"method":"my_method","params":["foo", "bar"],"extra_field":[]}"#;
246 let deserialized: InvalidRequest = serde_json::from_str(s).unwrap();
247 assert_eq!(deserialized, InvalidRequest { id: Id::Number(120) });
248 }
249
250 #[test]
252 fn serialize_call() {
253 let method = "subtract";
254 let id = Id::Number(1); let params = Some(RawValue::from_string("[42,23]".into()).unwrap());
256
257 let test_vector: &[(&'static str, Option<_>, Option<_>, &'static str)] = &[
258 (
260 r#"{"jsonrpc":"2.0","id":1,"method":"subtract","params":[42,23]}"#,
261 Some(id.clone()),
262 params.clone(),
263 method,
264 ),
265 (r#"{"jsonrpc":"2.0","id":1,"method":"\"m"}"#, Some(id.clone()), None, "\"m"),
267 (r#"{"jsonrpc":"2.0","id":null,"method":"subtract","params":[42,23]}"#, None, params, method),
269 (r#"{"jsonrpc":"2.0","id":1,"method":"subtract"}"#, Some(id), None, method),
271 (r#"{"jsonrpc":"2.0","id":null,"method":"subtract"}"#, None, None, method),
273 ];
274
275 for (ser, id, params, method) in test_vector.iter().cloned() {
276 let request = serde_json::to_string(&RequestSer {
277 jsonrpc: TwoPointZero,
278 method: method.into(),
279 id: id.unwrap_or(Id::Null),
280 params: params.map(Cow::Owned),
281 })
282 .unwrap();
283
284 assert_eq!(&request, ser);
285 }
286 }
287
288 #[test]
289 fn serialize_notif() {
290 let exp = r#"{"jsonrpc":"2.0","method":"say_hello","params":["hello"]}"#;
291 let params = Some(RawValue::from_string(r#"["hello"]"#.into()).unwrap());
292 let req = NotificationSer::owned("say_hello", params);
293 let ser = serde_json::to_string(&req).unwrap();
294 assert_eq!(exp, ser);
295 }
296
297 #[test]
298 fn serialize_notif_escaped_method_name() {
299 let exp = r#"{"jsonrpc":"2.0","method":"\"method\""}"#;
300 let req = NotificationSer::owned("\"method\"", None);
301 let ser = serde_json::to_string(&req).unwrap();
302 assert_eq!(exp, ser);
303 }
304}