mirror of
https://github.com/hanzoai/metrics.git
synced 2026-10-30 20:03:39 +00:00
1234 lines
35 KiB
Go
1234 lines
35 KiB
Go
package easyproto
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math"
|
|
"sync"
|
|
"unsafe"
|
|
)
|
|
|
|
// FieldContext represents a single protobuf-encoded field after NextField() or FieldByNum() call.
|
|
type FieldContext struct {
|
|
// FieldNum is the number of protobuf field read after NextField() or FieldByNum() call.
|
|
FieldNum uint32
|
|
|
|
// wireType is the wire type for the given field
|
|
wireType wireType
|
|
|
|
// data is probobuf-encoded field data for wireType=wireTypeLen
|
|
data []byte
|
|
|
|
// intValue contains int value for wireType!=wireTypeLen
|
|
intValue uint64
|
|
}
|
|
|
|
// FieldByNum sets fc to the field with the given fieldNum at protobuf-encoded src.
|
|
//
|
|
// false is returned if src doesn't contain a field with the given fieldNum.
|
|
//
|
|
// It is unsafe modifying src while FieldContext is in use.
|
|
//
|
|
// See also NextField().
|
|
func (fc *FieldContext) FieldByNum(src []byte, fieldNum uint32) (bool, error) {
|
|
for len(src) > 0 {
|
|
var err error
|
|
src, err = fc.NextField(src)
|
|
if err != nil {
|
|
return false, fmt.Errorf("cannot read the next field while searching for fieldNum=%d: %w", fieldNum, err)
|
|
}
|
|
if fc.FieldNum != fieldNum {
|
|
continue
|
|
}
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// NextField reads the next field from protobuf-encoded src.
|
|
//
|
|
// It returns the tail left after reading the next field from src.
|
|
//
|
|
// It is unsafe modifying src while FieldContext is in use.
|
|
//
|
|
// See also FieldByNum().
|
|
func (fc *FieldContext) NextField(src []byte) ([]byte, error) {
|
|
if len(src) >= 2 {
|
|
n := uint16(src[0])<<8 | uint16(src[1])
|
|
if (n&0x8080 == 0) && (n&0x0700 == (uint16(wireTypeLen) << 8)) {
|
|
// Fast path - read message with the length smaller than 0x80 bytes.
|
|
msgLen := int(n & 0xff)
|
|
src = src[2:]
|
|
if len(src) < msgLen {
|
|
return src, fmt.Errorf("cannot read field from %d bytes; need at least %d bytes", len(src), msgLen)
|
|
}
|
|
fc.FieldNum = uint32(n >> (8 + 3))
|
|
fc.wireType = wireTypeLen
|
|
fc.data = src[:msgLen]
|
|
src = src[msgLen:]
|
|
return src, nil
|
|
}
|
|
}
|
|
|
|
// Read field tag. See https://protobuf.dev/programming-guides/encoding/#structure
|
|
if len(src) == 0 {
|
|
return src, fmt.Errorf("cannot unmarshal field from empty message")
|
|
}
|
|
|
|
var fieldNum uint64
|
|
tag := uint64(src[0])
|
|
if tag < 0x80 {
|
|
src = src[1:]
|
|
fieldNum = tag >> 3
|
|
} else {
|
|
var offset int
|
|
tag, offset = binary.Uvarint(src)
|
|
if offset <= 0 {
|
|
return src, fmt.Errorf("cannot unmarshal field tag from uvarint")
|
|
}
|
|
src = src[offset:]
|
|
fieldNum = tag >> 3
|
|
if fieldNum > math.MaxUint32 {
|
|
return src, fmt.Errorf("fieldNum=%d is bigger than uint32max=%d", fieldNum, uint64(math.MaxUint32))
|
|
}
|
|
}
|
|
|
|
wt := wireType(tag & 0x07)
|
|
|
|
fc.FieldNum = uint32(fieldNum)
|
|
fc.wireType = wt
|
|
|
|
// Read the remaining data
|
|
if wt == wireTypeLen {
|
|
u64, offset := binary.Uvarint(src)
|
|
if offset <= 0 {
|
|
return src, fmt.Errorf("cannot read message length for field #%d", fieldNum)
|
|
}
|
|
src = src[offset:]
|
|
if uint64(len(src)) < u64 {
|
|
return src, fmt.Errorf("cannot read data for field #%d from %d bytes; need at least %d bytes", fieldNum, len(src), u64)
|
|
}
|
|
fc.data = src[:u64]
|
|
src = src[u64:]
|
|
return src, nil
|
|
}
|
|
if wt == wireTypeVarint {
|
|
u64, offset := binary.Uvarint(src)
|
|
if offset <= 0 {
|
|
return src, fmt.Errorf("cannot read varint after field tag for field #%d", fieldNum)
|
|
}
|
|
src = src[offset:]
|
|
fc.intValue = u64
|
|
return src, nil
|
|
}
|
|
if wt == wireTypeI64 {
|
|
if len(src) < 8 {
|
|
return src, fmt.Errorf("cannot read i64 for field #%d", fieldNum)
|
|
}
|
|
u64 := binary.LittleEndian.Uint64(src)
|
|
src = src[8:]
|
|
fc.intValue = u64
|
|
return src, nil
|
|
}
|
|
if wt == wireTypeI32 {
|
|
if len(src) < 4 {
|
|
return src, fmt.Errorf("cannot read i32 for field #%d", fieldNum)
|
|
}
|
|
u32 := binary.LittleEndian.Uint32(src)
|
|
src = src[4:]
|
|
fc.intValue = uint64(u32)
|
|
return src, nil
|
|
}
|
|
return src, fmt.Errorf("unknown wireType=%d", wt)
|
|
}
|
|
|
|
// UnmarshalMessageLen unmarshals protobuf message length from src.
|
|
//
|
|
// It returns the tail left after unmarshaling message length from src.
|
|
//
|
|
// It is expected that src is marshaled with Marshaler.MarshalWithLen().
|
|
//
|
|
// False is returned if message length cannot be unmarshaled from src.
|
|
func UnmarshalMessageLen(src []byte) (int, []byte, bool) {
|
|
u64, offset := binary.Uvarint(src)
|
|
if offset <= 0 {
|
|
return 0, src, false
|
|
}
|
|
src = src[offset:]
|
|
if u64 > math.MaxInt32 {
|
|
return 0, src, false
|
|
}
|
|
return int(u64), src, true
|
|
}
|
|
|
|
// wireType is the type of of protobuf-encoded field
|
|
//
|
|
// See https://protobuf.dev/programming-guides/encoding/#structure
|
|
type wireType byte
|
|
|
|
const (
|
|
// VARINT type - one of int32, int64, uint32, uint64, sint32, sint64, bool, enum
|
|
wireTypeVarint = wireType(0)
|
|
|
|
// I64 type
|
|
wireTypeI64 = wireType(1)
|
|
|
|
// Len type
|
|
wireTypeLen = wireType(2)
|
|
|
|
// I32 type
|
|
wireTypeI32 = wireType(5)
|
|
)
|
|
|
|
func (wt wireType) String() string {
|
|
switch wt {
|
|
case wireTypeVarint:
|
|
return "varint"
|
|
case wireTypeI64:
|
|
return "i64"
|
|
case wireTypeLen:
|
|
return "len"
|
|
case wireTypeI32:
|
|
return "i32"
|
|
default:
|
|
return fmt.Sprintf("unknown (%d)", int(wt))
|
|
}
|
|
}
|
|
|
|
// Int32 returns int32 value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain int32 value.
|
|
func (fc *FieldContext) Int32() (int32, bool) {
|
|
if fc.wireType != wireTypeVarint {
|
|
return 0, false
|
|
}
|
|
return getInt32(fc.intValue)
|
|
}
|
|
|
|
// Int64 returns int64 value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain int64 value.
|
|
func (fc *FieldContext) Int64() (int64, bool) {
|
|
if fc.wireType != wireTypeVarint {
|
|
return 0, false
|
|
}
|
|
return int64(fc.intValue), true
|
|
}
|
|
|
|
// Uint32 returns uint32 value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain uint32 value.
|
|
func (fc *FieldContext) Uint32() (uint32, bool) {
|
|
if fc.wireType != wireTypeVarint {
|
|
return 0, false
|
|
}
|
|
return getUint32(fc.intValue)
|
|
}
|
|
|
|
// Uint64 returns uint64 value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain uint64 value.
|
|
func (fc *FieldContext) Uint64() (uint64, bool) {
|
|
if fc.wireType != wireTypeVarint {
|
|
return 0, false
|
|
}
|
|
return fc.intValue, true
|
|
}
|
|
|
|
// Sint32 returns sint32 value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain sint32 value.
|
|
func (fc *FieldContext) Sint32() (int32, bool) {
|
|
if fc.wireType != wireTypeVarint {
|
|
return 0, false
|
|
}
|
|
u32, ok := getUint32(fc.intValue)
|
|
if !ok {
|
|
return 0, false
|
|
}
|
|
i32 := decodeZigZagInt32(u32)
|
|
return i32, true
|
|
}
|
|
|
|
// Sint64 returns sint64 value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain sint64 value.
|
|
func (fc *FieldContext) Sint64() (int64, bool) {
|
|
if fc.wireType != wireTypeVarint {
|
|
return 0, false
|
|
}
|
|
i64 := decodeZigZagInt64(fc.intValue)
|
|
return i64, true
|
|
}
|
|
|
|
// Bool returns bool value for fc.
|
|
//
|
|
// False is returned in the second result if fc doesn't contain bool value.
|
|
func (fc *FieldContext) Bool() (bool, bool) {
|
|
if fc.wireType != wireTypeVarint {
|
|
return false, false
|
|
}
|
|
return getBool(fc.intValue)
|
|
}
|
|
|
|
// Enum returns enum value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain enum value.
|
|
func (fc *FieldContext) Enum() (int32, bool) {
|
|
if fc.wireType != wireTypeVarint {
|
|
return 0, false
|
|
}
|
|
return getInt32(fc.intValue)
|
|
}
|
|
|
|
// Fixed64 returns fixed64 value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain fixed64 value.
|
|
func (fc *FieldContext) Fixed64() (uint64, bool) {
|
|
if fc.wireType != wireTypeI64 {
|
|
return 0, false
|
|
}
|
|
return fc.intValue, true
|
|
}
|
|
|
|
// Sfixed64 returns sfixed64 value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain sfixed64 value.
|
|
func (fc *FieldContext) Sfixed64() (int64, bool) {
|
|
if fc.wireType != wireTypeI64 {
|
|
return 0, false
|
|
}
|
|
return int64(fc.intValue), true
|
|
}
|
|
|
|
// Double returns dobule value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain double value.
|
|
func (fc *FieldContext) Double() (float64, bool) {
|
|
if fc.wireType != wireTypeI64 {
|
|
return 0, false
|
|
}
|
|
v := math.Float64frombits(fc.intValue)
|
|
return v, true
|
|
}
|
|
|
|
// String returns string value for fc.
|
|
//
|
|
// The returned string is valid while the underlying buffer isn't changed.
|
|
//
|
|
// False is returned if fc doesn't contain string value.
|
|
func (fc *FieldContext) String() (string, bool) {
|
|
if fc.wireType != wireTypeLen {
|
|
return "", false
|
|
}
|
|
s := unsafeBytesToString(fc.data)
|
|
return s, true
|
|
}
|
|
|
|
// Bytes returns bytes value for fc.
|
|
//
|
|
// The returned byte slice is valid while the underlying buffer isn't changed.
|
|
//
|
|
// False is returned if fc doesn't contain bytes value.
|
|
func (fc *FieldContext) Bytes() ([]byte, bool) {
|
|
if fc.wireType != wireTypeLen {
|
|
return nil, false
|
|
}
|
|
return fc.data, true
|
|
}
|
|
|
|
// MessageData returns protobuf message data for fc.
|
|
//
|
|
// False is returned if fc doesn't contain message data.
|
|
func (fc *FieldContext) MessageData() ([]byte, bool) {
|
|
if fc.wireType != wireTypeLen {
|
|
return nil, false
|
|
}
|
|
return fc.data, true
|
|
}
|
|
|
|
// Fixed32 returns fixed32 value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain fixed32 value.
|
|
func (fc *FieldContext) Fixed32() (uint32, bool) {
|
|
if fc.wireType != wireTypeI32 {
|
|
return 0, false
|
|
}
|
|
u32 := mustGetUint32(fc.intValue)
|
|
return u32, true
|
|
}
|
|
|
|
// Sfixed32 returns sfixed32 value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain sfixed value.
|
|
func (fc *FieldContext) Sfixed32() (int32, bool) {
|
|
if fc.wireType != wireTypeI32 {
|
|
return 0, false
|
|
}
|
|
i32 := mustGetInt32(fc.intValue)
|
|
return i32, true
|
|
}
|
|
|
|
// Float returns float value for fc.
|
|
//
|
|
// False is returned if fc doesn't contain float value.
|
|
func (fc *FieldContext) Float() (float32, bool) {
|
|
if fc.wireType != wireTypeI32 {
|
|
return 0, false
|
|
}
|
|
u32 := mustGetUint32(fc.intValue)
|
|
v := math.Float32frombits(u32)
|
|
return v, true
|
|
}
|
|
|
|
// UnpackInt32s unpacks int32 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackInt32s(src []byte, fieldNum uint32, dst []int32) ([]int32, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackInt32s)
|
|
}
|
|
|
|
// UnpackInt32s unpacks int32 values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain int32 values.
|
|
func (fc *FieldContext) UnpackInt32s(dst []int32) ([]int32, bool) {
|
|
if fc.wireType == wireTypeVarint {
|
|
i32, ok := getInt32(fc.intValue)
|
|
if !ok {
|
|
return dst, false
|
|
}
|
|
dst = append(dst, i32)
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
u64, offset := binary.Uvarint(src)
|
|
if offset <= 0 {
|
|
return dstOrig, false
|
|
}
|
|
src = src[offset:]
|
|
i32, ok := getInt32(u64)
|
|
if !ok {
|
|
return dstOrig, false
|
|
}
|
|
dst = append(dst, i32)
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackInt64s unpacks int64 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackInt64s(src []byte, fieldNum uint32, dst []int64) ([]int64, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackInt64s)
|
|
}
|
|
|
|
// UnpackInt64s unpacks int64 values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain int64 values.
|
|
func (fc *FieldContext) UnpackInt64s(dst []int64) ([]int64, bool) {
|
|
if fc.wireType == wireTypeVarint {
|
|
dst = append(dst, int64(fc.intValue))
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
u64, offset := binary.Uvarint(src)
|
|
if offset <= 0 {
|
|
return dstOrig, false
|
|
}
|
|
src = src[offset:]
|
|
dst = append(dst, int64(u64))
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackUint32s unpacks uint32 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackUint32s(src []byte, fieldNum uint32, dst []uint32) ([]uint32, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackUint32s)
|
|
}
|
|
|
|
// UnpackUint32s unpacks uint32 values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain uint32 values.
|
|
func (fc *FieldContext) UnpackUint32s(dst []uint32) ([]uint32, bool) {
|
|
if fc.wireType == wireTypeVarint {
|
|
u32, ok := getUint32(fc.intValue)
|
|
if !ok {
|
|
return dst, false
|
|
}
|
|
dst = append(dst, u32)
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
u64, offset := binary.Uvarint(src)
|
|
if offset <= 0 {
|
|
return dstOrig, false
|
|
}
|
|
src = src[offset:]
|
|
u32, ok := getUint32(u64)
|
|
if !ok {
|
|
return dstOrig, false
|
|
}
|
|
dst = append(dst, u32)
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackUint64s unpacks uint64 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackUint64s(src []byte, fieldNum uint32, dst []uint64) ([]uint64, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackUint64s)
|
|
}
|
|
|
|
// UnpackUint64s unpacks uint64 values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain uint64 values.
|
|
func (fc *FieldContext) UnpackUint64s(dst []uint64) ([]uint64, bool) {
|
|
if fc.wireType == wireTypeVarint {
|
|
dst = append(dst, fc.intValue)
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
u64, offset := binary.Uvarint(src)
|
|
if offset <= 0 {
|
|
return dstOrig, false
|
|
}
|
|
src = src[offset:]
|
|
dst = append(dst, u64)
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackSint32s unpacks sint32 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackSint32s(src []byte, fieldNum uint32, dst []int32) ([]int32, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackSint32s)
|
|
}
|
|
|
|
// UnpackSint32s unpacks sint32 values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain sint32 values.
|
|
func (fc *FieldContext) UnpackSint32s(dst []int32) ([]int32, bool) {
|
|
if fc.wireType == wireTypeVarint {
|
|
u32, ok := getUint32(fc.intValue)
|
|
if !ok {
|
|
return dst, false
|
|
}
|
|
i32 := decodeZigZagInt32(u32)
|
|
dst = append(dst, i32)
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
u64, offset := binary.Uvarint(src)
|
|
if offset <= 0 {
|
|
return dstOrig, false
|
|
}
|
|
src = src[offset:]
|
|
u32, ok := getUint32(u64)
|
|
if !ok {
|
|
return dstOrig, false
|
|
}
|
|
i32 := decodeZigZagInt32(u32)
|
|
dst = append(dst, i32)
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackSint64s unpacks sint64 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackSint64s(src []byte, fieldNum uint32, dst []int64) ([]int64, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackSint64s)
|
|
}
|
|
|
|
// UnpackSint64s unpacks sint64 values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain sint64 values.
|
|
func (fc *FieldContext) UnpackSint64s(dst []int64) ([]int64, bool) {
|
|
if fc.wireType == wireTypeVarint {
|
|
i64 := decodeZigZagInt64(fc.intValue)
|
|
dst = append(dst, i64)
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
u64, offset := binary.Uvarint(src)
|
|
if offset <= 0 {
|
|
return dstOrig, false
|
|
}
|
|
src = src[offset:]
|
|
i64 := decodeZigZagInt64(u64)
|
|
dst = append(dst, i64)
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackBools unpacks bool values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackBools(src []byte, fieldNum uint32, dst []bool) ([]bool, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackBools)
|
|
}
|
|
|
|
// UnpackBools unpacks bool values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned in the second result if fc doesn't contain bool values.
|
|
func (fc *FieldContext) UnpackBools(dst []bool) ([]bool, bool) {
|
|
if fc.wireType == wireTypeVarint {
|
|
v, ok := getBool(fc.intValue)
|
|
if !ok {
|
|
return dst, false
|
|
}
|
|
dst = append(dst, v)
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
u64, offset := binary.Uvarint(src)
|
|
if offset <= 0 {
|
|
return dstOrig, false
|
|
}
|
|
src = src[offset:]
|
|
v, ok := getBool(u64)
|
|
if !ok {
|
|
return dst, false
|
|
}
|
|
dst = append(dst, v)
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackFixed64s unpacks fixed64 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackFixed64s(src []byte, fieldNum uint32, dst []uint64) ([]uint64, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackFixed64s)
|
|
}
|
|
|
|
// UnpackFixed64s unpacks fixed64 values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain fixed64 values.
|
|
func (fc *FieldContext) UnpackFixed64s(dst []uint64) ([]uint64, bool) {
|
|
if fc.wireType == wireTypeI64 {
|
|
u64 := fc.intValue
|
|
dst = append(dst, u64)
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
if len(src) < 8 {
|
|
return dstOrig, false
|
|
}
|
|
u64 := binary.LittleEndian.Uint64(src)
|
|
src = src[8:]
|
|
dst = append(dst, u64)
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackSfixed64s unpacks sfixed64 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackSfixed64s(src []byte, fieldNum uint32, dst []int64) ([]int64, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackSfixed64s)
|
|
}
|
|
|
|
// UnpackSfixed64s unpacks sfixed64 values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain sfixed64 values.
|
|
func (fc *FieldContext) UnpackSfixed64s(dst []int64) ([]int64, bool) {
|
|
if fc.wireType == wireTypeI64 {
|
|
u64 := fc.intValue
|
|
dst = append(dst, int64(u64))
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
if len(src) < 8 {
|
|
return dstOrig, false
|
|
}
|
|
u64 := binary.LittleEndian.Uint64(src)
|
|
src = src[8:]
|
|
dst = append(dst, int64(u64))
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackDoubles unpacks double values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackDoubles(src []byte, fieldNum uint32, dst []float64) ([]float64, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackDoubles)
|
|
}
|
|
|
|
// UnpackDoubles unpacks double values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain double values.
|
|
func (fc *FieldContext) UnpackDoubles(dst []float64) ([]float64, bool) {
|
|
if fc.wireType == wireTypeI64 {
|
|
v := math.Float64frombits(fc.intValue)
|
|
dst = append(dst, v)
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
if len(src) < 8 {
|
|
return dstOrig, false
|
|
}
|
|
u64 := binary.LittleEndian.Uint64(src)
|
|
src = src[8:]
|
|
v := math.Float64frombits(u64)
|
|
dst = append(dst, v)
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackFixed32s unpacks fixed32 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackFixed32s(src []byte, fieldNum uint32, dst []uint32) ([]uint32, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackFixed32s)
|
|
}
|
|
|
|
// UnpackFixed32s unpacks fixed32 values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain fixed32 values.
|
|
func (fc *FieldContext) UnpackFixed32s(dst []uint32) ([]uint32, bool) {
|
|
if fc.wireType == wireTypeI32 {
|
|
u32 := mustGetUint32(fc.intValue)
|
|
dst = append(dst, u32)
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
if len(src) < 4 {
|
|
return dstOrig, false
|
|
}
|
|
u32 := binary.LittleEndian.Uint32(src)
|
|
src = src[4:]
|
|
dst = append(dst, u32)
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackSfixed32s unpacks sfixed32 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackSfixed32s(src []byte, fieldNum uint32, dst []int32) ([]int32, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackSfixed32s)
|
|
}
|
|
|
|
// UnpackSfixed32s unpacks sfixed32 values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain sfixed32 values.
|
|
func (fc *FieldContext) UnpackSfixed32s(dst []int32) ([]int32, bool) {
|
|
if fc.wireType == wireTypeI32 {
|
|
i32 := mustGetInt32(fc.intValue)
|
|
dst = append(dst, i32)
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
if len(src) < 4 {
|
|
return dstOrig, false
|
|
}
|
|
u32 := binary.LittleEndian.Uint32(src)
|
|
src = src[4:]
|
|
dst = append(dst, int32(u32))
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
// UnpackFloats unpacks float values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result.
|
|
func UnpackFloats(src []byte, fieldNum uint32, dst []float32) ([]float32, error) {
|
|
return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackFloats)
|
|
}
|
|
|
|
// UnpackFloats unpacks float values from fc, appends them to dst and returns the result.
|
|
//
|
|
// False is returned if fc doesn't contain float values.
|
|
func (fc *FieldContext) UnpackFloats(dst []float32) ([]float32, bool) {
|
|
if fc.wireType == wireTypeI32 {
|
|
u32 := mustGetUint32(fc.intValue)
|
|
v := math.Float32frombits(u32)
|
|
dst = append(dst, v)
|
|
return dst, true
|
|
}
|
|
if fc.wireType != wireTypeLen {
|
|
return dst, false
|
|
}
|
|
src := fc.data
|
|
dstOrig := dst
|
|
for len(src) > 0 {
|
|
if len(src) < 4 {
|
|
return dstOrig, false
|
|
}
|
|
u32 := binary.LittleEndian.Uint32(src)
|
|
src = src[4:]
|
|
v := math.Float32frombits(u32)
|
|
dst = append(dst, v)
|
|
}
|
|
return dst, true
|
|
}
|
|
|
|
func (fc *FieldContext) getField(src []byte, fieldNum uint32, neededWireType wireType) (bool, error) {
|
|
ok, err := fc.FieldByNum(src, fieldNum)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if !ok {
|
|
return false, nil
|
|
}
|
|
if fc.wireType != neededWireType {
|
|
return false, fmt.Errorf("fieldNum=%d contains unexpected wireType; got %s; want %s", fieldNum, fc.wireType, neededWireType)
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func unpackArray[T any](src []byte, fieldNum uint32, dst []T, unpackFunc func(fc *FieldContext, dst []T) ([]T, bool)) ([]T, error) {
|
|
v := fieldContextPool.Get()
|
|
if v == nil {
|
|
v = &FieldContext{}
|
|
}
|
|
defer fieldContextPool.Put(v)
|
|
|
|
fc := v.(*FieldContext)
|
|
for len(src) > 0 {
|
|
var err error
|
|
src, err = fc.NextField(src)
|
|
if err != nil {
|
|
return dst, fmt.Errorf("cannot read the next field while searching for fieldNum=%d: %w", fieldNum, err)
|
|
}
|
|
if fc.FieldNum != fieldNum {
|
|
continue
|
|
}
|
|
|
|
var ok bool
|
|
dst, ok = unpackFunc(fc, dst)
|
|
if !ok {
|
|
return dst, fmt.Errorf("cannot unpack bools from field with fieldNum=%d", fieldNum)
|
|
}
|
|
}
|
|
return dst, nil
|
|
}
|
|
|
|
var fieldContextPool sync.Pool
|
|
|
|
// GetInt32 returns the int32 value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetInt32(src []byte, fieldNum uint32) (n int32, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeVarint)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
n, ok = getInt32(fc.intValue)
|
|
if !ok {
|
|
return 0, false, fmt.Errorf("fieldNum=%d contains too big integer %d, which cannot be converted to int32", fieldNum, fc.intValue)
|
|
}
|
|
return n, true, nil
|
|
}
|
|
|
|
// GetInt64 returns the int64 value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetInt64(src []byte, fieldNum uint32) (n int64, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeVarint)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
return int64(fc.intValue), true, nil
|
|
}
|
|
|
|
// GetUint32 returns the uint32 value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetUint32(src []byte, fieldNum uint32) (n uint32, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeVarint)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
n, ok = getUint32(fc.intValue)
|
|
if !ok {
|
|
return 0, false, fmt.Errorf("fieldNum=%d contains too big integer %d, which cannot be converted to uint32", fieldNum, fc.intValue)
|
|
}
|
|
return n, true, nil
|
|
}
|
|
|
|
// GetUint64 returns the int64 value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetUint64(src []byte, fieldNum uint32) (n uint64, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeVarint)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
return fc.intValue, true, nil
|
|
}
|
|
|
|
// GetSint32 returns sint32 value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetSint32(src []byte, fieldNum uint32) (n int32, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeVarint)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
u32, ok := getUint32(fc.intValue)
|
|
if !ok {
|
|
return 0, false, fmt.Errorf("fieldNum=%d contains too big integer %d, which cannot be converted to uint32", fieldNum, fc.intValue)
|
|
}
|
|
n = decodeZigZagInt32(u32)
|
|
return n, true, nil
|
|
}
|
|
|
|
// GetSint64 returns sint64 value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetSint64(src []byte, fieldNum uint32) (n int64, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeVarint)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
n = decodeZigZagInt64(fc.intValue)
|
|
return n, true, nil
|
|
}
|
|
|
|
// GetBool returns bool value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetBool(src []byte, fieldNum uint32) (b bool, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeVarint)
|
|
if err != nil {
|
|
return false, false, err
|
|
}
|
|
if !ok {
|
|
return false, false, nil
|
|
}
|
|
b, ok = getBool(fc.intValue)
|
|
if !ok {
|
|
return false, false, fmt.Errorf("fieldNum=%d contains invalid integer %d, which cannot be converted to bool", fieldNum, fc.intValue)
|
|
}
|
|
return b, true, nil
|
|
}
|
|
|
|
// GetEnum returns enum value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetEnum(src []byte, fieldNum uint32) (n int32, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeVarint)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
n, ok = getInt32(fc.intValue)
|
|
if !ok {
|
|
return 0, false, fmt.Errorf("fieldNum=%d contains invalid integer %d, which cannot be converted to enum", fieldNum, fc.intValue)
|
|
}
|
|
return n, true, nil
|
|
}
|
|
|
|
// GetFixed64 returns fixed64 value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetFixed64(src []byte, fieldNum uint32) (n uint64, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeI64)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
return fc.intValue, true, nil
|
|
}
|
|
|
|
// GetSfixed64 returns sfixed64 value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetSfixed64(src []byte, fieldNum uint32) (n int64, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeI64)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
return int64(fc.intValue), true, nil
|
|
}
|
|
|
|
// GetDouble returns double value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetDouble(src []byte, fieldNum uint32) (f float64, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeI64)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
f = math.Float64frombits(fc.intValue)
|
|
return f, true, nil
|
|
}
|
|
|
|
// GetString returns string value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
// The returned string is valid until src is changed.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetString(src []byte, fieldNum uint32) (s string, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeLen)
|
|
if err != nil {
|
|
return "", false, err
|
|
}
|
|
if !ok {
|
|
return "", false, nil
|
|
}
|
|
return unsafeBytesToString(fc.data), true, nil
|
|
}
|
|
|
|
// GetBytes returns bytes slice for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
// The returned bytes slice is valid until src is changed.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetBytes(src []byte, fieldNum uint32) (b []byte, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeLen)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
if !ok {
|
|
return nil, false, nil
|
|
}
|
|
return fc.data, true, nil
|
|
}
|
|
|
|
// GetMessageData returns message data for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
// The returned message data is valid until src is changed.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetMessageData(src []byte, fieldNum uint32) (data []byte, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeLen)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
if !ok {
|
|
return nil, false, nil
|
|
}
|
|
return fc.data, true, nil
|
|
}
|
|
|
|
// GetFixed32 returns fixed32 value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetFixed32(src []byte, fieldNum uint32) (n uint32, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeI32)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
n = mustGetUint32(fc.intValue)
|
|
return n, true, nil
|
|
}
|
|
|
|
// GetSfixed32 returns sfixed32 value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetSfixed32(src []byte, fieldNum uint32) (n int32, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeI32)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
n = mustGetInt32(fc.intValue)
|
|
return n, true, nil
|
|
}
|
|
|
|
// GetFloat returns float32 value for the given fieldNum from protobuf-encoded message at src.
|
|
//
|
|
// ok=false is returned if src doesn't contain the given fieldNum.
|
|
//
|
|
// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src.
|
|
// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src.
|
|
func GetFloat(src []byte, fieldNum uint32) (f float32, ok bool, err error) {
|
|
var fc FieldContext
|
|
ok, err = fc.getField(src, fieldNum, wireTypeI32)
|
|
if err != nil {
|
|
return 0, false, err
|
|
}
|
|
if !ok {
|
|
return 0, false, nil
|
|
}
|
|
u32 := mustGetUint32(fc.intValue)
|
|
f = math.Float32frombits(u32)
|
|
return f, true, nil
|
|
}
|
|
|
|
func decodeZigZagInt64(u64 uint64) int64 {
|
|
return int64(u64>>1) ^ (int64(u64<<63) >> 63)
|
|
}
|
|
|
|
func decodeZigZagInt32(u32 uint32) int32 {
|
|
return int32(u32>>1) ^ (int32(u32<<31) >> 31)
|
|
}
|
|
|
|
func unsafeBytesToString(b []byte) string {
|
|
return *(*string)(unsafe.Pointer(&b))
|
|
}
|
|
|
|
func getInt32(u64 uint64) (int32, bool) {
|
|
u32, ok := getUint32(u64)
|
|
if !ok {
|
|
return 0, false
|
|
}
|
|
return int32(u32), true
|
|
}
|
|
|
|
func getUint32(u64 uint64) (uint32, bool) {
|
|
if u64 > math.MaxUint32 {
|
|
return 0, false
|
|
}
|
|
return uint32(u64), true
|
|
}
|
|
|
|
func mustGetInt32(u64 uint64) int32 {
|
|
u32 := mustGetUint32(u64)
|
|
return int32(u32)
|
|
}
|
|
|
|
func mustGetUint32(u64 uint64) uint32 {
|
|
u32, ok := getUint32(u64)
|
|
if !ok {
|
|
panic(fmt.Errorf("BUG: cannot get uint32 from %d", u64))
|
|
}
|
|
return u32
|
|
}
|
|
|
|
func getBool(u64 uint64) (bool, bool) {
|
|
if u64 == 0 {
|
|
return false, true
|
|
}
|
|
if u64 == 1 {
|
|
return true, true
|
|
}
|
|
return false, false
|
|
}
|