Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: Remove ProtocolName trait in favor of always using strings #2966

Closed
wants to merge 3 commits into from

Conversation

efarg
Copy link
Contributor

@efarg efarg commented Oct 3, 2022

@efarg efarg marked this pull request as ready for review October 3, 2022 10:21
@thomaseizinger
Copy link
Contributor

Thanks for opening this!

I can't push to your branch unfortunately but here is a patch that should fix a few of the hardest errors. Hope this helps :)

Index: core/src/either.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/either.rs b/core/src/either.rs
--- a/core/src/either.rs	(revision 8fd23bc0eff8fea08e10a4750a3321c8f963f034)
+++ b/core/src/either.rs	(revision 1ef648184017f9c2d7420f84776364b131d57fc4)
@@ -22,7 +22,7 @@
 use crate::{
     muxing::StreamMuxer,
     transport::{ListenerId, Transport, TransportError, TransportEvent},
-    Multiaddr, ProtocolName,
+    Multiaddr,
 };
 use futures::{
     io::{IoSlice, IoSliceMut},
@@ -310,20 +310,6 @@
     }
 }
 
-#[derive(Debug, Clone)]
-pub enum EitherName {
-    A(ProtocolName),
-    B(ProtocolName),
-}
-
-impl EitherName {
-    fn protocol_name(&self) -> &str {
-        match self {
-            EitherName::A(a) => a.protocol_name(),
-            EitherName::B(b) => b.protocol_name(),
-        }
-    }
-}
 #[pin_project(project = EitherTransportProj)]
 #[derive(Debug)]
 #[must_use = "transports do nothing unless polled"]
Index: core/src/upgrade.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/upgrade.rs b/core/src/upgrade.rs
--- a/core/src/upgrade.rs	(revision 8fd23bc0eff8fea08e10a4750a3321c8f963f034)
+++ b/core/src/upgrade.rs	(revision 1ef648184017f9c2d7420f84776364b131d57fc4)
@@ -135,21 +135,26 @@
 //     }
 // }
 
+#[derive(Clone, Debug, Eq, PartialEq)]
 pub struct ProtocolName(Cow<'static, str>);
 
 impl ProtocolName {
     fn protocol_name(&self) -> &str {
-	self.0.as_ref()
+        self.0.as_ref()
     }
 }
 
 impl AsRef<str> for ProtocolName {
     fn as_ref(&self) -> &str {
-	self.0.as_ref()
+        self.0.as_ref()
     }
 }
 
-
+impl AsRef<[u8]> for ProtocolName {
+    fn as_ref(&self) -> &[u8] {
+        self.0.as_ref().as_bytes()
+    }
+}
 
 /// Common trait for upgrades that can be applied on inbound substreams, outbound substreams,
 /// or both.
Index: core/src/upgrade/apply.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/upgrade/apply.rs b/core/src/upgrade/apply.rs
--- a/core/src/upgrade/apply.rs	(revision 8fd23bc0eff8fea08e10a4750a3321c8f963f034)
+++ b/core/src/upgrade/apply.rs	(revision 1ef648184017f9c2d7420f84776364b131d57fc4)
@@ -23,7 +23,7 @@
 use futures::{future::Either, prelude::*};
 use log::debug;
 use multistream_select::{self, DialerSelectFuture, ListenerSelectFuture};
-use std::{iter, mem, pin::Pin, task::Context, task::Poll};
+use std::{mem, pin::Pin, task::Context, task::Poll};
 
 pub use multistream_select::Version;
 
@@ -53,10 +53,7 @@
     C: AsyncRead + AsyncWrite + Unpin,
     U: InboundUpgrade<Negotiated<C>>,
 {
-    let iter = up
-        .protocol_info()
-        .into_iter()
-        .map(NameWrap as fn(_) -> NameWrap<_>);
+    let iter = up.protocol_info().into_iter();
     let future = multistream_select::listener_select_proto(conn, iter);
     InboundUpgradeApply {
         inner: InboundUpgradeApplyState::Init {
@@ -72,10 +69,7 @@
     C: AsyncRead + AsyncWrite + Unpin,
     U: OutboundUpgrade<Negotiated<C>>,
 {
-    let iter = up
-        .protocol_info()
-        .into_iter()
-        .map(NameWrap as fn(_) -> NameWrap<_>);
+    let iter = up.protocol_info().into_iter();
     let future = multistream_select::dialer_select_proto(conn, iter, v);
     OutboundUpgradeApply {
         inner: OutboundUpgradeApplyState::Init {
@@ -100,7 +94,7 @@
     U: InboundUpgrade<Negotiated<C>>,
 {
     Init {
-        future: ListenerSelectFuture<C, NameWrap<ProtocolName>>,
+        future: ListenerSelectFuture<C, ProtocolName>,
         upgrade: U,
     },
     Upgrade {
@@ -138,7 +132,7 @@
                         }
                     };
                     self.inner = InboundUpgradeApplyState::Upgrade {
-                        future: Box::pin(upgrade.upgrade_inbound(io, info.0)),
+                        future: Box::pin(upgrade.upgrade_inbound(io, info)),
                     };
                 }
                 InboundUpgradeApplyState::Upgrade { mut future } => {
@@ -180,7 +174,7 @@
     U: OutboundUpgrade<Negotiated<C>>,
 {
     Init {
-        future: DialerSelectFuture<C, NameWrapIter<<U::InfoIter as IntoIterator>::IntoIter>>,
+        future: DialerSelectFuture<C, <U::InfoIter as IntoIterator>::IntoIter>,
         upgrade: U,
     },
     Upgrade {
@@ -218,7 +212,7 @@
                         }
                     };
                     self.inner = OutboundUpgradeApplyState::Upgrade {
-                        future: Box::pin(upgrade.upgrade_outbound(connection, info.0)),
+                        future: Box::pin(upgrade.upgrade_outbound(connection, info)),
                     };
                 }
                 OutboundUpgradeApplyState::Upgrade { mut future } => {
@@ -244,15 +238,3 @@
         }
     }
 }
-
-type NameWrapIter<I> = iter::Map<I, fn(<I as Iterator>::Item) -> NameWrap<<I as Iterator>::Item>>;
-
-/// Wrapper type to expose an `AsRef<[u8]>` impl for all types implementing `ProtocolName`.
-#[derive(Clone)]
-struct NameWrap<N>(N);
-
-impl<N> AsRef<[u8]> for NameWrap<N> {
-    fn as_ref(&self) -> &[u8] {
-        self.0.protocol_name().as_bytes()
-    }
-}
Index: core/src/upgrade/denied.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/upgrade/denied.rs b/core/src/upgrade/denied.rs
--- a/core/src/upgrade/denied.rs	(revision 8fd23bc0eff8fea08e10a4750a3321c8f963f034)
+++ b/core/src/upgrade/denied.rs	(revision 1ef648184017f9c2d7420f84776364b131d57fc4)
@@ -18,7 +18,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-use crate::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo, ProtocolName};
+use crate::upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeInfo};
 use futures::future;
 use std::iter;
 use void::Void;
Index: core/src/upgrade/either.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/upgrade/either.rs b/core/src/upgrade/either.rs
--- a/core/src/upgrade/either.rs	(revision 8fd23bc0eff8fea08e10a4750a3321c8f963f034)
+++ b/core/src/upgrade/either.rs	(revision 1ef648184017f9c2d7420f84776364b131d57fc4)
@@ -19,9 +19,10 @@
 // DEALINGS IN THE SOFTWARE.
 
 use crate::{
-    either::{EitherError, EitherFuture2, EitherName, EitherOutput},
-    upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo, ProtocolName},
+    either::{EitherError, EitherFuture2, EitherOutput},
+    upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeInfo},
 };
