libp2p_core/
either.rs

1// Copyright 2017 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21use std::{
22    pin::Pin,
23    task::{Context, Poll},
24};
25
26use either::Either;
27use futures::prelude::*;
28use pin_project::pin_project;
29
30use crate::{
31    muxing::{StreamMuxer, StreamMuxerEvent},
32    transport::{DialOpts, ListenerId, Transport, TransportError, TransportEvent},
33    Multiaddr,
34};
35
36impl<A, B> StreamMuxer for future::Either<A, B>
37where
38    A: StreamMuxer,
39    B: StreamMuxer,
40{
41    type Substream = future::Either<A::Substream, B::Substream>;
42    type Error = Either<A::Error, B::Error>;
43
44    fn poll_inbound(
45        self: Pin<&mut Self>,
46        cx: &mut Context<'_>,
47    ) -> Poll<Result<Self::Substream, Self::Error>> {
48        match self.as_pin_mut() {
49            future::Either::Left(inner) => inner
50                .poll_inbound(cx)
51                .map_ok(future::Either::Left)
52                .map_err(Either::Left),
53            future::Either::Right(inner) => inner
54                .poll_inbound(cx)
55                .map_ok(future::Either::Right)
56                .map_err(Either::Right),
57        }
58    }
59
60    fn poll_outbound(
61        self: Pin<&mut Self>,
62        cx: &mut Context<'_>,
63    ) -> Poll<Result<Self::Substream, Self::Error>> {
64        match self.as_pin_mut() {
65            future::Either::Left(inner) => inner
66                .poll_outbound(cx)
67                .map_ok(future::Either::Left)
68                .map_err(Either::Left),
69            future::Either::Right(inner) => inner
70                .poll_outbound(cx)
71                .map_ok(future::Either::Right)
72                .map_err(Either::Right),
73        }
74    }
75
76    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
77        match self.as_pin_mut() {
78            future::Either::Left(inner) => inner.poll_close(cx).map_err(Either::Left),
79            future::Either::Right(inner) => inner.poll_close(cx).map_err(Either::Right),
80        }
81    }
82
83    fn poll(
84        self: Pin<&mut Self>,
85        cx: &mut Context<'_>,
86    ) -> Poll<Result<StreamMuxerEvent, Self::Error>> {
87        match self.as_pin_mut() {
88            future::Either::Left(inner) => inner.poll(cx).map_err(Either::Left),
89            future::Either::Right(inner) => inner.poll(cx).map_err(Either::Right),
90        }
91    }
92}
93
94/// Implements `Future` and dispatches all method calls to either `First` or `Second`.
95#[pin_project(project = EitherFutureProj)]
96#[derive(Debug, Copy, Clone)]
97#[must_use = "futures do nothing unless polled"]
98pub enum EitherFuture<A, B> {
99    First(#[pin] A),
100    Second(#[pin] B),
101}
102
103impl<AFuture, BFuture, AInner, BInner> Future for EitherFuture<AFuture, BFuture>
104where
105    AFuture: TryFuture<Ok = AInner>,
106    BFuture: TryFuture<Ok = BInner>,
107{
108    type Output = Result<future::Either<AInner, BInner>, Either<AFuture::Error, BFuture::Error>>;
109
110    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
111        match self.project() {
112            EitherFutureProj::First(a) => TryFuture::try_poll(a, cx)
113                .map_ok(future::Either::Left)
114                .map_err(Either::Left),
115            EitherFutureProj::Second(a) => TryFuture::try_poll(a, cx)
116                .map_ok(future::Either::Right)
117                .map_err(Either::Right),
118        }
119    }
120}
121
122impl<A, B> Transport for Either<A, B>
123where
124    B: Transport,
125    A: Transport,
126{
127    type Output = future::Either<A::Output, B::Output>;
128    type Error = Either<A::Error, B::Error>;
129    type ListenerUpgrade = EitherFuture<A::ListenerUpgrade, B::ListenerUpgrade>;
130    type Dial = EitherFuture<A::Dial, B::Dial>;
131
132    fn poll(
133        self: Pin<&mut Self>,
134        cx: &mut Context<'_>,
135    ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
136        match self.as_pin_mut() {
137            Either::Left(a) => match a.poll(cx) {
138                Poll::Pending => Poll::Pending,
139                Poll::Ready(event) => {
140                    Poll::Ready(event.map_upgrade(EitherFuture::First).map_err(Either::Left))
141                }
142            },
143            Either::Right(b) => match b.poll(cx) {
144                Poll::Pending => Poll::Pending,
145                Poll::Ready(event) => Poll::Ready(
146                    event
147                        .map_upgrade(EitherFuture::Second)
148                        .map_err(Either::Right),
149                ),
150            },
151        }
152    }
153
154    fn remove_listener(&mut self, id: ListenerId) -> bool {
155        match self {
156            Either::Left(t) => t.remove_listener(id),
157            Either::Right(t) => t.remove_listener(id),
158        }
159    }
160
161    fn listen_on(
162        &mut self,
163        id: ListenerId,
164        addr: Multiaddr,
165    ) -> Result<(), TransportError<Self::Error>> {
166        use TransportError::*;
167        match self {
168            Either::Left(a) => a.listen_on(id, addr).map_err(|e| match e {
169                MultiaddrNotSupported(addr) => MultiaddrNotSupported(addr),
170                Other(err) => Other(Either::Left(err)),
171            }),
172            Either::Right(b) => b.listen_on(id, addr).map_err(|e| match e {
173                MultiaddrNotSupported(addr) => MultiaddrNotSupported(addr),
174                Other(err) => Other(Either::Right(err)),
175            }),
176        }
177    }
178
179    fn dial(
180        &mut self,
181        addr: Multiaddr,
182        opts: DialOpts,
183    ) -> Result<Self::Dial, TransportError<Self::Error>> {
184        use TransportError::*;
185        match self {
186            Either::Left(a) => match a.dial(addr, opts) {
187                Ok(connec) => Ok(EitherFuture::First(connec)),
188                Err(MultiaddrNotSupported(addr)) => Err(MultiaddrNotSupported(addr)),
189                Err(Other(err)) => Err(Other(Either::Left(err))),
190            },
191            Either::Right(b) => match b.dial(addr, opts) {
192                Ok(connec) => Ok(EitherFuture::Second(connec)),
193                Err(MultiaddrNotSupported(addr)) => Err(MultiaddrNotSupported(addr)),
194                Err(Other(err)) => Err(Other(Either::Right(err))),
195            },
196        }
197    }
198}