Repository: tokio-rs/mio
Pull request #1793 (2024-06-09 12:11:35)

Remove codeowners

Thomasdezeeuw: Unless you disagree @carllerche 

Patch:
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
deleted file mode 100644
index f860f8e..0000000
--- a/.github/CODEOWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Windows changes
-/src/sys/windows/       @carllerche
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5aa58b1..4a215c3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -124,25 +124,40 @@ jobs:
       #cargo fmt --all -- --check
       run: find src tests examples -type f -iname "*.rs" | xargs rustfmt --check
   CheckTargets:
-    runs-on: ubuntu-latest
-    timeout-minutes: 10
-    steps:
-    - uses: actions/checkout@v4
-    - uses: dtolnay/rust-toolchain@stable
-    - name: Install all targets
-      run: make install_targets
-    - name: Install Cargo-hack
-      run: cargo install --debug cargo-hack
-    - name: Check all targets
-      run: make check_all_targets
-  CheckTier3Targets:
-    name: Check
     runs-on: ubuntu-latest
     timeout-minutes: 10
     strategy:
       fail-fast: false
       matrix:
-        target: ["aarch64-apple-ios", "aarch64-apple-tvos", "aarch64-unknown-openbsd", "arm64_32-apple-watchos", "armv7-sony-vita-newlibeabihf", "sparcv9-sun-solaris", "x86_64-pc-solaris", "x86_64-unknown-dragonfly", "x86_64-unknown-openbsd"]
+        target:
+          - aarch64-apple-darwin
+          - aarch64-apple-ios
+          - aarch64-apple-tvos
+          - aarch64-apple-visionos
+          - aarch64-linux-android
+          - aarch64-unknown-openbsd
+          - arm-linux-androideabi
+          - arm64_32-apple-watchos
+          - armv7-sony-vita-newlibeabihf
+          - i686-unknown-linux-gnu
+          - sparcv9-sun-solaris
+          - wasm32-wasi
+          - x86_64-apple-darwin
+          - x86_64-apple-ios
+          - x86_64-pc-solaris
+          # TODO: solve the following err:
+          # `Error calling dlltool 'x86_64-w64-mingw32-dlltool'`, build log:
+          # <https://github.com/tokio-rs/mio/actions/runs/9436499623/job/25991326487?pr=1794>.
+          #- x86_64-pc-windows-gnu
+          - x86_64-pc-windows-msvc
+          - x86_64-unknown-dragonfly
+          - x86_64-unknown-freebsd
+          - x86_64-unknown-illumos
+          - x86_64-unknown-linux-gnu
+          - x86_64-unknown-linux-musl
+          - x86_64-unknown-netbsd
+          - x86_64-unknown-openbsd
+          - x86_64-unknown-redox
     steps:
     - uses: actions/checkout@v4
     - uses: dtolnay/rust-toolchain@nightly
@@ -178,6 +193,5 @@ jobs:
       - Docs
       - Rustfmt
       - CheckTargets
-      - CheckTier3Targets
     steps:
       - run: exit 0
diff --git a/examples/tcp_listenfd_server.rs b/examples/tcp_listenfd_server.rs
index 2b8b0c4..edd85e2 100644
--- a/examples/tcp_listenfd_server.rs
+++ b/examples/tcp_listenfd_server.rs
@@ -19,12 +19,8 @@ const DATA: &[u8] = b"Hello world!\n";
 
 #[cfg(not(windows))]
 fn get_first_listen_fd_listener() -> Option<std::net::TcpListener> {
-    #[cfg(target_os = "hermit")]
-    use std::os::hermit::io::FromRawFd;
-    #[cfg(unix)]
-    use std::os::unix::io::FromRawFd;
-    #[cfg(target_os = "wasi")]
-    use std::os::wasi::io::FromRawFd;
+    #[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
+    use std::os::fd::FromRawFd;
 
     let stdlistener = unsafe { std::net::TcpListener::from_raw_fd(3) };
     stdlistener.set_nonblocking(true).unwrap();
diff --git a/src/interest.rs b/src/interest.rs
index 2bab786..bac01fc 100644
--- a/src/interest.rs
+++ b/src/interest.rs
@@ -38,6 +38,7 @@ impl Interest {
         target_os = "ios",
         target_os = "macos",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     ))]
     pub const AIO: Interest = Interest(unsafe { NonZeroU8::new_unchecked(AIO) });
@@ -163,6 +164,7 @@ impl fmt::Debug for Interest {
             target_os = "ios",
             target_os = "macos",
             target_os = "tvos",
+            target_os = "visionos",
             target_os = "watchos",
         ))]
         {
diff --git a/src/io_source.rs b/src/io_source.rs
index ec773c3..ae3d052 100644
--- a/src/io_source.rs
+++ b/src/io_source.rs
@@ -1,10 +1,6 @@
 use std::ops::{Deref, DerefMut};
-#[cfg(target_os = "hermit")]
-use std::os::hermit::io::AsRawFd;
-#[cfg(unix)]
-use std::os::unix::io::AsRawFd;
-#[cfg(target_os = "wasi")]
-use std::os::wasi::io::AsRawFd;
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
+use std::os::fd::AsRawFd;
 #[cfg(windows)]
 use std::os::windows::io::AsRawSocket;
 #[cfg(debug_assertions)]
@@ -23,7 +19,7 @@ use crate::{event, Interest, Registry, Token};
 /// Mio supports registering any FD or socket that can be registered with the
 /// underlying OS selector. `IoSource` provides the necessary bridge.
 ///
-/// [`RawFd`]: std::os::unix::io::RawFd
+/// [`RawFd`]: std::os::fd::RawFd
 /// [`RawSocket`]: std::os::windows::io::RawSocket
 ///
 /// # Notes
diff --git a/src/net/mod.rs b/src/net/mod.rs
index 7d714ca..15c405c 100644
--- a/src/net/mod.rs
+++ b/src/net/mod.rs
@@ -36,4 +36,4 @@ pub use self::udp::UdpSocket;
 #[cfg(unix)]
 mod uds;
 #[cfg(unix)]
-pub use self::uds::{SocketAddr, UnixDatagram, UnixListener, UnixStream};
+pub use self::uds::{UnixDatagram, UnixListener, UnixStream};
diff --git a/src/net/tcp/listener.rs b/src/net/tcp/listener.rs
index 2ed7ec8..7267474 100644
--- a/src/net/tcp/listener.rs
+++ b/src/net/tcp/listener.rs
@@ -1,10 +1,6 @@
 use std::net::{self, SocketAddr};
-#[cfg(target_os = "hermit")]
-use std::os::hermit::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-#[cfg(unix)]
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-#[cfg(target_os = "wasi")]
-use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
+use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 #[cfg(windows)]
 use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
 use std::{fmt, io};
@@ -168,21 +164,21 @@ impl fmt::Debug for TcpListener {
     }
 }
 
-#[cfg(any(unix, target_os = "hermit"))]
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
 impl IntoRawFd for TcpListener {
     fn into_raw_fd(self) -> RawFd {
         self.inner.into_inner().into_raw_fd()
     }
 }
 
-#[cfg(any(unix, target_os = "hermit"))]
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
 impl AsRawFd for TcpListener {
     fn as_raw_fd(&self) -> RawFd {
         self.inner.as_raw_fd()
     }
 }
 
