From 0c34d9fdd45e81892824ba5faf3875ab35f14f1b Mon Sep 17 00:00:00 2001
From: hanabi1224 <harlowmoo@gmail.com>
Date: Fri, 15 Nov 2024 02:09:15 +0700
Subject: [PATCH] chore: deprecate `void` crate (#5676)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

## Description

<!--
Please write a summary of your changes and why you made them.
This section will appear as the commit message after merging.
Please craft it accordingly.
For a quick primer on good commit messages, check out this blog post:
https://cbea.ms/git-commit/

Please include any relevant issues in here, for example:

Related https://github.com/libp2p/rust-libp2p/issues/ABCD.
Fixes https://github.com/libp2p/rust-libp2p/issues/XYZ.
-->

The `void` crate provides a `Void` type that is conceptually equivalent
to the [`never`
type(!)](https://doc.rust-lang.org/std/primitive.never.html). This PR
tries to remove `void` crate from the dependency tree by replacing
`void::Void` with
[`std::convert::Infallible`](https://doc.rust-lang.org/std/convert/enum.Infallible.html)
that will eventually become an alias of the `never` type(!)

> This enum has the same role as [the ! “never”
type](https://doc.rust-lang.org/std/primitive.never.html), which is
unstable in this version of Rust. When ! is stabilized, we plan to make
Infallible a type alias to it:

## Notes & open questions

<!--
Any notes, remarks or open questions you have to make about the PR which
don't need to go into the final commit message.
-->

## Change checklist

<!-- Please add a Changelog entry in the appropriate crates and bump the
crate versions if needed. See
<https://github.com/libp2p/rust-libp2p/blob/master/docs/release.md#development-between-releases>-->

- [x] I have performed a self-review of my own code
- [ ] I have made corresponding changes to the documentation
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] A changelog entry has been made in the appropriate crates
---
 Cargo.lock                                    | 26 ----------------
 core/Cargo.toml                               |  1 -
 core/src/lib.rs                               | 10 +++++++
 core/src/upgrade/denied.rs                    | 10 +++----
 core/src/upgrade/pending.rs                   | 10 +++----
 core/src/upgrade/ready.rs                     |  6 ++--
 examples/file-sharing/Cargo.toml              |  1 -
 identity/Cargo.toml                           |  3 +-
 identity/src/ecdsa.rs                         |  7 +++--
 misc/allow-block-list/Cargo.toml              |  1 -
 misc/allow-block-list/src/lib.rs              |  6 ++--
 misc/connection-limits/Cargo.toml             |  1 -
 misc/connection-limits/src/lib.rs             | 10 +++----
 misc/memory-connection-limits/Cargo.toml      |  1 -
 misc/memory-connection-limits/src/lib.rs      |  6 ++--
 .../tests/util/mod.rs                         |  6 ++--
 protocols/autonat/Cargo.toml                  |  3 +-
 .../src/v2/client/handler/dial_back.rs        |  6 ++--
 .../src/v2/client/handler/dial_request.rs     |  5 ++--
 protocols/autonat/src/v2/server/behaviour.rs  |  2 +-
 .../src/v2/server/handler/dial_request.rs     |  3 +-
 protocols/dcutr/Cargo.toml                    |  1 -
 protocols/dcutr/src/behaviour.rs              |  6 ++--
 protocols/dcutr/src/handler/relayed.rs        |  6 ++--
 protocols/gossipsub/Cargo.toml                |  1 -
 protocols/gossipsub/src/handler.rs            |  4 +--
 protocols/gossipsub/src/protocol.rs           |  6 ++--
 protocols/identify/Cargo.toml                 |  1 -
 protocols/identify/src/handler.rs             |  2 +-
 protocols/kad/Cargo.toml                      |  1 -
 protocols/kad/src/handler.rs                  |  4 +--
 protocols/mdns/Cargo.toml                     |  1 -
 protocols/mdns/src/behaviour.rs               |  2 +-
 protocols/perf/Cargo.toml                     |  1 -
 protocols/perf/src/client.rs                  |  4 +--
 protocols/perf/src/client/handler.rs          |  4 +--
 protocols/perf/src/server/handler.rs          | 14 ++++-----
 protocols/ping/Cargo.toml                     |  1 -
 protocols/ping/src/handler.rs                 |  8 ++---
 protocols/relay/Cargo.toml                    |  1 -
 protocols/relay/src/behaviour.rs              |  2 +-
 protocols/relay/src/behaviour/handler.rs      |  2 +-
 protocols/relay/src/priv_client.rs            |  6 ++--
 protocols/relay/src/priv_client/handler.rs    | 14 ++++-----
 protocols/rendezvous/Cargo.toml               |  1 -
 protocols/request-response/Cargo.toml         |  1 -
 protocols/request-response/src/handler.rs     |  4 +--
 .../request-response/src/handler/protocol.rs  |  6 ++--
 protocols/stream/Cargo.toml                   |  1 -
 protocols/stream/src/behaviour.rs             |  2 +-
 protocols/stream/src/handler.rs               |  9 +++---
 protocols/stream/src/upgrade.rs               |  9 ++++--
 protocols/upnp/Cargo.toml                     |  1 -
 protocols/upnp/src/behaviour.rs               |  2 +-
 swarm/Cargo.toml                              |  2 --
 swarm/src/behaviour/toggle.rs                 |  4 +--
 swarm/src/connection.rs                       | 30 +++++++++----------
 swarm/src/connection/pool.rs                  |  4 +--
 swarm/src/connection/pool/task.rs             | 10 +++----
 swarm/src/dummy.rs                            | 20 ++++++-------
 swarm/src/handler/one_shot.rs                 |  4 +--
 swarm/src/handler/pending.rs                  | 16 +++++-----
 swarm/tests/connection_close.rs               |  6 ++--
 swarm/tests/listener.rs                       |  3 +-
 swarm/tests/swarm_derive.rs                   | 10 +++----
 65 files changed, 168 insertions(+), 193 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index e5e41d3bdf8..5ef3a17a4a1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1570,7 +1570,6 @@ dependencies = [
  "tokio",
  "tracing",
  "tracing-subscriber",
- "void",
 ]
 
 [[package]]
@@ -2586,7 +2585,6 @@ dependencies = [
  "libp2p-swarm",
  "libp2p-swarm-derive",
  "libp2p-swarm-test",
- "void",
 ]
 
 [[package]]
@@ -2615,7 +2613,6 @@ dependencies = [
  "tokio",
  "tracing",
  "tracing-subscriber",
- "void",
  "web-time 1.1.0",
 ]
 
@@ -2633,7 +2630,6 @@ dependencies = [
  "libp2p-swarm-test",
  "quickcheck-ext",
  "rand 0.8.5",
- "void",
 ]
 
 [[package]]
@@ -2663,7 +2659,6 @@ dependencies = [
  "thiserror",
  "tracing",
  "unsigned-varint 0.8.0",
- "void",
  "web-time 1.1.0",
 ]
 
@@ -2697,7 +2692,6 @@ dependencies = [
  "thiserror",
  "tracing",
  "tracing-subscriber",
- "void",
  "web-time 1.1.0",
 ]
 
@@ -2772,7 +2766,6 @@ dependencies = [
  "smallvec",
  "tracing",
  "tracing-subscriber",
- "void",
  "web-time 1.1.0",
 ]
 
@@ -2797,7 +2790,6 @@ dependencies = [
  "thiserror",
  "tracing",
  "tracing-subscriber",
- "void",
 ]
 
 [[package]]
@@ -2825,7 +2817,6 @@ dependencies = [
  "sha2 0.10.8",
  "thiserror",
  "tracing",
- "void",
  "zeroize",
 ]
 
@@ -2860,7 +2851,6 @@ dependencies = [
  "tracing",
  "tracing-subscriber",
  "uint",
- "void",
  "web-time 1.1.0",
 ]
 
@@ -2887,7 +2877,6 @@ dependencies = [
  "tokio",
  "tracing",
  "tracing-subscriber",
- "void",
 ]
 
 [[package]]
@@ -2905,7 +2894,6 @@ dependencies = [
  "rand 0.8.5",
  "sysinfo",
  "tracing",
- "void",
 ]
 
 [[package]]
@@ -3015,7 +3003,6 @@ dependencies = [
  "tokio",
  "tracing",
  "tracing-subscriber",
- "void",
  "web-time 1.1.0",
 ]
 
@@ -3035,7 +3022,6 @@ dependencies = [
  "tokio",
  "tracing",
  "tracing-subscriber",
- "void",
  "web-time 1.1.0",
 ]
 
@@ -3132,7 +3118,6 @@ dependencies = [
  "thiserror",
  "tracing",
  "tracing-subscriber",
- "void",
  "web-time 1.1.0",
 ]
 
@@ -3162,7 +3147,6 @@ dependencies = [
  "tokio",
  "tracing",
  "tracing-subscriber",
- "void",
  "web-time 1.1.0",
 ]
 
@@ -3191,7 +3175,6 @@ dependencies = [
  "smallvec",
  "tracing",
  "tracing-subscriber",
- "void",
  "web-time 1.1.0",
 ]
 
@@ -3228,7 +3211,6 @@ dependencies = [
  "tokio",
  "tracing",
  "tracing-subscriber",
- "void",
 ]
 
 [[package]]
@@ -3261,7 +3243,6 @@ dependencies = [
  "tracing",
  "tracing-subscriber",
  "trybuild",
- "void",
  "wasm-bindgen-futures",
  "web-time 1.1.0",
 ]
@@ -3356,7 +3337,6 @@ dependencies = [
  "libp2p-swarm",
  "tokio",
  "tracing",
- "void",
 ]
 
 [[package]]
@@ -6507,12 +6487,6 @@ version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
-[[package]]
-name = "void"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-
 [[package]]
 name = "waitgroup"
 version = "0.1.2"
diff --git a/core/Cargo.toml b/core/Cargo.toml
index 8a083276e7f..d8260e14d1f 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -31,7 +31,6 @@ smallvec = "1.13.2"
 thiserror = "1.0"
 tracing = { workspace = true }
 unsigned-varint = { workspace = true }
-void = "1"
 
 [dev-dependencies]
 async-std = { version = "1.6.2", features = ["attributes"] }
diff --git a/core/src/lib.rs b/core/src/lib.rs
index a42f56773df..ab5afbedae4 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -66,3 +66,13 @@ pub use upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
 #[derive(Debug, thiserror::Error)]
 #[error(transparent)]
 pub struct DecodeError(quick_protobuf::Error);
+
+pub mod util {
+    use std::convert::Infallible;
+
+    /// A safe version of [`std::intrinsics::unreachable`].
+    #[inline(always)]
+    pub fn unreachable(x: Infallible) -> ! {
+        match x {}
+    }
+}
diff --git a/core/src/upgrade/denied.rs b/core/src/upgrade/denied.rs
index 353a184822d..568bbfb056d 100644
--- a/core/src/upgrade/denied.rs
+++ b/core/src/upgrade/denied.rs
@@ -20,8 +20,8 @@
 
 use crate::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
 use futures::future;
+use std::convert::Infallible;
 use std::iter;
-use void::Void;
 
 /// Dummy implementation of `UpgradeInfo`/`InboundUpgrade`/`OutboundUpgrade` that doesn't support
 /// any protocol.
@@ -38,8 +38,8 @@ impl UpgradeInfo for DeniedUpgrade {
 }
 
 impl<C> InboundUpgrade<C> for DeniedUpgrade {
-    type Output = Void;
-    type Error = Void;
+    type Output = Infallible;
+    type Error = Infallible;
     type Future = future::Pending<Result<Self::Output, Self::Error>>;
 
     fn upgrade_inbound(self, _: C, _: Self::Info) -> Self::Future {
@@ -48,8 +48,8 @@ impl<C> InboundUpgrade<C> for DeniedUpgrade {
 }
 
 impl<C> OutboundUpgrade<C> for DeniedUpgrade {
-    type Output = Void;
-    type Error = Void;
+    type Output = Infallible;
+    type Error = Infallible;
     type Future = future::Pending<Result<Self::Output, Self::Error>>;
 
     fn upgrade_outbound(self, _: C, _: Self::Info) -> Self::Future {
diff --git a/core/src/upgrade/pending.rs b/core/src/upgrade/pending.rs
index 6931e20bfdc..5e3c65422f1 100644
--- a/core/src/upgrade/pending.rs
+++ b/core/src/upgrade/pending.rs
@@ -21,8 +21,8 @@
 
 use crate::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
 use futures::future;
+use std::convert::Infallible;
 use std::iter;
-use void::Void;
 
 /// Implementation of [`UpgradeInfo`], [`InboundUpgrade`] and [`OutboundUpgrade`] that always
 /// returns a pending upgrade.
@@ -53,8 +53,8 @@ impl<C, P> InboundUpgrade<C> for PendingUpgrade<P>
 where
     P: AsRef<str> + Clone,
 {
-    type Output = Void;
-    type Error = Void;
+    type Output = Infallible;
+    type Error = Infallible;
     type Future = future::Pending<Result<Self::Output, Self::Error>>;
 
     fn upgrade_inbound(self, _: C, _: Self::Info) -> Self::Future {
@@ -66,8 +66,8 @@ impl<C, P> OutboundUpgrade<C> for PendingUpgrade<P>
 where
     P: AsRef<str> + Clone,
 {
-    type Output = Void;
-    type Error = Void;
+    type Output = Infallible;
+    type Error = Infallible;
     type Future = future::Pending<Result<Self::Output, Self::Error>>;
 
     fn upgrade_outbound(self, _: C, _: Self::Info) -> Self::Future {
diff --git a/core/src/upgrade/ready.rs b/core/src/upgrade/ready.rs
index 7e235902651..13270aa8b6d 100644
--- a/core/src/upgrade/ready.rs
+++ b/core/src/upgrade/ready.rs
@@ -21,8 +21,8 @@
 
 use crate::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
 use futures::future;
+use std::convert::Infallible;
 use std::iter;
-use void::Void;
 
 /// Implementation of [`UpgradeInfo`], [`InboundUpgrade`] and [`OutboundUpgrade`] that directly yields the substream.
 #[derive(Debug, Copy, Clone)]
@@ -53,7 +53,7 @@ where
     P: AsRef<str> + Clone,
 {
     type Output = C;
-    type Error = Void;
+    type Error = Infallible;
     type Future = future::Ready<Result<Self::Output, Self::Error>>;
 
     fn upgrade_inbound(self, stream: C, _: Self::Info) -> Self::Future {
@@ -66,7 +66,7 @@ where
     P: AsRef<str> + Clone,
 {
     type Output = C;
-    type Error = Void;
+    type Error = Infallible;
     type Future = future::Ready<Result<Self::Output, Self::Error>>;
 
     fn upgrade_outbound(self, stream: C, _: Self::Info) -> Self::Future {
diff --git a/examples/file-sharing/Cargo.toml b/examples/file-sharing/Cargo.toml
index 7cbb96cc7ed..d098ce44317 100644
--- a/examples/file-sharing/Cargo.toml
+++ b/examples/file-sharing/Cargo.toml
@@ -16,7 +16,6 @@ futures = { workspace = true }
 libp2p = { path = "../../libp2p", features = [ "tokio", "cbor", "dns", "kad", "noise", "macros", "request-response", "tcp", "websocket", "yamux"] }
 tracing = { workspace = true }
 tracing-subscriber = { workspace = true, features = ["env-filter"] }
-void = "1.0.2"
 
 [lints]
 workspace = true
diff --git a/identity/Cargo.toml b/identity/Cargo.toml
index cb0b8cb000e..370533eed58 100644
--- a/identity/Cargo.toml
+++ b/identity/Cargo.toml
@@ -26,7 +26,6 @@ sec1 = { version = "0.7", default-features = false, optional = true }
 serde = { version = "1", optional = true, features = ["derive"] }
 sha2 = { version = "0.10.8", optional = true }
 thiserror = { version = "1.0", optional = true }
-void = { version = "1.0", optional = true }
 zeroize = { version = "1.8", optional = true }
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
@@ -34,7 +33,7 @@ ring = { workspace = true, features = ["alloc", "std"], optional = true }
 
 [features]
 secp256k1 = ["dep:libsecp256k1", "dep:asn1_der", "dep:sha2", "dep:hkdf", "dep:zeroize"]
-ecdsa = ["dep:p256", "dep:void", "dep:zeroize", "dep:sec1", "dep:sha2", "dep:hkdf"]
+ecdsa = ["dep:p256", "dep:zeroize", "dep:sec1", "dep:sha2", "dep:hkdf"]
 rsa = ["dep:ring", "dep:asn1_der", "dep:rand", "dep:zeroize"]
 ed25519 = ["dep:ed25519-dalek", "dep:zeroize", "dep:sha2", "dep:hkdf"]
 peerid = ["dep:multihash", "dep:bs58", "dep:thiserror", "dep:sha2", "dep:hkdf"]
diff --git a/identity/src/ecdsa.rs b/identity/src/ecdsa.rs
index 65cbe885b86..922675097df 100644
--- a/identity/src/ecdsa.rs
+++ b/identity/src/ecdsa.rs
@@ -32,7 +32,7 @@ use p256::{
     EncodedPoint,
 };
 use sec1::{DecodeEcPrivateKey, EncodeEcPrivateKey};
-use void::Void;
+use std::convert::Infallible;
 use zeroize::Zeroize;
 
 /// An ECDSA keypair generated using `secp256r1` curve.
@@ -182,7 +182,10 @@ impl PublicKey {
     /// Try to decode a public key from a DER encoded byte buffer as defined by SEC1 standard.
     pub fn try_decode_der(k: &[u8]) -> Result<PublicKey, DecodingError> {
         let buf = Self::del_asn1_header(k).ok_or_else(|| {
-            DecodingError::failed_to_parse::<Void, _>("ASN.1-encoded ecdsa p256 public key", None)
+            DecodingError::failed_to_parse::<Infallible, _>(
+                "ASN.1-encoded ecdsa p256 public key",
+                None,
+            )
         })?;
         Self::try_from_bytes(buf)
     }
diff --git a/misc/allow-block-list/Cargo.toml b/misc/allow-block-list/Cargo.toml
index 1ff0ccff906..c169be87056 100644
--- a/misc/allow-block-list/Cargo.toml
+++ b/misc/allow-block-list/Cargo.toml
@@ -13,7 +13,6 @@ categories = ["network-programming", "asynchronous"]
 libp2p-core = { workspace = true }
 libp2p-swarm = { workspace = true }
 libp2p-identity = { workspace = true, features = ["peerid"] }
-void = "1"
 
 [dev-dependencies]
 async-std = { version = "1.12.0", features = ["attributes"] }
diff --git a/misc/allow-block-list/src/lib.rs b/misc/allow-block-list/src/lib.rs
index 56de29d1985..f93cf4ffefa 100644
--- a/misc/allow-block-list/src/lib.rs
+++ b/misc/allow-block-list/src/lib.rs
@@ -69,9 +69,9 @@ use libp2p_swarm::{
     THandlerInEvent, THandlerOutEvent, ToSwarm,
 };
 use std::collections::{HashSet, VecDeque};
+use std::convert::Infallible;
 use std::fmt;
 use std::task::{Context, Poll, Waker};
-use void::Void;
 
 /// A [`NetworkBehaviour`] that can act as an allow or block list.
 #[derive(Default, Debug)]
@@ -222,7 +222,7 @@ where
     S: Enforce,
 {
     type ConnectionHandler = dummy::ConnectionHandler;
-    type ToSwarm = Void;
+    type ToSwarm = Infallible;
 
     fn handle_established_inbound_connection(
         &mut self,
@@ -273,7 +273,7 @@ where
     ) {
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        void::unreachable(event)
+        libp2p_core::util::unreachable(event)
     }
 
     fn poll(
diff --git a/misc/connection-limits/Cargo.toml b/misc/connection-limits/Cargo.toml
index 56fe97f984b..0d17cb74862 100644
--- a/misc/connection-limits/Cargo.toml
+++ b/misc/connection-limits/Cargo.toml
@@ -13,7 +13,6 @@ categories = ["network-programming", "asynchronous"]
 libp2p-core = { workspace = true }
 libp2p-swarm = { workspace = true }
 libp2p-identity = { workspace = true, features = ["peerid"] }
-void = "1"
 
 [dev-dependencies]
 async-std = { version = "1.12.0", features = ["attributes"] }
diff --git a/misc/connection-limits/src/lib.rs b/misc/connection-limits/src/lib.rs
index 05a9b639f26..016a7f2cfd4 100644
--- a/misc/connection-limits/src/lib.rs
+++ b/misc/connection-limits/src/lib.rs
@@ -26,9 +26,9 @@ use libp2p_swarm::{
     THandlerInEvent, THandlerOutEvent, ToSwarm,
 };
 use std::collections::{HashMap, HashSet};
+use std::convert::Infallible;
 use std::fmt;
 use std::task::{Context, Poll};
-use void::Void;
 
 /// A [`NetworkBehaviour`] that enforces a set of [`ConnectionLimits`].
 ///
@@ -203,7 +203,7 @@ impl ConnectionLimits {
 
 impl NetworkBehaviour for Behaviour {
     type ConnectionHandler = dummy::ConnectionHandler;
-    type ToSwarm = Void;
+    type ToSwarm = Infallible;
 
     fn handle_pending_inbound_connection(
         &mut self,
@@ -357,7 +357,7 @@ impl NetworkBehaviour for Behaviour {
     ) {
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        void::unreachable(event)
+        libp2p_core::util::unreachable(event)
     }
 
     fn poll(&mut self, _: &mut Context<'_>) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
@@ -551,7 +551,7 @@ mod tests {
 
     impl NetworkBehaviour for ConnectionDenier {
         type ConnectionHandler = dummy::ConnectionHandler;
-        type ToSwarm = Void;
+        type ToSwarm = Infallible;
 
         fn handle_established_inbound_connection(
             &mut self,
@@ -590,7 +590,7 @@ mod tests {
         ) {
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            void::unreachable(event)
+            libp2p_core::util::unreachable(event)
         }
 
         fn poll(
diff --git a/misc/memory-connection-limits/Cargo.toml b/misc/memory-connection-limits/Cargo.toml
index f56ed33d5ad..19ae256e853 100644
--- a/misc/memory-connection-limits/Cargo.toml
+++ b/misc/memory-connection-limits/Cargo.toml
@@ -16,7 +16,6 @@ libp2p-swarm = { workspace = true }
 libp2p-identity = { workspace = true, features = ["peerid"] }
 sysinfo = "0.30"
 tracing = { workspace = true }
-void = "1"
 
 [dev-dependencies]
 async-std = { version = "1.12.0", features = ["attributes"] }
diff --git a/misc/memory-connection-limits/src/lib.rs b/misc/memory-connection-limits/src/lib.rs
index 757ff770487..e2a89977991 100644
--- a/misc/memory-connection-limits/src/lib.rs
+++ b/misc/memory-connection-limits/src/lib.rs
@@ -24,7 +24,7 @@ use libp2p_swarm::{
     dummy, ConnectionDenied, ConnectionId, FromSwarm, NetworkBehaviour, THandler, THandlerInEvent,
     THandlerOutEvent, ToSwarm,
 };
-use void::Void;
+use std::convert::Infallible;
 
 use std::{
     fmt,
@@ -139,7 +139,7 @@ impl Behaviour {
 
 impl NetworkBehaviour for Behaviour {
     type ConnectionHandler = dummy::ConnectionHandler;
-    type ToSwarm = Void;
+    type ToSwarm = Infallible;
 
     fn handle_pending_inbound_connection(
         &mut self,
@@ -192,7 +192,7 @@ impl NetworkBehaviour for Behaviour {
     ) {
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        void::unreachable(event)
+        libp2p_core::util::unreachable(event)
     }
 
     fn poll(&mut self, _: &mut Context<'_>) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
diff --git a/misc/memory-connection-limits/tests/util/mod.rs b/misc/memory-connection-limits/tests/util/mod.rs
index 01e8cd9f655..333b0ee135f 100644
--- a/misc/memory-connection-limits/tests/util/mod.rs
+++ b/misc/memory-connection-limits/tests/util/mod.rs
@@ -26,7 +26,7 @@ use libp2p_swarm::{
     dummy, ConnectionDenied, ConnectionId, FromSwarm, NetworkBehaviour, THandler, THandlerInEvent,
     THandlerOutEvent, ToSwarm,
 };
-use void::Void;
+use std::convert::Infallible;
 
 #[derive(libp2p_swarm_derive::NetworkBehaviour)]
 #[behaviour(prelude = "libp2p_swarm::derive_prelude")]
@@ -62,7 +62,7 @@ impl<const MEM_PENDING: usize, const MEM_ESTABLISHED: usize> NetworkBehaviour
     for ConsumeMemoryBehaviour<MEM_PENDING, MEM_ESTABLISHED>
 {
     type ConnectionHandler = dummy::ConnectionHandler;
-    type ToSwarm = Void;
+    type ToSwarm = Infallible;
 
     fn handle_pending_inbound_connection(
         &mut self,
@@ -118,7 +118,7 @@ impl<const MEM_PENDING: usize, const MEM_ESTABLISHED: usize> NetworkBehaviour
     ) {
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        void::unreachable(event)
+        libp2p_core::util::unreachable(event)
     }
 
     fn poll(&mut self, _: &mut Context<'_>) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
diff --git a/protocols/autonat/Cargo.toml b/protocols/autonat/Cargo.toml
index 0c0e757641d..169006e7508 100644
--- a/protocols/autonat/Cargo.toml
+++ b/protocols/autonat/Cargo.toml
@@ -30,7 +30,6 @@ quick-protobuf-codec = { workspace = true }
 rand = "0.8"
 rand_core = { version = "0.6", optional = true }
 thiserror = { version = "1.0.52", optional = true }
-void = { version = "1", optional = true }
 
 [dev-dependencies]
 tokio = { version = "1", features = ["macros", "rt", "sync"]}
@@ -43,7 +42,7 @@ libp2p-swarm = { workspace = true, features = ["macros"]}
 [features]
 default = ["v1", "v2"]
 v1 = ["dep:libp2p-request-response", "dep:web-time", "dep:async-trait"]
-v2 = ["dep:bytes", "dep:either", "dep:futures-bounded", "dep:thiserror", "dep:void", "dep:rand_core"]
+v2 = ["dep:bytes", "dep:either", "dep:futures-bounded", "dep:thiserror", "dep:rand_core"]
 
 # Passing arguments to the docsrs builder in order to properly document cfg's.
 # More information: https://docs.rs/about/builds#cross-compiling
diff --git a/protocols/autonat/src/v2/client/handler/dial_back.rs b/protocols/autonat/src/v2/client/handler/dial_back.rs
index 98a41a82504..b3b3a59c02d 100644
--- a/protocols/autonat/src/v2/client/handler/dial_back.rs
+++ b/protocols/autonat/src/v2/client/handler/dial_back.rs
@@ -11,7 +11,7 @@ use libp2p_swarm::{
     handler::{ConnectionEvent, FullyNegotiatedInbound, ListenUpgradeError},
     ConnectionHandler, ConnectionHandlerEvent, StreamProtocol, SubstreamProtocol,
 };
-use void::Void;
+use std::convert::Infallible;
 
 use crate::v2::{protocol, Nonce, DIAL_BACK_PROTOCOL};
 
@@ -28,7 +28,7 @@ impl Handler {
 }
 
 impl ConnectionHandler for Handler {
-    type FromBehaviour = Void;
+    type FromBehaviour = Infallible;
     type ToBehaviour = IncomingNonce;
     type InboundProtocol = ReadyUpgrade<StreamProtocol>;
     type OutboundProtocol = DeniedUpgrade;
@@ -86,7 +86,7 @@ impl ConnectionHandler for Handler {
             // TODO: remove when Rust 1.82 is MSRVprotocols/autonat/src/v2/client/handler/dial_back.rs
             #[allow(unreachable_patterns)]
             ConnectionEvent::ListenUpgradeError(ListenUpgradeError { error, .. }) => {
-                void::unreachable(error);
+                libp2p_core::util::unreachable(error);
             }
             _ => {}
         }
diff --git a/protocols/autonat/src/v2/client/handler/dial_request.rs b/protocols/autonat/src/v2/client/handler/dial_request.rs
index 85ad176ec30..0f303167523 100644
--- a/protocols/autonat/src/v2/client/handler/dial_request.rs
+++ b/protocols/autonat/src/v2/client/handler/dial_request.rs
@@ -15,6 +15,7 @@ use libp2p_swarm::{
 };
 use std::{
     collections::VecDeque,
+    convert::Infallible,
     io,
     iter::{once, repeat},
     task::{Context, Poll},
@@ -208,7 +209,7 @@ impl ConnectionHandler for Handler {
 
 async fn start_stream_handle(
     req: DialRequest,
-    stream_recv: oneshot::Receiver<Result<Stream, StreamUpgradeError<void::Void>>>,
+    stream_recv: oneshot::Receiver<Result<Stream, StreamUpgradeError<Infallible>>>,
 ) -> Result<(Multiaddr, usize), Error> {
     let stream = stream_recv
         .await
@@ -218,7 +219,7 @@ async fn start_stream_handle(
             StreamUpgradeError::Timeout => Error::Io(io::ErrorKind::TimedOut.into()),
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            StreamUpgradeError::Apply(v) => void::unreachable(v),
+            StreamUpgradeError::Apply(v) => libp2p_core::util::unreachable(v),
             StreamUpgradeError::Io(e) => Error::Io(e),
         })?;
 
diff --git a/protocols/autonat/src/v2/server/behaviour.rs b/protocols/autonat/src/v2/server/behaviour.rs
index 9264c728fe4..027cfff7c13 100644
--- a/protocols/autonat/src/v2/server/behaviour.rs
+++ b/protocols/autonat/src/v2/server/behaviour.rs
@@ -114,7 +114,7 @@ where
             }
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            Either::Left(Either::Right(v)) => void::unreachable(v),
+            Either::Left(Either::Right(v)) => libp2p_core::util::unreachable(v),
             Either::Right(Either::Left(cmd)) => {
                 let addr = cmd.addr.clone();
                 let opts = DialOpts::peer_id(peer_id)
diff --git a/protocols/autonat/src/v2/server/handler/dial_request.rs b/protocols/autonat/src/v2/server/handler/dial_request.rs
index 14ddb153416..5058e0f3f42 100644
--- a/protocols/autonat/src/v2/server/handler/dial_request.rs
+++ b/protocols/autonat/src/v2/server/handler/dial_request.rs
@@ -1,4 +1,5 @@
 use std::{
+    convert::Infallible,
     io,
     task::{Context, Poll},
     time::Duration,
@@ -73,7 +74,7 @@ impl<R> ConnectionHandler for Handler<R>
 where
     R: RngCore + Send + Clone + 'static,
 {
-    type FromBehaviour = void::Void;
+    type FromBehaviour = Infallible;
     type ToBehaviour = Either<DialBackCommand, Event>;
     type InboundProtocol = ReadyUpgrade<StreamProtocol>;
     type OutboundProtocol = DeniedUpgrade;
diff --git a/protocols/dcutr/Cargo.toml b/protocols/dcutr/Cargo.toml
index 6b1d04f82f5..c470291af0d 100644
--- a/protocols/dcutr/Cargo.toml
+++ b/protocols/dcutr/Cargo.toml
@@ -23,7 +23,6 @@ quick-protobuf = "0.8"
 quick-protobuf-codec = { workspace = true }
 thiserror = "1.0"
 tracing = { workspace = true }
-void = "1"
 lru = "0.12.3"
 futures-bounded = { workspace = true }
 
diff --git a/protocols/dcutr/src/behaviour.rs b/protocols/dcutr/src/behaviour.rs
index babd56bd28e..7d0366c98bc 100644
--- a/protocols/dcutr/src/behaviour.rs
+++ b/protocols/dcutr/src/behaviour.rs
@@ -36,10 +36,10 @@ use libp2p_swarm::{
 use libp2p_swarm::{NetworkBehaviour, NotifyHandler, THandlerInEvent, ToSwarm};
 use lru::LruCache;
 use std::collections::{HashMap, HashSet, VecDeque};
+use std::convert::Infallible;
 use std::num::NonZeroUsize;
 use std::task::{Context, Poll};
 use thiserror::Error;
-use void::Void;
 
 pub(crate) const MAX_NUMBER_OF_UPGRADE_ATTEMPTS: u8 = 3;
 
@@ -68,7 +68,7 @@ enum InnerError {
 
 pub struct Behaviour {
     /// Queue of actions to return when polled.
-    queued_events: VecDeque<ToSwarm<Event, Either<handler::relayed::Command, Void>>>,
+    queued_events: VecDeque<ToSwarm<Event, Either<handler::relayed::Command, Infallible>>>,
 
     /// All direct (non-relayed) connections.
     direct_connections: HashMap<PeerId, HashSet<ConnectionId>>,
@@ -316,7 +316,7 @@ impl NetworkBehaviour for Behaviour {
             }
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            Either::Right(never) => void::unreachable(never),
+            Either::Right(never) => libp2p_core::util::unreachable(never),
         };
     }
 
diff --git a/protocols/dcutr/src/handler/relayed.rs b/protocols/dcutr/src/handler/relayed.rs
index 72af9fec264..ad12a196cb9 100644
--- a/protocols/dcutr/src/handler/relayed.rs
+++ b/protocols/dcutr/src/handler/relayed.rs
@@ -117,7 +117,7 @@ impl Handler {
             // A connection listener denies all incoming substreams, thus none can ever be fully negotiated.
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            future::Either::Right(output) => void::unreachable(output),
+            future::Either::Right(output) => libp2p_core::util::unreachable(output),
         }
     }
 
@@ -157,7 +157,7 @@ impl Handler {
     ) {
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        void::unreachable(error.into_inner());
+        libp2p_core::util::unreachable(error.into_inner());
     }
 
     fn on_dial_upgrade_error(
@@ -170,7 +170,7 @@ impl Handler {
         let error = match error {
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            StreamUpgradeError::Apply(v) => void::unreachable(v),
+            StreamUpgradeError::Apply(v) => libp2p_core::util::unreachable(v),
             StreamUpgradeError::NegotiationFailed => outbound::Error::Unsupported,
             StreamUpgradeError::Io(e) => outbound::Error::Io(e),
             StreamUpgradeError::Timeout => outbound::Error::Io(io::ErrorKind::TimedOut.into()),
diff --git a/protocols/gossipsub/Cargo.toml b/protocols/gossipsub/Cargo.toml
index 734ac36a231..1416cdb8de3 100644
--- a/protocols/gossipsub/Cargo.toml
+++ b/protocols/gossipsub/Cargo.toml
@@ -36,7 +36,6 @@ serde = { version = "1", optional = true, features = ["derive"] }
 sha2 = "0.10.8"
 smallvec = "1.13.2"
 tracing = { workspace = true }
-void = "1.0.2"
 
 # Metrics dependencies
 prometheus-client = { workspace = true }
diff --git a/protocols/gossipsub/src/handler.rs b/protocols/gossipsub/src/handler.rs
index 8e3b3a8b022..0ccea667268 100644
--- a/protocols/gossipsub/src/handler.rs
+++ b/protocols/gossipsub/src/handler.rs
@@ -495,7 +495,7 @@ impl ConnectionHandler for Handler {
                         Either::Left(protocol) => handler.on_fully_negotiated_inbound(protocol),
                         // TODO: remove when Rust 1.82 is MSRV
                         #[allow(unreachable_patterns)]
-                        Either::Right(v) => void::unreachable(v),
+                        Either::Right(v) => libp2p_core::util::unreachable(v),
                     },
                     ConnectionEvent::FullyNegotiatedOutbound(fully_negotiated_outbound) => {
                         handler.on_fully_negotiated_outbound(fully_negotiated_outbound)
@@ -511,7 +511,7 @@ impl ConnectionHandler for Handler {
                     ConnectionEvent::DialUpgradeError(DialUpgradeError {
                         error: StreamUpgradeError::Apply(e),
                         ..
-                    }) => void::unreachable(e),
+                    }) => libp2p_core::util::unreachable(e),
                     ConnectionEvent::DialUpgradeError(DialUpgradeError {
                         error: StreamUpgradeError::NegotiationFailed,
                         ..
diff --git a/protocols/gossipsub/src/protocol.rs b/protocols/gossipsub/src/protocol.rs
index c13caae58b6..13edecd5846 100644
--- a/protocols/gossipsub/src/protocol.rs
+++ b/protocols/gossipsub/src/protocol.rs
@@ -34,8 +34,8 @@ use libp2p_core::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
 use libp2p_identity::{PeerId, PublicKey};
 use libp2p_swarm::StreamProtocol;
 use quick_protobuf::Writer;
+use std::convert::Infallible;
 use std::pin::Pin;
-use void::Void;
 
 pub(crate) const SIGNING_PREFIX: &[u8] = b"libp2p-pubsub:";
 
@@ -102,7 +102,7 @@ where
     TSocket: AsyncRead + AsyncWrite + Unpin + Send + 'static,
 {
     type Output = (Framed<TSocket, GossipsubCodec>, PeerKind);
-    type Error = Void;
+    type Error = Infallible;
     type Future = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>;
 
     fn upgrade_inbound(self, socket: TSocket, protocol_id: Self::Info) -> Self::Future {
@@ -121,7 +121,7 @@ where
     TSocket: AsyncWrite + AsyncRead + Unpin + Send + 'static,
 {
     type Output = (Framed<TSocket, GossipsubCodec>, PeerKind);
-    type Error = Void;
+    type Error = Infallible;
     type Future = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>;
 
     fn upgrade_outbound(self, socket: TSocket, protocol_id: Self::Info) -> Self::Future {
diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml
index 13c43b6a71f..87b3ed63774 100644
--- a/protocols/identify/Cargo.toml
+++ b/protocols/identify/Cargo.toml
@@ -24,7 +24,6 @@ quick-protobuf = "0.8"
 smallvec = "1.13.2"
 thiserror = "1.0"
 tracing = { workspace = true }
-void = "1.0"
 either = "1.12.0"
 
 [dev-dependencies]
diff --git a/protocols/identify/src/handler.rs b/protocols/identify/src/handler.rs
index f9b77e0b63a..dd073d50ed6 100644
--- a/protocols/identify/src/handler.rs
+++ b/protocols/identify/src/handler.rs
@@ -398,7 +398,7 @@ impl ConnectionHandler for Handler {
             ConnectionEvent::DialUpgradeError(DialUpgradeError { error, .. }) => {
                 self.events.push(ConnectionHandlerEvent::NotifyBehaviour(
                     Event::IdentificationError(
-                        error.map_upgrade_err(|e| void::unreachable(e.into_inner())),
+                        error.map_upgrade_err(|e| libp2p_core::util::unreachable(e.into_inner())),
                     ),
                 ));
                 self.trigger_next_identify.reset(self.interval);
diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml
index 5b95b8ac17d..11df81afbf8 100644
--- a/protocols/kad/Cargo.toml
+++ b/protocols/kad/Cargo.toml
@@ -27,7 +27,6 @@ rand = "0.8"
 sha2 = "0.10.8"
 smallvec = "1.13.2"
 uint = "0.9"
-void = "1.0"
 futures-timer = "3.0.3"
 web-time = { workspace = true }
 serde = { version = "1.0", optional = true, features = ["derive"] }
diff --git a/protocols/kad/src/handler.rs b/protocols/kad/src/handler.rs
index 17c483da709..384ebc3f2b1 100644
--- a/protocols/kad/src/handler.rs
+++ b/protocols/kad/src/handler.rs
@@ -498,12 +498,12 @@ impl Handler {
         >,
     ) {
         // If `self.allow_listening` is false, then we produced a `DeniedUpgrade` and `protocol`
-        // is a `Void`.
+        // is a `Infallible`.
         let protocol = match protocol {
             future::Either::Left(p) => p,
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            future::Either::Right(p) => void::unreachable(p),
+            future::Either::Right(p) => libp2p_core::util::unreachable(p),
         };
 
         if self.protocol_status.is_none() {
diff --git a/protocols/mdns/Cargo.toml b/protocols/mdns/Cargo.toml
index 19ae5ce9f36..338501aa896 100644
--- a/protocols/mdns/Cargo.toml
+++ b/protocols/mdns/Cargo.toml
@@ -25,7 +25,6 @@ socket2 = { version = "0.5.7", features = ["all"] }
 tokio = { workspace = true, default-features = false, features = ["net", "time"], optional = true}
 tracing = { workspace = true }
 hickory-proto = { version = "0.24.1", default-features = false, features = ["mdns"] }
-void = "1.0.2"
 
 [features]
 tokio = ["dep:tokio", "if-watch/tokio"]
diff --git a/protocols/mdns/src/behaviour.rs b/protocols/mdns/src/behaviour.rs
index 6355fbf4943..cecd27bf78b 100644
--- a/protocols/mdns/src/behaviour.rs
+++ b/protocols/mdns/src/behaviour.rs
@@ -275,7 +275,7 @@ where
         _: ConnectionId,
         ev: THandlerOutEvent<Self>,
     ) {
-        void::unreachable(ev)
+        libp2p_core::util::unreachable(ev)
     }
 
     fn on_swarm_event(&mut self, event: FromSwarm) {
diff --git a/protocols/perf/Cargo.toml b/protocols/perf/Cargo.toml
index 398bdce65ec..a1a6128c6ed 100644
--- a/protocols/perf/Cargo.toml
+++ b/protocols/perf/Cargo.toml
@@ -32,7 +32,6 @@ thiserror = "1.0"
 tracing = { workspace = true }
 tracing-subscriber = { workspace = true, features = ["env-filter"] }
 tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread"] }
-void = "1"
 
 [dev-dependencies]
 rand = "0.8"
diff --git a/protocols/perf/src/client.rs b/protocols/perf/src/client.rs
index c4614e979db..9f984a5bba1 100644
--- a/protocols/perf/src/client.rs
+++ b/protocols/perf/src/client.rs
@@ -25,7 +25,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
 
 pub use behaviour::{Behaviour, Event};
 use libp2p_swarm::StreamUpgradeError;
-use void::Void;
+use std::convert::Infallible;
 
 static NEXT_RUN_ID: AtomicUsize = AtomicUsize::new(1);
 
@@ -43,7 +43,7 @@ impl RunId {
 #[derive(thiserror::Error, Debug)]
 pub enum RunError {
     #[error(transparent)]
-    Upgrade(#[from] StreamUpgradeError<Void>),
+    Upgrade(#[from] StreamUpgradeError<Infallible>),
     #[error("Failed to execute perf run: {0}")]
     Io(#[from] std::io::Error),
 }
diff --git a/protocols/perf/src/client/handler.rs b/protocols/perf/src/client/handler.rs
index 55fafad7fcc..85e864949f8 100644
--- a/protocols/perf/src/client/handler.rs
+++ b/protocols/perf/src/client/handler.rs
@@ -116,7 +116,7 @@ impl ConnectionHandler for Handler {
             #[allow(unreachable_patterns)]
             ConnectionEvent::FullyNegotiatedInbound(FullyNegotiatedInbound {
                 protocol, ..
-            }) => void::unreachable(protocol),
+            }) => libp2p_core::util::unreachable(protocol),
             ConnectionEvent::FullyNegotiatedOutbound(FullyNegotiatedOutbound {
                 protocol,
                 info: (),
@@ -149,7 +149,7 @@ impl ConnectionHandler for Handler {
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
             ConnectionEvent::ListenUpgradeError(ListenUpgradeError { info: (), error }) => {
-                void::unreachable(error)
+                libp2p_core::util::unreachable(error)
             }
             _ => {}
         }
diff --git a/protocols/perf/src/server/handler.rs b/protocols/perf/src/server/handler.rs
index 4cb535a452c..c1363ae2380 100644
--- a/protocols/perf/src/server/handler.rs
+++ b/protocols/perf/src/server/handler.rs
@@ -29,8 +29,8 @@ use libp2p_swarm::{
     },
     ConnectionHandler, ConnectionHandlerEvent, StreamProtocol, SubstreamProtocol,
 };
+use std::convert::Infallible;
 use tracing::error;
-use void::Void;
 
 use crate::Run;
 
@@ -61,11 +61,11 @@ impl Default for Handler {
 }
 
 impl ConnectionHandler for Handler {
-    type FromBehaviour = Void;
+    type FromBehaviour = Infallible;
     type ToBehaviour = Event;
     type InboundProtocol = ReadyUpgrade<StreamProtocol>;
     type OutboundProtocol = DeniedUpgrade;
-    type OutboundOpenInfo = Void;
+    type OutboundOpenInfo = Infallible;
     type InboundOpenInfo = ();
 
     fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, Self::InboundOpenInfo> {
@@ -75,7 +75,7 @@ impl ConnectionHandler for Handler {
     fn on_behaviour_event(&mut self, v: Self::FromBehaviour) {
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        void::unreachable(v)
+        libp2p_core::util::unreachable(v)
     }
 
     fn on_connection_event(
@@ -103,13 +103,13 @@ impl ConnectionHandler for Handler {
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
             ConnectionEvent::FullyNegotiatedOutbound(FullyNegotiatedOutbound { info, .. }) => {
-                void::unreachable(info)
+                libp2p_core::util::unreachable(info)
             }
 
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
             ConnectionEvent::DialUpgradeError(DialUpgradeError { info, .. }) => {
-                void::unreachable(info)
+                libp2p_core::util::unreachable(info)
             }
             ConnectionEvent::AddressChange(_)
             | ConnectionEvent::LocalProtocolsChange(_)
@@ -117,7 +117,7 @@ impl ConnectionHandler for Handler {
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
             ConnectionEvent::ListenUpgradeError(ListenUpgradeError { info: (), error }) => {
-                void::unreachable(error)
+                libp2p_core::util::unreachable(error)
             }
             _ => {}
         }
diff --git a/protocols/ping/Cargo.toml b/protocols/ping/Cargo.toml
index 794ab54ba42..755ebd35718 100644
--- a/protocols/ping/Cargo.toml
+++ b/protocols/ping/Cargo.toml
@@ -20,7 +20,6 @@ libp2p-swarm = { workspace = true }
 libp2p-identity = { workspace = true }
 rand = "0.8"
 tracing = { workspace = true }
-void = "1.0"
 
 [dev-dependencies]
 libp2p-swarm = { workspace = true, features = ["macros"] }
diff --git a/protocols/ping/src/handler.rs b/protocols/ping/src/handler.rs
index 7b36b2d4b3d..961716e934a 100644
--- a/protocols/ping/src/handler.rs
+++ b/protocols/ping/src/handler.rs
@@ -31,13 +31,13 @@ use libp2p_swarm::{
     SubstreamProtocol,
 };
 use std::collections::VecDeque;
+use std::convert::Infallible;
 use std::{
     error::Error,
     fmt, io,
     task::{Context, Poll},
     time::Duration,
 };
-use void::Void;
 
 /// The configuration for outbound pings.
 #[derive(Debug, Clone)]
@@ -212,7 +212,7 @@ impl Handler {
             },
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            StreamUpgradeError::Apply(e) => void::unreachable(e),
+            StreamUpgradeError::Apply(e) => libp2p_core::util::unreachable(e),
             StreamUpgradeError::Io(e) => Failure::Other { error: Box::new(e) },
         };
 
@@ -221,7 +221,7 @@ impl Handler {
 }
 
 impl ConnectionHandler for Handler {
-    type FromBehaviour = Void;
+    type FromBehaviour = Infallible;
     type ToBehaviour = Result<Duration, Failure>;
     type InboundProtocol = ReadyUpgrade<StreamProtocol>;
     type OutboundProtocol = ReadyUpgrade<StreamProtocol>;
@@ -232,7 +232,7 @@ impl ConnectionHandler for Handler {
         SubstreamProtocol::new(ReadyUpgrade::new(PROTOCOL_NAME), ())
     }
 
-    fn on_behaviour_event(&mut self, _: Void) {}
+    fn on_behaviour_event(&mut self, _: Infallible) {}
 
     #[tracing::instrument(level = "trace", name = "ConnectionHandler::poll", skip(self, cx))]
     fn poll(
diff --git a/protocols/relay/Cargo.toml b/protocols/relay/Cargo.toml
index 084fec07efd..a3a659619b6 100644
--- a/protocols/relay/Cargo.toml
+++ b/protocols/relay/Cargo.toml
@@ -27,7 +27,6 @@ rand = "0.8.4"
 static_assertions = "1"
 thiserror = "1.0"
 tracing = { workspace = true }
-void = "1"
 
 [dev-dependencies]
 libp2p-identity = { workspace = true, features = ["rand"] }
diff --git a/protocols/relay/src/behaviour.rs b/protocols/relay/src/behaviour.rs
index 46419ae64e3..e854ed2a1ff 100644
--- a/protocols/relay/src/behaviour.rs
+++ b/protocols/relay/src/behaviour.rs
@@ -368,7 +368,7 @@ impl NetworkBehaviour for Behaviour {
             Either::Left(e) => e,
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            Either::Right(v) => void::unreachable(v),
+            Either::Right(v) => libp2p_core::util::unreachable(v),
         };
 
         match event {
diff --git a/protocols/relay/src/behaviour/handler.rs b/protocols/relay/src/behaviour/handler.rs
index 23e90f4b3f8..92e45720f3f 100644
--- a/protocols/relay/src/behaviour/handler.rs
+++ b/protocols/relay/src/behaviour/handler.rs
@@ -451,7 +451,7 @@ impl Handler {
             StreamUpgradeError::Io(e) => outbound_stop::Error::Io(e),
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            StreamUpgradeError::Apply(v) => void::unreachable(v),
+            StreamUpgradeError::Apply(v) => libp2p_core::util::unreachable(v),
         };
 
         let stop_command = self
diff --git a/protocols/relay/src/priv_client.rs b/protocols/relay/src/priv_client.rs
index 8bbc813ec4c..fc9d28e66ed 100644
--- a/protocols/relay/src/priv_client.rs
+++ b/protocols/relay/src/priv_client.rs
@@ -44,11 +44,11 @@ use libp2p_swarm::{
     NotifyHandler, Stream, THandler, THandlerInEvent, THandlerOutEvent, ToSwarm,
 };
 use std::collections::{hash_map, HashMap, VecDeque};
+use std::convert::Infallible;
 use std::io::{Error, ErrorKind, IoSlice};
 use std::pin::Pin;
 use std::task::{Context, Poll};
 use transport::Transport;
-use void::Void;
 
 /// The events produced by the client `Behaviour`.
 #[derive(Debug)]
@@ -93,7 +93,7 @@ pub struct Behaviour {
     reservation_addresses: HashMap<ConnectionId, (Multiaddr, ReservationStatus)>,
 
     /// Queue of actions to return when polled.
-    queued_actions: VecDeque<ToSwarm<Event, Either<handler::In, Void>>>,
+    queued_actions: VecDeque<ToSwarm<Event, Either<handler::In, Infallible>>>,
 
     pending_handler_commands: HashMap<ConnectionId, handler::In>,
 }
@@ -238,7 +238,7 @@ impl NetworkBehaviour for Behaviour {
             Either::Left(e) => e,
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            Either::Right(v) => void::unreachable(v),
+            Either::Right(v) => libp2p_core::util::unreachable(v),
         };
 
         let event = match handler_event {
diff --git a/protocols/relay/src/priv_client/handler.rs b/protocols/relay/src/priv_client/handler.rs
index 05fdd5673ae..77b7f94ae60 100644
--- a/protocols/relay/src/priv_client/handler.rs
+++ b/protocols/relay/src/priv_client/handler.rs
@@ -37,10 +37,10 @@ use libp2p_swarm::{
     SubstreamProtocol,
 };
 use std::collections::VecDeque;
+use std::convert::Infallible;
 use std::task::{Context, Poll};
 use std::time::Duration;
 use std::{fmt, io};
-use void::Void;
 
 /// The maximum number of circuits being denied concurrently.
 ///
@@ -106,7 +106,7 @@ pub struct Handler {
         >,
     >,
 
-    pending_streams: VecDeque<oneshot::Sender<Result<Stream, StreamUpgradeError<Void>>>>,
+    pending_streams: VecDeque<oneshot::Sender<Result<Stream, StreamUpgradeError<Infallible>>>>,
 
     inflight_reserve_requests: futures_bounded::FuturesTupleSet<
         Result<outbound_hop::Reservation, outbound_hop::ReserveError>,
@@ -447,7 +447,7 @@ impl ConnectionHandler for Handler {
             }
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            ConnectionEvent::ListenUpgradeError(ev) => void::unreachable(ev.error),
+            ConnectionEvent::ListenUpgradeError(ev) => libp2p_core::util::unreachable(ev.error),
             ConnectionEvent::DialUpgradeError(ev) => {
                 if let Some(next) = self.pending_streams.pop_front() {
                     let _ = next.send(Err(ev.error));
@@ -580,27 +580,27 @@ impl Reservation {
     }
 }
 
-fn into_reserve_error(e: StreamUpgradeError<Void>) -> outbound_hop::ReserveError {
+fn into_reserve_error(e: StreamUpgradeError<Infallible>) -> outbound_hop::ReserveError {
     match e {
         StreamUpgradeError::Timeout => {
             outbound_hop::ReserveError::Io(io::ErrorKind::TimedOut.into())
         }
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        StreamUpgradeError::Apply(never) => void::unreachable(never),
+        StreamUpgradeError::Apply(never) => libp2p_core::util::unreachable(never),
         StreamUpgradeError::NegotiationFailed => outbound_hop::ReserveError::Unsupported,
         StreamUpgradeError::Io(e) => outbound_hop::ReserveError::Io(e),
     }
 }
 
-fn into_connect_error(e: StreamUpgradeError<Void>) -> outbound_hop::ConnectError {
+fn into_connect_error(e: StreamUpgradeError<Infallible>) -> outbound_hop::ConnectError {
     match e {
         StreamUpgradeError::Timeout => {
             outbound_hop::ConnectError::Io(io::ErrorKind::TimedOut.into())
         }
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        StreamUpgradeError::Apply(never) => void::unreachable(never),
+        StreamUpgradeError::Apply(never) => libp2p_core::util::unreachable(never),
         StreamUpgradeError::NegotiationFailed => outbound_hop::ConnectError::Unsupported,
         StreamUpgradeError::Io(e) => outbound_hop::ConnectError::Io(e),
     }
diff --git a/protocols/rendezvous/Cargo.toml b/protocols/rendezvous/Cargo.toml
index 78a6a1a0a4c..5aa70688dbe 100644
--- a/protocols/rendezvous/Cargo.toml
+++ b/protocols/rendezvous/Cargo.toml
@@ -26,7 +26,6 @@ quick-protobuf-codec = { workspace = true }
 rand = "0.8"
 thiserror = "1"
 tracing = { workspace = true }
-void = "1"
 
 [dev-dependencies]
 libp2p-swarm = { workspace = true, features = ["macros", "tokio"] }
diff --git a/protocols/request-response/Cargo.toml b/protocols/request-response/Cargo.toml
index c6b2eda348b..8376f3ce795 100644
--- a/protocols/request-response/Cargo.toml
+++ b/protocols/request-response/Cargo.toml
@@ -23,7 +23,6 @@ serde = { version = "1.0", optional = true}
 serde_json = { version = "1.0.117", optional = true }
 smallvec = "1.13.2"
 tracing = { workspace = true }
-void = "1.0.2"
 futures-timer = "3.0.3"
 futures-bounded = { workspace = true }
 
diff --git a/protocols/request-response/src/handler.rs b/protocols/request-response/src/handler.rs
index 0591b37dc30..dbd7a0708ce 100644
--- a/protocols/request-response/src/handler.rs
+++ b/protocols/request-response/src/handler.rs
@@ -242,7 +242,7 @@ where
             }
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            StreamUpgradeError::Apply(e) => void::unreachable(e),
+            StreamUpgradeError::Apply(e) => libp2p_core::util::unreachable(e),
             StreamUpgradeError::Io(e) => {
                 self.pending_events.push_back(Event::OutboundStreamFailed {
                     request_id: message.request_id,
@@ -260,7 +260,7 @@ where
     ) {
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        void::unreachable(error)
+        libp2p_core::util::unreachable(error)
     }
 }
 
diff --git a/protocols/request-response/src/handler/protocol.rs b/protocols/request-response/src/handler/protocol.rs
index 833cacdd6ce..a55faec2f16 100644
--- a/protocols/request-response/src/handler/protocol.rs
+++ b/protocols/request-response/src/handler/protocol.rs
@@ -23,6 +23,8 @@
 //! receives a request and sends a response, whereas the
 //! outbound upgrade send a request and receives a response.
 
+use std::convert::Infallible;
+
 use futures::future::{ready, Ready};
 use libp2p_core::upgrade::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
 use libp2p_swarm::Stream;
@@ -82,7 +84,7 @@ where
     P: AsRef<str> + Clone,
 {
     type Output = (Stream, P);
-    type Error = void::Void;
+    type Error = Infallible;
     type Future = Ready<Result<Self::Output, Self::Error>>;
 
     fn upgrade_inbound(self, io: Stream, protocol: Self::Info) -> Self::Future {
@@ -95,7 +97,7 @@ where
     P: AsRef<str> + Clone,
 {
     type Output = (Stream, P);
-    type Error = void::Void;
+    type Error = Infallible;
     type Future = Ready<Result<Self::Output, Self::Error>>;
 
     fn upgrade_outbound(self, io: Stream, protocol: Self::Info) -> Self::Future {
diff --git a/protocols/stream/Cargo.toml b/protocols/stream/Cargo.toml
index 9aa9559a2d6..cd83c5978fa 100644
--- a/protocols/stream/Cargo.toml
+++ b/protocols/stream/Cargo.toml
@@ -15,7 +15,6 @@ libp2p-core = { workspace = true }
 libp2p-identity = { workspace = true, features = ["peerid"] }
 libp2p-swarm = { workspace = true }
 tracing = { workspace = true }
-void = "1"
 rand = "0.8"
 
 [dev-dependencies]
diff --git a/protocols/stream/src/behaviour.rs b/protocols/stream/src/behaviour.rs
index 07549ccef54..e72af8fbfce 100644
--- a/protocols/stream/src/behaviour.rs
+++ b/protocols/stream/src/behaviour.rs
@@ -124,7 +124,7 @@ impl NetworkBehaviour for Behaviour {
         _connection_id: ConnectionId,
         event: THandlerOutEvent<Self>,
     ) {
-        void::unreachable(event);
+        libp2p_core::util::unreachable(event);
     }
 
     fn poll(
diff --git a/protocols/stream/src/handler.rs b/protocols/stream/src/handler.rs
index bf80e30c3c6..b7ec516d3b1 100644
--- a/protocols/stream/src/handler.rs
+++ b/protocols/stream/src/handler.rs
@@ -1,4 +1,5 @@
 use std::{
+    convert::Infallible,
     io,
     sync::{Arc, Mutex},
     task::{Context, Poll},
@@ -44,8 +45,8 @@ impl Handler {
 }
 
 impl ConnectionHandler for Handler {
-    type FromBehaviour = void::Void;
-    type ToBehaviour = void::Void;
+    type FromBehaviour = Infallible;
+    type ToBehaviour = Infallible;
     type InboundProtocol = Upgrade;
     type OutboundProtocol = Upgrade;
     type InboundOpenInfo = ();
@@ -98,7 +99,7 @@ impl ConnectionHandler for Handler {
     fn on_behaviour_event(&mut self, event: Self::FromBehaviour) {
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        void::unreachable(event)
+        libp2p_core::util::unreachable(event)
     }
 
     fn on_connection_event(
@@ -147,7 +148,7 @@ impl ConnectionHandler for Handler {
                     }
                     // TODO: remove when Rust 1.82 is MSRV
                     #[allow(unreachable_patterns)]
-                    swarm::StreamUpgradeError::Apply(v) => void::unreachable(v),
+                    swarm::StreamUpgradeError::Apply(v) => libp2p_core::util::unreachable(v),
                     swarm::StreamUpgradeError::NegotiationFailed => {
                         OpenStreamError::UnsupportedProtocol(p)
                     }
diff --git a/protocols/stream/src/upgrade.rs b/protocols/stream/src/upgrade.rs
index ac9fb3ed992..bbe679f4a2c 100644
--- a/protocols/stream/src/upgrade.rs
+++ b/protocols/stream/src/upgrade.rs
@@ -1,4 +1,7 @@
-use std::future::{ready, Ready};
+use std::{
+    convert::Infallible,
+    future::{ready, Ready},
+};
 
 use libp2p_core::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
 use libp2p_swarm::{Stream, StreamProtocol};
@@ -20,7 +23,7 @@ impl UpgradeInfo for Upgrade {
 impl InboundUpgrade<Stream> for Upgrade {
     type Output = (Stream, StreamProtocol);
 
-    type Error = void::Void;
+    type Error = Infallible;
 
     type Future = Ready<Result<Self::Output, Self::Error>>;
 
@@ -32,7 +35,7 @@ impl InboundUpgrade<Stream> for Upgrade {
 impl OutboundUpgrade<Stream> for Upgrade {
     type Output = (Stream, StreamProtocol);
 
-    type Error = void::Void;
+    type Error = Infallible;
 
     type Future = Ready<Result<Self::Output, Self::Error>>;
 
diff --git a/protocols/upnp/Cargo.toml b/protocols/upnp/Cargo.toml
index 209733f53e6..a069331b1ed 100644
--- a/protocols/upnp/Cargo.toml
+++ b/protocols/upnp/Cargo.toml
@@ -18,7 +18,6 @@ libp2p-core = { workspace = true }
 libp2p-swarm = { workspace = true }
 tokio = { workspace = true, default-features = false, features = ["rt"], optional = true }
 tracing = { workspace = true }
-void = "1.0.2"
 
 [features]
 tokio = ["igd-next/aio_tokio", "dep:tokio"]
diff --git a/protocols/upnp/src/behaviour.rs b/protocols/upnp/src/behaviour.rs
index 29a7fbf84a4..ee985042b68 100644
--- a/protocols/upnp/src/behaviour.rs
+++ b/protocols/upnp/src/behaviour.rs
@@ -366,7 +366,7 @@ impl NetworkBehaviour for Behaviour {
         _connection_id: ConnectionId,
         event: libp2p_swarm::THandlerOutEvent<Self>,
     ) {
-        void::unreachable(event)
+        libp2p_core::util::unreachable(event)
     }
 
     #[tracing::instrument(level = "trace", name = "NetworkBehaviour::poll", skip(self, cx))]
diff --git a/swarm/Cargo.toml b/swarm/Cargo.toml
index cdee67f3fb3..4c3b8821ed6 100644
--- a/swarm/Cargo.toml
+++ b/swarm/Cargo.toml
@@ -26,7 +26,6 @@ once_cell = "1.19.0"
 rand = "0.8"
 smallvec = "1.13.2"
 tracing = { workspace = true }
-void = "1"
 wasm-bindgen-futures = { version = "0.4.42", optional = true }
 
 [target.'cfg(not(any(target_os = "emscripten", target_os = "wasi", target_os = "unknown")))'.dependencies]
@@ -53,7 +52,6 @@ libp2p-swarm-test = { path = "../swarm-test" }                      # Using `pat
 libp2p-yamux = { path = "../muxers/yamux" }                         # Using `path` here because this is a cyclic dev-dependency which otherwise breaks releasing.
 quickcheck = { workspace = true }
 criterion = { version = "0.5", features = ["async_tokio"] }
-void = "1"
 once_cell = "1.19.0"
 trybuild = "1.0.95"
 tokio = { workspace = true, features = ["time", "rt", "macros", "rt-multi-thread"] }
diff --git a/swarm/src/behaviour/toggle.rs b/swarm/src/behaviour/toggle.rs
index 5d72534c91e..3dde364bf19 100644
--- a/swarm/src/behaviour/toggle.rs
+++ b/swarm/src/behaviour/toggle.rs
@@ -212,7 +212,7 @@ where
             future::Either::Left(out) => out,
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            future::Either::Right(v) => void::unreachable(v),
+            future::Either::Right(v) => libp2p_core::util::unreachable(v),
         };
 
         if let Either::Left(info) = info {
@@ -255,7 +255,7 @@ where
             Either::Left(e) => e,
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            Either::Right(v) => void::unreachable(v),
+            Either::Right(v) => libp2p_core::util::unreachable(v),
         };
 
         inner.on_connection_event(ConnectionEvent::ListenUpgradeError(ListenUpgradeError {
diff --git a/swarm/src/connection.rs b/swarm/src/connection.rs
index 859d138b83a..78c007fd71d 100644
--- a/swarm/src/connection.rs
+++ b/swarm/src/connection.rs
@@ -775,10 +775,10 @@ mod tests {
     use libp2p_core::upgrade::{DeniedUpgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo};
     use libp2p_core::StreamMuxer;
     use quickcheck::*;
+    use std::convert::Infallible;
     use std::sync::{Arc, Weak};
     use std::time::Instant;
     use tracing_subscriber::EnvFilter;
-    use void::Void;
 
     #[test]
     fn max_negotiating_inbound_streams() {
@@ -1016,7 +1016,7 @@ mod tests {
 
     impl StreamMuxer for DummyStreamMuxer {
         type Substream = PendingSubstream;
-        type Error = Void;
+        type Error = Infallible;
 
         fn poll_inbound(
             self: Pin<&mut Self>,
@@ -1051,7 +1051,7 @@ mod tests {
 
     impl StreamMuxer for PendingStreamMuxer {
         type Substream = PendingSubstream;
-        type Error = Void;
+        type Error = Infallible;
 
         fn poll_inbound(
             self: Pin<&mut Self>,
@@ -1113,7 +1113,7 @@ mod tests {
 
     struct MockConnectionHandler {
         outbound_requested: bool,
-        error: Option<StreamUpgradeError<Void>>,
+        error: Option<StreamUpgradeError<Infallible>>,
         upgrade_timeout: Duration,
     }
 
@@ -1133,7 +1133,7 @@ mod tests {
 
     #[derive(Default)]
     struct ConfigurableProtocolConnectionHandler {
-        events: Vec<ConnectionHandlerEvent<DeniedUpgrade, (), Void>>,
+        events: Vec<ConnectionHandlerEvent<DeniedUpgrade, (), Infallible>>,
         active_protocols: HashSet<StreamProtocol>,
         local_added: Vec<Vec<StreamProtocol>>,
         local_removed: Vec<Vec<StreamProtocol>>,
@@ -1166,8 +1166,8 @@ mod tests {
     }
 
     impl ConnectionHandler for MockConnectionHandler {
-        type FromBehaviour = Void;
-        type ToBehaviour = Void;
+        type FromBehaviour = Infallible;
+        type ToBehaviour = Infallible;
         type InboundProtocol = DeniedUpgrade;
         type OutboundProtocol = DeniedUpgrade;
         type InboundOpenInfo = ();
@@ -1194,13 +1194,13 @@ mod tests {
                 ConnectionEvent::FullyNegotiatedInbound(FullyNegotiatedInbound {
                     protocol,
                     ..
-                }) => void::unreachable(protocol),
+                }) => libp2p_core::util::unreachable(protocol),
                 // TODO: remove when Rust 1.82 is MSRV
                 #[allow(unreachable_patterns)]
                 ConnectionEvent::FullyNegotiatedOutbound(FullyNegotiatedOutbound {
                     protocol,
                     ..
-                }) => void::unreachable(protocol),
+                }) => libp2p_core::util::unreachable(protocol),
                 ConnectionEvent::DialUpgradeError(DialUpgradeError { error, .. }) => {
                     self.error = Some(error)
                 }
@@ -1216,7 +1216,7 @@ mod tests {
         fn on_behaviour_event(&mut self, event: Self::FromBehaviour) {
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            void::unreachable(event)
+            libp2p_core::util::unreachable(event)
         }
 
         fn connection_keep_alive(&self) -> bool {
@@ -1246,8 +1246,8 @@ mod tests {
     }
 
     impl ConnectionHandler for ConfigurableProtocolConnectionHandler {
-        type FromBehaviour = Void;
-        type ToBehaviour = Void;
+        type FromBehaviour = Infallible;
+        type ToBehaviour = Infallible;
         type InboundProtocol = ManyProtocolsUpgrade;
         type OutboundProtocol = DeniedUpgrade;
         type InboundOpenInfo = ();
@@ -1293,7 +1293,7 @@ mod tests {
         fn on_behaviour_event(&mut self, event: Self::FromBehaviour) {
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            void::unreachable(event)
+            libp2p_core::util::unreachable(event)
         }
 
         fn connection_keep_alive(&self) -> bool {
@@ -1333,7 +1333,7 @@ mod tests {
 
     impl<C> InboundUpgrade<C> for ManyProtocolsUpgrade {
         type Output = C;
-        type Error = Void;
+        type Error = Infallible;
         type Future = future::Ready<Result<Self::Output, Self::Error>>;
 
         fn upgrade_inbound(self, stream: C, _: Self::Info) -> Self::Future {
@@ -1343,7 +1343,7 @@ mod tests {
 
     impl<C> OutboundUpgrade<C> for ManyProtocolsUpgrade {
         type Output = C;
-        type Error = Void;
+        type Error = Infallible;
         type Future = future::Ready<Result<Self::Output, Self::Error>>;
 
         fn upgrade_outbound(self, stream: C, _: Self::Info) -> Self::Future {
diff --git a/swarm/src/connection/pool.rs b/swarm/src/connection/pool.rs
index 07f6968dec9..b2accf745ef 100644
--- a/swarm/src/connection/pool.rs
+++ b/swarm/src/connection/pool.rs
@@ -40,6 +40,7 @@ use futures::{
 use libp2p_core::connection::Endpoint;
 use libp2p_core::muxing::{StreamMuxerBox, StreamMuxerExt};
 use libp2p_core::transport::PortUse;
+use std::convert::Infallible;
 use std::task::Waker;
 use std::{
     collections::HashMap,
@@ -50,7 +51,6 @@ use std::{
     task::Poll,
 };
 use tracing::Instrument;
-use void::Void;
 use web_time::{Duration, Instant};
 
 mod concurrent_dial;
@@ -200,7 +200,7 @@ struct PendingConnection {
     peer_id: Option<PeerId>,
     endpoint: PendingPoint,
     /// When dropped, notifies the task which then knows to terminate.
-    abort_notifier: Option<oneshot::Sender<Void>>,
+    abort_notifier: Option<oneshot::Sender<Infallible>>,
     /// The moment we became aware of this possible connection, useful for timing metrics.
     accepted_at: Instant,
 }
diff --git a/swarm/src/connection/pool/task.rs b/swarm/src/connection/pool/task.rs
index 13977a17b85..3b808a30fd1 100644
--- a/swarm/src/connection/pool/task.rs
+++ b/swarm/src/connection/pool/task.rs
@@ -36,8 +36,8 @@ use futures::{
     SinkExt, StreamExt,
 };
 use libp2p_core::muxing::StreamMuxerBox;
+use std::convert::Infallible;
 use std::pin::Pin;
-use void::Void;
 
 /// Commands that can be sent to a task driving an established connection.
 #[derive(Debug)]
@@ -93,7 +93,7 @@ pub(crate) enum EstablishedConnectionEvent<ToBehaviour> {
 pub(crate) async fn new_for_pending_outgoing_connection(
     connection_id: ConnectionId,
     dial: ConcurrentDial,
-    abort_receiver: oneshot::Receiver<Void>,
+    abort_receiver: oneshot::Receiver<Infallible>,
     mut events: mpsc::Sender<PendingConnectionEvent>,
 ) {
     match futures::future::select(abort_receiver, Box::pin(dial)).await {
@@ -107,7 +107,7 @@ pub(crate) async fn new_for_pending_outgoing_connection(
         }
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        Either::Left((Ok(v), _)) => void::unreachable(v),
+        Either::Left((Ok(v), _)) => libp2p_core::util::unreachable(v),
         Either::Right((Ok((address, output, errors)), _)) => {
             let _ = events
                 .send(PendingConnectionEvent::ConnectionEstablished {
@@ -131,7 +131,7 @@ pub(crate) async fn new_for_pending_outgoing_connection(
 pub(crate) async fn new_for_pending_incoming_connection<TFut>(
     connection_id: ConnectionId,
     future: TFut,
-    abort_receiver: oneshot::Receiver<Void>,
+    abort_receiver: oneshot::Receiver<Infallible>,
     mut events: mpsc::Sender<PendingConnectionEvent>,
 ) where
     TFut: Future<Output = Result<(PeerId, StreamMuxerBox), std::io::Error>> + Send + 'static,
@@ -147,7 +147,7 @@ pub(crate) async fn new_for_pending_incoming_connection<TFut>(
         }
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        Either::Left((Ok(v), _)) => void::unreachable(v),
+        Either::Left((Ok(v), _)) => libp2p_core::util::unreachable(v),
         Either::Right((Ok(output), _)) => {
             let _ = events
                 .send(PendingConnectionEvent::ConnectionEstablished {
diff --git a/swarm/src/dummy.rs b/swarm/src/dummy.rs
index 0bd8c06862d..b87ef32c8f7 100644
--- a/swarm/src/dummy.rs
+++ b/swarm/src/dummy.rs
@@ -12,15 +12,15 @@ use libp2p_core::upgrade::DeniedUpgrade;
 use libp2p_core::Endpoint;
 use libp2p_core::Multiaddr;
 use libp2p_identity::PeerId;
+use std::convert::Infallible;
 use std::task::{Context, Poll};
-use void::Void;
 
 /// Implementation of [`NetworkBehaviour`] that doesn't do anything.
 pub struct Behaviour;
 
 impl NetworkBehaviour for Behaviour {
     type ConnectionHandler = ConnectionHandler;
-    type ToSwarm = Void;
+    type ToSwarm = Infallible;
 
     fn handle_established_inbound_connection(
         &mut self,
@@ -51,7 +51,7 @@ impl NetworkBehaviour for Behaviour {
     ) {
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        void::unreachable(event)
+        libp2p_core::util::unreachable(event)
     }
 
     fn poll(&mut self, _: &mut Context<'_>) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
@@ -66,12 +66,12 @@ impl NetworkBehaviour for Behaviour {
 pub struct ConnectionHandler;
 
 impl crate::handler::ConnectionHandler for ConnectionHandler {
-    type FromBehaviour = Void;
-    type ToBehaviour = Void;
+    type FromBehaviour = Infallible;
+    type ToBehaviour = Infallible;
     type InboundProtocol = DeniedUpgrade;
     type OutboundProtocol = DeniedUpgrade;
     type InboundOpenInfo = ();
-    type OutboundOpenInfo = Void;
+    type OutboundOpenInfo = Infallible;
 
     fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, Self::InboundOpenInfo> {
         SubstreamProtocol::new(DeniedUpgrade, ())
@@ -80,7 +80,7 @@ impl crate::handler::ConnectionHandler for ConnectionHandler {
     fn on_behaviour_event(&mut self, event: Self::FromBehaviour) {
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        void::unreachable(event)
+        libp2p_core::util::unreachable(event)
     }
 
     fn poll(
@@ -106,19 +106,19 @@ impl crate::handler::ConnectionHandler for ConnectionHandler {
             #[allow(unreachable_patterns)]
             ConnectionEvent::FullyNegotiatedInbound(FullyNegotiatedInbound {
                 protocol, ..
-            }) => void::unreachable(protocol),
+            }) => libp2p_core::util::unreachable(protocol),
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
             ConnectionEvent::FullyNegotiatedOutbound(FullyNegotiatedOutbound {
                 protocol, ..
-            }) => void::unreachable(protocol),
+            }) => libp2p_core::util::unreachable(protocol),
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
             ConnectionEvent::DialUpgradeError(DialUpgradeError { info: _, error }) => match error {
                 // TODO: remove when Rust 1.82 is MSRV
                 #[allow(unreachable_patterns)]
                 StreamUpgradeError::Timeout => unreachable!(),
-                StreamUpgradeError::Apply(e) => void::unreachable(e),
+                StreamUpgradeError::Apply(e) => libp2p_core::util::unreachable(e),
                 StreamUpgradeError::NegotiationFailed | StreamUpgradeError::Io(_) => {
                     unreachable!("Denied upgrade does not support any protocols")
                 }
diff --git a/swarm/src/handler/one_shot.rs b/swarm/src/handler/one_shot.rs
index fc1074b31e4..7c84f4bb11a 100644
--- a/swarm/src/handler/one_shot.rs
+++ b/swarm/src/handler/one_shot.rs
@@ -217,11 +217,11 @@ mod tests {
     use futures::executor::block_on;
     use futures::future::poll_fn;
     use libp2p_core::upgrade::DeniedUpgrade;
-    use void::Void;
+    use std::convert::Infallible;
 
     #[test]
     fn do_not_keep_idle_connection_alive() {
-        let mut handler: OneShotHandler<_, DeniedUpgrade, Void> = OneShotHandler::new(
+        let mut handler: OneShotHandler<_, DeniedUpgrade, Infallible> = OneShotHandler::new(
             SubstreamProtocol::new(DeniedUpgrade {}, ()),
             Default::default(),
         );
diff --git a/swarm/src/handler/pending.rs b/swarm/src/handler/pending.rs
index 9601f5cf78b..656a38849d5 100644
--- a/swarm/src/handler/pending.rs
+++ b/swarm/src/handler/pending.rs
@@ -24,8 +24,8 @@ use crate::handler::{
     FullyNegotiatedOutbound, SubstreamProtocol,
 };
 use libp2p_core::upgrade::PendingUpgrade;
+use std::convert::Infallible;
 use std::task::{Context, Poll};
-use void::Void;
 
 /// Implementation of [`ConnectionHandler`] that returns a pending upgrade.
 #[derive(Clone, Debug)]
@@ -40,11 +40,11 @@ impl PendingConnectionHandler {
 }
 
 impl ConnectionHandler for PendingConnectionHandler {
-    type FromBehaviour = Void;
-    type ToBehaviour = Void;
+    type FromBehaviour = Infallible;
+    type ToBehaviour = Infallible;
     type InboundProtocol = PendingUpgrade<String>;
     type OutboundProtocol = PendingUpgrade<String>;
-    type OutboundOpenInfo = Void;
+    type OutboundOpenInfo = Infallible;
     type InboundOpenInfo = ();
 
     fn listen_protocol(&self) -> SubstreamProtocol<Self::InboundProtocol, Self::InboundOpenInfo> {
@@ -54,7 +54,7 @@ impl ConnectionHandler for PendingConnectionHandler {
     fn on_behaviour_event(&mut self, v: Self::FromBehaviour) {
         // TODO: remove when Rust 1.82 is MSRV
         #[allow(unreachable_patterns)]
-        void::unreachable(v)
+        libp2p_core::util::unreachable(v)
     }
 
     fn poll(
@@ -80,17 +80,17 @@ impl ConnectionHandler for PendingConnectionHandler {
             #[allow(unreachable_patterns)]
             ConnectionEvent::FullyNegotiatedInbound(FullyNegotiatedInbound {
                 protocol, ..
-            }) => void::unreachable(protocol),
+            }) => libp2p_core::util::unreachable(protocol),
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
             ConnectionEvent::FullyNegotiatedOutbound(FullyNegotiatedOutbound {
                 protocol,
                 info: _info,
             }) => {
-                void::unreachable(protocol);
+                libp2p_core::util::unreachable(protocol);
                 #[allow(unreachable_code, clippy::used_underscore_binding)]
                 {
-                    void::unreachable(_info);
+                    libp2p_core::util::unreachable(_info);
                 }
             }
             // TODO: remove when Rust 1.82 is MSRV
diff --git a/swarm/tests/connection_close.rs b/swarm/tests/connection_close.rs
index 4d530f47684..1d1a25eb84b 100644
--- a/swarm/tests/connection_close.rs
+++ b/swarm/tests/connection_close.rs
@@ -9,8 +9,8 @@ use libp2p_swarm::{
     THandlerOutEvent, ToSwarm,
 };
 use libp2p_swarm_test::SwarmExt;
+use std::convert::Infallible;
 use std::task::{Context, Poll};
-use void::Void;
 
 #[async_std::test]
 async fn sends_remaining_events_to_behaviour_on_connection_close() {
@@ -96,7 +96,7 @@ impl NetworkBehaviour for Behaviour {
 }
 
 impl ConnectionHandler for HandlerWithState {
-    type FromBehaviour = Void;
+    type FromBehaviour = Infallible;
     type ToBehaviour = u64;
     type InboundProtocol = DeniedUpgrade;
     type OutboundProtocol = DeniedUpgrade;
@@ -132,7 +132,7 @@ impl ConnectionHandler for HandlerWithState {
     }
 
     fn on_behaviour_event(&mut self, event: Self::FromBehaviour) {
-        void::unreachable(event)
+        libp2p_core::util::unreachable(event)
     }
 
     fn on_connection_event(
diff --git a/swarm/tests/listener.rs b/swarm/tests/listener.rs
index 160b1f5b064..74b23cf3f7f 100644
--- a/swarm/tests/listener.rs
+++ b/swarm/tests/listener.rs
@@ -1,5 +1,6 @@
 use std::{
     collections::{HashSet, VecDeque},
+    convert::Infallible,
     task::{Context, Poll},
 };
 
@@ -79,7 +80,7 @@ impl Behaviour {
 
 impl NetworkBehaviour for Behaviour {
     type ConnectionHandler = dummy::ConnectionHandler;
-    type ToSwarm = void::Void;
+    type ToSwarm = Infallible;
 
     fn handle_established_inbound_connection(
         &mut self,
diff --git a/swarm/tests/swarm_derive.rs b/swarm/tests/swarm_derive.rs
index 667f68408cf..334d1b9d304 100644
--- a/swarm/tests/swarm_derive.rs
+++ b/swarm/tests/swarm_derive.rs
@@ -386,7 +386,7 @@ fn with_generics_constrained() {
 
     impl<A: Mark + 'static> NetworkBehaviour for Bar<A> {
         type ConnectionHandler = dummy::ConnectionHandler;
-        type ToSwarm = void::Void;
+        type ToSwarm = std::convert::Infallible;
 
         fn handle_established_inbound_connection(
             &mut self,
@@ -548,7 +548,7 @@ fn custom_out_event_no_type_parameters() {
 
     impl<T> NetworkBehaviour for TemplatedBehaviour<T> {
         type ConnectionHandler = dummy::ConnectionHandler;
-        type ToSwarm = void::Void;
+        type ToSwarm = std::convert::Infallible;
 
         fn handle_established_inbound_connection(
             &mut self,
@@ -579,7 +579,7 @@ fn custom_out_event_no_type_parameters() {
         ) {
             // TODO: remove when Rust 1.82 is MSRV
             #[allow(unreachable_patterns)]
-            void::unreachable(message);
+            libp2p_core::util::unreachable(message);
         }
 
         fn poll(
@@ -603,8 +603,8 @@ fn custom_out_event_no_type_parameters() {
         None,
     }
 
-    impl From<void::Void> for OutEvent {
-        fn from(_e: void::Void) -> Self {
+    impl From<std::convert::Infallible> for OutEvent {
+        fn from(_e: std::convert::Infallible) -> Self {
             Self::None
         }
     }