jsonrpc_sys/
request.rs

1use std::borrow::Cow;
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5use crate::Id;
6
7/// A JSON-RPC 2.0 request.
8#[derive(Debug, Clone)]
9pub struct Request<'a, P> {
10    /// The method to be invoked.
11    pub method: Cow<'a, str>,
12    /// The parameters to be passed to the method.
13    pub params: P,
14    /// The identifier associated with the request.
15    pub id: Option<Id<'a>>,
16}
17
18impl<'a, P> Serialize for Request<'a, P>
19where
20    P: Serialize,
21{
22    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
23    where
24        S: Serializer,
25    {
26        OutgoingRequest::from_request(self).serialize(serializer)
27    }
28}
29
30impl<'de, 'a, P> Deserialize<'de> for Request<'a, P>
31where
32    'de: 'a,
33    P: Deserialize<'de>,
34{
35    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
36    where
37        D: Deserializer<'de>,
38    {
39        IncomingRequest::deserialize(deserializer).and_then(IncomingRequest::into_request)
40    }
41}
42
43#[derive(Serialize)]
44struct OutgoingRequest<'a, P> {
45    jsonrpc: &'a str,
46    method: &'a str,
47    params: &'a P,
48    #[serde(skip_serializing_if = "Option::is_none")]
49    id: Option<crate::Id<'a>>,
50}
51
52impl<'a, P> OutgoingRequest<'a, P> {
53    fn from_request(req: &'a crate::Request<'_, P>) -> Self {
54        Self {
55            jsonrpc: "2.0",
56            method: &req.method,
57            params: &req.params,
58            id: req.id.as_ref().map(Id::reborrow),
59        }
60    }
61}
62
63#[derive(Deserialize)]
64struct IncomingRequest<'a, P> {
65    #[serde(borrow)]
66    jsonrpc: Cow<'a, str>,
67    #[serde(borrow)]
68    method: Cow<'a, str>,
69    params: P,
70    #[serde(borrow, default, deserialize_with = "deserialize_id")]
71    id: Option<crate::Id<'a>>,
72}
73
74impl<'a, P> IncomingRequest<'a, P> {
75    fn into_request<E>(self) -> Result<crate::Request<'a, P>, E>
76    where
77        E: serde::de::Error,
78        P: serde::Deserialize<'a>,
79    {
80        if self.jsonrpc != "2.0" {
81            return Err(E::invalid_value(
82                serde::de::Unexpected::Str(&self.jsonrpc),
83                &"2.0",
84            ));
85        }
86
87        Ok(crate::Request {
88            method: self.method,
89            params: self.params,
90            id: self.id,
91        })
92    }
93}
94
95/// Deserializes an `Id` from a JSON-RPC 2.0 request.
96///
97/// This deserialization function is useful to distinguish between a null id and no id
98/// specified in a request.
99fn deserialize_id<'de, D>(deserializer: D) -> Result<Option<crate::Id<'de>>, D::Error>
100where
101    D: Deserializer<'de>,
102{
103    let opt = Option::deserialize(deserializer)?;
104
105    match opt {
106        Some(some) => Ok(some),
107        None => Ok(Some(Id::Null)),
108    }
109}
110
111#[test]
112#[cfg(test)]
113fn null_id() {
114    let request = r#"{"jsonrpc":"2.0","method":"","id":null}"#;
115    let request: crate::Request<'_, Option<()>> = serde_json::from_str(request).unwrap();
116    assert_eq!(request.id, Some(Id::Null));
117}
118
119#[test]
120#[cfg(test)]
121fn no_id() {
122    let request = r#"{"jsonrpc":"2.0","method":""}"#;
123    let request: crate::Request<'_, Option<()>> = serde_json::from_str(request).unwrap();
124    assert_eq!(request.id, None);
125}