Rename reactor -> driver, prep for lib/reactivity

This commit is contained in:
2026-03-19 19:47:06 -04:00
parent 3fd8209420
commit 7b3c2fcbef
13 changed files with 490 additions and 62 deletions

View File

@@ -1,4 +1,7 @@
//! Portable async networking API.
//!
//! The public surface follows the general shape of `std::net`, but uses async methods for socket
//! operations that would otherwise block the caller.
use std::future::Future;
use std::io;
@@ -40,6 +43,10 @@ type PendingRead = Pin<Box<dyn Future<Output = io::Result<Vec<u8>>> + 'static>>;
type PendingWrite = Pin<Box<dyn Future<Output = io::Result<usize>> + 'static>>;
type PendingShutdown = Pin<Box<dyn Future<Output = io::Result<()>> + 'static>>;
/// Async TCP stream.
///
/// This type also implements Hyper's runtime I/O traits, allowing it to be used directly as an
/// HTTP transport.
pub struct TcpStream {
inner: Arc<TcpStreamInner>,
pending_read: Option<PendingRead>,
@@ -48,16 +55,19 @@ pub struct TcpStream {
}
#[derive(Clone, Debug)]
/// Async TCP listening socket.
pub struct TcpListener {
inner: Arc<TcpListenerInner>,
}
#[derive(Debug)]
/// Async UDP socket.
pub struct UdpSocket {
inner: Arc<UdpSocketInner>,
}
impl TcpStream {
/// Connects to the first resolved address that succeeds.
pub async fn connect<A>(addr: A) -> io::Result<Self>
where
A: ToSocketAddrs + Send + 'static,
@@ -79,6 +89,7 @@ impl TcpStream {
}))
}
/// Connects to `addr`, failing if the deadline elapses first.
pub async fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<Self> {
validate_timeout(timeout)?;
crate::sys::linux::net::connect_stream_timeout(*addr, timeout)
@@ -86,6 +97,7 @@ impl TcpStream {
.map(Self::from_owned_fd)
}
/// Reads bytes from the stream.
pub async fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let data = match self.read_timeout_value() {
Some(timeout) => {
@@ -105,6 +117,7 @@ impl TcpStream {
Ok(read)
}
/// Reads exactly `buf.len()` bytes from the stream.
pub async fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> {
while !buf.is_empty() {
let read = self.read(buf).await?;
@@ -119,6 +132,7 @@ impl TcpStream {
Ok(())
}
/// Writes bytes to the stream.
pub async fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self.write_timeout_value() {
Some(timeout) => {
@@ -135,6 +149,7 @@ impl TcpStream {
}
}
/// Writes the entire buffer to the stream.
pub async fn write_all(&mut self, mut buf: &[u8]) -> io::Result<()> {
while !buf.is_empty() {
let written = self.write(buf).await?;
@@ -149,6 +164,7 @@ impl TcpStream {
Ok(())
}
/// Shuts down the read, write, or both halves of the connection.
pub async fn shutdown(&self, how: Shutdown) -> io::Result<()> {
crate::sys::linux::net::shutdown(NetOp::Shutdown {
fd: self.raw_fd(),
@@ -157,50 +173,65 @@ impl TcpStream {
.await
}
/// Duplicates the underlying stream socket.
pub async fn try_clone(&self) -> io::Result<Self> {
crate::sys::linux::net::duplicate(self.raw_fd())
.await
.map(Self::from_owned_fd)
}
/// Returns the local socket address of this stream.
pub fn local_addr(&self) -> io::Result<SocketAddr> {
crate::sys::linux::net::local_addr(self.raw_fd())
}
/// Returns the remote peer address of this stream.
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
crate::sys::linux::net::peer_addr(self.raw_fd())
}
/// Reads the current `TCP_NODELAY` setting.
pub fn nodelay(&self) -> io::Result<bool> {
crate::sys::linux::net::nodelay(self.raw_fd())
}
/// Enables or disables `TCP_NODELAY`.
pub fn set_nodelay(&self, enabled: bool) -> io::Result<()> {
crate::sys::linux::net::set_nodelay(self.raw_fd(), enabled)
}
/// Reads the socket's IP time-to-live value.
pub fn ttl(&self) -> io::Result<u32> {
crate::sys::linux::net::ttl(self.raw_fd())
}
/// Sets the socket's IP time-to-live value.
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
crate::sys::linux::net::set_ttl(self.raw_fd(), ttl)
}
/// Returns the read timeout used by async read operations on this handle.
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
Ok(self.read_timeout_value())
}
/// Sets the read timeout used by async read operations on this handle.
///
/// Passing `Some(Duration::ZERO)` is rejected.
pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
validate_optional_timeout(timeout)?;
self.inner.timeouts.lock().unwrap().read = timeout;
Ok(())
}
/// Returns the write timeout used by async write operations on this handle.
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
Ok(self.write_timeout_value())
}
/// Sets the write timeout used by async write operations on this handle.
///
/// Passing `Some(Duration::ZERO)` is rejected.
pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
validate_optional_timeout(timeout)?;
self.inner.timeouts.lock().unwrap().write = timeout;
@@ -233,6 +264,7 @@ impl TcpStream {
}
impl TcpListener {
/// Binds a TCP listener to the first resolved address that succeeds.
pub async fn bind<A>(addr: A) -> io::Result<Self>
where
A: ToSocketAddrs + Send + 'static,
@@ -254,6 +286,7 @@ impl TcpListener {
}))
}
/// Accepts an incoming connection.
pub async fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let accepted = crate::sys::linux::net::accept(NetOp::Accept { fd: self.raw_fd() }).await?;
@@ -261,14 +294,17 @@ impl TcpListener {
Ok((stream, accepted.peer_addr))
}
/// Returns the local socket address of this listener.
pub fn local_addr(&self) -> io::Result<SocketAddr> {
crate::sys::linux::net::local_addr(self.raw_fd())
}
/// Reads the listener socket's IP time-to-live value.
pub fn ttl(&self) -> io::Result<u32> {
crate::sys::linux::net::ttl(self.raw_fd())
}
/// Sets the listener socket's IP time-to-live value.
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
crate::sys::linux::net::set_ttl(self.raw_fd(), ttl)
}
@@ -285,6 +321,7 @@ impl TcpListener {
}
impl UdpSocket {
/// Binds a UDP socket to the first resolved address that succeeds.
pub async fn bind<A>(addr: A) -> io::Result<Self>
where
A: ToSocketAddrs + Send + 'static,
@@ -306,6 +343,10 @@ impl UdpSocket {
}))
}
/// Connects the socket to a default peer.
///
/// Once connected, [`send`](Self::send), [`recv`](Self::recv), and [`peer_addr`](Self::peer_addr)
/// operate relative to that peer.
pub async fn connect<A>(&self, addr: A) -> io::Result<()>
where
A: ToSocketAddrs + Send + 'static,
@@ -332,6 +373,7 @@ impl UdpSocket {
}))
}
/// Sends a datagram to the connected peer.
pub async fn send(&self, buf: &[u8]) -> io::Result<usize> {
match self.write_timeout_value() {
Some(timeout) => {
@@ -348,6 +390,7 @@ impl UdpSocket {
}
}
/// Receives a datagram from the connected peer.
pub async fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
let data = match self.read_timeout_value() {
Some(timeout) => {
@@ -367,6 +410,7 @@ impl UdpSocket {
Ok(read)
}
/// Peeks at the next datagram from the connected peer without consuming it.
pub async fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
let data = match self.read_timeout_value() {
Some(timeout) => {
@@ -392,6 +436,7 @@ impl UdpSocket {
Ok(read)
}
/// Sends a datagram to `addr`.
pub async fn send_to<A>(&self, buf: &[u8], addr: A) -> io::Result<usize>
where
A: ToSocketAddrs + Send + 'static,
@@ -435,6 +480,7 @@ impl UdpSocket {
}))
}
/// Receives a datagram and returns the sender address.
pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
let datagram = match self.read_timeout_value() {
Some(timeout) => {
@@ -455,6 +501,7 @@ impl UdpSocket {
Ok((read, datagram.peer_addr))
}
/// Peeks at the next datagram and returns the sender address without consuming it.
pub async fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
let datagram = match self.read_timeout_value() {
Some(timeout) => {
@@ -480,50 +527,65 @@ impl UdpSocket {
Ok((read, datagram.peer_addr))
}
/// Duplicates the underlying UDP socket.
pub async fn try_clone(&self) -> io::Result<Self> {
crate::sys::linux::net::duplicate(self.raw_fd())
.await
.map(Self::from_owned_fd)
}
/// Returns the local socket address of this socket.
pub fn local_addr(&self) -> io::Result<SocketAddr> {
crate::sys::linux::net::local_addr(self.raw_fd())
}
/// Returns the connected peer address, if the socket has been connected.
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
crate::sys::linux::net::peer_addr(self.raw_fd())
}
/// Reads the `SO_BROADCAST` setting.
pub fn broadcast(&self) -> io::Result<bool> {
crate::sys::linux::net::broadcast(self.raw_fd())
}
/// Enables or disables `SO_BROADCAST`.
pub fn set_broadcast(&self, enabled: bool) -> io::Result<()> {
crate::sys::linux::net::set_broadcast(self.raw_fd(), enabled)
}
/// Reads the socket's IP time-to-live value.
pub fn ttl(&self) -> io::Result<u32> {
crate::sys::linux::net::ttl(self.raw_fd())
}
/// Sets the socket's IP time-to-live value.
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
crate::sys::linux::net::set_ttl(self.raw_fd(), ttl)
}
/// Returns the read timeout used by async receive operations on this handle.
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
Ok(self.read_timeout_value())
}
/// Sets the read timeout used by async receive operations on this handle.
///
/// Passing `Some(Duration::ZERO)` is rejected.
pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
validate_optional_timeout(timeout)?;
self.inner.timeouts.lock().unwrap().read = timeout;
Ok(())
}
/// Returns the write timeout used by async send operations on this handle.
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
Ok(self.write_timeout_value())
}
/// Sets the write timeout used by async send operations on this handle.
///
/// Passing `Some(Duration::ZERO)` is rejected.
pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
validate_optional_timeout(timeout)?;
self.inner.timeouts.lock().unwrap().write = timeout;