1use crate::{error, rpc, Error};
4use futures::{
5 task::{Context, Poll},
6 Future,
7};
8use pin_project::pin_project;
9use std::{marker::PhantomData, pin::Pin};
10
11pub fn decode<T: serde::de::DeserializeOwned>(value: rpc::Value) -> error::Result<T> {
14 serde_json::from_value(value).map_err(Into::into)
15}
16
17#[pin_project]
19#[derive(Debug)]
20pub struct CallFuture<T, F> {
21 #[pin]
22 inner: F,
23 _marker: PhantomData<T>,
24}
25
26impl<T, F> CallFuture<T, F> {
27 pub fn new(inner: F) -> Self {
29 CallFuture {
30 inner,
31 _marker: PhantomData,
32 }
33 }
34}
35
36impl<T, F> Future for CallFuture<T, F>
37where
38 T: serde::de::DeserializeOwned,
39 F: Future<Output = error::Result<rpc::Value>>,
40{
41 type Output = error::Result<T>;
42
43 fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
44 let this = self.project();
45 let x = ready!(this.inner.poll(ctx));
46 Poll::Ready(x.and_then(decode))
47 }
48}
49
50pub fn serialize<T: serde::Serialize>(t: &T) -> rpc::Value {
52 serde_json::to_value(t).expect("Types never fail to serialize.")
53}
54
55pub fn to_string<T: serde::Serialize>(request: &T) -> String {
57 serde_json::to_string(&request).expect("String serialization never fails.")
58}
59
60pub fn build_request(id: usize, method: &str, params: Vec<rpc::Value>) -> rpc::Call {
62 rpc::Call::MethodCall(rpc::MethodCall {
63 jsonrpc: Some(rpc::Version::V2),
64 method: method.into(),
65 params: rpc::Params::Array(params),
66 id: rpc::Id::Num(id as u64),
67 })
68}
69
70pub fn to_response_from_slice(response: &[u8]) -> error::Result<rpc::Response> {
73 if cfg!(feature = "arbitrary_precision") {
74 let val: serde_json::Value =
75 serde_json::from_slice(response).map_err(|e| Error::InvalidResponse(format!("{:?}", e)))?;
76 serde_json::from_value(val).map_err(|e| Error::InvalidResponse(format!("{:?}", e)))
77 } else {
78 serde_json::from_slice(response).map_err(|e| Error::InvalidResponse(format!("{:?}", e)))
79 }
80}
81
82pub fn to_notification_from_slice(notification: &[u8]) -> error::Result<rpc::Notification> {
84 serde_json::from_slice(notification).map_err(|e| error::Error::InvalidResponse(format!("{:?}", e)))
85}
86
87pub fn to_results_from_outputs(outputs: Vec<rpc::Output>) -> error::Result<Vec<error::Result<rpc::Value>>> {
89 Ok(outputs.into_iter().map(to_result_from_output).collect())
90}
91
92pub fn to_result_from_output(output: rpc::Output) -> error::Result<rpc::Value> {
94 match output {
95 rpc::Output::Success(success) => Ok(success.result),
96 rpc::Output::Failure(failure) => Err(error::Error::Rpc(failure.error)),
97 }
98}
99
100#[macro_use]
101#[cfg(test)]
102pub mod tests {
103 macro_rules! rpc_test {
104 (
106 $namespace: ident : $name: ident : $test_name: ident $(, $param: expr)+ => $method: expr, $results: expr;
107 $returned: expr => $expected: expr
108 ) => {
109 #[test]
110 fn $test_name() {
111 let mut transport = $crate::transports::test::TestTransport::default();
113 transport.set_response($returned);
114 let result = {
115 let eth = $namespace::new(&transport);
116
117 eth.$name($($param.into(), )+)
119 };
120
121 transport.assert_request($method, &$results.into_iter().map(Into::into).collect::<Vec<_>>());
123 transport.assert_no_more_requests();
124 let result = futures::executor::block_on(result);
125 assert_eq!(result, Ok($expected.into()));
126 }
127 };
128 (
130 $namespace: ident : $name: ident $(, $param: expr)+ => $method: expr, $results: expr;
131 $returned: expr => $expected: expr
132 ) => {
133 rpc_test! (
134 $namespace : $name : $name $(, $param)+ => $method, $results;
135 $returned => $expected
136 );
137 };
138
139 (
141 $namespace: ident: $name: ident: $test_name: ident => $method: expr;
142 $returned: expr => $expected: expr
143 ) => {
144 #[test]
145 fn $test_name() {
146 let mut transport = $crate::transports::test::TestTransport::default();
148 transport.set_response($returned);
149 let result = {
150 let eth = $namespace::new(&transport);
151
152 eth.$name()
154 };
155
156 transport.assert_request($method, &[]);
158 transport.assert_no_more_requests();
159 let result = futures::executor::block_on(result);
160 assert_eq!(result, Ok($expected.into()));
161 }
162 };
163
164 (
166 $namespace: ident: $name: ident => $method: expr;
167 $returned: expr => $expected: expr
168 ) => {
169 rpc_test! (
170 $namespace: $name: $name => $method;
171 $returned => $expected
172 );
173 }
174 }
175}