Flash 47 lines
// `errdefer |err|` capture: the deferred cleanup sees WHICH error is
// unwinding — `errdefer |err| <stmt>` (statement form) and
// `errdefer |err| { … }` (block form). The error binds by value, as in
// Zig (`|*err|` is rejected); plain `errdefer` stays capture-less and
// composes freely with the captured forms.
//
// Lives in examples/register/ (post-v0.5 grammar — the frozen stage0
// bootstrap compiler cannot parse it; gated by `zig build fixpoint`).
const InitError = error{ NoMemory, BadDevice }
// The driver's failure breadcrumbs: which error unwound, and how many
// cleanup steps ran on the way out.
var last_failure u16 = 0
var unwound u16 = 0
fn classify(err InitError) u16 {
if err == error.NoMemory {
return 1
}
return 2
}
fn claim(slot u16) InitError!u16 {
if slot == 0 {
return error.BadDevice
}
return slot
}
// Bring up a device: each acquired resource registers its unwind step,
// and the captured forms record the error that triggered the unwind.
pub fn bringup(slot u16) InitError!u16 {
id := try claim(slot)
// The statement form: one deferred statement, the error in scope.
errdefer |err| last_failure = classify(err)
// The block form: a multi-step unwind, the same capture.
errdefer |err| {
last_failure = classify(err)
unwound += 1
}
// A capture-less errdefer runs the same way — there is no error to name.
errdefer unwound += 1
_ = try claim(id + 1)
return id
}