+use either::Either;
 
 /// A type to represent two possible upgrade types (inbound or outbound).
 #[derive(Debug, Clone)]
@@ -35,15 +36,13 @@
     A: UpgradeInfo,
     B: UpgradeInfo,
 {
-    type InfoIter = EitherIter<
-        <A::InfoIter as IntoIterator>::IntoIter,
-        <B::InfoIter as IntoIterator>::IntoIter,
-    >;
+    type InfoIter =
+        Either<<A::InfoIter as IntoIterator>::IntoIter, <B::InfoIter as IntoIterator>::IntoIter>;
 
     fn protocol_info(&self) -> Self::InfoIter {
         match self {
-            EitherUpgrade::A(a) => EitherIter::A(a.protocol_info().into_iter()),
-            EitherUpgrade::B(b) => EitherIter::B(b.protocol_info().into_iter()),
+            EitherUpgrade::A(a) => Either::Left(a.protocol_info().into_iter()),
+            EitherUpgrade::B(b) => Either::Right(b.protocol_info().into_iter()),
         }
     }
 }
@@ -58,14 +57,9 @@
     type Future = EitherFuture2<A::Future, B::Future>;
 
     fn upgrade_inbound(self, sock: C, info: ProtocolName) -> Self::Future {
-        match (self, info) {
-            (EitherUpgrade::A(a), EitherName::A(info)) => {
-                EitherFuture2::A(a.upgrade_inbound(sock, info))
-            }
-            (EitherUpgrade::B(b), EitherName::B(info)) => {
-                EitherFuture2::B(b.upgrade_inbound(sock, info))
-            }
-            _ => panic!("Invalid invocation of EitherUpgrade::upgrade_inbound"),
+        match self {
+            EitherUpgrade::A(a) => EitherFuture2::A(a.upgrade_inbound(sock, info)),
+            EitherUpgrade::B(b) => EitherFuture2::B(b.upgrade_inbound(sock, info)),
         }
     }
 }
@@ -79,44 +73,10 @@
     type Error = EitherError<EA, EB>;
     type Future = EitherFuture2<A::Future, B::Future>;
 
