1use core::{
2 marker::PhantomData,
3 mem,
4 sync::atomic::{AtomicU32, Ordering},
5};
6
7use serde::{Deserialize, Serialize};
8
9use crate::{dataformat, request::Request, response::Response, RpcError, RpcErrorKind, RpcResult};
10
11#[allow(clippy::module_name_repetitions)]
12#[derive(Default)]
13pub struct RpcClient<'a, D, M, R> {
15 _phantom_d: PhantomData<D>,
16 _phantom_a: PhantomData<&'a ()>,
17 _phantom_m: PhantomData<M>,
18 _phantom_r: PhantomData<R>,
19 request_id: AtomicU32,
20}
21
22impl<'a, D, M, R> RpcClient<'a, D, M, R>
23where
24 D: dataformat::DataFormat,
25 M: Serialize + Deserialize<'a>,
26 R: Serialize + Deserialize<'a>,
27{
28 pub fn new() -> Self {
30 Self {
31 _phantom_d: PhantomData,
32 _phantom_a: PhantomData,
33 _phantom_m: PhantomData,
34 _phantom_r: PhantomData,
35 request_id: AtomicU32::new(0),
36 }
37 }
38 pub fn request(&self, method: M) -> Result<RpcClientRequest<D, M, R>, D::PackError> {
40 let id = self.request_id.fetch_add(1, Ordering::SeqCst);
41 let req = Request::new(id.into(), method);
42 let payload = D::pack(&req)?;
43 Ok(RpcClientRequest::new(Some(id), payload))
44 }
45 pub fn request0(&self, method: M) -> Result<RpcClientRequest<D, M, R>, D::PackError> {
47 let req = Request::new0(method);
48 let payload = D::pack(&req)?;
49 Ok(RpcClientRequest::new(None, payload))
50 }
51}
52
53pub struct RpcClientRequest<D, M, R> {
55 id: Option<u32>,
56 payload: Vec<u8>,
57 phantom_d: core::marker::PhantomData<D>,
58 phantom_m: core::marker::PhantomData<M>,
59 phantom_r: core::marker::PhantomData<R>,
60}
61
62impl<'a, D, M, R> RpcClientRequest<D, M, R>
63where
64 D: dataformat::DataFormat,
65 M: Serialize + Deserialize<'a>,
66 R: Serialize + Deserialize<'a>,
67{
68 pub fn new(id: Option<u32>, payload: Vec<u8>) -> Self {
70 Self {
71 id,
72 payload,
73 phantom_d: core::marker::PhantomData,
74 phantom_m: core::marker::PhantomData,
75 phantom_r: core::marker::PhantomData,
76 }
77 }
78 pub fn payload(&self) -> &[u8] {
80 &self.payload
81 }
82 pub fn take_payload(&mut self) -> Vec<u8> {
84 mem::take(&mut self.payload)
85 }
86 pub fn handle_response(&self, response_payload: &'a [u8]) -> RpcResult<R> {
88 let Some(id) = self.id else {
89 return Err(RpcError {
90 kind: RpcErrorKind::InvalidRequest,
91 message: Some("request ID is missing".to_owned()),
92 });
93 };
94 match D::unpack::<Response<R>>(response_payload) {
95 Ok(r) => {
96 let (res_id, res) = r.into_parts();
97 if res_id != id {
98 return Err(RpcError {
99 kind: RpcErrorKind::InvalidRequest,
100 message: Some("response ID does not match request ID".to_owned()),
101 });
102 }
103 res.into()
104 }
105 Err(e) => Err(RpcError {
106 kind: RpcErrorKind::ParseError,
107 message: Some(e.to_string()),
108 }),
109 }
110 }
111}