id_effect 0.2.0

Effect<A, E, R> (sync + async), context/layers, pipe — interpreter-style, no bundled executor
Documentation
# acquire_release — The RAII Pattern

`acquire_release` is a convenience wrapper around Scope that pairs acquisition and release into a single value.

## The Pattern

```rust
use id_effect::acquire_release;

let managed_connection = acquire_release(
    // Acquire: run this to get the resource
    open_connection(),
    // Release: run this when done (always runs)
    |conn| conn.close(),
);
```

`managed_connection` is itself an effect that:
1. When executed, opens the connection
2. Registers `conn.close()` as a finalizer in the current scope
3. Produces the connection for use

Use it with `flat_map` or `effect!`:

```rust
let result = managed_connection.flat_map(|conn| {
    do_work_with_conn(&conn)
});
// conn.close() runs after do_work_with_conn, regardless of outcome
```

Or inline:

```rust
effect! {
    let conn = ~ managed_connection;
    let data = ~ fetch_data(&conn);   // conn closes after this block
    process(data)
}
```

## Why This Is Better Than Manual Scope

`acquire_release` makes the acquisition-release pair inseparable. You can't accidentally call `open_connection()` without also registering its cleanup. The resource and its lifecycle are coupled at the point of creation.

```rust
// With manual scope: easy to forget the finalizer
let conn = ~ open_connection();
// ... (forgot: ~ scope.add_finalizer(...))

// With acquire_release: cleanup is mandatory, automatic
let conn = ~ acquire_release(open_connection(), |c| c.close());
```

## Resource Wrapping Pattern

A common convention is to wrap `acquire_release` in a helper function:

```rust
fn managed_db_connection(url: &str) -> Effect<Connection, DbError, ()> {
    acquire_release(
        Connection::open(url),
        |conn| conn.close(),
    )
}

// Usage
effect! {
    let conn = ~ managed_db_connection(config.db_url());
    ~ run_query(&conn, "SELECT 1")
}
```

The helper function documents that `open_connection()` must always be paired with `close()`. Callers don't think about the lifecycle; it's handled.

## Comparison with Drop

`acquire_release` is not a replacement for `impl Drop` — it's a complement:

- `impl Drop`: synchronous cleanup for types that own simple resources
- `acquire_release`: async cleanup for effects that acquire and release through the effect runtime

Use both appropriately. A `TcpStream` closing its OS file descriptor in `Drop` is fine. Closing a database connection pool that requires async coordination belongs in `acquire_release`.