github.com/RomiChan/protobuf@v0.1.1-0.20230204044148-2ed269a2e54d/proto/decode.go (about) 1 package proto 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "io" 7 "unsafe" 8 ) 9 10 func decodeZigZag64(v uint64) int64 { 11 return int64(v>>1) ^ -(int64(v) & 1) 12 } 13 14 type decodeFunc = func([]byte, unsafe.Pointer) (int, error) 15 16 var errVarintOverflow = errors.New("varint overflowed 64 bits integer") 17 18 func decodeVarint(b []byte) (uint64, int, error) { 19 if len(b) != 0 && b[0] < 0x80 { 20 // Fast-path for decoding the common case of varints that fit on a 21 // single byte. 22 // 23 // This path is ~60% faster than calling binary.Uvarint. 24 return uint64(b[0]), 1, nil 25 } 26 27 var x uint64 28 var s uint 29 30 for i, c := range b { 31 if c < 0x80 { 32 if i > 9 || i == 9 && c > 1 { 33 return 0, i, errVarintOverflow 34 } 35 return x | uint64(c)<<s, i + 1, nil 36 } 37 x |= uint64(c&0x7f) << s 38 s += 7 39 } 40 41 return x, len(b), io.ErrUnexpectedEOF 42 } 43 44 func decodeVarintZigZag(b []byte) (int64, int, error) { 45 v, n, err := decodeVarint(b) 46 return decodeZigZag64(v), n, err 47 } 48 49 func decodeLE32(b []byte) (uint32, int, error) { 50 if len(b) < 4 { 51 return 0, 0, io.ErrUnexpectedEOF 52 } 53 return binary.LittleEndian.Uint32(b), 4, nil 54 } 55 56 func decodeLE64(b []byte) (uint64, int, error) { 57 if len(b) < 8 { 58 return 0, 0, io.ErrUnexpectedEOF 59 } 60 return binary.LittleEndian.Uint64(b), 8, nil 61 } 62 63 func decodeTag(b []byte) (f fieldNumber, t wireType, n int, err error) { 64 v, n, err := decodeVarint(b) 65 return fieldNumber(v >> 3), wireType(v & 7), n, err 66 } 67 68 func decodeVarlen(b []byte) ([]byte, int, error) { 69 v, n, err := decodeVarint(b) 70 if err != nil { 71 return nil, n, err 72 } 73 if v > uint64(len(b)-n) { 74 return nil, n, io.ErrUnexpectedEOF 75 } 76 return b[n : n+int(v)], n + int(v), nil 77 }