pool-mod 1.0.0

Generic object and connection pooling. Async-safe with min/max sizing, idle timeouts, max-lifetime enforcement, validation-on-borrow, and health-check callbacks. Works for database connections, HTTP clients, worker threads, or any expensive resource.
Documentation
# pool-mod v1.0.0 — Stable

**The API is frozen.** v1.0.0 is the first stable release of `pool-mod`. There is
no new surface since v0.9.0 — the crate was already feature-complete and audited.
This release captures benchmark baselines, applies one internal hot-path
optimization, and commits to the public API under semantic versioning.

## What is pool-mod?

A generic object and connection pool for Rust. You implement one trait —
[`Manager`] — describing how to create, validate, and recycle a resource, and the
pool handles sizing, blocking acquisition with timeouts, a non-blocking `try_get`,
validation-on-borrow, and idle/lifetime expiry (lazy on checkout, or eager via an
opt-in background reaper). It is runtime-agnostic and has **zero runtime
dependencies**.

```rust
use pool_mod::{Manager, Pool};
use std::convert::Infallible;

struct Buffers { capacity: usize }

impl Manager for Buffers {
    type Resource = Vec<u8>;
    type Error = Infallible;
    fn create(&self) -> Result<Vec<u8>, Infallible> { Ok(Vec::with_capacity(self.capacity)) }
    fn recycle(&self, buf: &mut Vec<u8>) -> Result<(), Infallible> { buf.clear(); Ok(()) }
}

let pool = Pool::builder(Buffers { capacity: 4096 })
    .max_size(16)
    .min_idle(4)
    .build()
    .expect("configuration is valid");

let mut buf = pool.get().expect("a buffer is available");
buf.extend_from_slice(b"payload");
assert_eq!(buf.len(), 7);
```

## The 1.0 API

Frozen and stable under semantic versioning:

- [`Manager`] — `create`, `recycle`, and the optional `validate` health check.
- [`Pool`] — `builder` / `new`, `get` / `get_timeout` / `try_get`, `status`,
  `close`, `is_closed`; `Clone`, `Send`, `Sync`.
- `Builder`, `PoolConfig` (`max_size`, `min_idle`, `create_timeout`,
  `idle_timeout`, `max_lifetime`, `reap_interval`).
- [`Pooled`] — the RAII guard, `Send`, deref-coercing to the resource.
- `Status`, `Error` (`#[non_exhaustive]`), `prelude`, `VERSION`.

Within `1.x`: nothing is removed or renamed, signatures do not change in a
breaking way, additions are additive, and the MSRV (Rust 1.75) will not rise in a
patch. See [`docs/API.md`](https://github.com/jamesgober/pool-mod/blob/main/docs/API.md#compatibility).

## What's new in 1.0.0

### Hot-path optimization: signal only when someone is waiting

The acquire path now tracks the number of blocked acquirers under the pool lock.
Check-in, slot release, the reaper, and close consult that count and touch the
condition variable only when a thread is actually waiting — so the common,
uncontended borrow-and-return does no condvar signaling at all. The change is
internal; behavior is identical, and it is covered by the existing concurrency
tests (stress-looped to confirm no missed wakeups).

Measured effect on the steady-state hot path: about **8% faster** (~106 ns →
~98 ns locally).

### Benchmark baselines

Captured with `cargo bench` (Windows x86_64, Rust stable, single-threaded,
trivial resource):

| Benchmark              | Time/op |
|------------------------|--------:|
| `get` + return (reuse) | ~98 ns  |
| `try_get` + return     | ~97 ns  |
| `status` snapshot      | ~8.5 ns |

These figures measure the pool machinery against a no-op resource. In real use
the checkout cost is dominated by the resource's own work — the query or request
the pool exists to amortize. The steady-state checkout/return path is
allocation-free.

## Design summary

- **Runtime-agnostic, zero-dependency.** `get` blocks the calling thread; in async
  code, acquire on a blocking-friendly executor thread (`spawn_blocking`). The
  guard is `Send`, so it crosses `.await`.
- **Lock discipline.** The mutex guards only a queue and a few counters.
  `create` / `validate` / `recycle` always run outside the lock, so slow resource
  work never stalls other threads. The lock helper recovers from poisoning rather
  than turning an unrelated panic into a permanent outage.
- **One `unsafe` block.** `ManuallyDrop::take` in the guard's `Drop`, with a
  `// SAFETY:` proof and test coverage.
- **Expiry.** `idle_timeout` and `max_lifetime` apply on checkout by default; an
  opt-in `reap_interval` adds a background thread that prunes eagerly and stops
  cleanly when the pool is closed or dropped.

## Breaking changes

**None.** Identical public API and behavior to v0.9.0; the only code change is the
internal signaling optimization.

## Verification

Run on Windows x86_64 (Rust stable 1.95.0 and 1.75.0) and on Linux via WSL2
Ubuntu (Rust stable 1.95.0); these mirror the CI matrix.

```bash
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features
cargo +1.75 build --all-targets --all-features
cargo +1.75 test --all-features
cargo audit
cargo deny check
cargo bench
```

All green. Counts at this tag: 21 unit + 18 integration (10 lifecycle + 3 pool +
4 property + 1 smoke) + 17 doctests. The blocking and concurrency tests were
additionally stress-looped (80 runs) to confirm the signaling optimization
introduces no missed wakeups.

## Installation

```toml
[dependencies]
pool-mod = "1.0"
```

MSRV: Rust 1.75. Edition 2021.

## Documentation

- [README]https://github.com/jamesgober/pool-mod/blob/main/README.md
- [API Reference]https://github.com/jamesgober/pool-mod/blob/main/docs/API.md
- [CHANGELOG]https://github.com/jamesgober/pool-mod/blob/main/CHANGELOG.md

---

**Full diff:** [`v0.9.0...v1.0.0`](https://github.com/jamesgober/pool-mod/compare/v0.9.0...v1.0.0).
**Changelog:** [`CHANGELOG.md`](https://github.com/jamesgober/pool-mod/blob/main/CHANGELOG.md#100---2026-05-27).

[`Manager`]: https://docs.rs/pool-mod/1.0.0/pool_mod/trait.Manager.html
[`Pool`]: https://docs.rs/pool-mod/1.0.0/pool_mod/struct.Pool.html
[`Pooled`]: https://docs.rs/pool-mod/1.0.0/pool_mod/struct.Pooled.html