lsp_primitives/
json_rpc_erased.rs

1/// The json-rpc implementation used in json_rpc is strongly typed and heavily
2/// relies on Generics. In Rust all the required types are created at compile type.
3///
4/// This is, Vec<u8> and Vec<u32> are considered 2 different types.
5///
6/// When creating language bindings we must either
7/// - explicitly implement ffi for every type.
8/// - use a trait that erases tye type. In this case we replace the type by Vec<u8>. This byte-array can be parsed by the foreign language
9///
10/// If you are a rust-developer you probably want to use the json_rpc-module directly
11/// If you are building a foreign function interface you probably want to use the type-erased version
12///
13/// The JsonRpcMethodErased wraps the JsonRpcMethod and allows you to interface using Vec<u8>.
14/// Under the hood, the underlying type will be used. But the error will be raised at run-time and
15/// not at compile-time.
16///
17/// The JsonRpcMethodErased method
18/// - does not do strict type-checking at compile-time
19/// - comes at a small runtime cost (requires Box, serializes and deserializes some objects twice, unwrapping results)
20/// - comes at a small dev-cost for requiring a bit more error-handling
21///
22/// For library-authors the JsonRpcMethodUnerased is probably most suitable.
23/// When JsonRpcMethodUnerased is used your user can decide which abstraction they want to use.
24use crate::json_rpc::{
25    ErrorData, JsonRpcId, JsonRpcMethod, JsonRpcRequest, JsonRpcResponse, JsonRpcResponseFailure,
26    JsonRpcResponseSuccess,
27};
28use serde::Serialize;
29
30pub type JsonRpcRequestErased = JsonRpcRequest<Vec<u8>>;
31pub type JsonRpcResponseErased = JsonRpcResponse<Vec<u8>, Vec<u8>>;
32pub type JsonRpcResponseSuccessErased = JsonRpcResponseSuccess<Vec<u8>>;
33pub type JsonRpcResponseFailureErased = JsonRpcResponseFailure<Vec<u8>>;
34pub type JsonRpcErrorDataErased = ErrorData<Vec<u8>>;
35
36pub trait JsonRpcMethodErased<'a> {
37    fn name(&'a self) -> &'a str;
38
39    fn create_request(
40        &self,
41        params: Vec<u8>,
42        json_rpc_id: JsonRpcId,
43    ) -> Result<JsonRpcRequestErased, serde_json::Error>;
44
45    fn parse_json_response_str(
46        &self,
47        json_str: &str,
48    ) -> Result<JsonRpcResponseErased, serde_json::Error>;
49
50    fn parse_json_response_value(
51        &self,
52        json_str: serde_json::Value,
53    ) -> Result<JsonRpcResponseErased, serde_json::Error>;
54}
55
56impl<'a, I, O, E> JsonRpcMethodErased<'a> for JsonRpcMethod<'_, I, O, E>
57where
58    I: serde::de::DeserializeOwned + Serialize,
59    O: serde::de::DeserializeOwned + Serialize,
60    E: serde::de::DeserializeOwned + Serialize,
61{
62    fn name(&'a self) -> &str {
63        self.method
64    }
65
66    fn create_request(
67        &self,
68        params: Vec<u8>,
69        json_rpc_id: JsonRpcId,
70    ) -> Result<JsonRpcRequestErased, serde_json::Error> {
71        let typed_params: I = serde_json::from_slice(&params)?;
72        JsonRpcMethod::create_request(self, typed_params, json_rpc_id).erase()
73    }
74
75    fn parse_json_response_str(
76        &self,
77        json_str: &str,
78    ) -> Result<JsonRpcResponseErased, serde_json::Error> {
79        // Check if the json-struct matches the expected type
80        JsonRpcMethod::<I, O, E>::parse_json_response_str(self, json_str)?.erase()
81    }
82
83    fn parse_json_response_value(
84        &self,
85        json_value: serde_json::Value,
86    ) -> Result<JsonRpcResponseErased, serde_json::Error> {
87        JsonRpcMethod::<I, O, E>::parse_json_response_value(self, json_value)?.erase()
88    }
89}
90
91impl<I, O, E> JsonRpcMethod<'static, I, O, E>
92where
93    I: serde::de::DeserializeOwned + Serialize + 'static,
94    O: serde::de::DeserializeOwned + Serialize + 'static,
95    E: serde::de::DeserializeOwned + Serialize + 'static,
96{
97    pub fn erase_box(self) -> Box<dyn JsonRpcMethodErased<'static>> {
98        Box::new(self)
99    }
100
101    pub fn ref_erase(&self) -> &dyn JsonRpcMethodErased {
102        self
103    }
104}
105
106/// The trait JsonRpcUnerased is only intended to be used by library developers
107///
108/// The user of this library might want to use the strongly typed generic version
109/// or the fully type-erased version
110///
111/// As a library developer, we don't want to implement the same functionality twice
112/// for the same RPC-call.
113///
114/// That is why we introduce the JsonRpcUnerased trait.
115/// It fills in the serde_json::Value type wherever either I, O or E should be.
116///
117/// By using this trait, functionality will work for both type of users
118
119pub trait JsonRpcMethodUnerased<'a, I, O, E> {
120    fn name(&self) -> &str;
121
122    fn create_request(
123        &self,
124        params: I,
125        json_rpc_id: JsonRpcId,
126    ) -> Result<JsonRpcRequest<I>, serde_json::Error>;
127
128    fn parse_json_response_str(
129        &self,
130        json_str: &str,
131    ) -> Result<JsonRpcResponse<O, E>, serde_json::Error>;
132
133    fn parse_json_response_value(
134        &self,
135        json_value: serde_json::Value,
136    ) -> Result<JsonRpcResponse<O, E>, serde_json::Error>;
137}
138
139/// Dummy implementation for when the user uses the generic api
140impl<'a, I, O, E> JsonRpcMethodUnerased<'a, I, O, E> for JsonRpcMethod<'a, I, O, E>
141where
142    O: serde::de::DeserializeOwned,
143    E: serde::de::DeserializeOwned,
144{
145    fn name(&self) -> &str {
146        JsonRpcMethod::name(self)
147    }
148
149    fn create_request(
150        &self,
151        params: I,
152        json_rpc_id: JsonRpcId,
153    ) -> Result<JsonRpcRequest<I>, serde_json::Error> {
154        Ok(JsonRpcMethod::create_request(self, params, json_rpc_id))
155    }
156
157    fn parse_json_response_str(
158        &self,
159        json_str: &str,
160    ) -> Result<JsonRpcResponse<O, E>, serde_json::Error> {
161        JsonRpcMethod::parse_json_response_str(self, json_str)
162    }
163
164    fn parse_json_response_value(
165        &self,
166        json_value: serde_json::Value,
167    ) -> Result<JsonRpcResponse<O, E>, serde_json::Error> {
168        JsonRpcMethod::parse_json_response_value(self, json_value)
169    }
170}
171
172struct UneraseWrapper<'a> {
173    inner: &'a dyn JsonRpcMethodErased<'a>,
174}
175
176impl<'a> JsonRpcMethodUnerased<'a, Vec<u8>, Vec<u8>, Vec<u8>> for UneraseWrapper<'a> {
177    fn name(&self) -> &str {
178        self.inner.name()
179    }
180
181    fn create_request(
182        &self,
183        params: Vec<u8>,
184        json_rpc_id: JsonRpcId,
185    ) -> Result<JsonRpcRequestErased, serde_json::Error> {
186        self.inner.create_request(params, json_rpc_id)
187    }
188
189    fn parse_json_response_str(
190        &self,
191        json_str: &str,
192    ) -> Result<JsonRpcResponseErased, serde_json::Error> {
193        self.inner.parse_json_response_str(json_str)
194    }
195
196    fn parse_json_response_value(
197        &self,
198        json_value: serde_json::Value,
199    ) -> Result<JsonRpcResponseErased, serde_json::Error> {
200        self.inner.parse_json_response_value(json_value)
201    }
202}
203
204impl<'a> dyn JsonRpcMethodErased<'a> {
205    // The impl promises here we return a concrete type
206    // However, we'd rather keep the implementation details private in this module and don't want users messing with it
207    pub fn unerase(&'a self) -> impl JsonRpcMethodUnerased<Vec<u8>, Vec<u8>, Vec<u8>> {
208        UneraseWrapper::<'a> { inner: self }
209    }
210}
211
212impl<I> JsonRpcRequest<I>
213where
214    I: Serialize,
215{
216    fn erase(self) -> Result<JsonRpcRequestErased, serde_json::Error> {
217        let value = serde_json::to_vec(&self.params)?;
218        Ok(JsonRpcRequest {
219            jsonrpc: self.jsonrpc,
220            id: self.id,
221            method: self.method,
222            params: value,
223        })
224    }
225}
226
227impl<O> JsonRpcResponseSuccess<O>
228where
229    O: Serialize,
230{
231    fn erase(self) -> Result<JsonRpcResponseSuccessErased, serde_json::Error> {
232        Ok(JsonRpcResponseSuccessErased {
233            id: self.id,
234            result: serde_json::to_vec(&self.result)?,
235            jsonrpc: self.jsonrpc,
236        })
237    }
238}
239
240impl<E> JsonRpcResponseFailure<E>
241where
242    E: Serialize,
243{
244    fn erase(self) -> Result<JsonRpcResponseFailureErased, serde_json::Error> {
245        Ok(JsonRpcResponseFailureErased {
246            id: self.id,
247            error: self.error.erase()?,
248            jsonrpc: self.jsonrpc,
249        })
250    }
251}
252
253impl<E> ErrorData<E>
254where
255    E: Serialize,
256{
257    fn erase(self) -> Result<JsonRpcErrorDataErased, serde_json::Error> {
258        let error_data = if let Some(error) = &self.data {
259            Some(serde_json::to_vec(error)?)
260        } else {
261            None
262        };
263
264        let x = JsonRpcErrorDataErased {
265            code: self.code,
266            data: error_data,
267            message: self.message,
268        };
269
270        Ok(x)
271    }
272}
273
274impl<O, E> JsonRpcResponse<O, E>
275where
276    O: Serialize,
277    E: Serialize,
278{
279    fn erase(self) -> Result<JsonRpcResponseErased, serde_json::Error> {
280        let result = match self {
281            Self::Ok(ok) => JsonRpcResponseErased::Ok(ok.erase()?),
282            Self::Error(err) => JsonRpcResponseErased::Error(err.erase()?),
283        };
284
285        Ok(result)
286    }
287}
288
289#[cfg(test)]
290mod test {
291    use super::*;
292    use crate::json_rpc::{generate_random_rpc_id, DefaultError, JsonRpcMethod};
293
294    #[derive(Serialize, serde::Deserialize)]
295    struct TestRequestStruct {
296        test: String,
297    }
298
299    #[derive(Serialize, serde::Deserialize)]
300    struct TestResponseStruct {
301        response: String,
302    }
303
304    #[test]
305    fn create_rpc_request_from_method_erased() {
306        let rpc_method = JsonRpcMethod::<TestRequestStruct, (), DefaultError>::new("test.method");
307        let rpc_method_erased = rpc_method.erase_box();
308
309        // This rpc-request should work because the parameters match the schema
310        let json_data = serde_json::json!({"test" : "This should work"});
311        let vec_data: Vec<u8> = serde_json::to_vec(&json_data).unwrap();
312
313        let json_rpc_id = generate_random_rpc_id();
314        let rpc_request: JsonRpcRequest<Vec<u8>> = rpc_method_erased
315            .create_request(vec_data, json_rpc_id)
316            .unwrap();
317        assert_eq!(rpc_request.method, "test.method");
318    }
319
320    #[test]
321    fn create_rpc_request_from_method_erased_checks_types() {
322        let rpc_method = JsonRpcMethod::<TestRequestStruct, (), DefaultError>::new("test.method");
323        let rpc_method_erased = rpc_method.erase_box();
324
325        // This rpc-request should fail because the parameters do not match the schema
326        // The test field is missing
327        let param_vec = serde_json::to_vec(&serde_json::json!({})).unwrap();
328        let json_rpc_id = generate_random_rpc_id();
329        let rpc_request = rpc_method_erased.create_request(param_vec, json_rpc_id);
330        assert!(rpc_request.is_err());
331    }
332
333    #[test]
334    fn parse_rpc_request_from_method_erased() {
335        let rpc_method = JsonRpcMethod::<TestRequestStruct, TestResponseStruct, DefaultError>::new(
336            "test.method",
337        );
338        let rpc_method_erased = rpc_method.erase_box();
339
340        let json_value = serde_json::json!({
341            "jsonrpc" : "2.0",
342            "id" : "abcdef",
343            "result" : {"response" : "content"}
344        });
345
346        rpc_method_erased
347            .parse_json_response_value(json_value)
348            .unwrap();
349    }
350
351    #[test]
352    fn parse_rpc_request_from_method_erased_fails() {
353        let rpc_method = JsonRpcMethod::<TestRequestStruct, TestResponseStruct, DefaultError>::new(
354            "test.method",
355        );
356        let rpc_method_erased = rpc_method.erase_box();
357
358        let json_value = serde_json::json!({
359            "jsonrpd" : "2.0", // See the typo-here
360            "id" : "abcdef",
361            "result" : {"response" : "content"}
362        });
363
364        let result: Result<JsonRpcResponseErased, serde_json::Error> =
365            rpc_method_erased.parse_json_response_value(json_value);
366        assert!(result.is_err());
367
368        // TODO: improve the error-message here
369        // It currently gives a vague error-message about not matching one of the enum scenarios in JsonRpcResponse
370        // It should at least mention that the field jsonrpc is missing
371        //assert!(format!("{:?}", result).contains("jsonrpc"));
372    }
373}