✓
Passing This code compiles and runs correctly.
Code
// OWED: composite custody. A kind's proto carries TWO owned leaves —
// `r1`/`r2` are each `*Resource<owned!>`, two independent debts inside one
// value. `send | ok` consumes both at the producer; the winning `! env`
// arm mints `v.r1` and `v.r2` separately and settles each through the
// type's own discharger. The channel moves a leaf bundle, not a blob:
// custody deconstructs at the boundary and must account for every path.
import std/io
import std/proto
import std/channel
import std/pump
import app/lib/res
std/proto(Env) {
r1: *app/lib/res:Resource<owned!>
r2: *app/lib/res:Resource<owned!>
}
pub tor mk-env { a: *app/lib/res:Resource<!owned>, b: *app/lib/res:Resource<!owned> } -> Env
mk-env -> { r1: a, r2: b }
std/channel:new(inbox, capacity: 8) { env: Env }
std/channel(inbox)
! env v |> app/lib/res:free(r: v.r1) |> app/lib/res:free(r: v.r2) |> std/io:print.ln("env settled")
app/lib/res:new(): a |> app/lib/res:new(): b |> mk-env(a, b): e |> std/channel:send(inbox, e)
| ok |> std/channel:close(inbox)
| ok |> std/io:print.ln("sealed")
| full |> app/lib/res:free(r: e.r1) |> app/lib/res:free(r: e.r2) |> std/io:print.ln("full")
| closed |> app/lib/res:free(r: e.r1) |> app/lib/res:free(r: e.r2) |> std/io:print.ln("closed")
std/pump:create(main)
| drained |> std/io:print.ln("drained")
std/pump(main)
! step |> inbox-step()
! live |> inbox-live()
std/pump:run(main)
Supporting Files
// A minimal OWNED-POINTER resource type (non-string), for generalizing B-narrow
// past std/string. `new` issues <owned!>; `free` is the canonical VOID
// discharger consuming <!owned>; `tag` borrows to read a field.
const std = @import("std");
const Resource = struct { tag: i64 };
~pub tor new { } -> *Resource<owned!>
~proc new|zig {
const r = std.heap.page_allocator.create(Resource) catch unreachable;
r.* = .{ .tag = 42 };
return r;
}
// Canonical discharger: consumes <!owned>, frees the resource. Void (no output).
~pub tor free { r: *Resource<!owned> }
~proc free|zig {
std.heap.page_allocator.destroy(r);
}
// Borrow: read the tag without consuming the obligation.
~pub tor tag { r: *Resource<owned> } -> i64
~proc tag|zig {
return r.tag;
}
Actual
sealed
env settled
drained
Expected output
sealed
env settled
drained
Flows
flow ~std/proto click a branch to expand · @labels scroll to their anchor
std/proto (Env, source: r1: *app/lib/res:Resource<owned!>
r2: *app/lib/res:Resource<owned!>)
flow ~new click a branch to expand · @labels scroll to their anchor
new (expr: inbox, capacity: 8, source: env: Env)
flow ~std/channel click a branch to expand · @labels scroll to their anchor
std/channel (inbox)
flow ~new click a branch to expand · @labels scroll to their anchor
new
flow ~create click a branch to expand · @labels scroll to their anchor
create (expr: main)
flow ~std/pump click a branch to expand · @labels scroll to their anchor
std/pump (main)
flow ~run click a branch to expand · @labels scroll to their anchor
run (main)
Test Configuration
MUST_RUN