#![warn(missing_docs)]
extern crate arrayvec;
extern crate ethabi;
extern crate jsonrpc_core as rpc;
extern crate parking_lot;
extern crate rustc_serialize;
extern crate serde;
extern crate tokio_timer;
#[cfg_attr(test, macro_use)]
extern crate serde_json;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[macro_use]
pub extern crate futures;
#[macro_use]
pub mod helpers;
pub mod api;
pub mod contract;
pub mod transports;
pub mod types;
pub mod confirm;
use std::io;
use futures::Future;
pub use api::{Web3Main as Web3, ErasedWeb3};
pub type Result<T> = futures::BoxFuture<T, Error>;
#[derive(Debug, Clone, PartialEq)]
pub enum Error {
Unreachable,
InvalidResponse(String),
Transport(String),
Decoder(String),
Rpc(rpc::Error),
Internal,
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Error::Transport(format!("{:?}", err))
}
}
impl From<serde_json::Error> for Error {
fn from(err: serde_json::Error) -> Self {
Error::Decoder(format!("{:?}", err))
}
}
impl From<rpc::Error> for Error {
fn from(err: rpc::Error) -> Self {
Error::Rpc(err)
}
}
pub type RequestId = usize;
pub trait Transport {
type Out: futures::Future<Item=rpc::Value, Error=Error>;
fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (RequestId, rpc::Call);
fn send(&self, id: RequestId, request: rpc::Call) -> Self::Out;
fn execute(&self, method: &str, params: Vec<rpc::Value>) -> Self::Out {
let (id, request) = self.prepare(method, params);
self.send(id, request)
}
fn erase(self) -> Erased where
Self: Sized + 'static,
Self::Out: Send + 'static,
{
Erased(Box::new(Eraser(self)))
}
}
pub trait BatchTransport: Transport {
type Batch: futures::Future<Item=Vec<::std::result::Result<rpc::Value, Error>>, Error=Error>;
fn send_batch<T>(&self, requests: T) -> Self::Batch where
T: IntoIterator<Item=(RequestId, rpc::Call)>;
}
struct Eraser<T>(T);
impl<T: Transport> Transport for Eraser<T> where
T::Out: Send + 'static,
{
type Out = Result<rpc::Value>;
fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (RequestId, rpc::Call) {
self.0.prepare(method, params)
}
fn send(&self, id: RequestId, request: rpc::Call) -> Self::Out {
self.0.send(id, request).boxed()
}
}
pub struct Erased(Box<Transport<Out=Result<rpc::Value>>>);
impl Transport for Erased {
type Out = Result<rpc::Value>;
fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (RequestId, rpc::Call) {
self.0.prepare(method, params)
}
fn send(&self, id: RequestId, request: rpc::Call) -> Self::Out {
self.0.send(id, request)
}
}
impl<X, T> Transport for X where
T: Transport + ?Sized,
X: ::std::ops::Deref<Target=T>,
{
type Out = T::Out;
fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (RequestId, rpc::Call) {
(**self).prepare(method, params)
}
fn send(&self, id: RequestId, request: rpc::Call) -> Self::Out {
(**self).send(id, request)
}
}
impl<X, T> BatchTransport for X where
T: BatchTransport + ?Sized,
X: ::std::ops::Deref<Target=T>,
{
type Batch = T::Batch;
fn send_batch<I>(&self, requests: I) -> Self::Batch where
I: IntoIterator<Item=(RequestId, rpc::Call)>
{
(**self).send_batch(requests)
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use api::Web3Main;
use futures::BoxFuture;
use super::{rpc, Error, Transport, RequestId};
struct FakeTransport;
impl Transport for FakeTransport {
type Out = BoxFuture<rpc::Value, Error>;
fn prepare(&self, _method: &str, _params: Vec<rpc::Value>) -> (RequestId, rpc::Call) {
unimplemented!()
}
fn send(&self, _id: RequestId, _request: rpc::Call) -> Self::Out {
unimplemented!()
}
}
#[test]
fn should_allow_to_use_arc_as_transport() {
let transport = Arc::new(FakeTransport);
let transport2 = transport.clone();
let _web3_1 = Web3Main::new(transport);
let _web3_2 = Web3Main::new(transport2);
}
}