mirror of
https://github.com/kubernetes-sigs/descheduler.git
synced 2026-01-28 14:41:10 +01:00
[v0.34.0] bump to kubernetes 1.34 deps
Signed-off-by: Amir Alavi <amiralavi7@gmail.com>
This commit is contained in:
442
vendor/github.com/fxamacker/cbor/v2/encode.go
generated
vendored
442
vendor/github.com/fxamacker/cbor/v2/encode.go
generated
vendored
@@ -58,8 +58,10 @@ import (
|
||||
//
|
||||
// Marshal supports format string stored under the "cbor" key in the struct
|
||||
// field's tag. CBOR format string can specify the name of the field,
|
||||
// "omitempty" and "keyasint" options, and special case "-" for field omission.
|
||||
// If "cbor" key is absent, Marshal uses "json" key.
|
||||
// "omitempty", "omitzero" and "keyasint" options, and special case "-" for
|
||||
// field omission. If "cbor" key is absent, Marshal uses "json" key.
|
||||
// When using the "json" key, the "omitzero" option is honored when building
|
||||
// with Go 1.24+ to match stdlib encoding/json behavior.
|
||||
//
|
||||
// Struct field name is treated as integer if it has "keyasint" option in
|
||||
// its format string. The format string must specify an integer as its
|
||||
@@ -67,8 +69,8 @@ import (
|
||||
//
|
||||
// Special struct field "_" is used to specify struct level options, such as
|
||||
// "toarray". "toarray" option enables Go struct to be encoded as CBOR array.
|
||||
// "omitempty" is disabled by "toarray" to ensure that the same number
|
||||
// of elements are encoded every time.
|
||||
// "omitempty" and "omitzero" are disabled by "toarray" to ensure that the
|
||||
// same number of elements are encoded every time.
|
||||
//
|
||||
// Anonymous struct fields are marshaled as if their exported fields
|
||||
// were fields in the outer struct. Marshal follows the same struct fields
|
||||
@@ -92,7 +94,7 @@ import (
|
||||
//
|
||||
// Values of other types cannot be encoded in CBOR. Attempting
|
||||
// to encode such a value causes Marshal to return an UnsupportedTypeError.
|
||||
func Marshal(v interface{}) ([]byte, error) {
|
||||
func Marshal(v any) ([]byte, error) {
|
||||
return defaultEncMode.Marshal(v)
|
||||
}
|
||||
|
||||
@@ -103,7 +105,7 @@ func Marshal(v interface{}) ([]byte, error) {
|
||||
// partially encoded data if error is returned.
|
||||
//
|
||||
// See Marshal for more details.
|
||||
func MarshalToBuffer(v interface{}, buf *bytes.Buffer) error {
|
||||
func MarshalToBuffer(v any, buf *bytes.Buffer) error {
|
||||
return defaultEncMode.MarshalToBuffer(v, buf)
|
||||
}
|
||||
|
||||
@@ -130,6 +132,20 @@ func (e *MarshalerError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
type TranscodeError struct {
|
||||
err error
|
||||
rtype reflect.Type
|
||||
sourceFormat, targetFormat string
|
||||
}
|
||||
|
||||
func (e TranscodeError) Error() string {
|
||||
return "cbor: cannot transcode from " + e.sourceFormat + " to " + e.targetFormat + ": " + e.err.Error()
|
||||
}
|
||||
|
||||
func (e TranscodeError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
// UnsupportedTypeError is returned by Marshal when attempting to encode value
|
||||
// of an unsupported type.
|
||||
type UnsupportedTypeError struct {
|
||||
@@ -291,24 +307,51 @@ func (icm InfConvertMode) valid() bool {
|
||||
return icm >= 0 && icm < maxInfConvert
|
||||
}
|
||||
|
||||
// TimeMode specifies how to encode time.Time values.
|
||||
// TimeMode specifies how to encode time.Time values in compliance with RFC 8949 (CBOR):
|
||||
// - Section 3.4.1: Standard Date/Time String
|
||||
// - Section 3.4.2: Epoch-Based Date/Time
|
||||
// For more info, see:
|
||||
// - https://www.rfc-editor.org/rfc/rfc8949.html
|
||||
// NOTE: User applications that prefer to encode time with fractional seconds to an integer
|
||||
// (instead of floating point or text string) can use a CBOR tag number not assigned by IANA:
|
||||
// 1. Define a user-defined type in Go with just a time.Time or int64 as its data.
|
||||
// 2. Implement the cbor.Marshaler and cbor.Unmarshaler interface for that user-defined type
|
||||
// to encode or decode the tagged data item with an enclosed integer content.
|
||||
type TimeMode int
|
||||
|
||||
const (
|
||||
// TimeUnix causes time.Time to be encoded as epoch time in integer with second precision.
|
||||
// TimeUnix causes time.Time to encode to a CBOR time (tag 1) with an integer content
|
||||
// representing seconds elapsed (with 1-second precision) since UNIX Epoch UTC.
|
||||
// The TimeUnix option is location independent and has a clear precision guarantee.
|
||||
TimeUnix TimeMode = iota
|
||||
|
||||
// TimeUnixMicro causes time.Time to be encoded as epoch time in float-point rounded to microsecond precision.
|
||||
// TimeUnixMicro causes time.Time to encode to a CBOR time (tag 1) with a floating point content
|
||||
// representing seconds elapsed (with up to 1-microsecond precision) since UNIX Epoch UTC.
|
||||
// NOTE: The floating point content is encoded to the shortest floating-point encoding that preserves
|
||||
// the 64-bit floating point value. I.e., the floating point encoding can be IEEE 764:
|
||||
// binary64, binary32, or binary16 depending on the content's value.
|
||||
TimeUnixMicro
|
||||
|
||||
// TimeUnixDynamic causes time.Time to be encoded as integer if time.Time doesn't have fractional seconds,
|
||||
// otherwise float-point rounded to microsecond precision.
|
||||
// TimeUnixDynamic causes time.Time to encode to a CBOR time (tag 1) with either an integer content or
|
||||
// a floating point content, depending on the content's value. This option is equivalent to dynamically
|
||||
// choosing TimeUnix if time.Time doesn't have fractional seconds, and using TimeUnixMicro if time.Time
|
||||
// has fractional seconds.
|
||||
TimeUnixDynamic
|
||||
|
||||
// TimeRFC3339 causes time.Time to be encoded as RFC3339 formatted string with second precision.
|
||||
// TimeRFC3339 causes time.Time to encode to a CBOR time (tag 0) with a text string content
|
||||
// representing the time using 1-second precision in RFC3339 format. If the time.Time has a
|
||||
// non-UTC timezone then a "localtime - UTC" numeric offset will be included as specified in RFC3339.
|
||||
// NOTE: User applications can avoid including the RFC3339 numeric offset by:
|
||||
// - providing a time.Time value set to UTC, or
|
||||
// - using the TimeUnix, TimeUnixMicro, or TimeUnixDynamic option instead of TimeRFC3339.
|
||||
TimeRFC3339
|
||||
|
||||
// TimeRFC3339Nano causes time.Time to be encoded as RFC3339 formatted string with nanosecond precision.
|
||||
// TimeRFC3339Nano causes time.Time to encode to a CBOR time (tag 0) with a text string content
|
||||
// representing the time using 1-nanosecond precision in RFC3339 format. If the time.Time has a
|
||||
// non-UTC timezone then a "localtime - UTC" numeric offset will be included as specified in RFC3339.
|
||||
// NOTE: User applications can avoid including the RFC3339 numeric offset by:
|
||||
// - providing a time.Time value set to UTC, or
|
||||
// - using the TimeUnix, TimeUnixMicro, or TimeUnixDynamic option instead of TimeRFC3339Nano.
|
||||
TimeRFC3339Nano
|
||||
|
||||
maxTimeMode
|
||||
@@ -481,6 +524,24 @@ func (bmm BinaryMarshalerMode) valid() bool {
|
||||
return bmm >= 0 && bmm < maxBinaryMarshalerMode
|
||||
}
|
||||
|
||||
// TextMarshalerMode specifies how to encode types that implement encoding.TextMarshaler.
|
||||
type TextMarshalerMode int
|
||||
|
||||
const (
|
||||
// TextMarshalerNone does not recognize TextMarshaler implementations during encode.
|
||||
// This is the default behavior.
|
||||
TextMarshalerNone TextMarshalerMode = iota
|
||||
|
||||
// TextMarshalerTextString encodes the output of MarshalText to a CBOR text string.
|
||||
TextMarshalerTextString
|
||||
|
||||
maxTextMarshalerMode
|
||||
)
|
||||
|
||||
func (tmm TextMarshalerMode) valid() bool {
|
||||
return tmm >= 0 && tmm < maxTextMarshalerMode
|
||||
}
|
||||
|
||||
// EncOptions specifies encoding options.
|
||||
type EncOptions struct {
|
||||
// Sort specifies sorting order.
|
||||
@@ -538,6 +599,14 @@ type EncOptions struct {
|
||||
|
||||
// BinaryMarshaler specifies how to encode types that implement encoding.BinaryMarshaler.
|
||||
BinaryMarshaler BinaryMarshalerMode
|
||||
|
||||
// TextMarshaler specifies how to encode types that implement encoding.TextMarshaler.
|
||||
TextMarshaler TextMarshalerMode
|
||||
|
||||
// JSONMarshalerTranscoder sets the transcoding scheme used to marshal types that implement
|
||||
// json.Marshaler but do not also implement cbor.Marshaler. If nil, encoding behavior is not
|
||||
// influenced by whether or not a type implements json.Marshaler.
|
||||
JSONMarshalerTranscoder Transcoder
|
||||
}
|
||||
|
||||
// CanonicalEncOptions returns EncOptions for "Canonical CBOR" encoding,
|
||||
@@ -748,6 +817,9 @@ func (opts EncOptions) encMode() (*encMode, error) { //nolint:gocritic // ignore
|
||||
if !opts.BinaryMarshaler.valid() {
|
||||
return nil, errors.New("cbor: invalid BinaryMarshaler " + strconv.Itoa(int(opts.BinaryMarshaler)))
|
||||
}
|
||||
if !opts.TextMarshaler.valid() {
|
||||
return nil, errors.New("cbor: invalid TextMarshaler " + strconv.Itoa(int(opts.TextMarshaler)))
|
||||
}
|
||||
em := encMode{
|
||||
sort: opts.Sort,
|
||||
shortestFloat: opts.ShortestFloat,
|
||||
@@ -767,13 +839,15 @@ func (opts EncOptions) encMode() (*encMode, error) { //nolint:gocritic // ignore
|
||||
byteSliceLaterEncodingTag: byteSliceLaterEncodingTag,
|
||||
byteArray: opts.ByteArray,
|
||||
binaryMarshaler: opts.BinaryMarshaler,
|
||||
textMarshaler: opts.TextMarshaler,
|
||||
jsonMarshalerTranscoder: opts.JSONMarshalerTranscoder,
|
||||
}
|
||||
return &em, nil
|
||||
}
|
||||
|
||||
// EncMode is the main interface for CBOR encoding.
|
||||
type EncMode interface {
|
||||
Marshal(v interface{}) ([]byte, error)
|
||||
Marshal(v any) ([]byte, error)
|
||||
NewEncoder(w io.Writer) *Encoder
|
||||
EncOptions() EncOptions
|
||||
}
|
||||
@@ -783,7 +857,7 @@ type EncMode interface {
|
||||
// into the built-in buffer pool.
|
||||
type UserBufferEncMode interface {
|
||||
EncMode
|
||||
MarshalToBuffer(v interface{}, buf *bytes.Buffer) error
|
||||
MarshalToBuffer(v any, buf *bytes.Buffer) error
|
||||
|
||||
// This private method is to prevent users implementing
|
||||
// this interface and so future additions to it will
|
||||
@@ -812,6 +886,8 @@ type encMode struct {
|
||||
byteSliceLaterEncodingTag uint64
|
||||
byteArray ByteArrayMode
|
||||
binaryMarshaler BinaryMarshalerMode
|
||||
textMarshaler TextMarshalerMode
|
||||
jsonMarshalerTranscoder Transcoder
|
||||
}
|
||||
|
||||
var defaultEncMode, _ = EncOptions{}.encMode()
|
||||
@@ -888,22 +964,24 @@ func getMarshalerDecMode(indefLength IndefLengthMode, tagsMd TagsMode) *decMode
|
||||
// EncOptions returns user specified options used to create this EncMode.
|
||||
func (em *encMode) EncOptions() EncOptions {
|
||||
return EncOptions{
|
||||
Sort: em.sort,
|
||||
ShortestFloat: em.shortestFloat,
|
||||
NaNConvert: em.nanConvert,
|
||||
InfConvert: em.infConvert,
|
||||
BigIntConvert: em.bigIntConvert,
|
||||
Time: em.time,
|
||||
TimeTag: em.timeTag,
|
||||
IndefLength: em.indefLength,
|
||||
NilContainers: em.nilContainers,
|
||||
TagsMd: em.tagsMd,
|
||||
OmitEmpty: em.omitEmpty,
|
||||
String: em.stringType,
|
||||
FieldName: em.fieldName,
|
||||
ByteSliceLaterFormat: em.byteSliceLaterFormat,
|
||||
ByteArray: em.byteArray,
|
||||
BinaryMarshaler: em.binaryMarshaler,
|
||||
Sort: em.sort,
|
||||
ShortestFloat: em.shortestFloat,
|
||||
NaNConvert: em.nanConvert,
|
||||
InfConvert: em.infConvert,
|
||||
BigIntConvert: em.bigIntConvert,
|
||||
Time: em.time,
|
||||
TimeTag: em.timeTag,
|
||||
IndefLength: em.indefLength,
|
||||
NilContainers: em.nilContainers,
|
||||
TagsMd: em.tagsMd,
|
||||
OmitEmpty: em.omitEmpty,
|
||||
String: em.stringType,
|
||||
FieldName: em.fieldName,
|
||||
ByteSliceLaterFormat: em.byteSliceLaterFormat,
|
||||
ByteArray: em.byteArray,
|
||||
BinaryMarshaler: em.binaryMarshaler,
|
||||
TextMarshaler: em.textMarshaler,
|
||||
JSONMarshalerTranscoder: em.jsonMarshalerTranscoder,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -921,7 +999,7 @@ func (em *encMode) encTagBytes(t reflect.Type) []byte {
|
||||
// Marshal returns the CBOR encoding of v using em encoding mode.
|
||||
//
|
||||
// See the documentation for Marshal for details.
|
||||
func (em *encMode) Marshal(v interface{}) ([]byte, error) {
|
||||
func (em *encMode) Marshal(v any) ([]byte, error) {
|
||||
e := getEncodeBuffer()
|
||||
|
||||
if err := encode(e, em, reflect.ValueOf(v)); err != nil {
|
||||
@@ -943,7 +1021,7 @@ func (em *encMode) Marshal(v interface{}) ([]byte, error) {
|
||||
// partially encoded data if error is returned.
|
||||
//
|
||||
// See Marshal for more details.
|
||||
func (em *encMode) MarshalToBuffer(v interface{}, buf *bytes.Buffer) error {
|
||||
func (em *encMode) MarshalToBuffer(v any, buf *bytes.Buffer) error {
|
||||
if buf == nil {
|
||||
return fmt.Errorf("cbor: encoding buffer provided by user is nil")
|
||||
}
|
||||
@@ -957,7 +1035,7 @@ func (em *encMode) NewEncoder(w io.Writer) *Encoder {
|
||||
|
||||
// encodeBufferPool caches unused bytes.Buffer objects for later reuse.
|
||||
var encodeBufferPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
e := new(bytes.Buffer)
|
||||
e.Grow(32) // TODO: make this configurable
|
||||
return e
|
||||
@@ -975,6 +1053,7 @@ func putEncodeBuffer(e *bytes.Buffer) {
|
||||
|
||||
type encodeFunc func(e *bytes.Buffer, em *encMode, v reflect.Value) error
|
||||
type isEmptyFunc func(em *encMode, v reflect.Value) (empty bool, err error)
|
||||
type isZeroFunc func(v reflect.Value) (zero bool, err error)
|
||||
|
||||
func encode(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
||||
if !v.IsValid() {
|
||||
@@ -983,7 +1062,7 @@ func encode(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
||||
return nil
|
||||
}
|
||||
vt := v.Type()
|
||||
f, _ := getEncodeFunc(vt)
|
||||
f, _, _ := getEncodeFunc(vt)
|
||||
if f == nil {
|
||||
return &UnsupportedTypeError{vt}
|
||||
}
|
||||
@@ -1483,6 +1562,15 @@ func encodeStruct(e *bytes.Buffer, em *encMode, v reflect.Value) (err error) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if f.omitZero {
|
||||
zero, err := f.izf(fv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if zero {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if !f.keyAsInt && em.fieldName == FieldNameToByteString {
|
||||
e.Write(f.cborNameByteString)
|
||||
@@ -1665,6 +1753,107 @@ func (bme binaryMarshalerEncoder) isEmpty(em *encMode, v reflect.Value) (bool, e
|
||||
return len(data) == 0, nil
|
||||
}
|
||||
|
||||
type textMarshalerEncoder struct {
|
||||
alternateEncode encodeFunc
|
||||
alternateIsEmpty isEmptyFunc
|
||||
}
|
||||
|
||||
func (tme textMarshalerEncoder) encode(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
||||
if em.textMarshaler == TextMarshalerNone {
|
||||
return tme.alternateEncode(e, em, v)
|
||||
}
|
||||
|
||||
vt := v.Type()
|
||||
m, ok := v.Interface().(encoding.TextMarshaler)
|
||||
if !ok {
|
||||
pv := reflect.New(vt)
|
||||
pv.Elem().Set(v)
|
||||
m = pv.Interface().(encoding.TextMarshaler)
|
||||
}
|
||||
data, err := m.MarshalText()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cbor: cannot marshal text for %s: %w", vt, err)
|
||||
}
|
||||
if b := em.encTagBytes(vt); b != nil {
|
||||
e.Write(b)
|
||||
}
|
||||
|
||||
encodeHead(e, byte(cborTypeTextString), uint64(len(data)))
|
||||
e.Write(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tme textMarshalerEncoder) isEmpty(em *encMode, v reflect.Value) (bool, error) {
|
||||
if em.textMarshaler == TextMarshalerNone {
|
||||
return tme.alternateIsEmpty(em, v)
|
||||
}
|
||||
|
||||
m, ok := v.Interface().(encoding.TextMarshaler)
|
||||
if !ok {
|
||||
pv := reflect.New(v.Type())
|
||||
pv.Elem().Set(v)
|
||||
m = pv.Interface().(encoding.TextMarshaler)
|
||||
}
|
||||
data, err := m.MarshalText()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cbor: cannot marshal text for %s: %w", v.Type(), err)
|
||||
}
|
||||
return len(data) == 0, nil
|
||||
}
|
||||
|
||||
type jsonMarshalerEncoder struct {
|
||||
alternateEncode encodeFunc
|
||||
alternateIsEmpty isEmptyFunc
|
||||
}
|
||||
|
||||
func (jme jsonMarshalerEncoder) encode(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
||||
if em.jsonMarshalerTranscoder == nil {
|
||||
return jme.alternateEncode(e, em, v)
|
||||
}
|
||||
|
||||
vt := v.Type()
|
||||
m, ok := v.Interface().(jsonMarshaler)
|
||||
if !ok {
|
||||
pv := reflect.New(vt)
|
||||
pv.Elem().Set(v)
|
||||
m = pv.Interface().(jsonMarshaler)
|
||||
}
|
||||
|
||||
json, err := m.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
offset := e.Len()
|
||||
|
||||
if b := em.encTagBytes(vt); b != nil {
|
||||
e.Write(b)
|
||||
}
|
||||
|
||||
if err := em.jsonMarshalerTranscoder.Transcode(e, bytes.NewReader(json)); err != nil {
|
||||
return &TranscodeError{err: err, rtype: vt, sourceFormat: "json", targetFormat: "cbor"}
|
||||
}
|
||||
|
||||
// Validate that the transcode function has written exactly one well-formed data item.
|
||||
d := decoder{data: e.Bytes()[offset:], dm: getMarshalerDecMode(em.indefLength, em.tagsMd)}
|
||||
if err := d.wellformed(false, true); err != nil {
|
||||
e.Truncate(offset)
|
||||
return &TranscodeError{err: err, rtype: vt, sourceFormat: "json", targetFormat: "cbor"}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (jme jsonMarshalerEncoder) isEmpty(em *encMode, v reflect.Value) (bool, error) {
|
||||
if em.jsonMarshalerTranscoder == nil {
|
||||
return jme.alternateIsEmpty(em, v)
|
||||
}
|
||||
|
||||
// As with types implementing cbor.Marshaler, transcoded json.Marshaler values always encode
|
||||
// as exactly one complete CBOR data item.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func encodeMarshalerType(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
||||
if em.tagsMd == TagsForbidden && v.Type() == typeRawTag {
|
||||
return errors.New("cbor: cannot encode cbor.RawTag when TagsMd is TagsForbidden")
|
||||
@@ -1768,41 +1957,45 @@ func encodeHead(e *bytes.Buffer, t byte, n uint64) int {
|
||||
return headSize
|
||||
}
|
||||
|
||||
type jsonMarshaler interface{ MarshalJSON() ([]byte, error) }
|
||||
|
||||
var (
|
||||
typeMarshaler = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
||||
typeBinaryMarshaler = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem()
|
||||
typeTextMarshaler = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
typeJSONMarshaler = reflect.TypeOf((*jsonMarshaler)(nil)).Elem()
|
||||
typeRawMessage = reflect.TypeOf(RawMessage(nil))
|
||||
typeByteString = reflect.TypeOf(ByteString(""))
|
||||
)
|
||||
|
||||
func getEncodeFuncInternal(t reflect.Type) (ef encodeFunc, ief isEmptyFunc) {
|
||||
func getEncodeFuncInternal(t reflect.Type) (ef encodeFunc, ief isEmptyFunc, izf isZeroFunc) {
|
||||
k := t.Kind()
|
||||
if k == reflect.Ptr {
|
||||
return getEncodeIndirectValueFunc(t), isEmptyPtr
|
||||
if k == reflect.Pointer {
|
||||
return getEncodeIndirectValueFunc(t), isEmptyPtr, getIsZeroFunc(t)
|
||||
}
|
||||
switch t {
|
||||
case typeSimpleValue:
|
||||
return encodeMarshalerType, isEmptyUint
|
||||
return encodeMarshalerType, isEmptyUint, getIsZeroFunc(t)
|
||||
|
||||
case typeTag:
|
||||
return encodeTag, alwaysNotEmpty
|
||||
return encodeTag, alwaysNotEmpty, getIsZeroFunc(t)
|
||||
|
||||
case typeTime:
|
||||
return encodeTime, alwaysNotEmpty
|
||||
return encodeTime, alwaysNotEmpty, getIsZeroFunc(t)
|
||||
|
||||
case typeBigInt:
|
||||
return encodeBigInt, alwaysNotEmpty
|
||||
return encodeBigInt, alwaysNotEmpty, getIsZeroFunc(t)
|
||||
|
||||
case typeRawMessage:
|
||||
return encodeMarshalerType, isEmptySlice
|
||||
return encodeMarshalerType, isEmptySlice, getIsZeroFunc(t)
|
||||
|
||||
case typeByteString:
|
||||
return encodeMarshalerType, isEmptyString
|
||||
return encodeMarshalerType, isEmptyString, getIsZeroFunc(t)
|
||||
}
|
||||
if reflect.PtrTo(t).Implements(typeMarshaler) {
|
||||
return encodeMarshalerType, alwaysNotEmpty
|
||||
if reflect.PointerTo(t).Implements(typeMarshaler) {
|
||||
return encodeMarshalerType, alwaysNotEmpty, getIsZeroFunc(t)
|
||||
}
|
||||
if reflect.PtrTo(t).Implements(typeBinaryMarshaler) {
|
||||
if reflect.PointerTo(t).Implements(typeBinaryMarshaler) {
|
||||
defer func() {
|
||||
// capture encoding method used for modes that disable BinaryMarshaler
|
||||
bme := binaryMarshalerEncoder{
|
||||
@@ -1813,41 +2006,65 @@ func getEncodeFuncInternal(t reflect.Type) (ef encodeFunc, ief isEmptyFunc) {
|
||||
ief = bme.isEmpty
|
||||
}()
|
||||
}
|
||||
if reflect.PointerTo(t).Implements(typeTextMarshaler) {
|
||||
defer func() {
|
||||
// capture encoding method used for modes that disable TextMarshaler
|
||||
tme := textMarshalerEncoder{
|
||||
alternateEncode: ef,
|
||||
alternateIsEmpty: ief,
|
||||
}
|
||||
ef = tme.encode
|
||||
ief = tme.isEmpty
|
||||
}()
|
||||
}
|
||||
if reflect.PointerTo(t).Implements(typeJSONMarshaler) {
|
||||
defer func() {
|
||||
// capture encoding method used for modes that don't support transcoding
|
||||
// from types that implement json.Marshaler.
|
||||
jme := jsonMarshalerEncoder{
|
||||
alternateEncode: ef,
|
||||
alternateIsEmpty: ief,
|
||||
}
|
||||
ef = jme.encode
|
||||
ief = jme.isEmpty
|
||||
}()
|
||||
}
|
||||
|
||||
switch k {
|
||||
case reflect.Bool:
|
||||
return encodeBool, isEmptyBool
|
||||
return encodeBool, isEmptyBool, getIsZeroFunc(t)
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return encodeInt, isEmptyInt
|
||||
return encodeInt, isEmptyInt, getIsZeroFunc(t)
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return encodeUint, isEmptyUint
|
||||
return encodeUint, isEmptyUint, getIsZeroFunc(t)
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return encodeFloat, isEmptyFloat
|
||||
return encodeFloat, isEmptyFloat, getIsZeroFunc(t)
|
||||
|
||||
case reflect.String:
|
||||
return encodeString, isEmptyString
|
||||
return encodeString, isEmptyString, getIsZeroFunc(t)
|
||||
|
||||
case reflect.Slice:
|
||||
if t.Elem().Kind() == reflect.Uint8 {
|
||||
return encodeByteString, isEmptySlice
|
||||
return encodeByteString, isEmptySlice, getIsZeroFunc(t)
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case reflect.Array:
|
||||
f, _ := getEncodeFunc(t.Elem())
|
||||
f, _, _ := getEncodeFunc(t.Elem())
|
||||
if f == nil {
|
||||
return nil, nil
|
||||
return nil, nil, nil
|
||||
}
|
||||
return arrayEncodeFunc{f: f}.encode, isEmptySlice
|
||||
return arrayEncodeFunc{f: f}.encode, isEmptySlice, getIsZeroFunc(t)
|
||||
|
||||
case reflect.Map:
|
||||
f := getEncodeMapFunc(t)
|
||||
if f == nil {
|
||||
return nil, nil
|
||||
return nil, nil, nil
|
||||
}
|
||||
return f, isEmptyMap
|
||||
return f, isEmptyMap, getIsZeroFunc(t)
|
||||
|
||||
case reflect.Struct:
|
||||
// Get struct's special field "_" tag options
|
||||
@@ -1855,31 +2072,31 @@ func getEncodeFuncInternal(t reflect.Type) (ef encodeFunc, ief isEmptyFunc) {
|
||||
tag := f.Tag.Get("cbor")
|
||||
if tag != "-" {
|
||||
if hasToArrayOption(tag) {
|
||||
return encodeStructToArray, isEmptyStruct
|
||||
return encodeStructToArray, isEmptyStruct, isZeroFieldStruct
|
||||
}
|
||||
}
|
||||
}
|
||||
return encodeStruct, isEmptyStruct
|
||||
return encodeStruct, isEmptyStruct, getIsZeroFunc(t)
|
||||
|
||||
case reflect.Interface:
|
||||
return encodeIntf, isEmptyIntf
|
||||
return encodeIntf, isEmptyIntf, getIsZeroFunc(t)
|
||||
}
|
||||
return nil, nil
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func getEncodeIndirectValueFunc(t reflect.Type) encodeFunc {
|
||||
for t.Kind() == reflect.Ptr {
|
||||
for t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
f, _ := getEncodeFunc(t)
|
||||
f, _, _ := getEncodeFunc(t)
|
||||
if f == nil {
|
||||
return nil
|
||||
}
|
||||
return func(e *bytes.Buffer, em *encMode, v reflect.Value) error {
|
||||
for v.Kind() == reflect.Ptr && !v.IsNil() {
|
||||
for v.Kind() == reflect.Pointer && !v.IsNil() {
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
if v.Kind() == reflect.Pointer && v.IsNil() {
|
||||
e.Write(cborNil)
|
||||
return nil
|
||||
}
|
||||
@@ -1987,3 +2204,96 @@ func float32NaNFromReflectValue(v reflect.Value) float32 {
|
||||
f32 := p.Convert(reflect.TypeOf((*float32)(nil))).Elem().Interface().(float32)
|
||||
return f32
|
||||
}
|
||||
|
||||
type isZeroer interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
var isZeroerType = reflect.TypeOf((*isZeroer)(nil)).Elem()
|
||||
|
||||
// getIsZeroFunc returns a function for the given type that can be called to determine if a given value is zero.
|
||||
// Types that implement `IsZero() bool` are delegated to for non-nil values.
|
||||
// Types that do not implement `IsZero() bool` use the reflect.Value#IsZero() implementation.
|
||||
// The returned function matches behavior of stdlib encoding/json behavior in Go 1.24+.
|
||||
func getIsZeroFunc(t reflect.Type) isZeroFunc {
|
||||
// Provide a function that uses a type's IsZero method if defined.
|
||||
switch {
|
||||
case t == nil:
|
||||
return isZeroDefault
|
||||
case t.Kind() == reflect.Interface && t.Implements(isZeroerType):
|
||||
return isZeroInterfaceCustom
|
||||
case t.Kind() == reflect.Pointer && t.Implements(isZeroerType):
|
||||
return isZeroPointerCustom
|
||||
case t.Implements(isZeroerType):
|
||||
return isZeroCustom
|
||||
case reflect.PointerTo(t).Implements(isZeroerType):
|
||||
return isZeroAddrCustom
|
||||
default:
|
||||
return isZeroDefault
|
||||
}
|
||||
}
|
||||
|
||||
// isZeroInterfaceCustom returns true for nil or pointer-to-nil values,
|
||||
// and delegates to the custom IsZero() implementation otherwise.
|
||||
func isZeroInterfaceCustom(v reflect.Value) (bool, error) {
|
||||
kind := v.Kind()
|
||||
|
||||
switch kind {
|
||||
case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.Interface, reflect.Slice:
|
||||
if v.IsNil() {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Interface, reflect.Pointer:
|
||||
if elem := v.Elem(); elem.Kind() == reflect.Pointer && elem.IsNil() {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return v.Interface().(isZeroer).IsZero(), nil
|
||||
}
|
||||
|
||||
// isZeroPointerCustom returns true for nil values,
|
||||
// and delegates to the custom IsZero() implementation otherwise.
|
||||
func isZeroPointerCustom(v reflect.Value) (bool, error) {
|
||||
if v.IsNil() {
|
||||
return true, nil
|
||||
}
|
||||
return v.Interface().(isZeroer).IsZero(), nil
|
||||
}
|
||||
|
||||
// isZeroCustom delegates to the custom IsZero() implementation.
|
||||
func isZeroCustom(v reflect.Value) (bool, error) {
|
||||
return v.Interface().(isZeroer).IsZero(), nil
|
||||
}
|
||||
|
||||
// isZeroAddrCustom delegates to the custom IsZero() implementation of the addr of the value.
|
||||
func isZeroAddrCustom(v reflect.Value) (bool, error) {
|
||||
if !v.CanAddr() {
|
||||
// Temporarily box v so we can take the address.
|
||||
v2 := reflect.New(v.Type()).Elem()
|
||||
v2.Set(v)
|
||||
v = v2
|
||||
}
|
||||
return v.Addr().Interface().(isZeroer).IsZero(), nil
|
||||
}
|
||||
|
||||
// isZeroDefault calls reflect.Value#IsZero()
|
||||
func isZeroDefault(v reflect.Value) (bool, error) {
|
||||
if !v.IsValid() {
|
||||
// v is zero value
|
||||
return true, nil
|
||||
}
|
||||
return v.IsZero(), nil
|
||||
}
|
||||
|
||||
// isZeroFieldStruct is used to determine whether to omit toarray structs
|
||||
func isZeroFieldStruct(v reflect.Value) (bool, error) {
|
||||
structType, err := getEncodingStructType(v.Type())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return len(structType.fields) == 0, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user