package quicvarintimport ()// taken from the QUIC draftconst (// Min is the minimum value allowed for a QUIC varint.Min = 0// Max is the maximum allowed value for a QUIC varint (2^62-1).Max = maxVarInt8 maxVarInt1 = 63 maxVarInt2 = 16383 maxVarInt4 = 1073741823 maxVarInt8 = 4611686018427387903)type varintLengthError struct { Num uint64}func ( *varintLengthError) () string {returnfmt.Sprintf("value doesn't fit into 62 bits: %d", .Num)}// Read reads a number in the QUIC varint format from r.func ( io.ByteReader) (uint64, error) { , := .ReadByte()if != nil {return0, }// the first two bits of the first byte encode the length := 1 << (( & 0xc0) >> 6) := & (0xff - 0xc0)if == 1 {returnuint64(), nil } , := .ReadByte()if != nil {return0, }if == 2 {returnuint64() + uint64()<<8, nil } , := .ReadByte()if != nil {return0, } , := .ReadByte()if != nil {return0, }if == 4 {returnuint64() + uint64()<<8 + uint64()<<16 + uint64()<<24, nil } , := .ReadByte()if != nil {return0, } , := .ReadByte()if != nil {return0, } , := .ReadByte()if != nil {return0, } , := .ReadByte()if != nil {return0, }returnuint64() + uint64()<<8 + uint64()<<16 + uint64()<<24 + uint64()<<32 + uint64()<<40 + uint64()<<48 + uint64()<<56, nil}// Parse reads a number in the QUIC varint format.// It returns the number of bytes consumed.func ( []byte) (uint64/* value */, int/* bytes consumed */, error) {iflen() == 0 {return0, 0, io.EOF } := [0]switch >> 6 {case0: // 1-byte encoding: 00xxxxxxreturnuint64( & 0b00111111), 1, nilcase1: // 2-byte encoding: 01xxxxxxiflen() < 2 {return0, 0, io.ErrUnexpectedEOF }returnuint64([1]) | uint64(&0b00111111)<<8, 2, nilcase2: // 4-byte encoding: 10xxxxxxiflen() < 4 {return0, 0, io.ErrUnexpectedEOF }returnuint64([3]) | uint64([2])<<8 | uint64([1])<<16 | uint64(&0b00111111)<<24, 4, nilcase3: // 8-byte encoding: 00xxxxxxiflen() < 8 {return0, 0, io.ErrUnexpectedEOF }// binary.BigEndian.Uint64 only reads the first 8 bytes. Passing the full slice avoids slicing overhead.returnbinary.BigEndian.Uint64() & 0x3fffffffffffffff, 8, nil }panic("unreachable")}// Append appends i in the QUIC varint format.func ( []byte, uint64) []byte {if <= maxVarInt1 {returnappend(, uint8()) }if <= maxVarInt2 {returnappend(, []byte{uint8(>>8) | 0x40, uint8()}...) }if <= maxVarInt4 {returnappend(, []byte{uint8(>>24) | 0x80, uint8( >> 16), uint8( >> 8), uint8()}...) }if <= maxVarInt8 {returnappend(, []byte{uint8(>>56) | 0xc0, uint8( >> 48), uint8( >> 40), uint8( >> 32),uint8( >> 24), uint8( >> 16), uint8( >> 8), uint8(), }...) }panic(&varintLengthError{Num: })}// AppendWithLen append i in the QUIC varint format with the desired length.func ( []byte, uint64, int) []byte {if != 1 && != 2 && != 4 && != 8 {panic("invalid varint length") } := Len()if == {returnAppend(, ) }if > {panic(fmt.Sprintf("cannot encode %d in %d bytes", , )) }switch {case2: = append(, 0b01000000)case4: = append(, 0b10000000)case8: = append(, 0b11000000) }forrange - - 1 { = append(, 0) }for := range { = append(, uint8(>>(8*(-1-)))) }return}// Len determines the number of bytes that will be needed to write the number i.////gcassert:inlinefunc ( uint64) int {if <= maxVarInt1 {return1 }if <= maxVarInt2 {return2 }if <= maxVarInt4 {return4 }if <= maxVarInt8 {return8 }// Don't use a fmt.Sprintf here to format the error message. // The function would then exceed the inlining budget.panic(&varintLengthError{Num: })}
The pages are generated with Goldsv0.8.4. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.