ic_web3/transports/
either.rs

1//! A strongly-typed transport alternative.
2
3use crate::{api, error, rpc, BatchTransport, DuplexTransport, RequestId, Transport};
4use futures::{
5    future::{BoxFuture, FutureExt},
6    stream::{BoxStream, StreamExt},
7};
8
9/// A wrapper over two possible transports.
10///
11/// This type can be used to write semi-generic
12/// code without the hassle of making all functions generic.
13///
14/// See the `examples` folder for an example how to use it.
15#[derive(Debug, Clone)]
16pub enum Either<A, B> {
17    /// First possible transport.
18    Left(A),
19    /// Second possible transport.
20    Right(B),
21}
22
23impl<A, B, AOut, BOut> Transport for Either<A, B>
24where
25    A: Transport<Out = AOut>,
26    B: Transport<Out = BOut>,
27    AOut: futures::Future<Output = error::Result<rpc::Value>> + 'static + Send,
28    BOut: futures::Future<Output = error::Result<rpc::Value>> + 'static + Send,
29{
30    type Out = BoxFuture<'static, error::Result<rpc::Value>>;
31
32    fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (RequestId, rpc::Call) {
33        match *self {
34            Self::Left(ref a) => a.prepare(method, params),
35            Self::Right(ref b) => b.prepare(method, params),
36        }
37    }
38
39    fn send(&self, id: RequestId, request: rpc::Call) -> Self::Out {
40        match *self {
41            Self::Left(ref a) => a.send(id, request).boxed(),
42            Self::Right(ref b) => b.send(id, request).boxed(),
43        }
44    }
45}
46
47impl<A, B, ABatch, BBatch> BatchTransport for Either<A, B>
48where
49    A: BatchTransport<Batch = ABatch>,
50    B: BatchTransport<Batch = BBatch>,
51    A::Out: 'static + Send,
52    B::Out: 'static + Send,
53    ABatch: futures::Future<Output = error::Result<Vec<error::Result<rpc::Value>>>> + 'static + Send,
54    BBatch: futures::Future<Output = error::Result<Vec<error::Result<rpc::Value>>>> + 'static + Send,
55{
56    type Batch = BoxFuture<'static, error::Result<Vec<error::Result<rpc::Value>>>>;
57
58    fn send_batch<T>(&self, requests: T) -> Self::Batch
59    where
60        T: IntoIterator<Item = (RequestId, rpc::Call)>,
61    {
62        match *self {
63            Self::Left(ref a) => a.send_batch(requests).boxed(),
64            Self::Right(ref b) => b.send_batch(requests).boxed(),
65        }
66    }
67}
68
69impl<A, B, AStream, BStream> DuplexTransport for Either<A, B>
70where
71    A: DuplexTransport<NotificationStream = AStream>,
72    B: DuplexTransport<NotificationStream = BStream>,
73    A::Out: 'static + Send,
74    B::Out: 'static + Send,
75    AStream: futures::Stream<Item = rpc::Value> + 'static + Send,
76    BStream: futures::Stream<Item = rpc::Value> + 'static + Send,
77{
78    type NotificationStream = BoxStream<'static, rpc::Value>;
79
80    fn subscribe(&self, id: api::SubscriptionId) -> error::Result<Self::NotificationStream> {
81        Ok(match *self {
82            Self::Left(ref a) => a.subscribe(id)?.boxed(),
83            Self::Right(ref b) => b.subscribe(id)?.boxed(),
84        })
85    }
86
87    fn unsubscribe(&self, id: api::SubscriptionId) -> error::Result {
88        match *self {
89            Self::Left(ref a) => a.unsubscribe(id),
90            Self::Right(ref b) => b.unsubscribe(id),
91        }
92    }
93}