-#[cfg(any(unix, target_os = "hermit"))]
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
 impl FromRawFd for TcpListener {
     /// Converts a `RawFd` to a `TcpListener`.
     ///
@@ -195,6 +191,13 @@ impl FromRawFd for TcpListener {
     }
 }
 
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
+impl AsFd for TcpListener {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.inner.as_fd()
+    }
+}
+
 #[cfg(windows)]
 impl IntoRawSocket for TcpListener {
     fn into_raw_socket(self) -> RawSocket {
@@ -222,33 +225,6 @@ impl FromRawSocket for TcpListener {
     }
 }
 
-#[cfg(target_os = "wasi")]
-impl IntoRawFd for TcpListener {
-    fn into_raw_fd(self) -> RawFd {
-        self.inner.into_inner().into_raw_fd()
-    }
-}
-
-#[cfg(target_os = "wasi")]
-impl AsRawFd for TcpListener {
-    fn as_raw_fd(&self) -> RawFd {
-        self.inner.as_raw_fd()
-    }
-}
-
-#[cfg(target_os = "wasi")]
-impl FromRawFd for TcpListener {
-    /// Converts a `RawFd` to a `TcpListener`.
-    ///
-    /// # Notes
-    ///
-    /// The caller is responsible for ensuring that the socket is in
-    /// non-blocking mode.
-    unsafe fn from_raw_fd(fd: RawFd) -> TcpListener {
-        TcpListener::from_std(FromRawFd::from_raw_fd(fd))
-    }
-}
-
 impl From<TcpListener> for net::TcpListener {
     fn from(listener: TcpListener) -> Self {
         // Safety: This is safe since we are extracting the raw fd from a well-constructed
diff --git a/src/net/tcp/stream.rs b/src/net/tcp/stream.rs
index 8c2fba6..ce0e7b1 100644
--- a/src/net/tcp/stream.rs
+++ b/src/net/tcp/stream.rs
@@ -1,12 +1,8 @@
 use std::fmt;
 use std::io::{self, IoSlice, IoSliceMut, Read, Write};
 use std::net::{self, Shutdown, SocketAddr};
-#[cfg(target_os = "hermit")]
-use std::os::hermit::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-#[cfg(unix)]
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-#[cfg(target_os = "wasi")]
-use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
+use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 #[cfg(windows)]
 use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
 
@@ -232,8 +228,8 @@ impl TcpStream {
     /// #
     /// # fn main() -> Result<(), Box<dyn Error>> {
     /// use std::io;
-    /// #[cfg(unix)]
-    /// use std::os::unix::io::AsRawFd;
+    /// #[cfg(any(unix, target_os = "wasi"))]
+    /// use std::os::fd::AsRawFd;
     /// #[cfg(windows)]
     /// use std::os::windows::io::AsRawSocket;
     /// use mio::net::TcpStream;
@@ -350,21 +346,21 @@ impl fmt::Debug for TcpStream {
     }
 }
 
-#[cfg(any(unix, target_os = "hermit"))]
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
 impl IntoRawFd for TcpStream {
     fn into_raw_fd(self) -> RawFd {
         self.inner.into_inner().into_raw_fd()
     }
 }
 
-#[cfg(any(unix, target_os = "hermit"))]
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
 impl AsRawFd for TcpStream {
     fn as_raw_fd(&self) -> RawFd {
         self.inner.as_raw_fd()
     }
 }
 
-#[cfg(any(unix, target_os = "hermit"))]
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
 impl FromRawFd for TcpStream {
     /// Converts a `RawFd` to a `TcpStream`.
     ///
@@ -377,6 +373,13 @@ impl FromRawFd for TcpStream {
     }
 }
 
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
+impl AsFd for TcpStream {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.inner.as_fd()
+    }
+}
+
 #[cfg(windows)]
 impl IntoRawSocket for TcpStream {
     fn into_raw_socket(self) -> RawSocket {
@@ -404,33 +407,6 @@ impl FromRawSocket for TcpStream {
     }
 }
 
-#[cfg(target_os = "wasi")]
-impl IntoRawFd for TcpStream {
-    fn into_raw_fd(self) -> RawFd {
-        self.inner.into_inner().into_raw_fd()
-    }
-}
-
-#[cfg(target_os = "wasi")]
-impl AsRawFd for TcpStream {
-    fn as_raw_fd(&self) -> RawFd {
-        self.inner.as_raw_fd()
-    }
-}
-
-#[cfg(target_os = "wasi")]
-impl FromRawFd for TcpStream {
-    /// Converts a `RawFd` to a `TcpStream`.
-    ///
-    /// # Notes
-    ///
-    /// The caller is responsible for ensuring that the socket is in
-    /// non-blocking mode.
-    unsafe fn from_raw_fd(fd: RawFd) -> TcpStream {
-        TcpStream::from_std(FromRawFd::from_raw_fd(fd))
-    }
-}
-
 impl From<TcpStream> for net::TcpStream {
     fn from(stream: TcpStream) -> Self {
         // Safety: This is safe since we are extracting the raw fd from a well-constructed
diff --git a/src/net/udp.rs b/src/net/udp.rs
index 4fa65cf..e2933f2 100644
--- a/src/net/udp.rs
+++ b/src/net/udp.rs
@@ -7,19 +7,15 @@
 //!
 //! [portability guidelines]: ../struct.Poll.html#portability
 
-use crate::io_source::IoSource;
-use crate::{event, sys, Interest, Registry, Token};
-
-use std::fmt;
-use std::io;
-use std::net;
 use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
-#[cfg(target_os = "hermit")]
-use std::os::hermit::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-#[cfg(unix)]
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
+use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 #[cfg(windows)]
 use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
+use std::{fmt, io, net};
+
+use crate::io_source::IoSource;
+use crate::{event, sys, Interest, Registry, Token};
 
 /// A User Datagram Protocol socket.
 ///
@@ -574,8 +570,8 @@ impl UdpSocket {
     /// #
     /// # fn main() -> Result<(), Box<dyn Error>> {
     /// use std::io;
-    /// #[cfg(unix)]
-    /// use std::os::unix::io::AsRawFd;
+    /// #[cfg(any(unix, target_os = "wasi"))]
+    /// use std::os::fd::AsRawFd;
     /// #[cfg(windows)]
     /// use std::os::windows::io::AsRawSocket;
     /// use mio::net::UdpSocket;
@@ -644,21 +640,21 @@ impl fmt::Debug for UdpSocket {
     }
 }
 
-#[cfg(any(unix, target_os = "hermit"))]
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
 impl IntoRawFd for UdpSocket {
     fn into_raw_fd(self) -> RawFd {
         self.inner.into_inner().into_raw_fd()
     }
 }
 
-#[cfg(any(unix, target_os = "hermit"))]
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
 impl AsRawFd for UdpSocket {
     fn as_raw_fd(&self) -> RawFd {
         self.inner.as_raw_fd()
     }
 }
 
-#[cfg(any(unix, target_os = "hermit"))]
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
 impl FromRawFd for UdpSocket {
     /// Converts a `RawFd` to a `UdpSocket`.
     ///
@@ -671,6 +667,13 @@ impl FromRawFd for UdpSocket {
     }
 }
 
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
+impl AsFd for UdpSocket {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.inner.as_fd()
+    }
+}
+
 #[cfg(windows)]
 impl IntoRawSocket for UdpSocket {
     fn into_raw_socket(self) -> RawSocket {
diff --git a/src/net/uds/datagram.rs b/src/net/uds/datagram.rs
index 4d8ff82..bab4605 100644
--- a/src/net/uds/datagram.rs
+++ b/src/net/uds/datagram.rs
@@ -1,12 +1,12 @@
-use crate::io_source::IoSource;
-use crate::{event, sys, Interest, Registry, Token};
-
 use std::net::Shutdown;
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-use std::os::unix::net;
+use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
+use std::os::unix::net::{self, SocketAddr};
 use std::path::Path;
 use std::{fmt, io};
 
+use crate::io_source::IoSource;
+use crate::{event, sys, Interest, Registry, Token};
+
 /// A Unix datagram socket.
 pub struct UnixDatagram {
     inner: IoSource<net::UnixDatagram>,
@@ -15,7 +15,13 @@ pub struct UnixDatagram {
 impl UnixDatagram {
     /// Creates a Unix datagram socket bound to the given path.
     pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
-        sys::uds::datagram::bind(path.as_ref()).map(UnixDatagram::from_std)
+        let addr = SocketAddr::from_pathname(path)?;
+        UnixDatagram::bind_addr(&addr)
+    }
+
+    /// Creates a new `UnixDatagram` bound to the specified socket `address`.
+    pub fn bind_addr(address: &SocketAddr) -> io::Result<UnixDatagram> {
+        sys::uds::datagram::bind_addr(address).map(UnixDatagram::from_std)
     }
 
     /// Creates a new `UnixDatagram` from a standard `net::UnixDatagram`.
@@ -54,24 +60,23 @@ impl UnixDatagram {
     }
 
     /// Returns the address of this socket.
-    pub fn local_addr(&self) -> io::Result<sys::SocketAddr> {
-        sys::uds::datagram::local_addr(&self.inner)
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        self.inner.local_addr()
     }
 
     /// Returns the address of this socket's peer.
     ///
     /// The `connect` method will connect the socket to a peer.
-    pub fn peer_addr(&self) -> io::Result<sys::SocketAddr> {
-        sys::uds::datagram::peer_addr(&self.inner)
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        self.inner.peer_addr()
     }
 
     /// Receives data from the socket.
     ///
     /// On success, returns the number of bytes read and the address from
     /// whence the data came.
-    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, sys::SocketAddr)> {
-        self.inner
-            .do_io(|inner| sys::uds::datagram::recv_from(inner, buf))
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.inner.do_io(|inner| inner.recv_from(buf))
     }
 
     /// Receives data from the socket.
@@ -130,7 +135,7 @@ impl UnixDatagram {
     /// #
     /// # fn main() -> Result<(), Box<dyn Error>> {
     /// use std::io;
-    /// use std::os::unix::io::AsRawFd;
+    /// use std::os::fd::AsRawFd;
     /// use mio::net::UnixDatagram;
     ///
     /// let (dgram1, dgram2) = UnixDatagram::pair()?;
@@ -243,3 +248,9 @@ impl From<UnixDatagram> for net::UnixDatagram {
         unsafe { net::UnixDatagram::from_raw_fd(datagram.into_raw_fd()) }
     }
 }
+
+impl AsFd for UnixDatagram {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.inner.as_fd()
+    }
+}
diff --git a/src/net/uds/listener.rs b/src/net/uds/listener.rs
index da16053..bac82e8 100644
--- a/src/net/uds/listener.rs
+++ b/src/net/uds/listener.rs
@@ -1,12 +1,12 @@
-use crate::io_source::IoSource;
-use crate::net::{SocketAddr, UnixStream};
-use crate::{event, sys, Interest, Registry, Token};
-
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-use std::os::unix::net;
+use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
+use std::os::unix::net::{self, SocketAddr};
 use std::path::Path;
 use std::{fmt, io};
 
+use crate::io_source::IoSource;
+use crate::net::UnixStream;
+use crate::{event, sys, Interest, Registry, Token};
+
 /// A non-blocking Unix domain socket server.
 pub struct UnixListener {
     inner: IoSource<net::UnixListener>,
@@ -15,7 +15,8 @@ pub struct UnixListener {
 impl UnixListener {
     /// Creates a new `UnixListener` bound to the specified socket `path`.
     pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
-        sys::uds::listener::bind(path.as_ref()).map(UnixListener::from_std)
+        let addr = SocketAddr::from_pathname(path)?;
+        UnixListener::bind_addr(&addr)
     }
 
     /// Creates a new `UnixListener` bound to the specified socket `address`.
@@ -44,8 +45,8 @@ impl UnixListener {
     }
 
     /// Returns the local socket address of this listener.
-    pub fn local_addr(&self) -> io::Result<sys::SocketAddr> {
-        sys::uds::listener::local_addr(&self.inner)
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        self.inner.local_addr()
     }
 
     /// Returns the value of the `SO_ERROR` option.
@@ -116,3 +117,9 @@ impl From<UnixListener> for net::UnixListener {
         unsafe { net::UnixListener::from_raw_fd(listener.into_raw_fd()) }
     }
 }
+
+impl AsFd for UnixListener {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.inner.as_fd()
+    }
+}
diff --git a/src/net/uds/mod.rs b/src/net/uds/mod.rs
index 6b4ffdc..e02fd80 100644
--- a/src/net/uds/mod.rs
+++ b/src/net/uds/mod.rs
@@ -6,5 +6,3 @@ pub use self::listener::UnixListener;
 
 mod stream;
 pub use self::stream::UnixStream;
-
-pub use crate::sys::SocketAddr;
diff --git a/src/net/uds/stream.rs b/src/net/uds/stream.rs
index 70b5085..a25a419 100644
--- a/src/net/uds/stream.rs
+++ b/src/net/uds/stream.rs
@@ -1,14 +1,13 @@
-use crate::io_source::IoSource;
-use crate::net::SocketAddr;
-use crate::{event, sys, Interest, Registry, Token};
-
 use std::fmt;
 use std::io::{self, IoSlice, IoSliceMut, Read, Write};
 use std::net::Shutdown;
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-use std::os::unix::net;
+use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
+use std::os::unix::net::{self, SocketAddr};
 use std::path::Path;
 
+use crate::io_source::IoSource;
+use crate::{event, sys, Interest, Registry, Token};
+
 /// A non-blocking Unix stream socket.
 pub struct UnixStream {
     inner: IoSource<net::UnixStream>,
@@ -20,7 +19,8 @@ impl UnixStream {
     /// This may return a `WouldBlock` in which case the socket connection
     /// cannot be completed immediately. Usually it means the backlog is full.
     pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
-        sys::uds::stream::connect(path.as_ref()).map(UnixStream::from_std)
+        let addr = SocketAddr::from_pathname(path)?;
+        UnixStream::connect_addr(&addr)
     }
 
     /// Connects to the socket named by `address`.
@@ -59,13 +59,13 @@ impl UnixStream {
     }
 
     /// Returns the socket address of the local half of this connection.
-    pub fn local_addr(&self) -> io::Result<sys::SocketAddr> {
-        sys::uds::stream::local_addr(&self.inner)
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        self.inner.local_addr()
     }
 
     /// Returns the socket address of the remote half of this connection.
-    pub fn peer_addr(&self) -> io::Result<sys::SocketAddr> {
-        sys::uds::stream::peer_addr(&self.inner)
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        self.inner.peer_addr()
     }
 
     /// Returns the value of the `SO_ERROR` option.
@@ -100,7 +100,7 @@ impl UnixStream {
     /// #
     /// # fn main() -> Result<(), Box<dyn Error>> {
     /// use std::io;
-    /// use std::os::unix::io::AsRawFd;
+    /// use std::os::fd::AsRawFd;
     /// use mio::net::UnixStream;
     ///
     /// let (stream1, stream2) = UnixStream::pair()?;
@@ -261,3 +261,9 @@ impl From<UnixStream> for net::UnixStream {
         unsafe { net::UnixStream::from_raw_fd(stream.into_raw_fd()) }
     }
 }
+
+impl AsFd for UnixStream {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.inner.as_fd()
+    }
+}
diff --git a/src/poll.rs b/src/poll.rs
index 6ba9a91..8b0da06 100644
--- a/src/poll.rs
+++ b/src/poll.rs
@@ -8,7 +8,7 @@
         target_os = "vita"
     )),
 ))]
-use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::fd::{AsRawFd, RawFd};
 #[cfg(all(debug_assertions, not(target_os = "wasi")))]
 use std::sync::atomic::{AtomicBool, Ordering};
 #[cfg(all(debug_assertions, not(target_os = "wasi")))]
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index f60c209..5f1ee9c 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -80,9 +80,4 @@ cfg_not_os_poll! {
         #[cfg(feature = "os-ext")]
         pub use self::unix::SourceFd;
     }
-
-    #[cfg(unix)]
-    cfg_net! {
-        pub use self::unix::SocketAddr;
-    }
 }
