An allocator with finite memory must say no when it runs out. Today you make Alloc refuse a request that would spill past the end of the arena, returning an error instead of a bogus offset.
Return an out-of-memory error when an allocation would exceed the arena.
Every allocator has finite memory, so the interesting question is what it does at the edge. A bump allocator is out of space the moment the cursor plus the request would pass the end of the buffer. When that happens it must refuse cleanly - return an error and leave the cursor exactly where it was - never hand back an offset that points past the arena.
Pin the boundary now: filling the arena exactly (16 bytes into a 16-byte arena)
must still succeed, and it is only the next byte that fails. Check
cursor + n > len(buf) before bumping, so a request that fits right up to the last
byte is allowed and the first byte too many is rejected. Returning -1 as the
offset alongside the error makes a misuse obvious if the caller ignores it.
func (a *Arena) Alloc(n int) (int, error) {// reject before bumping if it would not fitif a.cursor+n > len(a.buf) {return -1, errors.New("out of memory")}off := a.cursora.cursor += nreturn off, nil}