This commit is contained in:
2026-02-19 10:07:43 +00:00
parent 007438e372
commit 6e637ecf77
1763 changed files with 60820 additions and 279516 deletions

View File

@@ -4,6 +4,7 @@
package cbor
import (
"bytes"
"encoding"
"encoding/base64"
"encoding/binary"
@@ -94,7 +95,7 @@ import (
//
// To unmarshal CBOR null (0xf6) and undefined (0xf7) values into a
// slice/map/pointer, Unmarshal sets Go value to nil. Because null is often
// used to mean "not present", unmarshalling CBOR null and undefined value
// used to mean "not present", unmarshaling CBOR null and undefined value
// into any other Go type has no effect and returns no error.
//
// Unmarshal supports CBOR tag 55799 (self-describe CBOR), tag 0 and 1 (time),
@@ -104,7 +105,7 @@ import (
// if there are any remaining bytes following the first valid CBOR data item.
// See UnmarshalFirst, if you want to unmarshal only the first
// CBOR data item without ExtraneousDataError caused by remaining bytes.
func Unmarshal(data []byte, v interface{}) error {
func Unmarshal(data []byte, v any) error {
return defaultDecMode.Unmarshal(data, v)
}
@@ -114,7 +115,7 @@ func Unmarshal(data []byte, v interface{}) error {
// If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
//
// See the documentation for Unmarshal for details.
func UnmarshalFirst(data []byte, v interface{}) (rest []byte, err error) {
func UnmarshalFirst(data []byte, v any) (rest []byte, err error) {
return defaultDecMode.UnmarshalFirst(data, v)
}
@@ -151,6 +152,10 @@ type Unmarshaler interface {
UnmarshalCBOR([]byte) error
}
type unmarshaler interface {
unmarshalCBOR([]byte) error
}
// InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
type InvalidUnmarshalError struct {
s string
@@ -193,12 +198,12 @@ func (e *InvalidMapKeyTypeError) Error() string {
// DupMapKeyError describes detected duplicate map key in CBOR map.
type DupMapKeyError struct {
Key interface{}
Key any
Index int
}
func (e *DupMapKeyError) Error() string {
return fmt.Sprintf("cbor: found duplicate map key \"%v\" at map element index %d", e.Key, e.Index)
return fmt.Sprintf("cbor: found duplicate map key %#v at map element index %d", e.Key, e.Index)
}
// UnknownFieldError describes detected unknown field in CBOR map when decoding to Go struct.
@@ -383,7 +388,7 @@ const (
// - return UnmarshalTypeError if value doesn't fit into int64
IntDecConvertSignedOrFail
// IntDecConvertSigned affects how CBOR integers (major type 0 and 1) decode to Go interface{}.
// IntDecConvertSignedOrBigInt affects how CBOR integers (major type 0 and 1) decode to Go interface{}.
// It makes CBOR integers (major type 0 and 1) decode to:
// - int64 if value fits
// - big.Int or *big.Int (see BigIntDecMode) if value doesn't fit into int64
@@ -489,11 +494,11 @@ type BigIntDecMode int
const (
// BigIntDecodeValue makes CBOR bignum decode to big.Int (instead of *big.Int)
// when unmarshalling into a Go interface{}.
// when unmarshaling into a Go interface{}.
BigIntDecodeValue BigIntDecMode = iota
// BigIntDecodePointer makes CBOR bignum decode to *big.Int when
// unmarshalling into a Go interface{}.
// unmarshaling into a Go interface{}.
BigIntDecodePointer
maxBigIntDecMode
@@ -745,6 +750,25 @@ func (bum BinaryUnmarshalerMode) valid() bool {
return bum >= 0 && bum < maxBinaryUnmarshalerMode
}
// TextUnmarshalerMode specifies how to decode into types that implement
// encoding.TextUnmarshaler.
type TextUnmarshalerMode int
const (
// TextUnmarshalerNone does not recognize TextUnmarshaler implementations during decode.
TextUnmarshalerNone TextUnmarshalerMode = iota
// TextUnmarshalerTextString will invoke UnmarshalText on the contents of a CBOR text
// string when decoding into a value that implements TextUnmarshaler.
TextUnmarshalerTextString
maxTextUnmarshalerMode
)
func (tum TextUnmarshalerMode) valid() bool {
return tum >= 0 && tum < maxTextUnmarshalerMode
}
// DecOptions specifies decoding options.
type DecOptions struct {
// DupMapKey specifies whether to enforce duplicate map key.
@@ -793,7 +817,7 @@ type DecOptions struct {
// TagsMd specifies whether to allow CBOR tags (major type 6).
TagsMd TagsMode
// IntDec specifies which Go integer type (int64 or uint64) to use
// IntDec specifies which Go integer type (int64, uint64, or [big.Int]) to use
// when decoding CBOR int (major type 0 and 1) to Go interface{}.
IntDec IntDecMode
@@ -807,7 +831,7 @@ type DecOptions struct {
ExtraReturnErrors ExtraDecErrorCond
// DefaultMapType specifies Go map type to create and decode to
// when unmarshalling CBOR into an empty interface value.
// when unmarshaling CBOR into an empty interface value.
// By default, unmarshal uses map[interface{}]interface{}.
DefaultMapType reflect.Type
@@ -879,6 +903,15 @@ type DecOptions struct {
// BinaryUnmarshaler specifies how to decode into types that implement
// encoding.BinaryUnmarshaler.
BinaryUnmarshaler BinaryUnmarshalerMode
// TextUnmarshaler specifies how to decode into types that implement
// encoding.TextUnmarshaler.
TextUnmarshaler TextUnmarshalerMode
// JSONUnmarshalerTranscoder sets the transcoding scheme used to unmarshal types that
// implement json.Unmarshaler but do not also implement cbor.Unmarshaler. If nil, decoding
// behavior is not influenced by whether or not a type implements json.Unmarshaler.
JSONUnmarshalerTranscoder Transcoder
}
// DecMode returns DecMode with immutable options and no tags (safe for concurrency).
@@ -1091,33 +1124,39 @@ func (opts DecOptions) decMode() (*decMode, error) { //nolint:gocritic // ignore
return nil, errors.New("cbor: invalid BinaryUnmarshaler " + strconv.Itoa(int(opts.BinaryUnmarshaler)))
}
if !opts.TextUnmarshaler.valid() {
return nil, errors.New("cbor: invalid TextUnmarshaler " + strconv.Itoa(int(opts.TextUnmarshaler)))
}
dm := decMode{
dupMapKey: opts.DupMapKey,
timeTag: opts.TimeTag,
maxNestedLevels: opts.MaxNestedLevels,
maxArrayElements: opts.MaxArrayElements,
maxMapPairs: opts.MaxMapPairs,
indefLength: opts.IndefLength,
tagsMd: opts.TagsMd,
intDec: opts.IntDec,
mapKeyByteString: opts.MapKeyByteString,
extraReturnErrors: opts.ExtraReturnErrors,
defaultMapType: opts.DefaultMapType,
utf8: opts.UTF8,
fieldNameMatching: opts.FieldNameMatching,
bigIntDec: opts.BigIntDec,
defaultByteStringType: opts.DefaultByteStringType,
byteStringToString: opts.ByteStringToString,
fieldNameByteString: opts.FieldNameByteString,
unrecognizedTagToAny: opts.UnrecognizedTagToAny,
timeTagToAny: opts.TimeTagToAny,
simpleValues: simpleValues,
nanDec: opts.NaN,
infDec: opts.Inf,
byteStringToTime: opts.ByteStringToTime,
byteStringExpectedFormat: opts.ByteStringExpectedFormat,
bignumTag: opts.BignumTag,
binaryUnmarshaler: opts.BinaryUnmarshaler,
dupMapKey: opts.DupMapKey,
timeTag: opts.TimeTag,
maxNestedLevels: opts.MaxNestedLevels,
maxArrayElements: opts.MaxArrayElements,
maxMapPairs: opts.MaxMapPairs,
indefLength: opts.IndefLength,
tagsMd: opts.TagsMd,
intDec: opts.IntDec,
mapKeyByteString: opts.MapKeyByteString,
extraReturnErrors: opts.ExtraReturnErrors,
defaultMapType: opts.DefaultMapType,
utf8: opts.UTF8,
fieldNameMatching: opts.FieldNameMatching,
bigIntDec: opts.BigIntDec,
defaultByteStringType: opts.DefaultByteStringType,
byteStringToString: opts.ByteStringToString,
fieldNameByteString: opts.FieldNameByteString,
unrecognizedTagToAny: opts.UnrecognizedTagToAny,
timeTagToAny: opts.TimeTagToAny,
simpleValues: simpleValues,
nanDec: opts.NaN,
infDec: opts.Inf,
byteStringToTime: opts.ByteStringToTime,
byteStringExpectedFormat: opts.ByteStringExpectedFormat,
bignumTag: opts.BignumTag,
binaryUnmarshaler: opts.BinaryUnmarshaler,
textUnmarshaler: opts.TextUnmarshaler,
jsonUnmarshalerTranscoder: opts.JSONUnmarshalerTranscoder,
}
return &dm, nil
@@ -1130,7 +1169,7 @@ type DecMode interface {
// Unmarshal returns an error.
//
// See the documentation for Unmarshal for details.
Unmarshal(data []byte, v interface{}) error
Unmarshal(data []byte, v any) error
// UnmarshalFirst parses the first CBOR data item into the value pointed to by v
// using the decoding mode. Any remaining bytes are returned in rest.
@@ -1138,7 +1177,7 @@ type DecMode interface {
// If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
//
// See the documentation for Unmarshal for details.
UnmarshalFirst(data []byte, v interface{}) (rest []byte, err error)
UnmarshalFirst(data []byte, v any) (rest []byte, err error)
// Valid checks whether data is a well-formed encoded CBOR data item and
// that it complies with configurable restrictions such as MaxNestedLevels,
@@ -1170,33 +1209,35 @@ type DecMode interface {
}
type decMode struct {
tags tagProvider
dupMapKey DupMapKeyMode
timeTag DecTagMode
maxNestedLevels int
maxArrayElements int
maxMapPairs int
indefLength IndefLengthMode
tagsMd TagsMode
intDec IntDecMode
mapKeyByteString MapKeyByteStringMode
extraReturnErrors ExtraDecErrorCond
defaultMapType reflect.Type
utf8 UTF8Mode
fieldNameMatching FieldNameMatchingMode
bigIntDec BigIntDecMode
defaultByteStringType reflect.Type
byteStringToString ByteStringToStringMode
fieldNameByteString FieldNameByteStringMode
unrecognizedTagToAny UnrecognizedTagToAnyMode
timeTagToAny TimeTagToAnyMode
simpleValues *SimpleValueRegistry
nanDec NaNMode
infDec InfMode
byteStringToTime ByteStringToTimeMode
byteStringExpectedFormat ByteStringExpectedFormatMode
bignumTag BignumTagMode
binaryUnmarshaler BinaryUnmarshalerMode
tags tagProvider
dupMapKey DupMapKeyMode
timeTag DecTagMode
maxNestedLevels int
maxArrayElements int
maxMapPairs int
indefLength IndefLengthMode
tagsMd TagsMode
intDec IntDecMode
mapKeyByteString MapKeyByteStringMode
extraReturnErrors ExtraDecErrorCond
defaultMapType reflect.Type
utf8 UTF8Mode
fieldNameMatching FieldNameMatchingMode
bigIntDec BigIntDecMode
defaultByteStringType reflect.Type
byteStringToString ByteStringToStringMode
fieldNameByteString FieldNameByteStringMode
unrecognizedTagToAny UnrecognizedTagToAnyMode
timeTagToAny TimeTagToAnyMode
simpleValues *SimpleValueRegistry
nanDec NaNMode
infDec InfMode
byteStringToTime ByteStringToTimeMode
byteStringExpectedFormat ByteStringExpectedFormatMode
bignumTag BignumTagMode
binaryUnmarshaler BinaryUnmarshalerMode
textUnmarshaler TextUnmarshalerMode
jsonUnmarshalerTranscoder Transcoder
}
var defaultDecMode, _ = DecOptions{}.decMode()
@@ -1211,32 +1252,34 @@ func (dm *decMode) DecOptions() DecOptions {
}
return DecOptions{
DupMapKey: dm.dupMapKey,
TimeTag: dm.timeTag,
MaxNestedLevels: dm.maxNestedLevels,
MaxArrayElements: dm.maxArrayElements,
MaxMapPairs: dm.maxMapPairs,
IndefLength: dm.indefLength,
TagsMd: dm.tagsMd,
IntDec: dm.intDec,
MapKeyByteString: dm.mapKeyByteString,
ExtraReturnErrors: dm.extraReturnErrors,
DefaultMapType: dm.defaultMapType,
UTF8: dm.utf8,
FieldNameMatching: dm.fieldNameMatching,
BigIntDec: dm.bigIntDec,
DefaultByteStringType: dm.defaultByteStringType,
ByteStringToString: dm.byteStringToString,
FieldNameByteString: dm.fieldNameByteString,
UnrecognizedTagToAny: dm.unrecognizedTagToAny,
TimeTagToAny: dm.timeTagToAny,
SimpleValues: simpleValues,
NaN: dm.nanDec,
Inf: dm.infDec,
ByteStringToTime: dm.byteStringToTime,
ByteStringExpectedFormat: dm.byteStringExpectedFormat,
BignumTag: dm.bignumTag,
BinaryUnmarshaler: dm.binaryUnmarshaler,
DupMapKey: dm.dupMapKey,
TimeTag: dm.timeTag,
MaxNestedLevels: dm.maxNestedLevels,
MaxArrayElements: dm.maxArrayElements,
MaxMapPairs: dm.maxMapPairs,
IndefLength: dm.indefLength,
TagsMd: dm.tagsMd,
IntDec: dm.intDec,
MapKeyByteString: dm.mapKeyByteString,
ExtraReturnErrors: dm.extraReturnErrors,
DefaultMapType: dm.defaultMapType,
UTF8: dm.utf8,
FieldNameMatching: dm.fieldNameMatching,
BigIntDec: dm.bigIntDec,
DefaultByteStringType: dm.defaultByteStringType,
ByteStringToString: dm.byteStringToString,
FieldNameByteString: dm.fieldNameByteString,
UnrecognizedTagToAny: dm.unrecognizedTagToAny,
TimeTagToAny: dm.timeTagToAny,
SimpleValues: simpleValues,
NaN: dm.nanDec,
Inf: dm.infDec,
ByteStringToTime: dm.byteStringToTime,
ByteStringExpectedFormat: dm.byteStringExpectedFormat,
BignumTag: dm.bignumTag,
BinaryUnmarshaler: dm.binaryUnmarshaler,
TextUnmarshaler: dm.textUnmarshaler,
JSONUnmarshalerTranscoder: dm.jsonUnmarshalerTranscoder,
}
}
@@ -1245,7 +1288,7 @@ func (dm *decMode) DecOptions() DecOptions {
// Unmarshal returns an error.
//
// See the documentation for Unmarshal for details.
func (dm *decMode) Unmarshal(data []byte, v interface{}) error {
func (dm *decMode) Unmarshal(data []byte, v any) error {
d := decoder{data: data, dm: dm}
// Check well-formedness.
@@ -1265,7 +1308,7 @@ func (dm *decMode) Unmarshal(data []byte, v interface{}) error {
// If v is nil, not a pointer, or a nil pointer, UnmarshalFirst returns an error.
//
// See the documentation for Unmarshal for details.
func (dm *decMode) UnmarshalFirst(data []byte, v interface{}) (rest []byte, err error) {
func (dm *decMode) UnmarshalFirst(data []byte, v any) (rest []byte, err error) {
d := decoder{data: data, dm: dm}
// check well-formedness.
@@ -1341,13 +1384,13 @@ type decoder struct {
// If CBOR data item fails to be decoded into v,
// error is returned and offset is moved to the next CBOR data item.
// Precondition: d.data contains at least one well-formed CBOR data item.
func (d *decoder) value(v interface{}) error {
func (d *decoder) value(v any) error {
// v can't be nil, non-pointer, or nil pointer value.
if v == nil {
return &InvalidUnmarshalError{"cbor: Unmarshal(nil)"}
}
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr {
if rv.Kind() != reflect.Pointer {
return &InvalidUnmarshalError{"cbor: Unmarshal(non-pointer " + rv.Type().String() + ")"}
} else if rv.IsNil() {
return &InvalidUnmarshalError{"cbor: Unmarshal(nil " + rv.Type().String() + ")"}
@@ -1361,9 +1404,9 @@ func (d *decoder) value(v interface{}) error {
func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolint:gocyclo
// Decode CBOR nil or CBOR undefined to pointer value by setting pointer value to nil.
if d.nextCBORNil() && v.Kind() == reflect.Ptr {
if d.nextCBORNil() && v.Kind() == reflect.Pointer {
d.skip()
v.Set(reflect.Zero(v.Type()))
v.SetZero()
return nil
}
@@ -1387,7 +1430,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
registeredType := d.dm.tags.getTypeFromTagNum(tagNums)
if registeredType != nil {
if registeredType.Implements(tInfo.nonPtrType) ||
reflect.PtrTo(registeredType).Implements(tInfo.nonPtrType) {
reflect.PointerTo(registeredType).Implements(tInfo.nonPtrType) {
v.Set(reflect.New(registeredType))
v = v.Elem()
tInfo = getTypeInfo(registeredType)
@@ -1399,7 +1442,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
// Create new value for the pointer v to point to.
// At this point, CBOR value is not nil/undefined if v is a pointer.
for v.Kind() == reflect.Ptr {
for v.Kind() == reflect.Pointer {
if v.IsNil() {
if !v.CanSet() {
d.skip()
@@ -1460,6 +1503,17 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
case specialTypeUnmarshalerIface:
return d.parseToUnmarshaler(v)
case specialTypeUnexportedUnmarshalerIface:
return d.parseToUnexportedUnmarshaler(v)
case specialTypeJSONUnmarshalerIface:
// This special type implies that the type does not also implement
// cbor.Umarshaler.
if d.dm.jsonUnmarshalerTranscoder == nil {
break
}
return d.parseToJSONUnmarshaler(v)
}
}
@@ -1516,14 +1570,14 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
return err
}
copied = copied || converted
return fillByteString(t, b, !copied, v, d.dm.byteStringToString, d.dm.binaryUnmarshaler)
return fillByteString(t, b, !copied, v, d.dm.byteStringToString, d.dm.binaryUnmarshaler, d.dm.textUnmarshaler)
case cborTypeTextString:
b, err := d.parseTextString()
if err != nil {
return err
}
return fillTextString(t, b, v)
return fillTextString(t, b, v, d.dm.textUnmarshaler)
case cborTypePrimitives:
_, ai, val := d.getHead()
@@ -1575,7 +1629,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
return nil
}
if tInfo.nonPtrKind == reflect.Slice || tInfo.nonPtrKind == reflect.Array {
return fillByteString(t, b, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler)
return fillByteString(t, b, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler, d.dm.textUnmarshaler)
}
if bi.IsUint64() {
return fillPositiveInt(t, bi.Uint64(), v)
@@ -1598,7 +1652,7 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
return nil
}
if tInfo.nonPtrKind == reflect.Slice || tInfo.nonPtrKind == reflect.Array {
return fillByteString(t, b, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler)
return fillByteString(t, b, !copied, v, ByteStringToStringForbidden, d.dm.binaryUnmarshaler, d.dm.textUnmarshaler)
}
if bi.IsInt64() {
return fillNegativeInt(t, bi.Int64(), v)
@@ -1788,12 +1842,12 @@ func (d *decoder) parseToTime() (time.Time, bool, error) {
// parseToUnmarshaler parses CBOR data to value implementing Unmarshaler interface.
// It assumes data is well-formed, and does not perform bounds checking.
func (d *decoder) parseToUnmarshaler(v reflect.Value) error {
if d.nextCBORNil() && v.Kind() == reflect.Ptr && v.IsNil() {
if d.nextCBORNil() && v.Kind() == reflect.Pointer && v.IsNil() {
d.skip()
return nil
}
if v.Kind() != reflect.Ptr && v.CanAddr() {
if v.Kind() != reflect.Pointer && v.CanAddr() {
v = v.Addr()
}
if u, ok := v.Interface().(Unmarshaler); ok {
@@ -1805,9 +1859,55 @@ func (d *decoder) parseToUnmarshaler(v reflect.Value) error {
return errors.New("cbor: failed to assert " + v.Type().String() + " as cbor.Unmarshaler")
}
// parseToUnexportedUnmarshaler parses CBOR data to value implementing unmarshaler interface.
// It assumes data is well-formed, and does not perform bounds checking.
func (d *decoder) parseToUnexportedUnmarshaler(v reflect.Value) error {
if d.nextCBORNil() && v.Kind() == reflect.Pointer && v.IsNil() {
d.skip()
return nil
}
if v.Kind() != reflect.Pointer && v.CanAddr() {
v = v.Addr()
}
if u, ok := v.Interface().(unmarshaler); ok {
start := d.off
d.skip()
return u.unmarshalCBOR(d.data[start:d.off])
}
d.skip()
return errors.New("cbor: failed to assert " + v.Type().String() + " as cbor.unmarshaler")
}
// parseToJSONUnmarshaler parses CBOR data to be transcoded to JSON and passed to the value's
// implementation of the json.Unmarshaler interface. It assumes data is well-formed, and does not
// perform bounds checking.
func (d *decoder) parseToJSONUnmarshaler(v reflect.Value) error {
if d.nextCBORNil() && v.Kind() == reflect.Pointer && v.IsNil() {
d.skip()
return nil
}
if v.Kind() != reflect.Pointer && v.CanAddr() {
v = v.Addr()
}
if u, ok := v.Interface().(jsonUnmarshaler); ok {
start := d.off
d.skip()
e := getEncodeBuffer()
defer putEncodeBuffer(e)
if err := d.dm.jsonUnmarshalerTranscoder.Transcode(e, bytes.NewReader(d.data[start:d.off])); err != nil {
return &TranscodeError{err: err, rtype: v.Type(), sourceFormat: "cbor", targetFormat: "json"}
}
return u.UnmarshalJSON(e.Bytes())
}
d.skip()
return errors.New("cbor: failed to assert " + v.Type().String() + " as json.Unmarshaler")
}
// parse parses CBOR data and returns value in default Go type.
// It assumes data is well-formed, and does not perform bounds checking.
func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //nolint:gocyclo
func (d *decoder) parse(skipSelfDescribedTag bool) (any, error) { //nolint:gocyclo
// Strip self-described CBOR tag number.
if skipSelfDescribedTag {
for d.nextCBORType() == cborTypeTag {
@@ -2224,15 +2324,15 @@ func (d *decoder) parseTextString() ([]byte, error) {
return b, nil
}
func (d *decoder) parseArray() ([]interface{}, error) {
func (d *decoder) parseArray() ([]any, error) {
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
hasSize := !indefiniteLength
count := int(val)
if !hasSize {
count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance
}
v := make([]interface{}, count)
var e interface{}
v := make([]any, count)
var e any
var err, lastErr error
for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ {
if e, lastErr = d.parse(true); lastErr != nil {
@@ -2290,20 +2390,19 @@ func (d *decoder) parseArrayToArray(v reflect.Value, tInfo *typeInfo) error {
}
// Set remaining Go array elements to zero values.
if gi < vLen {
zeroV := reflect.Zero(tInfo.elemTypeInfo.typ)
for ; gi < vLen; gi++ {
v.Index(gi).Set(zeroV)
v.Index(gi).SetZero()
}
}
return err
}
func (d *decoder) parseMap() (interface{}, error) {
func (d *decoder) parseMap() (any, error) {
_, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag()
hasSize := !indefiniteLength
count := int(val)
m := make(map[interface{}]interface{})
var k, e interface{}
m := make(map[any]any)
var k, e any
var err, lastErr error
keyCount := 0
for i := 0; (hasSize && i < count) || (!hasSize && !d.foundBreak()); i++ {
@@ -2376,13 +2475,13 @@ func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //noli
}
keyType, eleType := tInfo.keyTypeInfo.typ, tInfo.elemTypeInfo.typ
reuseKey, reuseEle := isImmutableKind(tInfo.keyTypeInfo.kind), isImmutableKind(tInfo.elemTypeInfo.kind)
var keyValue, eleValue, zeroKeyValue, zeroEleValue reflect.Value
var keyValue, eleValue reflect.Value
keyIsInterfaceType := keyType == typeIntf // If key type is interface{}, need to check if key value is hashable.
var err, lastErr error
keyCount := v.Len()
var existingKeys map[interface{}]bool // Store existing map keys, used for detecting duplicate map key.
var existingKeys map[any]bool // Store existing map keys, used for detecting duplicate map key.
if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
existingKeys = make(map[interface{}]bool, keyCount)
existingKeys = make(map[any]bool, keyCount)
if keyCount > 0 {
vKeys := v.MapKeys()
for i := 0; i < len(vKeys); i++ {
@@ -2395,10 +2494,7 @@ func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //noli
if !keyValue.IsValid() {
keyValue = reflect.New(keyType).Elem()
} else if !reuseKey {
if !zeroKeyValue.IsValid() {
zeroKeyValue = reflect.Zero(keyType)
}
keyValue.Set(zeroKeyValue)
keyValue.SetZero()
}
if lastErr = d.parseToValue(keyValue, tInfo.keyTypeInfo); lastErr != nil {
if err == nil {
@@ -2413,7 +2509,7 @@ func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //noli
if !isHashableValue(keyValue.Elem()) {
var converted bool
if d.dm.mapKeyByteString == MapKeyByteStringAllowed {
var k interface{}
var k any
k, converted = convertByteSliceToByteString(keyValue.Elem().Interface())
if converted {
keyValue.Set(reflect.ValueOf(k))
@@ -2433,10 +2529,7 @@ func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //noli
if !eleValue.IsValid() {
eleValue = reflect.New(eleType).Elem()
} else if !reuseEle {
if !zeroEleValue.IsValid() {
zeroEleValue = reflect.Zero(eleType)
}
eleValue.Set(zeroEleValue)
eleValue.SetZero()
}
if lastErr := d.parseToValue(eleValue, tInfo.elemTypeInfo); lastErr != nil {
if err == nil {
@@ -2584,7 +2677,7 @@ func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //n
// Keeps track of CBOR map keys to detect duplicate map key
keyCount := 0
var mapKeys map[interface{}]struct{}
var mapKeys map[any]struct{}
errOnUnknownField := (d.dm.extraReturnErrors & ExtraDecErrorUnknownField) > 0
@@ -2594,7 +2687,7 @@ MapEntryLoop:
// If duplicate field detection is enabled and the key at index j did not match any
// field, k will hold the map key.
var k interface{}
var k any
t := d.nextCBORType()
if t == cborTypeTextString || (t == cborTypeByteString && d.dm.fieldNameByteString == FieldNameByteStringAllowed) {
@@ -2764,7 +2857,7 @@ MapEntryLoop:
// check is never reached.
if d.dm.dupMapKey == DupMapKeyEnforcedAPF {
if mapKeys == nil {
mapKeys = make(map[interface{}]struct{}, 1)
mapKeys = make(map[any]struct{}, 1)
}
mapKeys[k] = struct{}{}
newKeyCount := len(mapKeys)
@@ -2968,20 +3061,25 @@ func (d *decoder) nextCBORNil() bool {
return d.data[d.off] == 0xf6 || d.data[d.off] == 0xf7
}
type jsonUnmarshaler interface{ UnmarshalJSON([]byte) error }
var (
typeIntf = reflect.TypeOf([]interface{}(nil)).Elem()
typeTime = reflect.TypeOf(time.Time{})
typeBigInt = reflect.TypeOf(big.Int{})
typeUnmarshaler = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
typeBinaryUnmarshaler = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()
typeString = reflect.TypeOf("")
typeByteSlice = reflect.TypeOf([]byte(nil))
typeIntf = reflect.TypeOf([]any(nil)).Elem()
typeTime = reflect.TypeOf(time.Time{})
typeBigInt = reflect.TypeOf(big.Int{})
typeUnmarshaler = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
typeUnexportedUnmarshaler = reflect.TypeOf((*unmarshaler)(nil)).Elem()
typeBinaryUnmarshaler = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()
typeTextUnmarshaler = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
typeJSONUnmarshaler = reflect.TypeOf((*jsonUnmarshaler)(nil)).Elem()
typeString = reflect.TypeOf("")
typeByteSlice = reflect.TypeOf([]byte(nil))
)
func fillNil(_ cborType, v reflect.Value) error {
switch v.Kind() {
case reflect.Slice, reflect.Map, reflect.Interface, reflect.Ptr:
v.Set(reflect.Zero(v.Type()))
case reflect.Slice, reflect.Map, reflect.Interface, reflect.Pointer:
v.SetZero()
return nil
}
return nil
@@ -3082,8 +3180,8 @@ func fillFloat(t cborType, val float64, v reflect.Value) error {
return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()}
}
func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts ByteStringToStringMode, bum BinaryUnmarshalerMode) error {
if bum == BinaryUnmarshalerByteString && reflect.PtrTo(v.Type()).Implements(typeBinaryUnmarshaler) {
func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts ByteStringToStringMode, bum BinaryUnmarshalerMode, tum TextUnmarshalerMode) error {
if bum == BinaryUnmarshalerByteString && reflect.PointerTo(v.Type()).Implements(typeBinaryUnmarshaler) {
if v.CanAddr() {
v = v.Addr()
if u, ok := v.Interface().(encoding.BinaryUnmarshaler); ok {
@@ -3095,9 +3193,26 @@ func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts B
}
return errors.New("cbor: cannot set new value for " + v.Type().String())
}
if bsts != ByteStringToStringForbidden && v.Kind() == reflect.String {
v.SetString(string(val))
return nil
if bsts != ByteStringToStringForbidden {
if tum == TextUnmarshalerTextString && reflect.PointerTo(v.Type()).Implements(typeTextUnmarshaler) {
if v.CanAddr() {
v = v.Addr()
if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
// The contract of TextUnmarshaler forbids retaining the input
// bytes, so no copying is required even if val is shared.
if err := u.UnmarshalText(val); err != nil {
return fmt.Errorf("cbor: cannot unmarshal text for %s: %w", v.Type(), err)
}
return nil
}
}
return errors.New("cbor: cannot set new value for " + v.Type().String())
}
if v.Kind() == reflect.String {
v.SetString(string(val))
return nil
}
}
if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 {
src := val
@@ -3117,9 +3232,8 @@ func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts B
}
// Set remaining Go array elements to zero values.
if i < vLen {
zeroV := reflect.Zero(reflect.TypeOf(byte(0)))
for ; i < vLen; i++ {
v.Index(i).Set(zeroV)
v.Index(i).SetZero()
}
}
return nil
@@ -3127,11 +3241,28 @@ func fillByteString(t cborType, val []byte, shared bool, v reflect.Value, bsts B
return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()}
}
func fillTextString(t cborType, val []byte, v reflect.Value) error {
func fillTextString(t cborType, val []byte, v reflect.Value, tum TextUnmarshalerMode) error {
// Check if the value implements TextUnmarshaler and the mode allows it
if tum == TextUnmarshalerTextString && reflect.PointerTo(v.Type()).Implements(typeTextUnmarshaler) {
if v.CanAddr() {
v = v.Addr()
if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
// The contract of TextUnmarshaler forbids retaining the input
// bytes, so no copying is required even if val is shared.
if err := u.UnmarshalText(val); err != nil {
return fmt.Errorf("cbor: cannot unmarshal text for %s: %w", v.Type(), err)
}
return nil
}
}
return errors.New("cbor: cannot set new value for " + v.Type().String())
}
if v.Kind() == reflect.String {
v.SetString(string(val))
return nil
}
return &UnmarshalTypeError{CBORType: t.String(), GoType: v.Type().String()}
}
@@ -3172,7 +3303,7 @@ func isHashableValue(rv reflect.Value) bool {
// This function also handles nested tags.
// CBOR data is already verified to be well-formed before this function is used,
// so the recursion won't exceed max nested levels.
func convertByteSliceToByteString(v interface{}) (interface{}, bool) {
func convertByteSliceToByteString(v any) (any, bool) {
switch v := v.(type) {
case []byte:
return ByteString(v), true