diff --git a/src/sys/shell/mod.rs b/src/sys/shell/mod.rs
index 76085b8..20ab7df 100644
--- a/src/sys/shell/mod.rs
+++ b/src/sys/shell/mod.rs
@@ -24,7 +24,7 @@ cfg_io_source! {
     #[cfg(windows)]
     use std::os::windows::io::RawSocket;
     #[cfg(unix)]
-    use std::os::unix::io::RawFd;
+    use std::os::fd::RawFd;
 
     #[cfg(any(windows, unix))]
     use crate::{Registry, Token, Interest};
diff --git a/src/sys/shell/selector.rs b/src/sys/shell/selector.rs
index 0a16898..83456ef 100644
--- a/src/sys/shell/selector.rs
+++ b/src/sys/shell/selector.rs
@@ -1,6 +1,6 @@
 use std::io;
 #[cfg(unix)]
-use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::fd::{AsRawFd, RawFd};
 use std::time::Duration;
 
 pub type Event = usize;
diff --git a/src/sys/shell/uds.rs b/src/sys/shell/uds.rs
index bac547b..446781a 100644
--- a/src/sys/shell/uds.rs
+++ b/src/sys/shell/uds.rs
@@ -1,10 +1,8 @@
 pub(crate) mod datagram {
-    use crate::net::SocketAddr;
     use std::io;
-    use std::os::unix::net;
-    use std::path::Path;
+    use std::os::unix::net::{self, SocketAddr};
 
-    pub(crate) fn bind(_: &Path) -> io::Result<net::UnixDatagram> {
+    pub(crate) fn bind_addr(_: &SocketAddr) -> io::Result<net::UnixDatagram> {
         os_required!()
     }
 
@@ -15,32 +13,13 @@ pub(crate) mod datagram {
     pub(crate) fn pair() -> io::Result<(net::UnixDatagram, net::UnixDatagram)> {
         os_required!()
     }
-
-    pub(crate) fn local_addr(_: &net::UnixDatagram) -> io::Result<SocketAddr> {
-        os_required!()
-    }
-
-    pub(crate) fn peer_addr(_: &net::UnixDatagram) -> io::Result<SocketAddr> {
-        os_required!()
-    }
-
-    pub(crate) fn recv_from(
-        _: &net::UnixDatagram,
-        _: &mut [u8],
-    ) -> io::Result<(usize, SocketAddr)> {
-        os_required!()
-    }
 }
 
 pub(crate) mod listener {
-    use crate::net::{SocketAddr, UnixStream};
     use std::io;
-    use std::os::unix::net;
-    use std::path::Path;
+    use std::os::unix::net::{self, SocketAddr};
 
-    pub(crate) fn bind(_: &Path) -> io::Result<net::UnixListener> {
-        os_required!()
-    }
+    use crate::net::UnixStream;
 
     pub(crate) fn bind_addr(_: &SocketAddr) -> io::Result<net::UnixListener> {
         os_required!()
@@ -49,21 +28,11 @@ pub(crate) mod listener {
     pub(crate) fn accept(_: &net::UnixListener) -> io::Result<(UnixStream, SocketAddr)> {
         os_required!()
     }
-
-    pub(crate) fn local_addr(_: &net::UnixListener) -> io::Result<SocketAddr> {
-        os_required!()
-    }
 }
 
 pub(crate) mod stream {
-    use crate::net::SocketAddr;
     use std::io;
-    use std::os::unix::net;
-    use std::path::Path;
-
-    pub(crate) fn connect(_: &Path) -> io::Result<net::UnixStream> {
-        os_required!()
-    }
+    use std::os::unix::net::{self, SocketAddr};
 
     pub(crate) fn connect_addr(_: &SocketAddr) -> io::Result<net::UnixStream> {
         os_required!()
@@ -72,12 +41,4 @@ pub(crate) mod stream {
     pub(crate) fn pair() -> io::Result<(net::UnixStream, net::UnixStream)> {
         os_required!()
     }
-
-    pub(crate) fn local_addr(_: &net::UnixStream) -> io::Result<SocketAddr> {
-        os_required!()
-    }
-
-    pub(crate) fn peer_addr(_: &net::UnixStream) -> io::Result<SocketAddr> {
-        os_required!()
-    }
 }
diff --git a/src/sys/unix/mod.rs b/src/sys/unix/mod.rs
index aa48cc0..dc53b43 100644
--- a/src/sys/unix/mod.rs
+++ b/src/sys/unix/mod.rs
@@ -4,6 +4,7 @@
 #[allow(unused_macros)]
 macro_rules! syscall {
     ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
+        #[allow(unused_unsafe)]
         let res = unsafe { libc::$fn($($arg, )*) };
         if res < 0 {
             Err(std::io::Error::last_os_error())
@@ -31,8 +32,6 @@ cfg_os_poll! {
         pub(crate) mod udp;
         #[cfg(not(target_os = "hermit"))]
         pub(crate) mod uds;
-        #[cfg(not(target_os = "hermit"))]
-        pub use self::uds::SocketAddr;
     }
 
     cfg_io_source! {
@@ -40,13 +39,9 @@ cfg_os_poll! {
         #[cfg(not(any(mio_unsupported_force_poll_poll, target_os = "espidf", target_os = "hermit", target_os = "solaris", target_os = "vita")))]
         mod stateless_io_source {
             use std::io;
-            #[cfg(target_os = "hermit")]
-            use std::os::hermit::io::RawFd;
-            #[cfg(unix)]
-            use std::os::unix::io::RawFd;
-            use crate::Registry;
-            use crate::Token;
-            use crate::Interest;
+            use std::os::fd::RawFd;
+
+            use crate::{Registry, Token, Interest};
 
             pub(crate) struct IoSourceState;
 
@@ -118,11 +113,6 @@ cfg_os_poll! {
 }
 
 cfg_not_os_poll! {
-    cfg_net! {
-        mod uds;
-        pub use self::uds::SocketAddr;
-    }
-
     cfg_any_os_ext! {
         mod sourcefd;
         #[cfg(feature = "os-ext")]
diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs
index 5a473bd..0298d0b 100644
--- a/src/sys/unix/net.rs
+++ b/src/sys/unix/net.rs
@@ -35,6 +35,7 @@ pub(crate) fn new_socket(domain: libc::c_int, socket_type: libc::c_int) -> io::R
         target_os = "ios",
         target_os = "macos",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     ))]
     if let Err(err) = syscall!(setsockopt(
@@ -53,6 +54,7 @@ pub(crate) fn new_socket(domain: libc::c_int, socket_type: libc::c_int) -> io::R
         target_os = "ios",
         target_os = "macos",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
         target_os = "espidf",
         target_os = "vita",
@@ -116,6 +118,7 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_
                     target_os = "netbsd",
                     target_os = "openbsd",
                     target_os = "tvos",
+                    target_os = "visionos",
                     target_os = "watchos",
                     target_os = "espidf",
                     target_os = "vita",
@@ -149,6 +152,7 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_
                     target_os = "netbsd",
                     target_os = "openbsd",
                     target_os = "tvos",
+                    target_os = "visionos",
                     target_os = "watchos",
                     target_os = "espidf",
                     target_os = "vita",
diff --git a/src/sys/unix/pipe.rs b/src/sys/unix/pipe.rs
index c44106a..986bd3f 100644
--- a/src/sys/unix/pipe.rs
+++ b/src/sys/unix/pipe.rs
@@ -3,7 +3,7 @@
 //! See the [`new`] function for documentation.
 
 use std::io;
-use std::os::unix::io::RawFd;
+use std::os::fd::RawFd;
 
 pub(crate) fn new_raw() -> io::Result<[RawFd; 2]> {
     let mut fds: [RawFd; 2] = [-1, -1];
@@ -31,6 +31,7 @@ pub(crate) fn new_raw() -> io::Result<[RawFd; 2]> {
         target_os = "ios",
         target_os = "macos",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
         target_os = "espidf",
         target_os = "nto",
@@ -68,6 +69,7 @@ pub(crate) fn new_raw() -> io::Result<[RawFd; 2]> {
         target_os = "openbsd",
         target_os = "redox",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
         target_os = "espidf",
         target_os = "solaris",
@@ -82,7 +84,7 @@ pub(crate) fn new_raw() -> io::Result<[RawFd; 2]> {
 cfg_os_ext! {
 use std::fs::File;
 use std::io::{IoSlice, IoSliceMut, Read, Write};
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
 use std::process::{ChildStderr, ChildStdin, ChildStdout};
 
 use crate::io_source::IoSource;
@@ -262,7 +264,7 @@ impl Sender {
     /// #
     /// # fn main() -> Result<(), Box<dyn Error>> {
     /// use std::io;
-    /// use std::os::unix::io::AsRawFd;
+    /// use std::os::fd::AsRawFd;
     /// use mio::unix::pipe;
     ///
     /// let (sender, receiver) = pipe::new()?;
@@ -427,7 +429,7 @@ impl Receiver {
     /// #
     /// # fn main() -> Result<(), Box<dyn Error>> {
     /// use std::io;
-    /// use std::os::unix::io::AsRawFd;
+    /// use std::os::fd::AsRawFd;
     /// use mio::unix::pipe;
     ///
     /// let (sender, receiver) = pipe::new()?;
@@ -542,11 +544,9 @@ impl From<ChildStderr> for Receiver {
     }
 }
 
-impl FromRawFd for Receiver {
-    unsafe fn from_raw_fd(fd: RawFd) -> Receiver {
-        Receiver {
-            inner: IoSource::new(File::from_raw_fd(fd)),
-        }
+impl IntoRawFd for Receiver {
+    fn into_raw_fd(self) -> RawFd {
+        self.inner.into_inner().into_raw_fd()
     }
 }
 
@@ -556,9 +556,17 @@ impl AsRawFd for Receiver {
     }
 }
 
-impl IntoRawFd for Receiver {
-    fn into_raw_fd(self) -> RawFd {
-        self.inner.into_inner().into_raw_fd()
+impl FromRawFd for Receiver {
+    unsafe fn from_raw_fd(fd: RawFd) -> Receiver {
+        Receiver {
+            inner: IoSource::new(File::from_raw_fd(fd)),
+        }
+    }
+}
+
+impl AsFd for Receiver {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.inner.as_fd()
     }
 }
 
diff --git a/src/sys/unix/selector/epoll.rs b/src/sys/unix/selector/epoll.rs
index e049575..de6cff3 100644
--- a/src/sys/unix/selector/epoll.rs
+++ b/src/sys/unix/selector/epoll.rs
@@ -1,4 +1,4 @@
-use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
 #[cfg(debug_assertions)]
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::time::Duration;
@@ -16,20 +16,22 @@ static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
 pub struct Selector {
     #[cfg(debug_assertions)]
     id: usize,
-    ep: RawFd,
+    ep: OwnedFd,
 }
 
 impl Selector {
     pub fn new() -> io::Result<Selector> {
+        // SAFETY: `epoll_create1(2)` ensures the fd is valid.
+        let ep = unsafe { OwnedFd::from_raw_fd(syscall!(epoll_create1(libc::EPOLL_CLOEXEC))?) };
         Ok(Selector {
             #[cfg(debug_assertions)]
             id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
-            ep: syscall!(epoll_create1(libc::EPOLL_CLOEXEC))?,
+            ep,
         })
     }
 
     pub fn try_clone(&self) -> io::Result<Selector> {
-        syscall!(fcntl(self.ep, libc::F_DUPFD_CLOEXEC, super::LOWEST_FD)).map(|ep| Selector {
+        self.ep.try_clone().map(|ep| Selector {
             // It's the same selector, so we use the same id.
             #[cfg(debug_assertions)]
             id: self.id,
@@ -52,7 +54,7 @@ impl Selector {
 
         events.clear();
         syscall!(epoll_wait(
-            self.ep,
+            self.ep.as_raw_fd(),
             events.as_mut_ptr(),
             events.capacity() as i32,
             timeout,
@@ -72,7 +74,8 @@ impl Selector {
             _pad: 0,
         };
 
-        syscall!(epoll_ctl(self.ep, libc::EPOLL_CTL_ADD, fd, &mut event)).map(|_| ())
+        let ep = self.ep.as_raw_fd();
+        syscall!(epoll_ctl(ep, libc::EPOLL_CTL_ADD, fd, &mut event)).map(|_| ())
     }
 
     pub fn reregister(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()> {
@@ -83,11 +86,13 @@ impl Selector {
             _pad: 0,
         };
 
-        syscall!(epoll_ctl(self.ep, libc::EPOLL_CTL_MOD, fd, &mut event)).map(|_| ())
+        let ep = self.ep.as_raw_fd();
+        syscall!(epoll_ctl(ep, libc::EPOLL_CTL_MOD, fd, &mut event)).map(|_| ())
     }
 
     pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
-        syscall!(epoll_ctl(self.ep, libc::EPOLL_CTL_DEL, fd, ptr::null_mut())).map(|_| ())
+        let ep = self.ep.as_raw_fd();
+        syscall!(epoll_ctl(ep, libc::EPOLL_CTL_DEL, fd, ptr::null_mut())).map(|_| ())
     }
 }
 
@@ -102,15 +107,7 @@ cfg_io_source! {
 
 impl AsRawFd for Selector {
     fn as_raw_fd(&self) -> RawFd {
-        self.ep
-    }
-}
-
-impl Drop for Selector {
-    fn drop(&mut self) {
-        if let Err(err) = syscall!(close(self.ep)) {
-            error!("error closing epoll: {}", err);
-        }
+        self.ep.as_raw_fd()
     }
 }
 
diff --git a/src/sys/unix/selector/kqueue.rs b/src/sys/unix/selector/kqueue.rs
index 8e5e410..7365102 100644
--- a/src/sys/unix/selector/kqueue.rs
+++ b/src/sys/unix/selector/kqueue.rs
@@ -1,7 +1,7 @@
 use crate::{Interest, Token};
 use std::mem::{self, MaybeUninit};
 use std::ops::{Deref, DerefMut};
-use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
 #[cfg(debug_assertions)]
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::time::Duration;
@@ -24,6 +24,7 @@ type Filter = libc::c_short;
     target_os = "ios",
     target_os = "macos",
     target_os = "tvos",
+    target_os = "visionos",
     target_os = "watchos"
 ))]
 type Filter = i16;
@@ -37,6 +38,7 @@ type Flags = libc::c_ushort;
     target_os = "ios",
     target_os = "macos",
     target_os = "tvos",
+    target_os = "visionos",
     target_os = "watchos"
 ))]
 type Flags = u16;
@@ -65,24 +67,23 @@ macro_rules! kevent {
 pub struct Selector {
     #[cfg(debug_assertions)]
     id: usize,
-    kq: RawFd,
+    kq: OwnedFd,
 }
 
 impl Selector {
     pub fn new() -> io::Result<Selector> {
-        let kq = syscall!(kqueue())?;
-        let selector = Selector {
+        // SAFETY: `kqueue(2)` ensures the fd is valid.
+        let kq = unsafe { OwnedFd::from_raw_fd(syscall!(kqueue())?) };
+        syscall!(fcntl(kq.as_raw_fd(), libc::F_SETFD, libc::FD_CLOEXEC))?;
+        Ok(Selector {
             #[cfg(debug_assertions)]
             id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
             kq,
-        };
-
-        syscall!(fcntl(kq, libc::F_SETFD, libc::FD_CLOEXEC))?;
-        Ok(selector)
+        })
     }
 
     pub fn try_clone(&self) -> io::Result<Selector> {
-        syscall!(fcntl(self.kq, libc::F_DUPFD_CLOEXEC, super::LOWEST_FD)).map(|kq| Selector {
+        self.kq.try_clone().map(|kq| Selector {
             // It's the same selector, so we use the same id.
             #[cfg(debug_assertions)]
             id: self.id,
@@ -106,7 +107,7 @@ impl Selector {
 
         events.clear();
         syscall!(kevent(
-            self.kq,
+            self.kq.as_raw_fd(),
             ptr::null(),
             0,
             events.as_mut_ptr(),
@@ -156,7 +157,7 @@ impl Selector {
             // the array.
             slice::from_raw_parts_mut(changes[0].as_mut_ptr(), n_changes)
         };
-        kevent_register(self.kq, changes, &[libc::EPIPE as i64])
+        kevent_register(self.kq.as_raw_fd(), changes, &[libc::EPIPE as i64])
     }
 
     pub fn reregister(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()> {
@@ -186,7 +187,7 @@ impl Selector {
         //
         // For the explanation of ignoring `EPIPE` see `register`.
         kevent_register(
-            self.kq,
+            self.kq.as_raw_fd(),
             &mut changes,
             &[libc::ENOENT as i64, libc::EPIPE as i64],
         )
@@ -204,7 +205,7 @@ impl Selector {
         // the ENOENT error when it comes up. The ENOENT error informs us that
         // the filter wasn't there in first place, but we don't really care
         // about that since our goal is to remove it.
-        kevent_register(self.kq, &mut changes, &[libc::ENOENT as i64])
+        kevent_register(self.kq.as_raw_fd(), &mut changes, &[libc::ENOENT as i64])
     }
 
     // Used by `Waker`.
@@ -213,6 +214,7 @@ impl Selector {
         target_os = "ios",
         target_os = "macos",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos"
     ))]
     pub fn setup_waker(&self, token: Token) -> io::Result<()> {
@@ -224,7 +226,8 @@ impl Selector {
             token.0
         );
 
-        syscall!(kevent(self.kq, &kevent, 1, &mut kevent, 1, ptr::null())).and_then(|_| {
+        let kq = self.kq.as_raw_fd();
+        syscall!(kevent(kq, &kevent, 1, &mut kevent, 1, ptr::null())).and_then(|_| {
             if (kevent.flags & libc::EV_ERROR) != 0 && kevent.data != 0 {
                 Err(io::Error::from_raw_os_error(kevent.data as i32))
             } else {
@@ -239,6 +242,7 @@ impl Selector {
         target_os = "ios",
         target_os = "macos",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos"
     ))]
     pub fn wake(&self, token: Token) -> io::Result<()> {
@@ -250,7 +254,8 @@ impl Selector {
         );
         kevent.fflags = libc::NOTE_TRIGGER;
 
-        syscall!(kevent(self.kq, &kevent, 1, &mut kevent, 1, ptr::null())).and_then(|_| {
+        let kq = self.kq.as_raw_fd();
+        syscall!(kevent(kq, &kevent, 1, &mut kevent, 1, ptr::null())).and_then(|_| {
             if (kevent.flags & libc::EV_ERROR) != 0 && kevent.data != 0 {
                 Err(io::Error::from_raw_os_error(kevent.data as i32))
             } else {
@@ -314,15 +319,7 @@ cfg_io_source! {
 
 impl AsRawFd for Selector {
     fn as_raw_fd(&self) -> RawFd {
-        self.kq
-    }
-}
-
-impl Drop for Selector {
-    fn drop(&mut self) {
-        if let Err(err) = syscall!(close(self.kq)) {
-            error!("error closing kqueue: {}", err);
-        }
+        self.kq.as_raw_fd()
     }
 }
 
@@ -376,6 +373,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             // Used by the `Awakener`. On platforms that use `eventfd` or a unix
@@ -389,6 +387,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             )))]
             {
@@ -429,6 +428,7 @@ pub mod event {
             target_os = "ios",
             target_os = "macos",
             target_os = "tvos",
+            target_os = "visionos",
             target_os = "watchos",
         ))]
         {
@@ -440,6 +440,7 @@ pub mod event {
             target_os = "ios",
             target_os = "macos",
             target_os = "tvos",
+            target_os = "visionos",
             target_os = "watchos",
         )))]
         {
@@ -478,6 +479,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos",
             ))]
             libc::EVFILT_FS,
@@ -489,6 +491,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos",
             ))]
             libc::EVFILT_USER,
@@ -502,6 +505,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::EVFILT_MACHPORT,
@@ -509,6 +513,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::EVFILT_VM,
@@ -539,6 +544,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::EV_FLAG0,
@@ -546,6 +552,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::EV_POLL,
@@ -553,6 +560,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::EV_OOBAND,
@@ -573,6 +581,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos",
             ))]
             libc::NOTE_TRIGGER,
@@ -582,6 +591,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos",
             ))]
             libc::NOTE_FFNOP,
@@ -591,6 +601,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos",
             ))]
             libc::NOTE_FFAND,
@@ -600,6 +611,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos",
             ))]
             libc::NOTE_FFOR,
@@ -609,6 +621,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos",
             ))]
             libc::NOTE_FFCOPY,
@@ -618,6 +631,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos",
             ))]
             libc::NOTE_FFCTRLMASK,
@@ -627,6 +641,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos",
             ))]
             libc::NOTE_FFLAGSMASK,
@@ -641,6 +656,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_EXTEND,
@@ -652,6 +668,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_NONE,
@@ -664,6 +681,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_SIGNAL,
@@ -671,6 +689,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_EXITSTATUS,
@@ -678,6 +697,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_EXIT_DETAIL,
@@ -708,6 +728,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_EXIT_DETAIL_MASK,
@@ -715,6 +736,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_EXIT_DECRYPTFAIL,
@@ -722,6 +744,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_EXIT_MEMORY,
@@ -729,6 +752,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_EXIT_CSERROR,
@@ -736,6 +760,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_VM_PRESSURE,
@@ -743,6 +768,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_VM_PRESSURE_TERMINATE,
@@ -750,6 +776,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_VM_PRESSURE_SUDDEN_TERMINATE,
@@ -757,6 +784,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_VM_ERROR,
@@ -765,6 +793,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_SECONDS,
@@ -775,6 +804,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_USECONDS,
@@ -783,6 +813,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_NSECONDS,
@@ -790,6 +821,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_ABSOLUTE,
@@ -797,6 +829,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_LEEWAY,
@@ -804,6 +837,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_CRITICAL,
@@ -811,6 +845,7 @@ pub mod event {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos"
             ))]
             libc::NOTE_BACKGROUND,
diff --git a/src/sys/unix/selector/mod.rs b/src/sys/unix/selector/mod.rs
index b712b74..8344404 100644
--- a/src/sys/unix/selector/mod.rs
+++ b/src/sys/unix/selector/mod.rs
@@ -59,6 +59,7 @@ cfg_io_source! {
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     )
 ))]
@@ -74,17 +75,8 @@ mod kqueue;
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     ),
 ))]
 pub(crate) use self::kqueue::{event, Event, Events, Selector};
-
-/// Lowest file descriptor used in `Selector::try_clone`.
-///
-/// # Notes
-///
-/// Usually fds 0, 1 and 2 are standard in, out and error. Some application
-/// blindly assume this to be true, which means using any one of those a select
-/// could result in some interesting and unexpected errors. Avoid that by using
-/// an fd that doesn't have a pre-determined usage.
-const LOWEST_FD: libc::c_int = 3;
diff --git a/src/sys/unix/selector/poll.rs b/src/sys/unix/selector/poll.rs
index 97b5704..65e1764 100644
--- a/src/sys/unix/selector/poll.rs
+++ b/src/sys/unix/selector/poll.rs
@@ -5,16 +5,12 @@
 
 use std::collections::HashMap;
 use std::fmt::{Debug, Formatter};
-#[cfg(target_os = "hermit")]
-use std::os::hermit::io::{AsRawFd, RawFd};
-#[cfg(unix)]
-use std::os::unix::io::{AsRawFd, RawFd};
+use std::os::fd::{AsRawFd, RawFd};
 use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
 use std::sync::{Arc, Condvar, Mutex};
 use std::time::Duration;
 use std::{cmp, fmt, io};
 
-use crate::sys::unix::selector::LOWEST_FD;
 use crate::sys::unix::waker::WakerInternal;
 use crate::{Interest, Token};
 
@@ -37,9 +33,6 @@ impl Selector {
     }
 
     pub fn try_clone(&self) -> io::Result<Selector> {
-        // Just to keep the compiler happy :)
-        let _ = LOWEST_FD;
-
         let state = self.state.clone();
 
         Ok(Selector { state })
diff --git a/src/sys/unix/sourcefd.rs b/src/sys/unix/sourcefd.rs
index 27c34a0..313b97f 100644
--- a/src/sys/unix/sourcefd.rs
+++ b/src/sys/unix/sourcefd.rs
@@ -1,10 +1,7 @@
-use crate::{event, Interest, Registry, Token};
-
 use std::io;
-#[cfg(target_os = "hermit")]
-use std::os::hermit::io::RawFd;
-#[cfg(not(target_os = "hermit"))]
-use std::os::unix::io::RawFd;
+use std::os::fd::RawFd;
+
+use crate::{event, Interest, Registry, Token};
 
 /// Adapter for [`RawFd`] providing an [`event::Source`] implementation.
 ///
@@ -41,7 +38,7 @@ use std::os::unix::io::RawFd;
 /// use mio::{Interest, Poll, Token};
 /// use mio::unix::SourceFd;
 ///
-/// use std::os::unix::io::AsRawFd;
+/// use std::os::fd::AsRawFd;
 /// use std::net::TcpListener;
 ///
 /// // Bind a std listener
@@ -65,7 +62,7 @@ use std::os::unix::io::RawFd;
 /// use mio::{event, Interest, Registry, Token};
 /// use mio::unix::SourceFd;
 ///
-/// use std::os::unix::io::RawFd;
+/// use std::os::fd::RawFd;
 /// use std::io;
 ///
 /// # #[allow(dead_code)]
diff --git a/src/sys/unix/tcp.rs b/src/sys/unix/tcp.rs
index d1396aa..cdf9200 100644
--- a/src/sys/unix/tcp.rs
+++ b/src/sys/unix/tcp.rs
@@ -2,10 +2,7 @@ use std::convert::TryInto;
 use std::io;
 use std::mem::{size_of, MaybeUninit};
 use std::net::{self, SocketAddr};
-#[cfg(target_os = "hermit")]
-use std::os::hermit::io::{AsRawFd, FromRawFd};
-#[cfg(not(target_os = "hermit"))]
-use std::os::unix::io::{AsRawFd, FromRawFd};
+use std::os::fd::{AsRawFd, FromRawFd};
 
 use crate::sys::unix::net::{new_socket, socket_addr, to_socket_addr};
 
@@ -91,6 +88,7 @@ pub(crate) fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream,
         target_os = "macos",
         target_os = "redox",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
         target_os = "espidf",
         target_os = "vita",
diff --git a/src/sys/unix/udp.rs b/src/sys/unix/udp.rs
index ecab324..7ad7ed9 100644
--- a/src/sys/unix/udp.rs
+++ b/src/sys/unix/udp.rs
@@ -1,12 +1,9 @@
-use crate::sys::unix::net::{new_ip_socket, socket_addr};
-
 use std::io;
 use std::mem;
 use std::net::{self, SocketAddr};
-#[cfg(target_os = "hermit")]
-use std::os::hermit::io::{AsRawFd, FromRawFd};
-#[cfg(not(target_os = "hermit"))]
-use std::os::unix::io::{AsRawFd, FromRawFd};
+use std::os::fd::{AsRawFd, FromRawFd};
+
+use crate::sys::unix::net::{new_ip_socket, socket_addr};
 
 pub fn bind(addr: SocketAddr) -> io::Result<net::UdpSocket> {
     let fd = new_ip_socket(addr, libc::SOCK_DGRAM)?;
diff --git a/src/sys/unix/uds/datagram.rs b/src/sys/unix/uds/datagram.rs
index 5853a4d..2010e8e 100644
--- a/src/sys/unix/uds/datagram.rs
+++ b/src/sys/unix/uds/datagram.rs
@@ -1,18 +1,16 @@
-use super::{socket_addr, SocketAddr};
-use crate::sys::unix::net::new_socket;
-
 use std::io;
-use std::os::unix::ffi::OsStrExt;
-use std::os::unix::io::{AsRawFd, FromRawFd};
-use std::os::unix::net;
-use std::path::Path;
+use std::os::fd::{AsRawFd, FromRawFd};
+use std::os::unix::net::{self, SocketAddr};
 
-pub(crate) fn bind(path: &Path) -> io::Result<net::UnixDatagram> {
-    let (sockaddr, socklen) = socket_addr(path.as_os_str().as_bytes())?;
-    let sockaddr = &sockaddr as *const libc::sockaddr_un as *const _;
+use crate::sys::unix::net::new_socket;
+use crate::sys::unix::uds::unix_addr;
 
+pub(crate) fn bind_addr(address: &SocketAddr) -> io::Result<net::UnixDatagram> {
     let socket = unbound()?;
-    syscall!(bind(socket.as_raw_fd(), sockaddr, socklen))?;
+
+    let (unix_address, addrlen) = unix_addr(address);
+    let sockaddr = &unix_address as *const libc::sockaddr_un as *const libc::sockaddr;
+    syscall!(bind(socket.as_raw_fd(), sockaddr, addrlen))?;
 
     Ok(socket)
 }
@@ -25,33 +23,3 @@ pub(crate) fn unbound() -> io::Result<net::UnixDatagram> {
 pub(crate) fn pair() -> io::Result<(net::UnixDatagram, net::UnixDatagram)> {
     super::pair(libc::SOCK_DGRAM)
 }
-
-pub(crate) fn local_addr(socket: &net::UnixDatagram) -> io::Result<SocketAddr> {
-    super::local_addr(socket.as_raw_fd())
-}
-
-pub(crate) fn peer_addr(socket: &net::UnixDatagram) -> io::Result<SocketAddr> {
-    super::peer_addr(socket.as_raw_fd())
-}
-
-pub(crate) fn recv_from(
-    socket: &net::UnixDatagram,
-    dst: &mut [u8],
-) -> io::Result<(usize, SocketAddr)> {
-    let mut count = 0;
-    let socketaddr = SocketAddr::new(|sockaddr, socklen| {
-        syscall!(recvfrom(
-            socket.as_raw_fd(),
-            dst.as_mut_ptr() as *mut _,
-            dst.len(),
-            0,
-            sockaddr,
-            socklen,
-        ))
-        .map(|c| {
-            count = c;
-            c as libc::c_int
-        })
-    })?;
-    Ok((count as usize, socketaddr))
-}
diff --git a/src/sys/unix/uds/listener.rs b/src/sys/unix/uds/listener.rs
index b942437..b23e79e 100644
--- a/src/sys/unix/uds/listener.rs
+++ b/src/sys/unix/uds/listener.rs
@@ -1,46 +1,36 @@
-use super::socket_addr;
-use crate::net::{SocketAddr, UnixStream};
-use crate::sys::unix::net::new_socket;
+use std::ffi::OsStr;
+use std::os::fd::{AsRawFd, FromRawFd};
 use std::os::unix::ffi::OsStrExt;
-use std::os::unix::io::{AsRawFd, FromRawFd};
-use std::os::unix::net;
+use std::os::unix::net::{self, SocketAddr};
 use std::path::Path;
 use std::{io, mem};
 
-pub(crate) fn bind(path: &Path) -> io::Result<net::UnixListener> {
-    let socket_address = {
-        let (sockaddr, socklen) = socket_addr(path.as_os_str().as_bytes())?;
-        SocketAddr::from_parts(sockaddr, socklen)
-    };
-
-    bind_addr(&socket_address)
-}
+use crate::net::UnixStream;
+use crate::sys::unix::net::new_socket;
+use crate::sys::unix::uds::{path_offset, unix_addr};
 
 pub(crate) fn bind_addr(address: &SocketAddr) -> io::Result<net::UnixListener> {
     let fd = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?;
     let socket = unsafe { net::UnixListener::from_raw_fd(fd) };
-    let sockaddr = address.raw_sockaddr() as *const libc::sockaddr_un as *const libc::sockaddr;
 
-    syscall!(bind(fd, sockaddr, *address.raw_socklen()))?;
+    let (unix_address, addrlen) = unix_addr(address);
+    let sockaddr = &unix_address as *const libc::sockaddr_un as *const libc::sockaddr;
+    syscall!(bind(fd, sockaddr, addrlen))?;
     syscall!(listen(fd, 1024))?;
 
     Ok(socket)
 }
 
 pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, SocketAddr)> {
-    let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed();
-
-    // This is safe to assume because a `libc::sockaddr_un` filled with `0`
-    // bytes is properly initialized.
+    // SAFETY: `libc::sockaddr_un` zero filled is properly initialized.
     //
     // `0` is a valid value for `sockaddr_un::sun_family`; it is
     // `libc::AF_UNSPEC`.
     //
     // `[0; 108]` is a valid value for `sockaddr_un::sun_path`; it begins an
     // abstract path.
-    let mut sockaddr = unsafe { sockaddr.assume_init() };
+    let mut sockaddr = unsafe { mem::zeroed::<libc::sockaddr_un>() };
 
-    sockaddr.sun_family = libc::AF_UNIX as libc::sa_family_t;
     let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t;
 
     #[cfg(not(any(
@@ -50,6 +40,7 @@ pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, So
         target_os = "netbsd",
         target_os = "redox",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
         target_os = "espidf",
         target_os = "vita",
@@ -76,6 +67,7 @@ pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, So
         target_os = "netbsd",
         target_os = "redox",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
         target_os = "espidf",
         target_os = "vita",
@@ -106,11 +98,18 @@ pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, So
         Ok(s)
     });
 
-    socket
-        .map(UnixStream::from_std)
-        .map(|stream| (stream, SocketAddr::from_parts(sockaddr, socklen)))
-}
+    let socket = socket.map(UnixStream::from_std)?;
 
-pub(crate) fn local_addr(listener: &net::UnixListener) -> io::Result<SocketAddr> {
-    super::local_addr(listener.as_raw_fd())
+    #[allow(unused_mut)] // See below.
+    let mut path_len = socklen as usize - path_offset(&sockaddr);
+    // On FreeBSD and Darwin, it returns a length of 14/16, but an unnamed (all
+    // zero) address. Map that to a length of 0 to match other OS.
+    if sockaddr.sun_path[0] == 0 {
+        path_len = 0;
+    }
+    let address = SocketAddr::from_pathname(Path::new(OsStr::from_bytes(unsafe {
+        // SAFETY: going from i8 to u8 is fine in this context.
+        &*(&sockaddr.sun_path[..path_len] as *const [libc::c_char] as *const [u8])
+    })))?;
+    Ok((socket, address))
 }
diff --git a/src/sys/unix/uds/mod.rs b/src/sys/unix/uds/mod.rs
index 20367fd..b6479c7 100644
--- a/src/sys/unix/uds/mod.rs
+++ b/src/sys/unix/uds/mod.rs
@@ -1,5 +1,17 @@
-mod socketaddr;
-pub use self::socketaddr::SocketAddr;
+#[cfg(target_os = "android")]
+use std::os::android::net::SocketAddrExt;
+#[cfg(target_os = "linux")]
+use std::os::linux::net::SocketAddrExt;
+use std::os::unix::ffi::OsStrExt;
+use std::os::unix::io::FromRawFd;
+use std::os::unix::net::SocketAddr;
+use std::{io, mem, ptr};
+
+pub(crate) mod datagram;
+pub(crate) mod listener;
+pub(crate) mod stream;
+
+const UNNAMED_ADDRESS: &[u8] = &[];
 
 /// Get the `sun_path` field offset of `sockaddr_un` for the target OS.
 ///
@@ -7,162 +19,152 @@ pub use self::socketaddr::SocketAddr;
 /// `size_of::<sa_family_t>()`, but some other implementations include
 /// other fields before `sun_path`, so the expression more portably
 /// describes the size of the address structure.
-pub(in crate::sys) fn path_offset(sockaddr: &libc::sockaddr_un) -> usize {
+fn path_offset(sockaddr: &libc::sockaddr_un) -> usize {
     let base = sockaddr as *const _ as usize;
     let path = &sockaddr.sun_path as *const _ as usize;
     path - base
 }
 
-cfg_os_poll! {
-    use std::cmp::Ordering;
-    use std::os::unix::io::{RawFd, FromRawFd};
-    use std::{io, mem};
-
-    pub(crate) mod datagram;
-    pub(crate) mod listener;
-    pub(crate) mod stream;
-
-    pub(in crate::sys) fn socket_addr(bytes: &[u8]) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
-        let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed();
-
-        // This is safe to assume because a `libc::sockaddr_un` filled with `0`
-        // bytes is properly initialized.
-        //
-        // `0` is a valid value for `sockaddr_un::sun_family`; it is
-        // `libc::AF_UNSPEC`.
-        //
-        // `[0; 108]` is a valid value for `sockaddr_un::sun_path`; it begins an
-        // abstract path.
-        let mut sockaddr = unsafe { sockaddr.assume_init() };
-
-        sockaddr.sun_family = libc::AF_UNIX as libc::sa_family_t;
-
-        match (bytes.first(), bytes.len().cmp(&sockaddr.sun_path.len())) {
-            // Abstract paths don't need a null terminator
-            (Some(&0), Ordering::Greater) => {
-                return Err(io::Error::new(
-                    io::ErrorKind::InvalidInput,
-                    "path must be no longer than libc::sockaddr_un.sun_path",
-                ));
+/// Converts a Rust `SocketAddr` into the system representation.
+fn unix_addr(address: &SocketAddr) -> (libc::sockaddr_un, libc::socklen_t) {
+    // SAFETY: `libc::sockaddr_un` zero filled is properly initialized.
+    //
+    // `0` is a valid value for `sockaddr_un::sun_family`; it is
+    // `libc::AF_UNSPEC`.
+    //
+    // `[0; 108]` is a valid value for `sockaddr_un::sun_path`; it begins an
+    // abstract path.
+    let mut sockaddr = unsafe { mem::zeroed::<libc::sockaddr_un>() };
+
+    sockaddr.sun_family = libc::AF_UNIX as libc::sa_family_t;
+
+    #[allow(unused_mut)] // Only used with abstract namespaces.
+    let mut offset = 0;
+    let addr = match address.as_pathname() {
+        Some(path) => path.as_os_str().as_bytes(),
+        #[cfg(any(target_os = "android", target_os = "linux"))]
+        None => match address.as_abstract_name() {
+            Some(name) => {
+                offset += 1;
+                name
             }
-            (_, Ordering::Greater) | (_, Ordering::Equal) => {
-                return Err(io::Error::new(
-                    io::ErrorKind::InvalidInput,
-                    "path must be shorter than libc::sockaddr_un.sun_path",
-                ));
-            }
-            _ => {}
-        }
+            None => UNNAMED_ADDRESS,
+        },
+        #[cfg(not(any(target_os = "android", target_os = "linux")))]
+        None => UNNAMED_ADDRESS,
+    };
+
+    // SAFETY: `addr` and `sockaddr.sun_path` are not overlapping and both point
+    // to valid memory.
+    // SAFETY: since `addr` is a valid Unix address, it must not be larger than
+    // `SUN_LEN` bytes, thus we won't overwrite the size of sockaddr.sun_path.
+    // SAFETY: null byte is already written because we zeroed the address above.
+    debug_assert!(offset + addr.len() <= sockaddr.sun_path.len());
+    unsafe {
+        ptr::copy_nonoverlapping(
+            addr.as_ptr(),
+            sockaddr.sun_path.as_mut_ptr().add(offset).cast(),
+            addr.len(),
+        )
+    };
+
+    let mut addrlen = path_offset(&sockaddr) + addr.len();
+    // +1 for null byte at the end of the path, not needed for abstract
+    // namespaces (which start with a null byte).
+    match addr.first() {
+        Some(&0) | None => {}
+        Some(_) => addrlen += 1,
+    }
 
-        for (dst, src) in sockaddr.sun_path.iter_mut().zip(bytes.iter()) {
-            *dst = *src as libc::c_char;
-        }
+    // SAFETY: the length is fine to cast to `socklen_t` as it's 32 bits and the
+    // address can be at most `SUN_LEN` bytes.
+    (sockaddr, addrlen as _)
+}
 
-        let offset = path_offset(&sockaddr);
-        let mut socklen = offset + bytes.len();
+fn pair<T>(flags: libc::c_int) -> io::Result<(T, T)>
+where
+    T: FromRawFd,
+{
+    #[cfg(not(any(
+        target_os = "aix",
+        target_os = "ios",
+        target_os = "macos",
+        target_os = "tvos",
+        target_os = "visionos",
+        target_os = "watchos",
+        target_os = "espidf",
+        target_os = "vita",
+    )))]
+    let flags = flags | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
+
+    let mut fds = [-1; 2];
+    syscall!(socketpair(libc::AF_UNIX, flags, 0, fds.as_mut_ptr()))?;
+    let pair = unsafe { (T::from_raw_fd(fds[0]), T::from_raw_fd(fds[1])) };
+
+    // Darwin (and others) doesn't have SOCK_NONBLOCK or SOCK_CLOEXEC.
+    //
+    // In order to set those flags, additional `fcntl` sys calls must be
+    // performed. If a `fnctl` fails after the sockets have been created,
+    // the file descriptors will leak. Creating `pair` above ensures that if
+    // there is an error, the file descriptors are closed.
+    #[cfg(any(
+        target_os = "aix",
+        target_os = "ios",
+        target_os = "macos",
+        target_os = "tvos",
+        target_os = "visionos",
+        target_os = "watchos",
+        target_os = "espidf",
+        target_os = "vita",
+    ))]
+    {
+        syscall!(fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK))?;
+        #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "nto")))]
+        syscall!(fcntl(fds[0], libc::F_SETFD, libc::FD_CLOEXEC))?;
+        syscall!(fcntl(fds[1], libc::F_SETFL, libc::O_NONBLOCK))?;
+        #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "nto")))]
+        syscall!(fcntl(fds[1], libc::F_SETFD, libc::FD_CLOEXEC))?;
+    }
 
