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  }