-    fn upgrade_outbound(self, sock: C, info: EitherName) -> Self::Future {
-        match (self, info) {
-            (EitherUpgrade::A(a), EitherName::A(info)) => {
-                EitherFuture2::A(a.upgrade_outbound(sock, info))
-            }
-            (EitherUpgrade::B(b), EitherName::B(info)) => {
-                EitherFuture2::B(b.upgrade_outbound(sock, info))
-            }
-            _ => panic!("Invalid invocation of EitherUpgrade::upgrade_outbound"),
-        }
-    }
-}
-
-/// A type to represent two possible `Iterator` types.
-#[derive(Debug, Clone)]
-pub enum EitherIter<A, B> {
-    A(A),
-    B(B),
-}
-
-impl<A, B> Iterator for EitherIter<A, B>
-where
-    A: Iterator,
-    B: Iterator,
-{
-    type Item = EitherName;
-
-    fn next(&mut self) -> Option<Self::Item> {
+    fn upgrade_outbound(self, sock: C, info: ProtocolName) -> Self::Future {
         match self {
-            EitherIter::A(a) => a.next().map(EitherName::A),
-            EitherIter::B(b) => b.next().map(EitherName::B),
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        match self {
-            EitherIter::A(a) => a.size_hint(),
-            EitherIter::B(b) => b.size_hint(),
+            EitherUpgrade::A(a) => EitherFuture2::A(a.upgrade_outbound(sock, info)),
+            EitherUpgrade::B(b) => EitherFuture2::B(b.upgrade_outbound(sock, info)),
         }
     }
 }
Index: core/src/upgrade/from_fn.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/upgrade/from_fn.rs b/core/src/upgrade/from_fn.rs
--- a/core/src/upgrade/from_fn.rs	(revision 8fd23bc0eff8fea08e10a4750a3321c8f963f034)
+++ b/core/src/upgrade/from_fn.rs	(revision 1ef648184017f9c2d7420f84776364b131d57fc4)
@@ -70,8 +70,7 @@
     fun: F,
 }
 
-impl<F> UpgradeInfo for FromFnUpgrade<F>
-{
+impl<F> UpgradeInfo for FromFnUpgrade<F> {
     type InfoIter = iter::Once<ProtocolName>;
 
     fn protocol_info(&self) -> Self::InfoIter {
Index: core/src/upgrade/map.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/upgrade/map.rs b/core/src/upgrade/map.rs
--- a/core/src/upgrade/map.rs	(revision 8fd23bc0eff8fea08e10a4750a3321c8f963f034)
+++ b/core/src/upgrade/map.rs	(revision 1ef648184017f9c2d7420f84776364b131d57fc4)
@@ -18,7 +18,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-use crate::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo, ProtocolName};
+use crate::upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeInfo};
 use futures::prelude::*;
 use std::{pin::Pin, task::Context, task::Poll};
 
Index: core/src/upgrade/optional.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/upgrade/optional.rs b/core/src/upgrade/optional.rs
--- a/core/src/upgrade/optional.rs	(revision 8fd23bc0eff8fea08e10a4750a3321c8f963f034)
+++ b/core/src/upgrade/optional.rs	(revision 1ef648184017f9c2d7420f84776364b131d57fc4)
@@ -18,7 +18,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-use crate::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo, ProtocolName};
+use crate::upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeInfo};
 
 /// Upgrade that can be disabled at runtime.
 ///
Index: core/src/upgrade/pending.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/upgrade/pending.rs b/core/src/upgrade/pending.rs
--- a/core/src/upgrade/pending.rs	(revision 8fd23bc0eff8fea08e10a4750a3321c8f963f034)
+++ b/core/src/upgrade/pending.rs	(revision 1ef648184017f9c2d7420f84776364b131d57fc4)
@@ -37,8 +37,7 @@
     }
 }
 