-        match bytes.first() {
-            // The struct has already been zeroes so the null byte for pathname
-            // addresses is already there.
-            Some(&0) | None => {}
-            Some(_) => socklen += 1,
-        }
+    Ok(pair)
+}
 
-        Ok((sockaddr, socklen as libc::socklen_t))
-    }
+#[cfg(test)]
+mod tests {
+    use std::os::unix::net::SocketAddr;
+    use std::path::Path;
+    use std::str;
 
-    fn pair<T>(flags: libc::c_int) -> io::Result<(T, T)>
-        where T: FromRawFd,
-    {
-        #[cfg(not(any(
-            target_os = "aix",
-            target_os = "ios",
-            target_os = "macos",
-            target_os = "tvos",
-            target_os = "watchos",
-            target_os = "espidf",
-            target_os = "vita",
-            target_os = "nto",
-        )))]
-        let flags = flags | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC;
-        #[cfg(target_os = "nto")]
-        let flags = flags | libc::SOCK_CLOEXEC;
-
-        let mut fds = [-1; 2];
-        syscall!(socketpair(libc::AF_UNIX, flags, 0, fds.as_mut_ptr()))?;
-        let pair = unsafe { (T::from_raw_fd(fds[0]), T::from_raw_fd(fds[1])) };
-
-        // Darwin (and others) doesn't have SOCK_NONBLOCK or SOCK_CLOEXEC.
-        //
-        // In order to set those flags, additional `fcntl` sys calls must be
-        // performed. If a `fnctl` fails after the sockets have been created,
-        // the file descriptors will leak. Creating `pair` above ensures that if
-        // there is an error, the file descriptors are closed.
-        #[cfg(any(
-            target_os = "aix",
-            target_os = "ios",
-            target_os = "macos",
-            target_os = "tvos",
-            target_os = "watchos",
-            target_os = "espidf",
-            target_os = "vita",
-            target_os = "nto",
-        ))]
-        {
-            syscall!(fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK))?;
-            #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "nto")))]
-            syscall!(fcntl(fds[0], libc::F_SETFD, libc::FD_CLOEXEC))?;
-            syscall!(fcntl(fds[1], libc::F_SETFL, libc::O_NONBLOCK))?;
-            #[cfg(not(any(target_os = "espidf", target_os = "vita", target_os = "nto")))]
-            syscall!(fcntl(fds[1], libc::F_SETFD, libc::FD_CLOEXEC))?;
-        }
-
-        Ok(pair)
-    }
+    use super::{path_offset, unix_addr};
 
