varint.go raw

   1  // Package varint is a variable integer encoding that works in reverse compared
   2  // to the stdlib binary Varint. The terminal byte in the encoding is the one
   3  // with the 8th bit set. This is basically like a base 128 encoding. It reads
   4  // forward using an io.Reader and writes forward using an io.Writer.
   5  package varint
   6  
   7  import (
   8  	"io"
   9  
  10  	"golang.org/x/exp/constraints"
  11  	"next.orly.dev/pkg/lol/chk"
  12  )
  13  
  14  func Encode[V constraints.Integer](w io.Writer, v V) {
  15  	x := []byte{0}
  16  	for {
  17  		x[0] = byte(v) & 127
  18  		v >>= 7
  19  		if v == 0 {
  20  			x[0] |= 128
  21  			_, _ = w.Write(x)
  22  			break
  23  		} else {
  24  			_, _ = w.Write(x)
  25  		}
  26  	}
  27  }
  28  
  29  func Decode(r io.Reader) (v uint64, err error) {
  30  	x := []byte{0}
  31  	v += uint64(x[0])
  32  	var i uint64
  33  	for {
  34  		if _, err = r.Read(x); chk.E(err) {
  35  			return
  36  		}
  37  		if x[0] >= 128 {
  38  			v += uint64(x[0]&127) << (i * 7)
  39  			return
  40  		} else {
  41  			v += uint64(x[0]) << (i * 7)
  42  			i++
  43  		}
  44  	}
  45  }
  46