-impl UpgradeInfo for PendingUpgrade
-{
+impl UpgradeInfo for PendingUpgrade {
     type InfoIter = iter::Once<ProtocolName>;
 
     fn protocol_info(&self) -> Self::InfoIter {
@@ -46,8 +45,7 @@
     }
 }
 
-impl<C> InboundUpgrade<C> for PendingUpgrade
-{
+impl<C> InboundUpgrade<C> for PendingUpgrade {
     type Output = Void;
     type Error = Void;
     type Future = future::Pending<Result<Self::Output, Self::Error>>;
@@ -57,8 +55,7 @@
     }
 }
 
-impl<C> OutboundUpgrade<C> for PendingUpgrade
-{
+impl<C> OutboundUpgrade<C> for PendingUpgrade {
     type Output = Void;
     type Error = Void;
     type Future = future::Pending<Result<Self::Output, Self::Error>>;
Index: core/src/upgrade/ready.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/upgrade/ready.rs b/core/src/upgrade/ready.rs
--- a/core/src/upgrade/ready.rs	(revision 8fd23bc0eff8fea08e10a4750a3321c8f963f034)
+++ b/core/src/upgrade/ready.rs	(revision 1ef648184017f9c2d7420f84776364b131d57fc4)
@@ -36,8 +36,7 @@
     }
 }
 
-impl UpgradeInfo for ReadyUpgrade
-{
+impl UpgradeInfo for ReadyUpgrade {
     type InfoIter = iter::Once<ProtocolName>;
 
     fn protocol_info(&self) -> Self::InfoIter {
@@ -45,8 +44,7 @@
     }
 }
 
-impl<C> InboundUpgrade<C> for ReadyUpgrade
-{
+impl<C> InboundUpgrade<C> for ReadyUpgrade {
     type Output = C;
     type Error = Void;
     type Future = future::Ready<Result<Self::Output, Self::Error>>;
@@ -56,8 +54,7 @@
     }
 }
 
-impl<C> OutboundUpgrade<C> for ReadyUpgrade
-{
+impl<C> OutboundUpgrade<C> for ReadyUpgrade {
     type Output = C;
     type Error = Void;
     type Future = future::Ready<Result<Self::Output, Self::Error>>;
Index: core/src/upgrade/select.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/upgrade/select.rs b/core/src/upgrade/select.rs
--- a/core/src/upgrade/select.rs	(revision 8fd23bc0eff8fea08e10a4750a3321c8f963f034)
+++ b/core/src/upgrade/select.rs	(revision 1ef648184017f9c2d7420f84776364b131d57fc4)
@@ -19,8 +19,9 @@
 // DEALINGS IN THE SOFTWARE.
 
 use crate::{
-    either::{EitherError, EitherFuture2, EitherName, EitherOutput},
+    either::{EitherError, EitherFuture2, EitherOutput},
     upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo},
+    ProtocolName,
 };
 
 /// Upgrade that combines two upgrades into one. Supports all the protocols supported by either
@@ -44,16 +45,16 @@
     A: UpgradeInfo,
     B: UpgradeInfo,
 {
-    type InfoIter = InfoIterChain<
+    type InfoIter = std::iter::Chain<
         <A::InfoIter as IntoIterator>::IntoIter,
         <B::InfoIter as IntoIterator>::IntoIter,
     >;
 
     fn protocol_info(&self) -> Self::InfoIter {
-        InfoIterChain(
-            self.0.protocol_info().into_iter(),
-            self.1.protocol_info().into_iter(),
-        )
+        self.0
+            .protocol_info()
+            .into_iter()
+            .chain(self.1.protocol_info().into_iter())
     }
 }
 
@@ -66,11 +67,26 @@
     type Error = EitherError<EA, EB>;
     type Future = EitherFuture2<A::Future, B::Future>;
 
-    fn upgrade_inbound(self, sock: C, info: EitherName) -> Self::Future {
-        match info {
-            EitherName::A(info) => EitherFuture2::A(self.0.upgrade_inbound(sock, info)),
-            EitherName::B(info) => EitherFuture2::B(self.1.upgrade_inbound(sock, info)),
+    fn upgrade_inbound(self, sock: C, info: ProtocolName) -> Self::Future {
+        if self
+            .0
+            .protocol_info()
+            .into_iter()
+            .any(|candidate| candidate == info)
+        {
+            return EitherFuture2::A(self.0.upgrade_inbound(sock, info));
         }
+
+        if self
+            .1
+            .protocol_info()
+            .into_iter()
+            .any(|candidate| candidate == info)
+        {
+            return EitherFuture2::B(self.1.upgrade_inbound(sock, info));
+        }
+
+        unreachable!("selected protocol must be suppored by one of the upgrades")
     }
 }
 
@@ -83,39 +99,25 @@
     type Error = EitherError<EA, EB>;
     type Future = EitherFuture2<A::Future, B::Future>;
 
-    fn upgrade_outbound(self, sock: C, info: EitherName) -> Self::Future {
-        match info {
-            EitherName::A(info) => EitherFuture2::A(self.0.upgrade_outbound(sock, info)),
-            EitherName::B(info) => EitherFuture2::B(self.1.upgrade_outbound(sock, info)),
+    fn upgrade_outbound(self, sock: C, info: ProtocolName) -> Self::Future {
+        if self
+            .0
+            .protocol_info()
+            .into_iter()
+            .any(|candidate| candidate == info)
+        {
+            return EitherFuture2::A(self.0.upgrade_outbound(sock, info));
         }
-    }
-}
 
-/// Iterator that combines the protocol names of twp upgrades.
-#[derive(Debug, Clone)]
-pub struct InfoIterChain<A, B>(A, B);
-
-impl<A, B> Iterator for InfoIterChain<A, B>
-where
-    A: Iterator,
-    B: Iterator,
-{
-    type Item = EitherName;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if let Some(info) = self.0.next() {
-            return Some(EitherName::A(info));
+        if self
+            .1
+            .protocol_info()
+            .into_iter()
+            .any(|candidate| candidate == info)
+        {
+            return EitherFuture2::B(self.1.upgrade_outbound(sock, info));
         }
-        if let Some(info) = self.1.next() {
-            return Some(EitherName::B(info));
-        }
-        None
-    }
 
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let (min1, max1) = self.0.size_hint();
-        let (min2, max2) = self.1.size_hint();
-        let max = max1.and_then(move |m1| max2.and_then(move |m2| m1.checked_add(m2)));
-        (min1.saturating_add(min2), max)
+        unreachable!("selected protocol must be suppored by one of the upgrades")
     }
 }

@thomaseizinger thomaseizinger changed the title WIP Issue #2831 core: Remove ProtocolName trait in favor of always using strings Oct 4, 2022
@efarg
Copy link
Contributor Author

efarg commented Oct 7, 2022

-use crate::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo, ProtocolName};
+use crate::upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeInfo};

Just out of curiosity. Any particular reason the order is important, or is it just a quirk or custom to import alphabetically? :)

@thomaseizinger
Copy link
Contributor

-use crate::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo, ProtocolName};
+use crate::upgrade::{InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeInfo};