-    // The following functions can't simply be replaced with a call to
-    // `net::UnixDatagram` because of our `SocketAddr` type.
+    #[test]
+    fn pathname_address() {
+        const PATH: &str = "./foo/bar.txt";
+        const PATH_LEN: usize = 13;
 
-    fn local_addr(socket: RawFd) -> io::Result<SocketAddr> {
-        SocketAddr::new(|sockaddr, socklen| syscall!(getsockname(socket, sockaddr, socklen)))
+        // Pathname addresses do have a null terminator, so `socklen` is
+        // expected to be `PATH_LEN` + `offset` + 1.
+        let address = SocketAddr::from_pathname(Path::new(PATH)).unwrap();
+        let (sockaddr, actual) = unix_addr(&address);
+        let offset = path_offset(&sockaddr);
+        let expected = PATH_LEN + offset + 1;
+        assert_eq!(expected as libc::socklen_t, actual)
     }
 
-    fn peer_addr(socket: RawFd) -> io::Result<SocketAddr> {
-        SocketAddr::new(|sockaddr, socklen| syscall!(getpeername(socket, sockaddr, socklen)))
-    }
+    #[test]
+    #[cfg(any(target_os = "android", target_os = "linux"))]
+    fn abstract_address() {
+        use std::os::linux::net::SocketAddrExt;
 
-    #[cfg(test)]
-    mod tests {
-        use super::{path_offset, socket_addr};
-        use std::os::unix::ffi::OsStrExt;
-        use std::path::Path;
-        use std::str;
-
-        #[test]
-        fn pathname_address() {
-            const PATH: &str = "./foo/bar.txt";
-            const PATH_LEN: usize = 13;
-
-            // Pathname addresses do have a null terminator, so `socklen` is
-            // expected to be `PATH_LEN` + `offset` + 1.
-            let path = Path::new(PATH);
-            let (sockaddr, actual) = socket_addr(path.as_os_str().as_bytes()).unwrap();
-            let offset = path_offset(&sockaddr);
-            let expected = PATH_LEN + offset + 1;
-            assert_eq!(expected as libc::socklen_t, actual)
-        }
-
-        #[test]
-        fn abstract_address() {
-            const PATH: &[u8] = &[0, 116, 111, 107, 105, 111];
-            const PATH_LEN: usize = 6;
-
-            // Abstract addresses do not have a null terminator, so `socklen` is
-            // expected to be `PATH_LEN` + `offset`.
-            let (sockaddr, actual) = socket_addr(PATH).unwrap();
-            let offset = path_offset(&sockaddr);
-            let expected = PATH_LEN + offset;
-            assert_eq!(expected as libc::socklen_t, actual)
-        }
+        const PATH: &[u8] = &[0, 116, 111, 107, 105, 111];
+        const PATH_LEN: usize = 6;
+
+        // Abstract addresses do not have a null terminator, so `socklen` is
+        // expected to be `PATH_LEN` + `offset`.
+        let address = SocketAddr::from_abstract_name(PATH).unwrap();
+        let (sockaddr, actual) = unix_addr(&address);
+        let offset = path_offset(&sockaddr);
+        let expected = PATH_LEN + offset;
+        assert_eq!(expected as libc::socklen_t, actual)
     }
 }
diff --git a/src/sys/unix/uds/socketaddr.rs b/src/sys/unix/uds/socketaddr.rs
deleted file mode 100644
index 8e0ef53..0000000
--- a/src/sys/unix/uds/socketaddr.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-use super::path_offset;
-use std::ffi::OsStr;
-use std::os::unix::ffi::OsStrExt;
-use std::path::Path;
-use std::{ascii, fmt};
-
-/// An address associated with a `mio` specific Unix socket.
-///
-/// This is implemented instead of imported from [`net::SocketAddr`] because
-/// there is no way to create a [`net::SocketAddr`]. One must be returned by
-/// [`accept`], so this is returned instead.
-///
-/// [`net::SocketAddr`]: std::os::unix::net::SocketAddr
-/// [`accept`]: #method.accept
-pub struct SocketAddr {
-    sockaddr: libc::sockaddr_un,
-    socklen: libc::socklen_t,
-}
-
-struct AsciiEscaped<'a>(&'a [u8]);
-
-enum AddressKind<'a> {
-    Unnamed,
-    Pathname(&'a Path),
-    Abstract(&'a [u8]),
-}
-
-impl SocketAddr {
-    fn address(&self) -> AddressKind<'_> {
-        let offset = path_offset(&self.sockaddr);
-        // Don't underflow in `len` below.
-        if (self.socklen as usize) < offset {
-            return AddressKind::Unnamed;
-        }
-        let len = self.socklen as usize - offset;
-        let path = unsafe { &*(&self.sockaddr.sun_path as *const [libc::c_char] as *const [u8]) };
-
-        // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
-        if len == 0
-            || (cfg!(not(any(target_os = "linux", target_os = "android")))
-                && self.sockaddr.sun_path[0] == 0)
-        {
-            AddressKind::Unnamed
-        } else if self.sockaddr.sun_path[0] == 0 {
-            AddressKind::Abstract(&path[1..len])
-        } else {
-            AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
-        }
-    }
-}
-
-cfg_os_poll! {
-    use std::{io, mem};
-
-    impl SocketAddr {
-        pub(crate) fn new<F>(f: F) -> io::Result<SocketAddr>
-        where
-            F: FnOnce(*mut libc::sockaddr, &mut libc::socklen_t) -> io::Result<libc::c_int>,
-        {
-            let mut sockaddr = {
-                let sockaddr = mem::MaybeUninit::<libc::sockaddr_un>::zeroed();
-                unsafe { sockaddr.assume_init() }
-            };
-
-            let raw_sockaddr = &mut sockaddr as *mut libc::sockaddr_un as *mut libc::sockaddr;
-            let mut socklen = mem::size_of_val(&sockaddr) as libc::socklen_t;
-
-            f(raw_sockaddr, &mut socklen)?;
-            Ok(SocketAddr::from_parts(sockaddr, socklen))
-        }
-
-        pub(crate) fn from_parts(sockaddr: libc::sockaddr_un, socklen: libc::socklen_t) -> SocketAddr {
-            SocketAddr { sockaddr, socklen }
-        }
-
-        pub(crate) fn raw_sockaddr(&self) -> &libc::sockaddr_un {
-            &self.sockaddr
-        }
-
-        pub(crate) fn raw_socklen(&self) -> &libc::socklen_t {
-            &self.socklen
-        }
-
-        /// Returns `true` if the address is unnamed.
-        ///
-        /// Documentation reflected in [`SocketAddr`]
-        ///
-        /// [`SocketAddr`]: std::os::unix::net::SocketAddr
-        pub fn is_unnamed(&self) -> bool {
-            matches!(self.address(), AddressKind::Unnamed)
-        }
-
-        /// Returns the contents of this address if it is a `pathname` address.
-        ///
-        /// Documentation reflected in [`SocketAddr`]
-        ///
-        /// [`SocketAddr`]: std::os::unix::net::SocketAddr
-        pub fn as_pathname(&self) -> Option<&Path> {
-            if let AddressKind::Pathname(path) = self.address() {
-                Some(path)
-            } else {
-                None
-            }
-        }
-
-        /// Returns the contents of this address if it is an abstract namespace
-        /// without the leading null byte.
-        // Link to std::os::unix::net::SocketAddr pending
-        // https://github.com/rust-lang/rust/issues/85410.
-        pub fn as_abstract_namespace(&self) -> Option<&[u8]> {
-            if let AddressKind::Abstract(path) = self.address() {
-                Some(path)
-            } else {
-                None
-            }
-        }
-    }
-}
-
-impl fmt::Debug for SocketAddr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.address() {
-            AddressKind::Unnamed => write!(fmt, "(unnamed)"),
-            AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
-            AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
-        }
-    }
-}
-
-impl<'a> fmt::Display for AsciiEscaped<'a> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "\"")?;
-        for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
-            write!(fmt, "{}", byte as char)?;
-        }
-        write!(fmt, "\"")
-    }
-}
diff --git a/src/sys/unix/uds/stream.rs b/src/sys/unix/uds/stream.rs
index 261d27b..dd2b2ca 100644
--- a/src/sys/unix/uds/stream.rs
+++ b/src/sys/unix/uds/stream.rs
@@ -1,27 +1,17 @@
-use super::{socket_addr, SocketAddr};
-use crate::sys::unix::net::new_socket;
-
 use std::io;
