base-endpoint 0.2.0

Runtime-independent binding and connecting through Base scheduler capabilities
Documentation

base-endpoint

Reusable descriptions of how to connect and bind, inspired by Ruby's IO::Endpoint. Application code depends on endpoint contracts, while endpoint implementations handle resolution, socket creation, optional TLS and establishment through explicit base-scheduler capabilities.

Usage

Add the crate together with the scheduler interface it uses:

cargo add base-endpoint base-scheduler

The API is experimental. This example binds a loopback listener and connects to it with the Native scheduler; add it with cargo add base-scheduler-native to run it:

use base_endpoint::{BindEndpoint, BindOptions, ConnectEndpoint, HostEndpoint};
use base_scheduler::{Cancellation, OperationError, SocketAccept, SocketClose, SocketLocalAddress};
use base_scheduler_native::NativeScheduler;

fn main() -> Result<(), OperationError> {
    let scheduler = NativeScheduler::new()?;
    scheduler.block_on(async {
        let cancellation = Cancellation::never();

        let listeners = HostEndpoint::new("127.0.0.1", 0)
            .bind(&scheduler, BindOptions::default(), &cancellation).await?;
        let port = scheduler.socket_local_address(&listeners[0])?.port();
        let client = HostEndpoint::new("127.0.0.1", port)
            .connect(&scheduler, &cancellation).await?;
        let (accepted, _peer) = scheduler.socket_accept(&listeners[0], &cancellation).await?;

        scheduler.socket_close(client).await?;
        scheduler.socket_close(accepted).await?;
        for listener in listeners {
            scheduler.socket_close(listener).await?;
        }
        scheduler.shutdown().await;
        Ok(())
    })
}

Consumers can depend only on the connection contract, without naming TCP, TLS or a runtime:

use base_endpoint::ConnectEndpoint;
use base_scheduler::{Cancellation, OperationResult};

async fn establish<S: Sync, E: ConnectEndpoint<S>>(
    scheduler: &S,
    endpoint: &E,
    cancellation: &Cancellation,
) -> OperationResult<E::Connection> {
    endpoint.connect(scheduler, cancellation).await
}

See the API documentation for hostname resolution, composite fallback, binding, cancellation and cleanup, TLS composition, the optional rustls provider, and the plaintext stream contracts.

Releasing

Prepare a release with cargo bake cargo:version:patch (or minor, major, or bump --version X.Y.Z), commit it with a Release: vVERSION trailer, then run cargo bake cargo:release and open a pull request. After review and merge, GitHub Actions publishes the release when the configured crates-io environment approves it, then creates or updates the matching GitHub Release from releases.md. Follow the shared Releasing skill for the standard process.

Releases

See releases.md for the full release history.

v0.2.0

  • Breaking: add the required ReadableStream::try_read_into, which attempts one read now without waiting. Scheduler stream readers forward it to SocketStreamReader::try_read_into, and the rustls duplex reader drives its receive lane to read the socket immediately. Implementations outside this crate must add it; wrappers should forward it.
  • Breaking: depend on base-scheduler 0.4, whose capability traits appear in this crate's public API.

v0.1.0

Initial release of the runtime-independent endpoints. Requires Rust 1.87 or later. The API is experimental.

  • Provide separate ConnectEndpoint and BindEndpoint contracts, with associated connection and listener types, so consumers can abstract over establishment without a particular transport or runtime.
  • Connect and bind TCP over IPv4 and IPv6 with AddressEndpoint and HostEndpoint. CompositeEndpoint composes any connect endpoints, and bind endpoints whose listeners the scheduler closes. Connection attempts fall back in order with fresh sockets and report the last error unless cancelled; binding is all-or-nothing and closes every socket it created on failure.
  • Describe plaintext byte I/O with stream::{ReadableStream, WritableStream}, which scheduler stream handles implement directly.
  • Wrap endpoints with TLS through tls::{TlsClientEndpoint, TlsServerEndpoint, TlsListener} over the TlsConnector, TlsAcceptor and TlsStream contracts. TlsSession reports the negotiated ALPN protocol, and a failed handshake leaves a TlsListener usable.
  • With the rustls feature, provide RustlsConnector, RustlsAcceptor and RustlsConnection, with sequential reads and writes, shutdown, close and abort. RustlsConnection::with_duplex runs an application with independent encrypted reader and writer handles, spawns no task, and joins lane retirement and socket closure before returning. A transport failure while it sends close_notify is reported as that failure rather than as cancellation.
  • Depend on the published base-scheduler 0.3 interface; no concrete runtime is a production dependency.

See Also

  • base-scheduler supplies the socket, stream and cancellation capabilities that endpoints use.

Contributing

Please open an issue or pull request on GitHub.