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