-use std::os::unix::ffi::OsStrExt;
-use std::os::unix::io::{AsRawFd, FromRawFd};
-use std::os::unix::net;
-use std::path::Path;
-
-pub(crate) fn connect(path: &Path) -> io::Result<net::UnixStream> {
-    let socket_address = {
-        let (sockaddr, socklen) = socket_addr(path.as_os_str().as_bytes())?;
-        SocketAddr::from_parts(sockaddr, socklen)
-    };
+use std::os::fd::FromRawFd;
+use std::os::unix::net::{self, SocketAddr};
 
-    connect_addr(&socket_address)
-}
+use crate::sys::unix::net::new_socket;
+use crate::sys::unix::uds::unix_addr;
 
 pub(crate) fn connect_addr(address: &SocketAddr) -> io::Result<net::UnixStream> {
     let fd = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?;
     let socket = unsafe { net::UnixStream::from_raw_fd(fd) };
-    let sockaddr = address.raw_sockaddr() as *const libc::sockaddr_un as *const libc::sockaddr;
 
-    match syscall!(connect(fd, sockaddr, *address.raw_socklen())) {
+    let (unix_address, addrlen) = unix_addr(address);
+    let sockaddr = &unix_address as *const libc::sockaddr_un as *const libc::sockaddr;
+    match syscall!(connect(fd, sockaddr, addrlen)) {
         Ok(_) => {}
         Err(ref err) if err.raw_os_error() == Some(libc::EINPROGRESS) => {}
         Err(e) => return Err(e),
@@ -33,11 +23,3 @@ pub(crate) fn connect_addr(address: &SocketAddr) -> io::Result<net::UnixStream>
 pub(crate) fn pair() -> io::Result<(net::UnixStream, net::UnixStream)> {
     super::pair(libc::SOCK_STREAM)
 }
-
-pub(crate) fn local_addr(socket: &net::UnixStream) -> io::Result<SocketAddr> {
-    super::local_addr(socket.as_raw_fd())
-}
-
-pub(crate) fn peer_addr(socket: &net::UnixStream) -> io::Result<SocketAddr> {
-    super::peer_addr(socket.as_raw_fd())
-}
diff --git a/src/sys/unix/waker.rs b/src/sys/unix/waker.rs
index fd85658..18f05b1 100644
--- a/src/sys/unix/waker.rs
+++ b/src/sys/unix/waker.rs
@@ -7,6 +7,7 @@
             target_os = "ios",
             target_os = "macos",
             target_os = "tvos",
+            target_os = "visionos",
             target_os = "watchos",
         )
     )),