Just out of curiosity. Any particular reason the order is important, or is it just a quirk or custom to import alphabetically? :)

I just ran the auto-formatter! I believe it sorts the imports alphabetically! It is cargo fmt in case you are unaware :)

@efarg
Copy link
Contributor Author

efarg commented Oct 17, 2022

@thomaseizinger I am trying to figure things out. So please ignore the commit text. :)

@thomaseizinger
Copy link
Contributor

@thomaseizinger I am trying to figure things out. So please ignore the commit text. :)

All good, just ping me whenever you have a question or want me to take another look 😊

1 similar comment
@thomaseizinger
Copy link
Contributor

@thomaseizinger I am trying to figure things out. So please ignore the commit text. :)

All good, just ping me whenever you have a question or want me to take another look 😊

@thomaseizinger
Copy link
Contributor

Setting to draft until ready.

@thomaseizinger thomaseizinger marked this pull request as draft November 2, 2022 04:05
@efarg
Copy link
Contributor Author

efarg commented Nov 14, 2022

@thomaseizinger

InboundUpgradeSend is commented to be something that shouldn't be implemented in swarm/src/upgrade.rs

/// Implemented automatically on all types that implement
/// [`InboundUpgrade`](upgrade::InboundUpgrade) and `Send + 'static`.
///
/// Do not implement this trait yourself. Instead, please implement
/// [`InboundUpgrade`](upgrade::InboundUpgrade).
pub trait InboundUpgradeSend: UpgradeInfoSend {
/// Equivalent to [`InboundUpgrade::Output`](upgrade::InboundUpgrade::Output).
type Output: Send + 'static;

But it is impl'd in swarm/src/handler/multi.rs

impl<K, H> InboundUpgradeSend for Upgrade<K, H>
where
H: InboundUpgradeSend,
K: Send + 'static,

Same goes for OutboundUpgradeSend and others. Am I missing something?

@thomaseizinger
Copy link
Contributor

I am not too familiar with those traits but I assume they were implemented for a reason.

Do they represent a blocker for you?

@thomaseizinger
Copy link
Contributor

Okay, I had a quick look at this and the reason these traits are implemented instead of the regular InboundUpgrade and OutboundUpgrade traits is that InboundUpgradeSend refers to the inner connection via NegotiatedSubstream which erases the type parameter from InboundUpgrade.

This is required for MultiHandler because we don't know at compile-time, how many protocols the MultiHandler composes and thus we wouldn't be able to specify the correct number of type parameters.

I think this shouldn't be much of a concern for your current endeavor though. You should be able to remove Info and adapt InboundUpgradeSend accordingly without breaking any of this :)

@thomaseizinger
Copy link
Contributor

Cross referencing #3128 which would have been slightly easier to implement with these changes.

@rkuhn
Copy link
Contributor

rkuhn commented Nov 17, 2022

Thanks for the notification! I think these two PRs are sufficiently orthogonal to treat them independently.

@thomaseizinger
Copy link
Contributor

@efarg How are you progressing on this? Let me know if you are stuck with something where I can help :)

I am keen to land this simplification!

@efarg
Copy link
Contributor Author

efarg commented Nov 23, 2022

@thomaseizinger sorry it's still very incomplete: https://github.com/efarg/rust-libp2p/tree/2966

@thomaseizinger
Copy link
Contributor

@efarg You seem to have disabled push access for me so I can't push a commit to this branch :)

Anyway, here is a patch that fixes the multi handler:

