id_effect 0.3.0

Effect<A, E, R> (sync + async), capability DI, pipe — interpreter-style, no bundled executor
Documentation
# Parallelism — Rayon by Default

Bulk **pure** transforms on collections and stream chunks use Rayon when the input is large enough. **`Effect` and `effect!` stay sequential** — ordering and capability borrows are unchanged.

## `Parallelism` policy

```rust
use id_effect::Parallelism;

// Default: parallel when len >= 1024
Parallelism::default();

// Always Rayon (old `*_par` behavior)
Parallelism::ForceParallel;

// Never Rayon (old primary `map` / `filter` behavior)
Parallelism::Serial;
```

| Policy | When Rayon runs |
|--------|-----------------|
| `Auto { threshold: 1024 }` | `len >= threshold` |
| `ForceParallel` | always |
| `Serial` | never |

## Collections and `vec`

Primary methods dispatch through the default policy:

```rust
use id_effect::vec;

let doubled = vec::map(vec![1, 2, 3], |x| x * 2);
```

Use explicit control when needed:

```rust
use id_effect::{Parallelism, vec};

// Force parallel on small inputs (benchmarks, tests)
vec::map_with(Parallelism::ForceParallel, v, |x| f(x));

// Non-`Send` or `FnMut` closure — serial escape hatch
vec::map_serial(v, |x| g(x));
```

The same pattern applies to `HashMap::map_values`, `filter`, red-black tree scans, `sort_with`, and similar bulk APIs: primary name, `*_serial`, `*_with(policy, …)`.

## Streams

`Stream::map` and `Stream::filter` apply the default policy **per chunk** after pulling upstream:

```rust
use id_effect::{Parallelism, Stream};

Stream::from_iterable(0..10_000)
    .map(|n| n * 2)                    // Auto threshold on chunk len
    .filter(|n| *n % 2 == 0)
    .run_collect();
```

```rust
// Explicit policy per operator
stream.map_with(Parallelism::Serial, |n| expensive(n));

// Captured mutable state — must use serial
let mut acc = 0;
stream.map_serial(move |n| { acc += n; acc });
```

### Not the same as `map_par_n`

[`Stream::map_par_n`](./ch13-03-backpressure.md) is **bounded async concurrency** for effectful steps — it does not use Rayon. Use it when each element runs an `Effect` and you want at most `n` in flight.

## Migration from `*_par`

Deprecated `*_par` methods are aliases to `ForceParallel`. Prefer:

| Old | New |
|-----|-----|
| `map_par(f)` | `map(f)` or `map_with(Parallelism::ForceParallel, f)` |
| `filter_par(p)` | `filter(p)` or `filter_with(Parallelism::ForceParallel, p)` |
| serial `map` / `filter` (pre-3.x) | `map_serial` / `filter_serial` |

See [ADR 0006](../../../../docs/adrs/0006-parallel-by-default.md) and example `071_stream_map_serial.rs`.