Skip to content

Commit

Permalink
Implement EitherTransport (#297)
Browse files Browse the repository at this point in the history
* Implement EitherTransport

* Fix formatting.
  • Loading branch information
tomusdrw committed Dec 11, 2019
1 parent 91180b7 commit 897fcfd
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 0 deletions.
23 changes: 23 additions & 0 deletions examples/either_transport.rs
@@ -0,0 +1,23 @@
extern crate web3;

use web3::futures::Future;

pub type Transport = web3::EitherTransport<web3::transports::Ipc, web3::transports::Http>;

fn main() {
let (_el, transport) = web3::transports::Ipc::new("./jsonrpc.ipc").unwrap();

run(web3::EitherTransport::Left(transport));
}

fn run(transport: Transport) {
let web3 = web3::Web3::new(transport);

println!("Calling accounts.");
let accounts = web3.eth().accounts().wait().unwrap();
println!("Accounts: {:?}", accounts);

println!("Calling balance.");
let balance = web3.eth().balance("0x0".parse().unwrap(), None).wait().unwrap();
println!("Balance: {}", balance);
}
86 changes: 86 additions & 0 deletions src/lib.rs
Expand Up @@ -131,6 +131,92 @@ where
}
}

/// A wrapper over two possible transports.
///
/// This type can be used to write semi-generic
/// code without the hassle of making all functions generic.
///
/// See the `examples` folder for an example how to use it.
#[derive(Debug, Clone)]
pub enum EitherTransport<A, B> {
/// First possible transport.
Left(A),
/// Second possible transport.
Right(B),
}

impl<A, B, AOut, BOut> Transport for EitherTransport<A, B>
where
A: Transport<Out = AOut>,
B: Transport<Out = BOut>,
AOut: futures::Future<Item = rpc::Value, Error = Error> + 'static,
BOut: futures::Future<Item = rpc::Value, Error = Error> + 'static,
{
type Out = Box<dyn futures::Future<Item = rpc::Value, Error = Error>>;

fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (RequestId, rpc::Call) {
match *self {
Self::Left(ref a) => a.prepare(method, params),
Self::Right(ref b) => b.prepare(method, params),
}
}

fn send(&self, id: RequestId, request: rpc::Call) -> Self::Out {
match *self {
Self::Left(ref a) => Box::new(a.send(id, request)),
Self::Right(ref b) => Box::new(b.send(id, request)),
}
}
}

impl<A, B, ABatch, BBatch> BatchTransport for EitherTransport<A, B>
where
A: BatchTransport<Batch = ABatch>,
B: BatchTransport<Batch = BBatch>,
A::Out: 'static,
B::Out: 'static,
ABatch: futures::Future<Item = Vec<::std::result::Result<rpc::Value, Error>>, Error = Error> + 'static,
BBatch: futures::Future<Item = Vec<::std::result::Result<rpc::Value, Error>>, Error = Error> + 'static,
{
type Batch = Box<dyn 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)>,
{
match *self {
Self::Left(ref a) => Box::new(a.send_batch(requests)),
Self::Right(ref b) => Box::new(b.send_batch(requests)),
}
}
}

impl<A, B, AStream, BStream> DuplexTransport for EitherTransport<A, B>
where
A: DuplexTransport<NotificationStream = AStream>,
B: DuplexTransport<NotificationStream = BStream>,
A::Out: 'static,
B::Out: 'static,
AStream: futures::Stream<Item = rpc::Value, Error = Error> + 'static,
BStream: futures::Stream<Item = rpc::Value, Error = Error> + 'static,
{
type NotificationStream = Box<dyn futures::Stream<Item = rpc::Value, Error = Error>>;

fn subscribe(&self, id: &api::SubscriptionId) -> Self::NotificationStream {
match *self {
Self::Left(ref a) => Box::new(a.subscribe(id)),
Self::Right(ref b) => Box::new(b.subscribe(id)),
}
}

fn unsubscribe(&self, id: &api::SubscriptionId) {
match *self {
Self::Left(ref a) => a.unsubscribe(id),
Self::Right(ref b) => b.unsubscribe(id),
}
}
}

#[cfg(test)]
mod tests {
use super::{rpc, Error, RequestId, Transport};
Expand Down

0 comments on commit 897fcfd

Please sign in to comment.