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](https://github.com/socketry/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:

```sh
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:

```rust
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:

```rust
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](https://docs.rs/base-endpoint) 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](https://github.com/base-rs/base-project/blob/main/context/releasing.md) for the standard process.

## Releases

<!-- bake-readme:releases:start -->

See [releases.md](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.

<!-- bake-readme:releases:end -->

## See Also

- [base-scheduler](https://github.com/base-rs/base-scheduler) supplies the socket, stream and cancellation capabilities that endpoints use.

## Contributing

Please open an issue or pull request on [GitHub](https://github.com/base-rs/base-endpoint).