WebAssembly stores almost every integer - lengths, indices, counts - in a compact variable-length encoding called LEB128. Today you decode the unsigned form, the workhorse the whole decoder depends on.
Decode an unsigned LEB128 integer from the cursor, consuming exactly the bytes it occupies.
WebAssembly is dense with integers - section sizes, vector lengths, function and type indices, opcode immediates - and storing each as a fixed four or eight bytes would bloat every module. Instead it uses LEB128 (Little-Endian Base 128): a variable-length encoding where each byte holds seven bits of the value, least-significant group first, and the top bit of each byte is a continuation flag. A clear top bit means this is the last byte; a set top bit means keep reading. Small numbers take one byte, larger ones take as many as they need.
Decoding is a short loop: pull seven bits out of each byte, shift them into place, and stop when you hit a byte whose high bit is clear. The subtlety that bites people is consuming exactly the right number of bytes - the cursor must sit on the byte right after the value when you finish, because whatever comes next is the next field. Get this decoder right and the rest of the binary format is mostly calling it in the right order.
// Each byte carries 7 payload bits, low group first. The high bit (0x80)// is the continuation flag: set means "another byte follows".func (c *Cursor) readVarU32() (uint32, error) {var result uint32var shift uintfor {b, err := c.readByte()if err != nil { return 0, err }result |= uint32(b&0x7F) << shiftif b&0x80 == 0 { break }shift += 7}return result, nil}