tcp
import std::net::socket::tcp; · source
TcpListener
type struct TcpListener {
fd: i32;
static bind(local: SocketAddr) -> Result<TcpListener, IoError>;
static from_fd(sock: i32) -> TcpListener;
raw_fd(&this) -> i32;
set_nonblocking(mut &this, on: boolean) -> Result<(), IoError>;
local_addr(&this) -> Result<SocketAddr, IoError>;
drop(mut &this) -> void;
}
TcpListener::bind is the one plain call in this file — binding does not wait. Everything else is a future with a start(...) constructor:
import std::net::socket::tcp;
import std::net::addr::socket_addr;
import std::io::buf;
async function serve(addr: SocketAddr) -> Result<(), IoError> {
mut listener: TcpListener = TcpListener::bind(addr)?;
loop {
mut accepted: TcpAccepted = await TcpAccept::start(listener);
listener = accepted.take_listener();
mut conn: BufStream<TcpStream> = BufStream<TcpStream>::of(accepted.take_result()?);
await handle(conn);
}
}
TcpAccept puts the sockets it produces in non-blocking mode, and the listener closes its descriptor through an inherent drop.
TcpStream
type struct TcpStream {
fd: i32;
static from_fd(sock: i32) -> TcpStream;
raw_fd(&this) -> i32;
shutdown_write(mut &this) -> Result<(), IoError>;
set_nonblocking(mut &this, on: boolean) -> Result<(), IoError>;
drop(mut &this) -> void;
}
A connected socket. You get one from TcpConnect or TcpAccept, both of which leave it in non-blocking mode; a stream adopted with from_fd needs set_nonblocking(true) before it is used with a future. shutdown_write half-closes so the peer sees EOF. It closes its descriptor through an inherent drop.
The futures
Every operation that can wait is one of these four, each with a start(...) constructor. Each attempts its syscall on the non-blocking socket, and if the socket is not ready registers the polling task's waker with the current Reactor and returns Pending. Registering after the failed attempt is what makes the race safe: the reactor arms level-triggered, so readiness that arrived in between is still reported. These futures park only where a reactor exists — an Executor's worker threads — and polling one anywhere else panics rather than parking a task that could never be woken.
Dropping a future mid-operation releases its reactor registration and, for TcpConnect, closes the half-connected socket — see cancellation is a drop. Only the direction that future owned is cancelled, so a write parked on the same socket keeps waiting.
TcpConnect
type struct TcpConnect {
fd: i32;
addr: u8[28];
addrlen: u32;
err: IoError;
rt: Reactor*;
static start(remote: SocketAddr) -> TcpConnect;
}
Completes with Result<TcpStream, IoError>. The socket is opened and the handshake started at construction; each poll asks the OS whether it finished, parking on writability in between.
TcpAccept
type struct TcpAccept {
listener: TcpListener;
rt: Reactor*;
static start(listener: TcpListener) -> TcpAccept;
}
Completes with a TcpAccepted: the listener back, plus the new stream or the error.
TcpRead
type struct TcpRead {
stream: TcpStream;
buf: Array<u8>;
rt: Reactor*;
static start(stream: TcpStream, buf: Array<u8>) -> TcpRead;
}
Completes with a TcpIo: the stream and buffer back, with outcome() the byte count — 0 at EOF. A read fills buf's [0, length) and truncates it to what arrived, so hand in one sized with resize.
TcpWrite
type struct TcpWrite {
stream: TcpStream;
buf: Array<u8>;
rt: Reactor*;
static start(stream: TcpStream, buf: Array<u8>) -> TcpWrite;
}
Completes with a TcpIo whose outcome() is the bytes accepted, which may be fewer than offered — the caller sends the remainder in another operation.
The outcomes
type struct TcpIo {
stream: TcpStream;
buf: Array<u8>;
result: Result<u64, IoError>;
take_stream(mut &this) -> TcpStream;
take_buf(mut &this) -> Array<u8>;
outcome(&this) -> Result<u64, IoError>;
}
type struct TcpAccepted {
listener: TcpListener;
result: Result<TcpStream, IoError>;
take_listener(mut &this) -> TcpListener;
take_result(mut &this) -> Result<TcpStream, IoError>;
}
The outputs hand their handles back through take_* rather than by field: a TcpStream closes its descriptor when dropped, so the compiler will not let a field be moved out of an outcome that would still drop it. take_stream swaps in a closed placeholder, leaving nothing behind to close. outcome() is how many bytes moved, or why none did.
Trait implementations
implement trait AsyncTransport for struct TcpStream
implement trait Future for struct TcpConnect
implement trait Drop for struct TcpConnect
implement trait Future for struct TcpAccept
implement trait Drop for struct TcpAccept
implement trait Future for struct TcpRead
implement trait Drop for struct TcpRead
implement trait Future for struct TcpWrite
implement trait Drop for struct TcpWrite
AsyncTransport is what lets BufStream<TcpStream> exist — its read_into and write_from are TcpRead and TcpWrite with the move-out/move-back handled inside.