nexus-async-net 0.6.2

Async WebSocket adapter for nexus-net. Tokio-compatible, zero-copy, SIMD-accelerated.
Documentation
# Async HTTP / REST

The async REST surface is `rest::HttpConnection<S>` — an async
HTTP/1.1 keep-alive connection that wraps a nexus-net
`ResponseReader` on the inbound side and accepts nexus-net
`Request<'_>` bytes on the outbound side.

For production, you almost always want a **pool** of these
connections with self-healing reconnect. See
[client-pool.md](./client-pool.md) and
[atomic-client-pool.md](./atomic-client-pool.md).

## `HttpConnection` basics

```rust
use nexus_async_net::rest::HttpConnectionBuilder;
use nexus_net::rest::RequestWriter;
use nexus_net::http::ResponseReader;
use nexus_net::tls::TlsConfig;
use std::time::Duration;

#[tokio::main(flavor = "current_thread")]
async fn main() -> anyhow::Result<()> {
    let tls = TlsConfig::new()?;

    let mut conn = HttpConnectionBuilder::new()
        .tls(&tls)
        .disable_nagle()
        .connect_timeout(Duration::from_secs(3))
        .connect("https://api.binance.com")
        .await?;

    // RequestWriter owns the outbound WriteBuf.
    let mut writer = RequestWriter::new("api.binance.com")?;
    writer.default_header("X-MBX-APIKEY", api_key)?;
    writer.set_base_path("/api/v3")?;

    let mut reader = ResponseReader::new(32 * 1024);

    let req = writer.get("/ticker/price")
        .query("symbol", "BTCUSDT")
        .finish()?;

    let resp = conn.send(req, &mut reader).await?;
    println!("{}: {} bytes", resp.status(), resp.body().len());

    // Reuse conn for the next request (keep-alive).
    let req = writer.get("/depth")
        .query("symbol", "BTCUSDT")
        .query("limit", "100")
        .finish()?;
    let resp = conn.send(req, &mut reader).await?;

    Ok(())
}
```

Note that `RequestWriter`, `Request<'_>`, `ResponseReader`, and
`RestResponse<'_>` all come from nexus-net. The async layer only
adds the wire-level `send(...).await`.

See [nexus-net/docs/http.md](../../nexus-net/docs/http.md) for
`RequestWriter` typestate mechanics, body variants, and chunked
transfer.

## Builder options

```rust
HttpConnectionBuilder::new()
    .tls(&tls)                                   // feature "tls"
    .disable_nagle()
    .connect_timeout(Duration::from_secs(3))
    .tcp_keepalive(Duration::from_secs(60))      // feature "socket-opts"
    .recv_buffer_size(1 << 20)                   // feature "socket-opts"
    .send_buffer_size(1 << 20);                  // feature "socket-opts"
```

## Single connection vs pool

A single `HttpConnection` is **not concurrent-safe** — `send()` takes
`&mut self` because the underlying `WriteBuf` and
`ResponseReader` are owned. If you have concurrent tasks that need
to issue REST calls, you need either:

- **One `HttpConnection` per task** (fine for a few connections),
- **`ClientPool`** for single-threaded tokio (`current_thread`
  runtime + `LocalSet`), or
- **`AtomicClientPool`** for multi-threaded tokio.

The pool also handles reconnect — see [reconnect.md](./reconnect.md).

## Poisoning

On a transport error mid-request, `HttpConnection` is marked
poisoned (`is_poisoned() == true`) and subsequent `send()` calls
return `RestError::ConnectionPoisoned`. The caller must create a
new connection. When using a pool, this is automatic — see the
pool docs.

## Patterns

- Single-task keep-alive client: use `HttpConnection` directly.
- Trading system (single thread): use `ClientPool`.
- Web server / multi-thread: use `AtomicClientPool`.
- REST+WebSocket side-by-side on the same exchange: independent
  connections — they're separate protocols.

See [patterns.md](./patterns.md) for full recipes.