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 crate::muxing::StreamMuxerEvent;
22use crate::transport::DialOpts;
23use crate::{
24    muxing::StreamMuxer,
25    transport::{ListenerId, Transport, TransportError, TransportEvent},
26    Multiaddr,
27};
28use either::Either;
29use futures::prelude::*;
30use pin_project::pin_project;
31use std::{pin::Pin, task::Context, task::Poll};
32
33impl<A, B> StreamMuxer for future::Either<A, B>
34where
35    A: StreamMuxer,
36    B: StreamMuxer,
37{
38    type Substream = future::Either<A::Substream, B::Substream>;
39    type Error = Either<A::Error, B::Error>;
40
41    fn poll_inbound(
42        self: Pin<&mut Self>,
43        cx: &mut Context<'_>,
44    ) -> Poll<Result<Self::Substream, Self::Error>> {
45        match self.as_pin_mut() {
46            future::Either::Left(inner) => inner
47                .poll_inbound(cx)
48                .map_ok(future::Either::Left)
49                .map_err(Either::Left),
50            future::Either::Right(inner) => inner
51                .poll_inbound(cx)
52                .map_ok(future::Either::Right)
53                .map_err(Either::Right),
54        }
55    }
56
57    fn poll_outbound(
58        self: Pin<&mut Self>,
59        cx: &mut Context<'_>,
60    ) -> Poll<Result<Self::Substream, Self::Error>> {
61        match self.as_pin_mut() {
62            future::Either::Left(inner) => inner
63                .poll_outbound(cx)
64                .map_ok(future::Either::Left)
65                .map_err(Either::Left),
66            future::Either::Right(inner) => inner
67                .poll_outbound(cx)
68                .map_ok(future::Either::Right)
69                .map_err(Either::Right),
70        }
71    }
72
73    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
74        match self.as_pin_mut() {
75            future::Either::Left(inner) => inner.poll_close(cx).map_err(Either::Left),
76            future::Either::Right(inner) => inner.poll_close(cx).map_err(Either::Right),
77        }
78    }
79
80    fn poll(
81        self: Pin<&mut Self>,
82        cx: &mut Context<'_>,
83    ) -> Poll<Result<StreamMuxerEvent, Self::Error>> {
84        match self.as_pin_mut() {
85            future::Either::Left(inner) => inner.poll(cx).map_err(Either::Left),
86            future::Either::Right(inner) => inner.poll(cx).map_err(Either::Right),
87        }
88    }
89}
90
91/// Implements `Future` and dispatches all method calls to either `First` or `Second`.
92#[pin_project(project = EitherFutureProj)]
93#[derive(Debug, Copy, Clone)]
94#[must_use = "futures do nothing unless polled"]
95pub enum EitherFuture<A, B> {
96    First(#[pin] A),
97    Second(#[pin] B),
98}
99
100impl<AFuture, BFuture, AInner, BInner> Future for EitherFuture<AFuture, BFuture>
101where
102    AFuture: TryFuture<Ok = AInner>,
103    BFuture: TryFuture<Ok = BInner>,
104{
105    type Output = Result<future::Either<AInner, BInner>, Either<AFuture::Error, BFuture::Error>>;
106
107    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
108        match self.project() {
109            EitherFutureProj::First(a) => TryFuture::try_poll(a, cx)
110                .map_ok(future::Either::Left)
111                .map_err(Either::Left),
112            EitherFutureProj::Second(a) => TryFuture::try_poll(a, cx)
113                .map_ok(future::Either::Right)
114                .map_err(Either::Right),
115        }
116    }
117}
118
119impl<A, B> Transport for Either<A, B>
120where
121    B: Transport,
122    A: Transport,
123{
124    type Output = future::Either<A::Output, B::Output>;
125    type Error = Either<A::Error, B::Error>;
126    type ListenerUpgrade = EitherFuture<A::ListenerUpgrade, B::ListenerUpgrade>;
127    type Dial = EitherFuture<A::Dial, B::Dial>;
128
129    fn poll(
130        self: Pin<&mut Self>,
131        cx: &mut Context<'_>,
132    ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
133        match self.as_pin_mut() {
134            Either::Left(a) => match a.poll(cx) {
135                Poll::Pending => Poll::Pending,
136                Poll::Ready(event) => {
137                    Poll::Ready(event.map_upgrade(EitherFuture::First).map_err(Either::Left))
138                }
139            },
140            Either::Right(b) => match b.poll(cx) {
141                Poll::Pending => Poll::Pending,
142                Poll::Ready(event) => Poll::Ready(
143                    event
144                        .map_upgrade(EitherFuture::Second)
145                        .map_err(Either::Right),
146                ),
147            },
148        }
149    }
150
151    fn remove_listener(&mut self, id: ListenerId) -> bool {
152        match self {
153            Either::Left(t) => t.remove_listener(id),
154            Either::Right(t) => t.remove_listener(id),
155        }
156    }
157
158    fn listen_on(
159        &mut self,
160        id: ListenerId,
161        addr: Multiaddr,
162    ) -> Result<(), TransportError<Self::Error>> {
163        use TransportError::*;
164        match self {
165            Either::Left(a) => a.listen_on(id, addr).map_err(|e| match e {
166                MultiaddrNotSupported(addr) => MultiaddrNotSupported(addr),
167                Other(err) => Other(Either::Left(err)),
168            }),
169            Either::Right(b) => b.listen_on(id, addr).map_err(|e| match e {
170                MultiaddrNotSupported(addr) => MultiaddrNotSupported(addr),
171                Other(err) => Other(Either::Right(err)),
172            }),
173        }
174    }
175
176    fn dial(
177        &mut self,
178        addr: Multiaddr,
179        opts: DialOpts,
180    ) -> Result<Self::Dial, TransportError<Self::Error>> {
181        use TransportError::*;
182        match self {
183            Either::Left(a) => match a.dial(addr, opts) {
184                Ok(connec) => Ok(EitherFuture::First(connec)),
185                Err(MultiaddrNotSupported(addr)) => Err(MultiaddrNotSupported(addr)),
186                Err(Other(err)) => Err(Other(Either::Left(err))),
187            },
188            Either::Right(b) => match b.dial(addr, opts) {
189                Ok(connec) => Ok(EitherFuture::Second(connec)),
190                Err(MultiaddrNotSupported(addr)) => Err(MultiaddrNotSupported(addr)),
191                Err(Other(err)) => Err(Other(Either::Right(err))),
192            },
193        }
194    }
195}