pending-requests 0.1.0

Track in-flight requests and await their responses by key, for request/response protocols multiplexed over a single connection.
Documentation
# pending-requests

Track in-flight requests and await their responses by key.

A `PendingRequests` registry lets one task register a request under a key, hand
back a future, and have another task deliver the matching response later. This
is the classic pattern behind request/response protocols multiplexed over a
single connection (request id in, response with the same id out).

## Features

- Await a response by key with a per-registry or per-request timeout.
- Cheap to clone: every clone shares the same pending set, so a reader task can
  deliver responses while many sender tasks await theirs.
- Precise outcomes: a response, a timeout, or a cancellation are distinct errors.
- No leaks: entries are removed on response, timeout, cancellation, or when the
  waiter is dropped.

## Example

```rust
use std::time::Duration;
use pending_requests::PendingRequests;

#[tokio::main]
async fn main() {
    let requests = PendingRequests::<u64, String>::new();

    // Register a request keyed by its id.
    let waiter = requests.prepare_response(1).unwrap();

    // Elsewhere (e.g. a socket reader task), deliver the response:
    let responder = requests.clone();
    responder.handle_response(1, "pong".to_string()).unwrap();

    assert_eq!(waiter.await.unwrap(), "pong");
}
```

## API overview

| Method | Purpose |
| --- | --- |
| `prepare_response(key)` | Register a request, get a `ResponseWaiter` future. |
| `prepare_response_with_timeout(key, dur)` | Same, with a per-request timeout. |
| `handle_response(key, resp)` | Deliver a response to a waiter. |
| `cancel(&key)` | Cancel one request (waiter resolves with `Canceled`). |
| `cancel_all()` | Cancel every pending request; returns the count. |
| `contains(&key)` | Whether a request is pending for `key`. |
| `set_timeout(dur)` / `timeout()` | Get/set the default timeout (works through a clone). |
| `len()` / `is_empty()` | Number of pending requests. |

A `ResponseWaiter` resolves to:

- `Ok(response)` — the response was delivered,
- `Err(RequestTimeout)` — the timeout elapsed first,
- `Err(Canceled)` — the request was canceled or the registry was fully dropped.

## Timeout cleanup

A request's timer lives inside its `ResponseWaiter`; there is no background
task per request. Cleanup of a timed-out entry happens when the waiter is
polled or dropped. In normal usage you always `.await` the waiter, so this is
automatic. If you register a request and then neither poll nor drop the waiter,
its entry stays until you do.

## License

Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
[MIT license](LICENSE-MIT) at your option.