diff --git a/example/examples/echo-dialer.rs b/example/examples/echo-dialer.rs
index 8cbbd0f3..fb4e8854 100644
--- a/example/examples/echo-dialer.rs
+++ b/example/examples/echo-dialer.rs
@@ -32,7 +32,8 @@ extern crate tokio_io;
use futures::{Future, Sink, Stream};
use futures::sync::oneshot;
use std::env;
-use swarm::{DeniedConnectionUpgrade, SimpleProtocol, Transport, UpgradeExt};
+use swarm::Transport;
+use swarm::upgrade::{self, DeniedConnectionUpgrade, SimpleProtocol, UpgradeExt};
use tcp::TcpConfig;
use tokio_core::reactor::Core;
use tokio_io::AsyncRead;
@@ -62,7 +63,7 @@ fn main() {
// On top of TCP/IP, we will use either the plaintext protocol or the secio protocol,
// depending on which one the remote supports.
.with_upgrade({
- let plain_text = swarm::PlainTextConfig;
+ let plain_text = upgrade::PlainTextConfig;
let secio = {
let private_key = include_bytes!("test-private-key.pk8");
diff --git a/example/examples/echo-server.rs b/example/examples/echo-server.rs
index aa0fca83..4c11f66f 100644
--- a/example/examples/echo-server.rs
+++ b/example/examples/echo-server.rs
@@ -32,7 +32,8 @@ extern crate tokio_io;
use futures::future::{loop_fn, Future, IntoFuture, Loop};
use futures::{Sink, Stream};
use std::env;
-use swarm::{SimpleProtocol, Transport, UpgradeExt};
+use swarm::Transport;
+use swarm::upgrade::{self, SimpleProtocol, UpgradeExt};
use tcp::TcpConfig;
use tokio_core::reactor::Core;
use tokio_io::AsyncRead;
@@ -61,7 +62,7 @@ fn main() {
// On top of TCP/IP, we will use either the plaintext protocol or the secio protocol,
// depending on which one the remote supports.
.with_upgrade({
- let plain_text = swarm::PlainTextConfig;
+ let plain_text = upgrade::PlainTextConfig;
let secio = {
let private_key = include_bytes!("test-private-key.pk8");
diff --git a/example/examples/floodsub.rs b/example/examples/floodsub.rs
index 3da19aa2..54edd4fc 100644
--- a/example/examples/floodsub.rs
+++ b/example/examples/floodsub.rs
@@ -37,7 +37,8 @@ use futures::future::Future;
use futures::Stream;
use peerstore::PeerId;
use std::{env, mem};
-use swarm::{Multiaddr, Transport, UpgradeExt};
+use swarm::{Multiaddr, Transport};
+use swarm::upgrade::{self, UpgradeExt};
use tcp::TcpConfig;
use tokio_core::reactor::Core;
use websocket::WsConfig;
@@ -64,7 +65,7 @@ fn main() {
// On top of TCP/IP, we will use either the plaintext protocol or the secio protocol,
// depending on which one the remote supports.
.with_upgrade({
- let plain_text = swarm::PlainTextConfig;
+ let plain_text = upgrade::PlainTextConfig;
let secio = {
let private_key = include_bytes!("test-private-key.pk8");
diff --git a/example/examples/kademlia.rs b/example/examples/kademlia.rs
index cfb3b763..6ed14742 100644
--- a/example/examples/kademlia.rs
+++ b/example/examples/kademlia.rs
@@ -39,7 +39,8 @@ use peerstore::PeerId;
use std::env;
use std::sync::Arc;
use std::time::Duration;
-use swarm::{Transport, UpgradeExt};
+use swarm::Transport;
+use swarm::upgrade::{self, UpgradeExt};
use tcp::TcpConfig;
use tokio_core::reactor::Core;
@@ -69,7 +70,7 @@ fn main() {
// On top of TCP/IP, we will use either the plaintext protocol or the secio protocol,
// depending on which one the remote supports.
.with_upgrade({
- let plain_text = swarm::PlainTextConfig;
+ let plain_text = upgrade::PlainTextConfig;
let secio = {
let private_key = include_bytes!("test-private-key.pk8");
diff --git a/example/examples/ping-client.rs b/example/examples/ping-client.rs
index 2a721408..5e7a5abc 100644
--- a/example/examples/ping-client.rs
+++ b/example/examples/ping-client.rs
@@ -32,7 +32,8 @@ extern crate tokio_io;
use futures::Future;
use futures::sync::oneshot;
use std::env;
-use swarm::{DeniedConnectionUpgrade, Transport, UpgradeExt};
+use swarm::Transport;
+use swarm::upgrade::{self, DeniedConnectionUpgrade, UpgradeExt};
use tcp::TcpConfig;
use tokio_core::reactor::Core;
@@ -54,7 +55,7 @@ fn main() {
// On top of TCP/IP, we will use either the plaintext protocol or the secio protocol,
// depending on which one the remote supports.
.with_upgrade({
- let plain_text = swarm::PlainTextConfig;
+ let plain_text = upgrade::PlainTextConfig;
let secio = {
let private_key = include_bytes!("test-private-key.pk8");
diff --git a/ping/src/lib.rs b/ping/src/lib.rs
index daea084e..4b6daf5b 100644
--- a/ping/src/lib.rs
+++ b/ping/src/lib.rs
@@ -92,8 +92,7 @@ use bytes::{BufMut, Bytes, BytesMut};
use futures::{Future, Sink, Stream};
use futures::future::{loop_fn, FutureResult, IntoFuture, Loop};
use futures::sync::{mpsc, oneshot};
-use libp2p_swarm::Multiaddr;
-use libp2p_swarm::transport::{ConnectionUpgrade, Endpoint};
+use libp2p_swarm::{ConnectionUpgrade, Endpoint, Multiaddr};
use log::Level;
use parking_lot::Mutex;
use rand::Rand;
@@ -310,7 +309,7 @@ mod tests {
use futures::future::join_all;
use futures::Future;
use futures::Stream;
- use libp2p_swarm::transport::{ConnectionUpgrade, Endpoint};
+ use libp2p_swarm::{ConnectionUpgrade, Endpoint};
#[test]
fn ping_pong() {
diff --git a/swarm/src/connection_reuse.rs b/swarm/src/connection_reuse.rs
index b3e822ee..a771257e 100644
--- a/swarm/src/connection_reuse.rs
+++ b/swarm/src/connection_reuse.rs
@@ -50,7 +50,8 @@ use muxing::StreamMuxer;
use parking_lot::Mutex;
use std::io::Error as IoError;
use std::sync::Arc;
-use transport::{ConnectionUpgrade, MuxedTransport, Transport, UpgradedNode};
+use transport::{MuxedTransport, Transport, UpgradedNode};
+use upgrade::ConnectionUpgrade;
/// Allows reusing the same muxed connection multiple times.
///
diff --git a/swarm/src/either.rs b/swarm/src/either.rs
new file mode 100644
index 00000000..e143b368
--- /dev/null
+++ b/swarm/src/either.rs
@@ -0,0 +1,216 @@
+// Copyright 2017 Parity Technologies (UK) Ltd.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+use futures::prelude::*;
+use multiaddr::Multiaddr;
+use muxing::StreamMuxer;
+use std::io::{Error as IoError, Read, Write};
+use tokio_io::{AsyncRead, AsyncWrite};
+
+/// Implements `AsyncRead` and `AsyncWrite` and dispatches all method calls to
+/// either `First` or `Second`.
+#[derive(Debug, Copy, Clone)]
+pub enum EitherSocket {
+ First(A),
+ Second(B),
+}
+
+impl AsyncRead for EitherSocket
+where
+ A: AsyncRead,
+ B: AsyncRead,
+{
+ #[inline]
+ unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
+ match self {
+ &EitherSocket::First(ref a) => a.prepare_uninitialized_buffer(buf),
+ &EitherSocket::Second(ref b) => b.prepare_uninitialized_buffer(buf),
+ }
+ }
+}
+
+impl Read for EitherSocket
+where
+ A: Read,
+ B: Read,
+{
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> Result {
+ match self {
+ &mut EitherSocket::First(ref mut a) => a.read(buf),
+ &mut EitherSocket::Second(ref mut b) => b.read(buf),
+ }
+ }
+}
+
+impl AsyncWrite for EitherSocket
+where
+ A: AsyncWrite,
+ B: AsyncWrite,
+{
+ #[inline]
+ fn shutdown(&mut self) -> Poll<(), IoError> {
+ match self {
+ &mut EitherSocket::First(ref mut a) => a.shutdown(),
+ &mut EitherSocket::Second(ref mut b) => b.shutdown(),
+ }
+ }
+}
+
+impl Write for EitherSocket
+where
+ A: Write,
+ B: Write,
+{
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> Result {
+ match self {
+ &mut EitherSocket::First(ref mut a) => a.write(buf),
+ &mut EitherSocket::Second(ref mut b) => b.write(buf),
+ }
+ }
+
+ #[inline]
+ fn flush(&mut self) -> Result<(), IoError> {
+ match self {
+ &mut EitherSocket::First(ref mut a) => a.flush(),
+ &mut EitherSocket::Second(ref mut b) => b.flush(),
+ }
+ }
+}
+
+impl StreamMuxer for EitherSocket
+where
+ A: StreamMuxer,
+ B: StreamMuxer,
+{
+ type Substream = EitherSocket;
+ type InboundSubstream = EitherTransportFuture;
+ type OutboundSubstream = EitherTransportFuture;
+
+ #[inline]
+ fn inbound(self) -> Self::InboundSubstream {
+ match self {
+ EitherSocket::First(a) => EitherTransportFuture::First(a.inbound()),
+ EitherSocket::Second(b) => EitherTransportFuture::Second(b.inbound()),
+ }
+ }
+
+ #[inline]
+ fn outbound(self) -> Self::OutboundSubstream {
+ match self {
+ EitherSocket::First(a) => EitherTransportFuture::First(a.outbound()),
+ EitherSocket::Second(b) => EitherTransportFuture::Second(b.outbound()),
+ }
+ }
+}
+
+/// Implements `Future` and redirects calls to either `First` or `Second`.
+///
+/// Additionally, the output will be wrapped inside a `EitherSocket`.
+// TODO: This type is needed because of the lack of `impl Trait` in stable Rust.
+// If Rust had impl Trait we could use the Either enum from the futures crate and add some
+// modifiers to it. This custom enum is a combination of Either and these modifiers.
+#[derive(Debug, Copy, Clone)]
+pub enum EitherTransportFuture {
+ First(A),
+ Second(B),
+}
+
+impl Future for EitherTransportFuture
+where
+ A: Future,
+ B: Future,
+{
+ type Item = EitherSocket;
+ type Error = IoError;
+
+ #[inline]
+ fn poll(&mut self) -> Poll {
+ match self {
+ &mut EitherTransportFuture::First(ref mut a) => {
+ let item = try_ready!(a.poll());
+ Ok(Async::Ready(EitherSocket::First(item)))
+ }
+ &mut EitherTransportFuture::Second(ref mut b) => {
+ let item = try_ready!(b.poll());
+ Ok(Async::Ready(EitherSocket::Second(item)))
+ }
+ }
+ }
+}
+
+/// Implements `Stream` and dispatches all method calls to either `First` or `Second`.
+#[derive(Debug, Copy, Clone)]
+pub enum EitherListenStream {
+ First(A),
+ Second(B),
+}
+
+impl Stream for EitherListenStream
+where
+ AStream: Stream- ,
+ BStream: Stream
- ,
+{
+ type Item = EitherListenUpgrade;
+ type Error = IoError;
+
+ #[inline]
+ fn poll(&mut self) -> Poll