effectful 0.2.1

Effect<A, E, R> (sync + async), context/layers, pipe — interpreter-style, no bundled executor
Documentation
# Pools — Reusing Expensive Resources

`Pool<A, E>` and `KeyedPool<K, A, E>` manage reusable values with a capacity gate. A checkout is tied to a `Scope`: when the scope closes, the value is returned to the idle list unless invalidated.

## Pool

```rust,ignore
use effectful::Pool;

let pool_effect = Pool::make(10, || open_connection("postgres://localhost/app"));
let pool: Pool<Connection, DbError> = run_blocking(pool_effect, ())?;
```

`Pool::make(capacity, factory)` returns `Effect<Pool<A, E>, Never, ()>`. The factory is an effect that creates a fresh value when no reusable idle value is available.

## Checking Out

```rust,ignore
use effectful::{Scope, run_blocking};

let scope = Scope::make();
let conn = run_blocking(pool.get(), scope.clone())?;

// Use conn while scope is open.

scope.close(); // returns conn to the pool's idle list
```

`pool.get()` returns `Effect<A, E, Scope>`. It acquires capacity, reuses an idle value or runs the factory, and registers a finalizer in the provided scope.

## Invalidating Values

```rust,ignore
run_blocking(pool.invalidate(conn.clone()), ())?;
```

Invalidated values are not reused when their checkout scope closes.

## KeyedPool

Use `KeyedPool` when resource creation depends on a key.

```rust,ignore
use effectful::KeyedPool;

let pools_effect = KeyedPool::make(20, |key: DbRole| open_connection_for(key));
let pools: KeyedPool<DbRole, Connection, DbError> = run_blocking(pools_effect, ())?;

let scope = Scope::make();
let primary = run_blocking(pools.get(DbRole::Primary), scope.clone())?;
let replica = run_blocking(pools.get(DbRole::Replica), scope.clone())?;

scope.close();
```

Capacity is global across all keys. Idle values are stored per key.

## TTL

Both pool types have `make_with_ttl`. Idle values older than the TTL are discarded on checkout.

```rust,ignore
let pool = run_blocking(
    Pool::make_with_ttl(10, Duration::from_secs(300), || open_connection(url.clone())),
    (),
)?;
```

## Pool as a Service

In applications, build the pool at startup and provide it as a service or context value. Business code should depend on the pool abstraction and checkout inside an explicit `Scope`.