Index: core/src/upgrade.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/core/src/upgrade.rs b/core/src/upgrade.rs
--- a/core/src/upgrade.rs	(revision 327bdcb3b9889ed3a5d3ebb4346200785bf684ce)
+++ b/core/src/upgrade.rs	(revision 1efa7bb73cd029932512060bb24d4aa344b2af58)
@@ -135,11 +135,15 @@
 //     }
 // }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash)]
 pub struct ProtocolName(Cow<'static, str>);
 
 impl ProtocolName {
-    fn protocol_name(&self) -> &str {
+    pub fn new(protocol: impl Into<Cow<'static, str>>) -> Self {
+        Self(protocol.into())
+    }
+
+    pub fn protocol_name(&self) -> &str {
         self.0.as_ref()
     }
 }
Index: swarm/src/handler/multi.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/swarm/src/handler/multi.rs b/swarm/src/handler/multi.rs
--- a/swarm/src/handler/multi.rs	(revision 327bdcb3b9889ed3a5d3ebb4346200785bf684ce)
+++ b/swarm/src/handler/multi.rs	(revision 1efa7bb73cd029932512060bb24d4aa344b2af58)
@@ -37,7 +37,7 @@
     error,
     fmt::{self, Debug},
     hash::Hash,
-    iter::{self, FromIterator},
+    iter::FromIterator,
     task::{Context, Poll},
     time::Duration,
 };
@@ -112,7 +112,8 @@
             .fold(
                 (Upgrade::new(), Info::new(), Duration::from_secs(0)),
                 |(mut upg, mut inf, mut timeout), (k, (u, i, t))| {
-                    upg.upgrades.push((k.clone(), u));
+                    upg.add_upgrade(k.clone(), u);
+
                     inf.infos.push((k, i));
                     timeout = cmp::max(timeout, t);
                     (upg, inf, timeout)
@@ -385,23 +386,13 @@
     }
 
     fn inbound_protocol(&self) -> <Self::Handler as ConnectionHandler>::InboundProtocol {
-        Upgrade {
-            upgrades: self
-                .handlers
-                .iter()
-                .map(|(k, h)| (k.clone(), h.inbound_protocol()))
-                .collect(),
-        }
-    }
-}
+        let mut upgrade = Upgrade::new();
 
-/// Index and protocol name pair used as `UpgradeInfo::Info`.
-#[derive(Debug, Clone)]
-pub struct IndexedProtoName(usize, ProtocolName);
+        for (key, handler) in &self.handlers {
+            upgrade.add_upgrade(key.clone(), handler.inbound_protocol());
+        }
 
-impl IndexedProtoName {
-    fn protocol_name(&self) -> &[u8] {
-        self.1.protocol_name()
+        upgrade
     }
 }
 
@@ -427,17 +418,33 @@
 /// Inbound and outbound upgrade for all [`ConnectionHandler`]s.
 #[derive(Clone)]
 pub struct Upgrade<K, H> {
-    upgrades: Vec<(K, H)>,
+    handler_by_protocol: HashMap<ProtocolName, K>,
+    upgrades_by_handler: HashMap<K, H>,
 }
 
 impl<K, H> Upgrade<K, H> {
     fn new() -> Self {
         Upgrade {
-            upgrades: Vec::new(),
+            handler_by_protocol: Default::default(),
+            upgrades_by_handler: Default::default(),
+        }
+    }
+}
+
+impl<K, H> Upgrade<K, H>
+where
+    K: Clone + Eq + Hash,
+    H: InboundUpgradeSend,
+{
+    fn add_upgrade(&mut self, key: K, upgrade: H) {
+        for proto in upgrade.protocol_info() {
+            self.handler_by_protocol.insert(proto, key.clone());
         }
+        self.upgrades_by_handler.insert(key, upgrade);
     }
 }
 
+// TODO: Derive this?
 impl<K, H> fmt::Debug for Upgrade<K, H>
 where
     K: fmt::Debug + Eq + Hash,
@@ -445,7 +452,8 @@
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Upgrade")
-            .field("upgrades", &self.upgrades)
+            .field("handler_by_protocol", &self.handler_by_protocol)
+            .field("upgrades_by_handler", &self.upgrades_by_handler)
             .finish()
     }
 }
