github.com/segmentio/encoding@v0.4.0/proto/decode.go (about)

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