@@ -18,6 +19,9 @@
     )),
 ))]
 mod fdbased {
+    use std::io;
+    use std::os::fd::AsRawFd;
+
     #[cfg(all(
         not(mio_unsupported_force_waker_pipe),
         any(target_os = "linux", target_os = "android"),
@@ -35,8 +39,6 @@ mod fdbased {
     use crate::sys::unix::waker::pipe::WakerInternal;
     use crate::sys::Selector;
     use crate::{Interest, Token};
-    use std::io;
-    use std::os::unix::io::AsRawFd;
 
     #[derive(Debug)]
     pub struct Waker {
@@ -65,6 +67,7 @@ mod fdbased {
             target_os = "ios",
             target_os = "macos",
             target_os = "tvos",
+            target_os = "visionos",
             target_os = "watchos",
         )
     )),
@@ -89,10 +92,7 @@ pub use self::fdbased::Waker;
 mod eventfd {
     use std::fs::File;
     use std::io::{self, Read, Write};
-    #[cfg(target_os = "hermit")]
-    use std::os::hermit::io::{AsRawFd, FromRawFd, RawFd};
-    #[cfg(not(target_os = "hermit"))]
-    use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+    use std::os::fd::{AsRawFd, FromRawFd, RawFd};
 
     /// Waker backed by `eventfd`.
     ///
@@ -180,6 +180,7 @@ pub(crate) use self::eventfd::WakerInternal;
         target_os = "ios",
         target_os = "macos",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     )
 ))]
