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 v0.5.0 — Implementation

**Depth, not breadth.** v0.2.0 already implemented the full resource lifecycle;
v0.5.0 proves it. This release adds property-based tests for the pool's
invariants, integration tests for the timing-dependent lifecycle paths, Criterion
benchmarks for the acquire/return hot path, and one ergonomic addition —
[`Pool::try_get`]. The dependency tree is pinned so the whole suite, benchmarks
included, builds on the MSRV. No breaking changes.

## What is pool-mod?

A generic object and connection pool for Rust. Implement one trait describing how
to create, validate, and recycle a resource, and the pool handles sizing, blocking
acquisition with timeouts, validation-on-borrow, and idle/lifetime expiry. It is
runtime-agnostic and pulls in no runtime dependencies.

## What's new in 0.5.0

### `Pool::try_get` — non-blocking checkout

A convenience that returns a resource if one can be handed out immediately and
`Error::Timeout` at once otherwise — equivalent to `get_timeout(Duration::ZERO)`,
but it reads as intent at the call site.

```rust
use pool_mod::{Error, Manager, Pool};
# use std::convert::Infallible;
# struct M;
# impl Manager for M {
#   type Resource = u32; type Error = Infallible;
#   fn create(&self) -> Result<u32, Infallible> { Ok(0) }
#   fn recycle(&self, _r: &mut u32) -> Result<(), Infallible> { Ok(()) }
# }
let pool = Pool::builder(M).max_size(1).build().expect("valid");
let first = pool.try_get().expect("room to create one");
assert!(matches!(pool.try_get(), Err(Error::Timeout)));
```

### Property-based tests

`tests/proptests.rs` exercises the pool's invariants over a wide input space with
`proptest`:

- **Configuration** — a valid `(max_size, min_idle)` builds and pre-warms exactly
  `min_idle` resources; an invalid pair is rejected with `InvalidConfig`.
- **The `max_size` ceiling** — greedily acquiring more than the pool can hold
  yields exactly `max_size` guards, and never more.
- **The occupancy identity** — `size == idle + in_use` holds both while saturated
  and after every guard is released.
- **Reuse** — sequential borrow-and-return creates exactly one resource, no matter
  how many times it repeats.
- **Close** — closing always drops every idle resource and rejects further
  checkouts.

### Integration tests for the lifecycle

`tests/lifecycle.rs` covers the timing- and failure-dependent paths that unit
tests stub with `Duration::ZERO`:

- An idle resource is reused inside its `idle_timeout` window and replaced once it
  ages past it (verified with real elapsed time).
- A resource is replaced after `max_lifetime`.
- A `recycle` failure discards the resource instead of pooling it, freeing the
  slot.
- Closing the pool while a resource is checked out discards that resource on
  return rather than pooling it.
- A thread blocked in `get_timeout` is woken when another thread returns a
  resource.

### Criterion benchmarks

`benches/pool.rs` measures the steady-state hot path — borrow and return against a
pre-warmed pool — via both `get` and `try_get`, plus the cost of a `status`
snapshot. Run with `cargo bench`. Tracked baselines are deferred to the 0.9.x
hardening phase.

### MSRV-pinned dependency tree

`proptest` and `criterion` pull a deep transitive tree, several crates of which
have since moved to edition 2024 (Rust 1.85+). The committed `Cargo.lock` pins the
dev-dependency tree to versions that still build on Rust 1.75 — `proptest` 1.4,
the `clap` 4.5 line, `tempfile` 3.14, `half` 2.4, and the `rand` 0.8 chain. These
are dev-only and never reach published consumers.

## Breaking changes

**None.** `Pool::try_get` is additive; everything else is tests, benchmarks, and a
lockfile pin.

## 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
cargo bench --no-run
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features
cargo +1.75 build --all-targets --all-features
cargo +1.75 test --all-features
```

All green. Counts at this tag: 19 unit tests, 6 lifecycle + 3 pool + 4 property +
1 smoke integration tests, and 17 doctests.

## What's next

- **0.9.0 — Hardening + audit.** Feature freeze and the mandatory pre-1.0 audit:
  a background idle reaper, tracked benchmark baselines, exhaustive error-path
  review, and the full REPS checklist (`cargo deny`, `cargo audit`, coverage).

## Installation

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

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.2.0...v0.5.0`](https://github.com/jamesgober/pool-mod/compare/v0.2.0...v0.5.0).
**Changelog:** [`CHANGELOG.md`](https://github.com/jamesgober/pool-mod/blob/main/CHANGELOG.md#050---2026-05-27).

[`Pool::try_get`]: https://docs.rs/pool-mod/0.5.0/pool_mod/struct.Pool.html#method.try_get