Needs and ~Key — Reading from Env

To use a capability inside an effect, declare required keys in R with caps! and borrow with ~Key, require!, or Needs::need.

Declaring requirements with caps!

Put the keys your effect needs in the third type parameter:

#![allow(unused)]
fn main() {
fn get_user(id: u64) -> Effect<User, DbError, caps!(Database)> { ... }
fn notify_user(id: u64, msg: &str) -> Effect<(), AppError, caps!(UserRepo, EmailService)> { ... }
}

Library helpers can stay generic when callers supply a wider Env:

#![allow(unused)]
fn main() {
fn get_user<R>(id: u64) -> Effect<User, DbError, R>
where
    R: id_effect::Needs<Database> + 'static,
{
    effect!(|r: &mut R| {
        let db = ~Database;
        db.fetch_user(id)
    })
}
}

~Key — capability lookup inside effect bodies

#![allow(unused)]
fn main() {
use id_effect::{effect, require, caps};

fn get_user(id: u64) -> Effect<User, DbError, caps!(Database)> {
    effect!(|r| {
        let db = ~Database;
        db.fetch_user(id)
    })
}
}

~Key inside effect! expands to a typed borrow from r. require!(K) is equivalent sugar.

If get_user requires Database but you run it with an empty Env, you get a runtime missing-capability error when the effect executes — not a silent None. For static verification, keep caps!(…) or Needs<K> bounds on public APIs so callers must wire providers before run_with.

When building tests manually:

#![allow(unused)]
fn main() {
let mut env = Env::new();
// forgot env.insert::<Cap<Database>>(...)
run_blocking(get_user(42), env); // panics on ~Key / get
}

Prefer build_env or typed test helpers so incomplete wiring fails at setup time.

Summary

ToolUse
caps!(K1, K2, …)Declare dependencies in R
~Key / require!(K)Borrow inside effect!
env.get::<Cap<K>>()Direct access when you hold &Env
env.try_get::<Cap<K>>()Fallible lookup without panic

An application that satisfies all Needs bounds at the edge and passes a complete provider list to run_with is an application where every dependency is explicit — no service-locator globals.