ajhahn.de
← Flash
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
}