Real input can be malformed, and a decoder that reads past the end of a buffer or loops forever on garbage is a bug. Today you make the reader fail cleanly on a varint that runs off the end and on one that is impossibly long.
Make ReadVarint report an error on a truncated varint and on one longer than ten bytes.
A varint says “keep going” with its continuation flag, but the buffer can end
before a byte with the flag clear ever arrives - a truncated varint. Without a
guard, the reader indexes past the slice and panics. Check AtEnd before every
ReadByte and return an error instead. This is the first place the reader’s
signature grows an error; later lessons thread that through.
The other failure is an over-long varint. A 64-bit value needs at most ten 7-bit groups (nine full groups is 63 bits, the tenth carries the last bit), so any varint that has not terminated by its tenth byte is malformed and must be rejected rather than shifted into oblivion. Pinning both edges now - the empty-continuation case and the ten-byte ceiling - means every varint the rest of the decoder reads is either a real number or a clean error.
func (r *Reader) ReadVarint() (uint64, error) {var result uint64var shift uintfor i := 0; ; i++ {if r.AtEnd() { return 0, errTruncated }if i >= 10 { return 0, errVarintTooLong } // 64 bits need <= 10 groupsb := r.ReadByte()result |= uint64(b&0x7F) << shiftif b&0x80 == 0 { return result, nil }shift += 7}}