@@ -455,14 +463,12 @@
     H: UpgradeInfoSend,
     K: Send + 'static,
 {
-    type InfoIter = std::vec::IntoIter<IndexedProtoName>;
+    type InfoIter = std::vec::IntoIter<ProtocolName>;
 
     fn protocol_info(&self) -> Self::InfoIter {
-        self.upgrades
-            .iter()
-            .enumerate()
-            .flat_map(|(i, (_, h))| iter::repeat(i).zip(h.protocol_info()))
-            .map(|(i, h)| IndexedProtoName(i, h))
+        self.handler_by_protocol
+            .keys()
+            .cloned()
             .collect::<Vec<_>>()
             .into_iter()
     }
@@ -471,15 +477,26 @@
 impl<K, H> InboundUpgradeSend for Upgrade<K, H>
 where
     H: InboundUpgradeSend,
-    K: Send + 'static,
+    K: Eq + Hash + Send + 'static,
 {
     type Output = (K, <H as InboundUpgradeSend>::Output);
     type Error = (K, <H as InboundUpgradeSend>::Error);
     type Future = BoxFuture<'static, Result<Self::Output, Self::Error>>;
 
-    fn upgrade_inbound(mut self, resource: NegotiatedSubstream, info: ProtocolName) -> Self::Future {
-        let IndexedProtoName(index, info) = info;
-        let (key, upgrade) = self.upgrades.remove(index);
+    fn upgrade_inbound(
+        mut self,
+        resource: NegotiatedSubstream,
+        info: ProtocolName,
+    ) -> Self::Future {
+        let key = self
+            .handler_by_protocol
+            .remove(&info)
+            .expect("to only negotiate protocols we support");
+        let upgrade = self
+            .upgrades_by_handler
+            .remove(&key)
+            .expect("to only negotiate protocols we support");
+
         upgrade
             .upgrade_inbound(resource, info)
             .map(move |out| match out {
@@ -493,15 +510,26 @@
 impl<K, H> OutboundUpgradeSend for Upgrade<K, H>
 where
     H: OutboundUpgradeSend,
-    K: Send + 'static,
+    K: Eq + Hash + Send + 'static,
 {
     type Output = (K, <H as OutboundUpgradeSend>::Output);
     type Error = (K, <H as OutboundUpgradeSend>::Error);
     type Future = BoxFuture<'static, Result<Self::Output, Self::Error>>;
 
-    fn upgrade_outbound(mut self, resource: NegotiatedSubstream, info: ProtocolName) -> Self::Future {
-        let IndexedProtoName(index, info) = info;
-        let (key, upgrade) = self.upgrades.remove(index);
+    fn upgrade_outbound(
+        mut self,
+        resource: NegotiatedSubstream,
+        info: ProtocolName,
+    ) -> Self::Future {
+        let key = self
+            .handler_by_protocol
+            .remove(&info)
+            .expect("to only negotiate protocols we support");
+        let upgrade = self
+            .upgrades_by_handler
+            .remove(&key)
+            .expect("to only negotiate protocols we support");
+
         upgrade
             .upgrade_outbound(resource, info)
             .map(move |out| match out {
@@ -520,12 +548,11 @@
 {
     let mut set = HashSet::new();
     for infos in iter {
-        for i in infos.protocol_info() {
-            let v = Vec::from(i.protocol_name());
-            if set.contains(&v) {
-                return Err(DuplicateProtonameError(v));
+        for proto in infos.protocol_info() {
+            if set.contains(&proto) {
+                return Err(DuplicateProtonameError(proto));
             } else {
-                set.insert(v);
+                set.insert(proto);
             }
         }
     }
@@ -534,22 +561,20 @@
 
 /// It is an error if two handlers share the same protocol name.
 #[derive(Debug, Clone)]
-pub struct DuplicateProtonameError(Vec<u8>);
+pub struct DuplicateProtonameError(ProtocolName);
 
 impl DuplicateProtonameError {
     /// The protocol name bytes that occured in more than one handler.
+    // TODO: Change this to a `&str`
     pub fn protocol_name(&self) -> &[u8] {
-        &self.0
+        self.0.protocol_name().as_bytes()
     }
 }
 
 impl fmt::Display for DuplicateProtonameError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if let Ok(s) = std::str::from_utf8(&self.0) {
-            write!(f, "duplicate protocol name: {}", s)
-        } else {
-            write!(f, "duplicate protocol name: {:?}", self.0)
-        }
+        // TODO: Directly implement `fmt::Display` on `ProtocolName`
+        write!(f, "duplicate protocol name: {}", self.0.protocol_name())
     }
 }
 
Index: swarm/src/handler/pending.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/swarm/src/handler/pending.rs b/swarm/src/handler/pending.rs
--- a/swarm/src/handler/pending.rs	(revision 327bdcb3b9889ed3a5d3ebb4346200785bf684ce)
+++ b/swarm/src/handler/pending.rs	(revision 1efa7bb73cd029932512060bb24d4aa344b2af58)
@@ -26,7 +26,7 @@
 use crate::NegotiatedSubstream;
 use libp2p_core::{
     upgrade::{InboundUpgrade, OutboundUpgrade, PendingUpgrade},
-    Multiaddr,
+    Multiaddr, ProtocolName,
 };
 use std::task::{Context, Poll};
 use void::Void;
@@ -53,7 +53,10 @@
     type InboundOpenInfo = ();
 
     fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, Self::InboundOpenInfo> {
-        SubstreamProtocol::new(PendingUpgrade::new(self.protocol_name.clone()), ())
+        SubstreamProtocol::new(
+            PendingUpgrade::new(ProtocolName::new(self.protocol_name.clone())),
+            (),
+        )
     }
 
     fn inject_fully_negotiated_inbound(
Index: swarm/src/lib.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs
--- a/swarm/src/lib.rs	(revision 327bdcb3b9889ed3a5d3ebb4346200785bf684ce)
+++ b/swarm/src/lib.rs	(revision 1efa7bb73cd029932512060bb24d4aa344b2af58)
@@ -90,7 +90,6 @@
     multihash::Multihash,
     muxing::StreamMuxerBox,
     transport::{self, ListenerId, TransportError, TransportEvent},
-    upgrade::ProtocolName,
     Endpoint, Executor, Multiaddr, Negotiated, PeerId, Transport,
 };
 use registry::{AddressIntoIter, Addresses};
@@ -1384,7 +1383,7 @@
             .inbound_protocol()
             .protocol_info()
             .into_iter()
-            .map(|info| info.protocol_name().to_vec())
+            .map(|info| info.protocol_name().as_bytes().to_vec())
             .collect();
 
         // If no executor has been explicitly configured, try to set up a thread pool.
Index: swarm/src/upgrade.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/swarm/src/upgrade.rs b/swarm/src/upgrade.rs
--- a/swarm/src/upgrade.rs	(revision 327bdcb3b9889ed3a5d3ebb4346200785bf684ce)
+++ b/swarm/src/upgrade.rs	(revision 1efa7bb73cd029932512060bb24d4aa344b2af58)
@@ -22,7 +22,6 @@
 
 use futures::prelude::*;
 use libp2p_core::upgrade;
-use std::iter;
 
 /// Implemented automatically on all types that implement [`UpgradeInfo`](upgrade::UpgradeInfo)
 /// and `Send + 'static`.
@@ -30,8 +29,8 @@
 /// Do not implement this trait yourself. Instead, please implement
 /// [`UpgradeInfo`](upgrade::UpgradeInfo).
 pub trait UpgradeInfoSend: Send + 'static {
-/// Equivalent to [`UpgradeInfo::Info`](upgrade::UpgradeInfo::Info).
-//type Info: upgrade::ProtocolName + Clone + Send + 'static;
+    /// Equivalent to [`UpgradeInfo::Info`](upgrade::UpgradeInfo::Info).
+    //type Info: upgrade::ProtocolName + Clone + Send + 'static;
     /// Equivalent to [`UpgradeInfo::InfoIter`](upgrade::UpgradeInfo::InfoIter).
     type InfoIter: Iterator<Item = upgrade::ProtocolName> + Send + 'static;
 
@@ -39,8 +38,12 @@
     fn protocol_info(&self) -> Self::InfoIter;
 }
 
-impl UpgradeInfoSend for upgrade::ProtocolName {
-    type InfoIter = iter::Once<upgrade::ProtocolName>;
+impl<T> UpgradeInfoSend for T
+where
+    T: upgrade::UpgradeInfo + Send + 'static,
+    <T::InfoIter as IntoIterator>::IntoIter: Send + 'static,
+{
+    type InfoIter = <<T as upgrade::UpgradeInfo>::InfoIter as IntoIterator>::IntoIter;
 
     fn protocol_info(&self) -> Self::InfoIter {
         upgrade::UpgradeInfo::protocol_info(self).into_iter()
@@ -61,7 +64,11 @@
     type Future: Future<Output = Result<Self::Output, Self::Error>> + Send + 'static;
 
     /// Equivalent to [`OutboundUpgrade::upgrade_outbound`](upgrade::OutboundUpgrade::upgrade_outbound).
-    fn upgrade_outbound(self, socket: NegotiatedSubstream, info: upgrade::ProtocolName) -> Self::Future;
+    fn upgrade_outbound(
+        self,
+        socket: NegotiatedSubstream,
+        info: upgrade::ProtocolName,
+    ) -> Self::Future;
 }
 
 impl<T> OutboundUpgradeSend for T
@@ -75,7 +82,11 @@
     type Error = T::Error;
     type Future = T::Future;
 
-    fn upgrade_outbound(self, socket: NegotiatedSubstream, info: upgrade::ProtocolName) -> Self::Future {
+    fn upgrade_outbound(
+        self,
+        socket: NegotiatedSubstream,
+        info: upgrade::ProtocolName,
+    ) -> Self::Future {
         upgrade::OutboundUpgrade::upgrade_outbound(self, socket, info)
     }
 }
@@ -94,7 +105,11 @@
     type Future: Future<Output = Result<Self::Output, Self::Error>> + Send + 'static;
 
     /// Equivalent to [`InboundUpgrade::upgrade_inbound`](upgrade::InboundUpgrade::upgrade_inbound).
-    fn upgrade_inbound(self, socket: NegotiatedSubstream, info: upgrade::ProtocolName) -> Self::Future;
+    fn upgrade_inbound(
+        self,
+        socket: NegotiatedSubstream,
+        info: upgrade::ProtocolName,
+    ) -> Self::Future;
 }
 
 impl<T> InboundUpgradeSend for T
@@ -108,7 +123,11 @@
     type Error = T::Error;
     type Future = T::Future;
 
-    fn upgrade_inbound(self, socket: NegotiatedSubstream, info: upgrade::ProtocolName) -> Self::Future {
+    fn upgrade_inbound(
+        self,
+        socket: NegotiatedSubstream,
+        info: upgrade::ProtocolName,
+    ) -> Self::Future {
         upgrade::InboundUpgrade::upgrade_inbound(self, socket, info)
     }
 }
@@ -134,7 +153,11 @@
     type Error = T::Error;
     type Future = T::Future;
 
-    fn upgrade_outbound(self, socket: NegotiatedSubstream, info: upgrade::ProtocolName) -> Self::Future {
+    fn upgrade_outbound(
+        self,
+        socket: NegotiatedSubstream,
+        info: upgrade::ProtocolName,
+    ) -> Self::Future {
         OutboundUpgradeSend::upgrade_outbound(self.0, socket, info)
     }
 }
@@ -144,7 +167,11 @@
     type Error = T::Error;
     type Future = T::Future;
 
-    fn upgrade_inbound(self, socket: NegotiatedSubstream, info: upgrade::ProtocolName) -> Self::Future {
+    fn upgrade_inbound(
+        self,
+        socket: NegotiatedSubstream,
+        info: upgrade::ProtocolName,
+    ) -> Self::Future {
         InboundUpgradeSend::upgrade_inbound(self.0, socket, info)
     }
 }

@efarg
Copy link
Contributor Author

efarg commented Dec 2, 2022

@efarg You seem to have disabled push access for me so I can't push a commit to this branch :)

I think that happened because my github token expired a couple days back. Not sure. Sorry. Were you pushing to master or 2966?

@thomaseizinger
Copy link
Contributor

@efarg You seem to have disabled push access for me so I can't push a commit to this branch :)

I think that happened because my github token expired a couple days back. Not sure. Sorry. Were you pushing to master or 2966?

To master, i.e. where this PR is opened from.

There should be a checkbox on the right side of this PR, next to the list of "participants" where you can select "allow edits from maintainers". Make sure that is checked!

@thomaseizinger
Copy link
Contributor

In any case, did the patch help you? :)

@thomaseizinger
Copy link
Contributor

@efarg Friendly ping. Did you manage to make any progress on this?

@mergify
Copy link
Contributor

mergify bot commented Mar 22, 2023

This pull request has merge conflicts. Could you please resolve them @efarg? 🙏

@thomaseizinger
Copy link
Contributor

Replaced by #3746.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants