github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/quicvarint/varint.go (about) 1 package quicvarint 2 3 import ( 4 "fmt" 5 "io" 6 7 "github.com/danielpfeifer02/quic-go-prio-packs/internal/protocol" 8 ) 9 10 // taken from the QUIC draft 11 const ( 12 // Min is the minimum value allowed for a QUIC varint. 13 Min = 0 14 15 // Max is the maximum allowed value for a QUIC varint (2^62-1). 16 Max = maxVarInt8 17 18 maxVarInt1 = 63 19 maxVarInt2 = 16383 20 maxVarInt4 = 1073741823 21 maxVarInt8 = 4611686018427387903 22 ) 23 24 // Read reads a number in the QUIC varint format from r. 25 func Read(r io.ByteReader) (uint64, error) { 26 firstByte, err := r.ReadByte() 27 if err != nil { 28 return 0, err 29 } 30 // the first two bits of the first byte encode the length 31 len := 1 << ((firstByte & 0xc0) >> 6) 32 b1 := firstByte & (0xff - 0xc0) 33 if len == 1 { 34 return uint64(b1), nil 35 } 36 b2, err := r.ReadByte() 37 if err != nil { 38 return 0, err 39 } 40 if len == 2 { 41 return uint64(b2) + uint64(b1)<<8, nil 42 } 43 b3, err := r.ReadByte() 44 if err != nil { 45 return 0, err 46 } 47 b4, err := r.ReadByte() 48 if err != nil { 49 return 0, err 50 } 51 if len == 4 { 52 return uint64(b4) + uint64(b3)<<8 + uint64(b2)<<16 + uint64(b1)<<24, nil 53 } 54 b5, err := r.ReadByte() 55 if err != nil { 56 return 0, err 57 } 58 b6, err := r.ReadByte() 59 if err != nil { 60 return 0, err 61 } 62 b7, err := r.ReadByte() 63 if err != nil { 64 return 0, err 65 } 66 b8, err := r.ReadByte() 67 if err != nil { 68 return 0, err 69 } 70 return uint64(b8) + uint64(b7)<<8 + uint64(b6)<<16 + uint64(b5)<<24 + uint64(b4)<<32 + uint64(b3)<<40 + uint64(b2)<<48 + uint64(b1)<<56, nil 71 } 72 73 // Append appends i in the QUIC varint format. 74 func Append(b []byte, i uint64) []byte { 75 if i <= maxVarInt1 { 76 return append(b, uint8(i)) 77 } 78 if i <= maxVarInt2 { 79 return append(b, []byte{uint8(i>>8) | 0x40, uint8(i)}...) 80 } 81 if i <= maxVarInt4 { 82 return append(b, []byte{uint8(i>>24) | 0x80, uint8(i >> 16), uint8(i >> 8), uint8(i)}...) 83 } 84 if i <= maxVarInt8 { 85 return append(b, []byte{ 86 uint8(i>>56) | 0xc0, uint8(i >> 48), uint8(i >> 40), uint8(i >> 32), 87 uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i), 88 }...) 89 } 90 panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i)) 91 } 92 93 // AppendWithLen append i in the QUIC varint format with the desired length. 94 func AppendWithLen(b []byte, i uint64, length protocol.ByteCount) []byte { 95 if length != 1 && length != 2 && length != 4 && length != 8 { 96 panic("invalid varint length") 97 } 98 l := Len(i) 99 if l == length { 100 return Append(b, i) 101 } 102 if l > length { 103 panic(fmt.Sprintf("cannot encode %d in %d bytes", i, length)) 104 } 105 if length == 2 { 106 b = append(b, 0b01000000) 107 } else if length == 4 { 108 b = append(b, 0b10000000) 109 } else if length == 8 { 110 b = append(b, 0b11000000) 111 } 112 for j := protocol.ByteCount(1); j < length-l; j++ { 113 b = append(b, 0) 114 } 115 for j := protocol.ByteCount(0); j < l; j++ { 116 b = append(b, uint8(i>>(8*(l-1-j)))) 117 } 118 return b 119 } 120 121 // Len determines the number of bytes that will be needed to write the number i. 122 func Len(i uint64) protocol.ByteCount { 123 if i <= maxVarInt1 { 124 return 1 125 } 126 if i <= maxVarInt2 { 127 return 2 128 } 129 if i <= maxVarInt4 { 130 return 4 131 } 132 if i <= maxVarInt8 { 133 return 8 134 } 135 // Don't use a fmt.Sprintf here to format the error message. 136 // The function would then exceed the inlining budget. 137 panic(struct { 138 message string 139 num uint64 140 }{"value doesn't fit into 62 bits: ", i}) 141 }