@@ -221,6 +222,7 @@ mod kqueue {
         target_os = "ios",
         target_os = "macos",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     )
 ))]
@@ -241,7 +243,7 @@ mod pipe {
     use crate::sys::unix::pipe;
     use std::fs::File;
     use std::io::{self, Read, Write};
-    use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+    use std::os::fd::{AsRawFd, FromRawFd, RawFd};
 
     /// Waker backed by a unix pipe.
     ///


Test patch:
diff --git a/tests/aio.rs b/tests/aio.rs
index 9753d41..4cfb6d6 100644
--- a/tests/aio.rs
+++ b/tests/aio.rs
@@ -4,14 +4,13 @@
 ))]
 #![cfg(all(feature = "os-poll", feature = "net"))]
 
-use mio::{event::Source, Events, Interest, Poll, Registry, Token};
-use std::{
-    fs::File,
-    io, mem,
-    os::unix::io::{AsRawFd, RawFd},
-    pin::Pin,
-    ptr,
-};
+use std::fs::File;
+use std::os::fd::{AsRawFd, RawFd};
+use std::pin::Pin;
+use std::{io, mem, ptr};
+
+use mio::event::Source;
+use mio::{Events, Interest, Poll, Registry, Token};
 
 mod util;
 use util::{expect_events, expect_no_events, init, temp_file, ExpectEvent};
diff --git a/tests/interest.rs b/tests/interest.rs
index f477d59..cc59eec 100644
--- a/tests/interest.rs
+++ b/tests/interest.rs
@@ -31,6 +31,7 @@ fn fmt_debug() {
         target_os = "ios",
         target_os = "macos",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     ))]
     {
diff --git a/tests/tcp_listener.rs b/tests/tcp_listener.rs
index 086e619..c927c31 100644
--- a/tests/tcp_listener.rs
+++ b/tests/tcp_listener.rs
@@ -6,7 +6,7 @@ use mio::{Interest, Token};
 use std::io::{self, Read};
 use std::net::{self, SocketAddr};
 #[cfg(unix)]
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd};
 use std::sync::{Arc, Barrier};
 use std::thread;
 
diff --git a/tests/tcp_stream.rs b/tests/tcp_stream.rs
index b307a2a..bbce14a 100644
--- a/tests/tcp_stream.rs
+++ b/tests/tcp_stream.rs
@@ -4,7 +4,7 @@
 use std::io::{self, IoSlice, IoSliceMut, Read, Write};
 use std::net::{self, Shutdown, SocketAddr};
 #[cfg(unix)]
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd};
 use std::sync::{mpsc::channel, Arc, Barrier};
 use std::thread;
 use std::time::Duration;
@@ -298,6 +298,7 @@ fn shutdown_read() {
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     ))]
     {
@@ -388,6 +389,7 @@ fn shutdown_both() {
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     ))]
     {
diff --git a/tests/udp_socket.rs b/tests/udp_socket.rs
index 2a3a20c..ac82077 100644
--- a/tests/udp_socket.rs
+++ b/tests/udp_socket.rs
@@ -6,7 +6,7 @@ use mio::net::UdpSocket;
 use mio::{Events, Interest, Poll, Registry, Token};
 use std::net::{self, IpAddr, SocketAddr};
 #[cfg(unix)]
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd};
 use std::str;
 use std::sync::{Arc, Barrier};
 use std::thread;
diff --git a/tests/unix_listener.rs b/tests/unix_listener.rs
index d1d9cf0..c13e9cb 100644
--- a/tests/unix_listener.rs
+++ b/tests/unix_listener.rs
@@ -133,17 +133,51 @@ fn unix_listener_deregister() {
     handle.join().unwrap();
 }
 
-#[cfg(target_os = "linux")]
 #[test]
+#[cfg(any(target_os = "android", target_os = "linux"))]
 fn unix_listener_abstract_namespace() {
     use rand::Rng;
+    use std::os::linux::net::SocketAddrExt;
+    use std::os::unix::net::SocketAddr;
+
+    let (mut poll, mut events) = init_with_poll();
+    let barrier = Arc::new(Barrier::new(2));
+
     let num: u64 = rand::thread_rng().gen();
-    let name = format!("\u{0000}-mio-abstract-uds-{}", num);
-    let listener = UnixListener::bind(&name).unwrap();
+    let name = format!("mio-abstract-uds-{}", num);
+    let address = SocketAddr::from_abstract_name(name.as_bytes()).unwrap();
+    let mut listener = UnixListener::bind_addr(&address).unwrap();
     assert_eq!(
-        listener.local_addr().unwrap().as_abstract_namespace(),
-        Some(&name.as_bytes()[1..]),
+        listener.local_addr().unwrap().as_abstract_name(),
+        address.as_abstract_name(),
     );
+
+    poll.registry()
+        .register(
+            &mut listener,
+            TOKEN_1,
+            Interest::WRITABLE.add(Interest::READABLE),
+        )
+        .unwrap();
+    expect_no_events(&mut poll, &mut events);
+
+    let barrier2 = barrier.clone();
+    let handle = thread::spawn(move || {
+        let conn = net::UnixStream::connect_addr(&address).unwrap();
+        barrier2.wait();
+        drop(conn);
+    });
+    expect_events(
+        &mut poll,
+        &mut events,
+        vec![ExpectEvent::new(TOKEN_1, Interest::READABLE)],
+    );
+
+    let (_, address) = listener.accept().unwrap();
+    assert!(address.is_unnamed());
+
+    barrier.wait();
+    handle.join().unwrap();
 }
 
 fn smoke_test<F>(new_listener: F, test_name: &'static str)
diff --git a/tests/unix_stream.rs b/tests/unix_stream.rs
index 87cfbd1..a501bae 100644
--- a/tests/unix_stream.rs
+++ b/tests/unix_stream.rs
@@ -231,6 +231,7 @@ fn unix_stream_shutdown_read() {
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     ))]
     {
@@ -280,6 +281,7 @@ fn unix_stream_shutdown_write() {
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     ))]
     expect_events(
@@ -346,6 +348,7 @@ fn unix_stream_shutdown_both() {
         target_os = "netbsd",
         target_os = "openbsd",
         target_os = "tvos",
+        target_os = "visionos",
         target_os = "watchos",
     ))]
     {
diff --git a/tests/util/mod.rs b/tests/util/mod.rs
index 7a192d9..858c146 100644
--- a/tests/util/mod.rs
+++ b/tests/util/mod.rs
@@ -7,7 +7,7 @@ use std::mem::size_of;
 use std::net::SocketAddr;
 use std::ops::BitOr;
 #[cfg(unix)]
-use std::os::unix::io::AsRawFd;
+use std::os::fd::AsRawFd;
 use std::path::PathBuf;
 use std::sync::Once;
 use std::time::Duration;
@@ -253,6 +253,7 @@ pub fn set_linger_zero(socket: &TcpStream) {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos",
             ))]
             libc::SO_LINGER_SEC,
@@ -260,6 +261,7 @@ pub fn set_linger_zero(socket: &TcpStream) {
                 target_os = "ios",
                 target_os = "macos",
                 target_os = "tvos",
+                target_os = "visionos",
                 target_os = "watchos",
             )))]
             libc::SO_LINGER,