mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 16:12:25 -05:00
- github.com/KimMachineGun/automemlimit v0.7.2 => v0.7.3
- github.com/gin-contrib/cors v1.7.5 => v1.7.6
- github.com/minio/minio-go/v7 v7.0.92 => v7.0.94
- github.com/spf13/cast v1.8.0 => v1.9.2
- github.com/uptrace/bun{,/*} v1.2.11 => v1.2.14
- golang.org/x/image v0.27.0 => v0.28.0
- golang.org/x/net v0.40.0 => v0.41.0
- code.superseriousbusiness.org/go-swagger v0.31.0-gts-go1.23-fix => v0.32.3-gts-go1.23-fix
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4304
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
944 lines
28 KiB
Go
944 lines
28 KiB
Go
// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
|
|
// Use of this source code is governed by a MIT license found in the LICENSE file.
|
|
|
|
package codec
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"math"
|
|
"reflect"
|
|
"slices"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
func init() {
|
|
for _, v := range []interface{}{
|
|
(*string)(nil),
|
|
(*bool)(nil),
|
|
(*int)(nil),
|
|
(*int8)(nil),
|
|
(*int16)(nil),
|
|
(*int32)(nil),
|
|
(*int64)(nil),
|
|
(*uint)(nil),
|
|
(*uint8)(nil),
|
|
(*uint16)(nil),
|
|
(*uint32)(nil),
|
|
(*uint64)(nil),
|
|
(*uintptr)(nil),
|
|
(*float32)(nil),
|
|
(*float64)(nil),
|
|
(*complex64)(nil),
|
|
(*complex128)(nil),
|
|
(*[]byte)(nil),
|
|
([]byte)(nil),
|
|
(*time.Time)(nil),
|
|
(*Raw)(nil),
|
|
(*interface{})(nil),
|
|
} {
|
|
decBuiltinRtids = append(decBuiltinRtids, i2rtid(v))
|
|
}
|
|
slices.Sort(decBuiltinRtids)
|
|
}
|
|
|
|
const msgBadDesc = "unrecognized descriptor byte"
|
|
|
|
var decBuiltinRtids []uintptr
|
|
|
|
// decDriver calls (DecodeBytes and DecodeStringAsBytes) return a state
|
|
// of the view they return, allowing consumers to handle appropriately.
|
|
//
|
|
// sequencing of this is intentional:
|
|
// - mutable if <= dBytesAttachBuffer (buf | view | invalid)
|
|
// - noCopy if >= dBytesAttachViewZerocopy
|
|
type dBytesAttachState uint8
|
|
|
|
const (
|
|
dBytesAttachInvalid dBytesAttachState = iota
|
|
dBytesAttachView // (bytes && !zerocopy && !buf)
|
|
dBytesAttachBuffer // (buf)
|
|
dBytesAttachViewZerocopy // (bytes && zerocopy && !buf)
|
|
dBytesDetach // (!bytes && !buf)
|
|
)
|
|
|
|
type dBytesIntoState uint8
|
|
|
|
const (
|
|
dBytesIntoNoChange dBytesIntoState = iota
|
|
dBytesIntoParamOut
|
|
dBytesIntoParamOutSlice
|
|
dBytesIntoNew
|
|
)
|
|
|
|
func (x dBytesAttachState) String() string {
|
|
switch x {
|
|
case dBytesAttachInvalid:
|
|
return "invalid"
|
|
case dBytesAttachView:
|
|
return "view"
|
|
case dBytesAttachBuffer:
|
|
return "buffer"
|
|
case dBytesAttachViewZerocopy:
|
|
return "view-zerocopy"
|
|
case dBytesDetach:
|
|
return "detach"
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
const (
|
|
decDefMaxDepth = 1024 // maximum depth
|
|
decDefChanCap = 64 // should be large, as cap cannot be expanded
|
|
decScratchByteArrayLen = (4 + 3) * 8 // around cacheLineSize ie ~64, depending on Decoder size
|
|
|
|
// MARKER: massage decScratchByteArrayLen to ensure xxxDecDriver structs fit within cacheLine*N
|
|
|
|
// decFailNonEmptyIntf configures whether we error
|
|
// when decoding naked into a non-empty interface.
|
|
//
|
|
// Typically, we cannot decode non-nil stream value into
|
|
// nil interface with methods (e.g. io.Reader).
|
|
// However, in some scenarios, this should be allowed:
|
|
// - MapType
|
|
// - SliceType
|
|
// - Extensions
|
|
//
|
|
// Consequently, we should relax this. Put it behind a const flag for now.
|
|
decFailNonEmptyIntf = false
|
|
|
|
// decUseTransient says whether we should use the transient optimization.
|
|
//
|
|
// There's potential for GC corruption or memory overwrites if transient isn't
|
|
// used carefully, so this flag helps turn it off quickly if needed.
|
|
//
|
|
// Use it everywhere needed so we can completely remove unused code blocks.
|
|
decUseTransient = true
|
|
)
|
|
|
|
var (
|
|
errNeedMapOrArrayDecodeToStruct = errors.New("only encoded map or array can decode into struct")
|
|
errCannotDecodeIntoNil = errors.New("cannot decode into nil")
|
|
|
|
errExpandSliceCannotChange = errors.New("expand slice: cannot change")
|
|
|
|
errDecoderNotInitialized = errors.New("Decoder not initialized")
|
|
|
|
errDecUnreadByteNothingToRead = errors.New("cannot unread - nothing has been read")
|
|
errDecUnreadByteLastByteNotRead = errors.New("cannot unread - last byte has not been read")
|
|
errDecUnreadByteUnknown = errors.New("cannot unread - reason unknown")
|
|
errMaxDepthExceeded = errors.New("maximum decoding depth exceeded")
|
|
)
|
|
|
|
type decNotDecodeableReason uint8
|
|
|
|
const (
|
|
decNotDecodeableReasonUnknown decNotDecodeableReason = iota
|
|
decNotDecodeableReasonBadKind
|
|
decNotDecodeableReasonNonAddrValue
|
|
decNotDecodeableReasonNilReference
|
|
)
|
|
|
|
type decDriverI interface {
|
|
|
|
// this will check if the next token is a break.
|
|
CheckBreak() bool
|
|
|
|
// TryNil tries to decode as nil.
|
|
// If a nil is in the stream, it consumes it and returns true.
|
|
//
|
|
// Note: if TryNil returns true, that must be handled.
|
|
TryNil() bool
|
|
|
|
// ContainerType returns one of: Bytes, String, Nil, Slice or Map.
|
|
//
|
|
// Return unSet if not known.
|
|
//
|
|
// Note: Implementations MUST fully consume sentinel container types, specifically Nil.
|
|
ContainerType() (vt valueType)
|
|
|
|
// DecodeNaked will decode primitives (number, bool, string, []byte) and RawExt.
|
|
// For maps and arrays, it will not do the decoding in-band, but will signal
|
|
// the decoder, so that is done later, by setting the fauxUnion.valueType field.
|
|
//
|
|
// Note: Numbers are decoded as int64, uint64, float64 only (no smaller sized number types).
|
|
// for extensions, DecodeNaked must read the tag and the []byte if it exists.
|
|
// if the []byte is not read, then kInterfaceNaked will treat it as a Handle
|
|
// that stores the subsequent value in-band, and complete reading the RawExt.
|
|
//
|
|
// extensions should also use readx to decode them, for efficiency.
|
|
// kInterface will extract the detached byte slice if it has to pass it outside its realm.
|
|
DecodeNaked()
|
|
|
|
DecodeInt64() (i int64)
|
|
DecodeUint64() (ui uint64)
|
|
|
|
DecodeFloat32() (f float32)
|
|
DecodeFloat64() (f float64)
|
|
|
|
DecodeBool() (b bool)
|
|
|
|
// DecodeStringAsBytes returns the bytes representing a string.
|
|
// It will return a view into scratch buffer or input []byte (if applicable).
|
|
//
|
|
// Note: This can also decode symbols, if supported.
|
|
//
|
|
// Users should consume it right away and not store it for later use.
|
|
DecodeStringAsBytes() (v []byte, state dBytesAttachState)
|
|
|
|
// DecodeBytes returns the bytes representing a binary value.
|
|
// It will return a view into scratch buffer or input []byte (if applicable).
|
|
DecodeBytes() (out []byte, state dBytesAttachState)
|
|
// DecodeBytes(bs []byte, isstring, zerocopy bool) (bsOut []byte)
|
|
|
|
// DecodeExt will decode into an extension.
|
|
// ext is never nil.
|
|
DecodeExt(v interface{}, basetype reflect.Type, xtag uint64, ext Ext)
|
|
// decodeExt(verifyTag bool, tag byte) (xtag byte, xbs []byte)
|
|
|
|
// DecodeRawExt will decode into a *RawExt
|
|
DecodeRawExt(re *RawExt)
|
|
|
|
DecodeTime() (t time.Time)
|
|
|
|
// ReadArrayStart will return the length of the array.
|
|
// If the format doesn't prefix the length, it returns containerLenUnknown.
|
|
// If the expected array was a nil in the stream, it returns containerLenNil.
|
|
ReadArrayStart() int
|
|
|
|
// ReadMapStart will return the length of the array.
|
|
// If the format doesn't prefix the length, it returns containerLenUnknown.
|
|
// If the expected array was a nil in the stream, it returns containerLenNil.
|
|
ReadMapStart() int
|
|
|
|
decDriverContainerTracker
|
|
|
|
reset()
|
|
|
|
// atEndOfDecode()
|
|
|
|
// nextValueBytes will return the bytes representing the next value in the stream.
|
|
// It generally will include the last byte read, as that is a part of the next value
|
|
// in the stream.
|
|
nextValueBytes() []byte
|
|
|
|
// descBd will describe the token descriptor that signifies what type was decoded
|
|
descBd() string
|
|
|
|
// isBytes() bool
|
|
|
|
resetInBytes(in []byte)
|
|
resetInIO(r io.Reader)
|
|
|
|
NumBytesRead() int
|
|
|
|
init(h Handle, shared *decoderBase, dec decoderI) (fp interface{})
|
|
|
|
// driverStateManager
|
|
decNegintPosintFloatNumber
|
|
}
|
|
|
|
type decInit2er struct{}
|
|
|
|
func (decInit2er) init2(dec decoderI) {}
|
|
|
|
type decDriverContainerTracker interface {
|
|
ReadArrayElem(firstTime bool)
|
|
ReadMapElemKey(firstTime bool)
|
|
ReadMapElemValue()
|
|
ReadArrayEnd()
|
|
ReadMapEnd()
|
|
}
|
|
|
|
type decNegintPosintFloatNumber interface {
|
|
decInteger() (ui uint64, neg, ok bool)
|
|
decFloat() (f float64, ok bool)
|
|
}
|
|
|
|
type decDriverNoopNumberHelper struct{}
|
|
|
|
func (x decDriverNoopNumberHelper) decInteger() (ui uint64, neg, ok bool) {
|
|
panic("decInteger unsupported")
|
|
}
|
|
func (x decDriverNoopNumberHelper) decFloat() (f float64, ok bool) { panic("decFloat unsupported") }
|
|
|
|
type decDriverNoopContainerReader struct{}
|
|
|
|
func (x decDriverNoopContainerReader) ReadArrayStart() (v int) { panic("ReadArrayStart unsupported") }
|
|
func (x decDriverNoopContainerReader) ReadMapStart() (v int) { panic("ReadMapStart unsupported") }
|
|
func (x decDriverNoopContainerReader) ReadArrayEnd() {}
|
|
func (x decDriverNoopContainerReader) ReadMapEnd() {}
|
|
func (x decDriverNoopContainerReader) ReadArrayElem(firstTime bool) {}
|
|
func (x decDriverNoopContainerReader) ReadMapElemKey(firstTime bool) {}
|
|
func (x decDriverNoopContainerReader) ReadMapElemValue() {}
|
|
func (x decDriverNoopContainerReader) CheckBreak() (v bool) { return }
|
|
|
|
// ----
|
|
|
|
type decFnInfo struct {
|
|
ti *typeInfo
|
|
xfFn Ext
|
|
xfTag uint64
|
|
addrD bool // decoding into a pointer is preferred
|
|
addrDf bool // force: if addrD, then decode function MUST take a ptr
|
|
}
|
|
|
|
// DecodeOptions captures configuration options during decode.
|
|
type DecodeOptions struct {
|
|
// MapType specifies type to use during schema-less decoding of a map in the stream.
|
|
// If nil (unset), we default to map[string]interface{} iff json handle and MapKeyAsString=true,
|
|
// else map[interface{}]interface{}.
|
|
MapType reflect.Type
|
|
|
|
// SliceType specifies type to use during schema-less decoding of an array in the stream.
|
|
// If nil (unset), we default to []interface{} for all formats.
|
|
SliceType reflect.Type
|
|
|
|
// MaxInitLen defines the maxinum initial length that we "make" a collection
|
|
// (string, slice, map, chan). If 0 or negative, we default to a sensible value
|
|
// based on the size of an element in the collection.
|
|
//
|
|
// For example, when decoding, a stream may say that it has 2^64 elements.
|
|
// We should not auto-matically provision a slice of that size, to prevent Out-Of-Memory crash.
|
|
// Instead, we provision up to MaxInitLen, fill that up, and start appending after that.
|
|
MaxInitLen int
|
|
|
|
// ReaderBufferSize is the size of the buffer used when reading.
|
|
//
|
|
// if > 0, we use a smart buffer internally for performance purposes.
|
|
ReaderBufferSize int
|
|
|
|
// MaxDepth defines the maximum depth when decoding nested
|
|
// maps and slices. If 0 or negative, we default to a suitably large number (currently 1024).
|
|
MaxDepth int16
|
|
|
|
// If ErrorIfNoField, return an error when decoding a map
|
|
// from a codec stream into a struct, and no matching struct field is found.
|
|
ErrorIfNoField bool
|
|
|
|
// If ErrorIfNoArrayExpand, return an error when decoding a slice/array that cannot be expanded.
|
|
// For example, the stream contains an array of 8 items, but you are decoding into a [4]T array,
|
|
// or you are decoding into a slice of length 4 which is non-addressable (and so cannot be set).
|
|
ErrorIfNoArrayExpand bool
|
|
|
|
// If SignedInteger, use the int64 during schema-less decoding of unsigned values (not uint64).
|
|
SignedInteger bool
|
|
|
|
// MapValueReset controls how we decode into a map value.
|
|
//
|
|
// By default, we MAY retrieve the mapping for a key, and then decode into that.
|
|
// However, especially with big maps, that retrieval may be expensive and unnecessary
|
|
// if the stream already contains all that is necessary to recreate the value.
|
|
//
|
|
// If true, we will never retrieve the previous mapping,
|
|
// but rather decode into a new value and set that in the map.
|
|
//
|
|
// If false, we will retrieve the previous mapping if necessary e.g.
|
|
// the previous mapping is a pointer, or is a struct or array with pre-set state,
|
|
// or is an interface.
|
|
MapValueReset bool
|
|
|
|
// SliceElementReset: on decoding a slice, reset the element to a zero value first.
|
|
//
|
|
// concern: if the slice already contained some garbage, we will decode into that garbage.
|
|
SliceElementReset bool
|
|
|
|
// InterfaceReset controls how we decode into an interface.
|
|
//
|
|
// By default, when we see a field that is an interface{...},
|
|
// or a map with interface{...} value, we will attempt decoding into the
|
|
// "contained" value.
|
|
//
|
|
// However, this prevents us from reading a string into an interface{}
|
|
// that formerly contained a number.
|
|
//
|
|
// If true, we will decode into a new "blank" value, and set that in the interface.
|
|
// If false, we will decode into whatever is contained in the interface.
|
|
InterfaceReset bool
|
|
|
|
// InternString controls interning of strings during decoding.
|
|
//
|
|
// Some handles, e.g. json, typically will read map keys as strings.
|
|
// If the set of keys are finite, it may help reduce allocation to
|
|
// look them up from a map (than to allocate them afresh).
|
|
//
|
|
// Note: Handles will be smart when using the intern functionality.
|
|
// Every string should not be interned.
|
|
// An excellent use-case for interning is struct field names,
|
|
// or map keys where key type is string.
|
|
InternString bool
|
|
|
|
// PreferArrayOverSlice controls whether to decode to an array or a slice.
|
|
//
|
|
// This only impacts decoding into a nil interface{}.
|
|
//
|
|
// Consequently, it has no effect on codecgen.
|
|
//
|
|
// *Note*: This only applies if using go1.5 and above,
|
|
// as it requires reflect.ArrayOf support which was absent before go1.5.
|
|
PreferArrayOverSlice bool
|
|
|
|
// DeleteOnNilMapValue controls how to decode a nil value in the stream.
|
|
//
|
|
// If true, we will delete the mapping of the key.
|
|
// Else, just set the mapping to the zero value of the type.
|
|
//
|
|
// Deprecated: This does NOTHING and is left behind for compiling compatibility.
|
|
// This change is necessitated because 'nil' in a stream now consistently
|
|
// means the zero value (ie reset the value to its zero state).
|
|
DeleteOnNilMapValue bool
|
|
|
|
// RawToString controls how raw bytes in a stream are decoded into a nil interface{}.
|
|
// By default, they are decoded as []byte, but can be decoded as string (if configured).
|
|
RawToString bool
|
|
|
|
// ZeroCopy controls whether decoded values of []byte or string type
|
|
// point into the input []byte parameter passed to a NewDecoderBytes/ResetBytes(...) call.
|
|
//
|
|
// To illustrate, if ZeroCopy and decoding from a []byte (not io.Writer),
|
|
// then a []byte or string in the output result may just be a slice of (point into)
|
|
// the input bytes.
|
|
//
|
|
// This optimization prevents unnecessary copying.
|
|
//
|
|
// However, it is made optional, as the caller MUST ensure that the input parameter []byte is
|
|
// not modified after the Decode() happens, as any changes are mirrored in the decoded result.
|
|
ZeroCopy bool
|
|
|
|
// PreferPointerForStructOrArray controls whether a struct or array
|
|
// is stored in a nil interface{}, or a pointer to it.
|
|
//
|
|
// This mostly impacts when we decode registered extensions.
|
|
PreferPointerForStructOrArray bool
|
|
|
|
// ValidateUnicode controls will cause decoding to fail if an expected unicode
|
|
// string is well-formed but include invalid codepoints.
|
|
//
|
|
// This could have a performance impact.
|
|
ValidateUnicode bool
|
|
}
|
|
|
|
// ----------------------------------------
|
|
|
|
type decoderBase struct {
|
|
perType decPerType
|
|
|
|
h *BasicHandle
|
|
|
|
rtidFn, rtidFnNoExt *atomicRtidFnSlice
|
|
|
|
buf []byte
|
|
|
|
// used for interning strings
|
|
is internerMap
|
|
|
|
err error
|
|
|
|
// sd decoderI
|
|
|
|
blist bytesFreeList
|
|
|
|
mtr bool // is maptype a known type?
|
|
str bool // is slicetype a known type?
|
|
jsms bool // is json handle, and MapKeyAsString
|
|
|
|
bytes bool // uses a bytes reader
|
|
bufio bool // uses a ioDecReader with buffer size > 0
|
|
|
|
// ---- cpu cache line boundary?
|
|
// ---- writable fields during execution --- *try* to keep in sep cache line
|
|
maxdepth int16
|
|
depth int16
|
|
|
|
// Extensions can call Decode() within a current Decode() call.
|
|
// We need to know when the top level Decode() call returns,
|
|
// so we can decide whether to Release() or not.
|
|
calls uint16 // what depth in mustDecode are we in now.
|
|
|
|
c containerState
|
|
|
|
// decByteState
|
|
|
|
n fauxUnion
|
|
|
|
// b is an always-available scratch buffer used by Decoder and decDrivers.
|
|
// By being always-available, it can be used for one-off things without
|
|
// having to get from freelist, use, and return back to freelist.
|
|
//
|
|
// Use it for a narrow set of things e.g.
|
|
// - binc uses it for parsing numbers, represented at 8 or less bytes
|
|
// - uses as potential buffer for struct field names
|
|
b [decScratchByteArrayLen]byte
|
|
|
|
hh Handle
|
|
// cache the mapTypeId and sliceTypeId for faster comparisons
|
|
mtid uintptr
|
|
stid uintptr
|
|
}
|
|
|
|
func (d *decoderBase) maxInitLen() uint {
|
|
return uint(max(1024, d.h.MaxInitLen))
|
|
}
|
|
|
|
func (d *decoderBase) naked() *fauxUnion {
|
|
return &d.n
|
|
}
|
|
|
|
func (d *decoderBase) fauxUnionReadRawBytes(dr decDriverI, asString, rawToString bool) { //, handleZeroCopy bool) {
|
|
// fauxUnion is only used within DecodeNaked calls; consequently, we should try to intern.
|
|
d.n.l, d.n.a = dr.DecodeBytes()
|
|
if asString || rawToString {
|
|
d.n.v = valueTypeString
|
|
d.n.s = d.detach2Str(d.n.l, d.n.a)
|
|
} else {
|
|
d.n.v = valueTypeBytes
|
|
d.n.l = d.detach2Bytes(d.n.l, d.n.a)
|
|
}
|
|
}
|
|
|
|
// Return a fixed (detached) string representation of a []byte.
|
|
//
|
|
// Possibly get an interned version of a string,
|
|
// iff InternString=true and decoding a map key.
|
|
//
|
|
// This should mostly be used for map keys, struct field names, etc
|
|
// where the key type is string. This is because keys of a map/struct are
|
|
// typically reused across many objects.
|
|
func (d *decoderBase) detach2Str(v []byte, state dBytesAttachState) (s string) {
|
|
// note: string([]byte) checks - and optimizes - for len 0 and len 1
|
|
if len(v) <= 1 {
|
|
s = string(v)
|
|
} else if state >= dBytesAttachViewZerocopy { // !scratchBuf && d.bytes && d.h.ZeroCopy
|
|
s = stringView(v)
|
|
} else if d.is == nil || d.c != containerMapKey || len(v) > internMaxStrLen {
|
|
s = string(v)
|
|
} else {
|
|
s = d.is.string(v)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (d *decoderBase) usableStructFieldNameBytes(buf, v []byte, state dBytesAttachState) (out []byte) {
|
|
// In JSON, mapElemValue reads a colon and spaces.
|
|
// In bufio mode of ioDecReader, fillbuf could overwrite the read buffer
|
|
// which readXXX() calls return sub-slices from.
|
|
//
|
|
// Consequently, we detach the bytes in this special case.
|
|
//
|
|
// Note: ioDecReader (non-bufio) and bytesDecReader do not have
|
|
// this issue (as no fillbuf exists where bytes might be returned from).
|
|
if d.bufio && d.h.jsonHandle && state < dBytesAttachViewZerocopy {
|
|
if cap(buf) > len(v) {
|
|
out = buf[:len(v)]
|
|
} else if len(d.b) > len(v) {
|
|
out = d.b[:len(v)]
|
|
} else {
|
|
out = make([]byte, len(v), max(64, len(v)))
|
|
}
|
|
copy(out, v)
|
|
return
|
|
}
|
|
return v
|
|
}
|
|
|
|
func (d *decoderBase) detach2Bytes(in []byte, state dBytesAttachState) (out []byte) {
|
|
if cap(in) == 0 || state >= dBytesAttachViewZerocopy {
|
|
return in
|
|
}
|
|
if len(in) == 0 {
|
|
return zeroByteSlice
|
|
}
|
|
out = make([]byte, len(in))
|
|
copy(out, in)
|
|
return out
|
|
}
|
|
|
|
func (d *decoderBase) attachState(usingBufFromReader bool) (r dBytesAttachState) {
|
|
if usingBufFromReader {
|
|
r = dBytesAttachBuffer
|
|
} else if !d.bytes {
|
|
r = dBytesDetach
|
|
} else if d.h.ZeroCopy {
|
|
r = dBytesAttachViewZerocopy
|
|
} else {
|
|
r = dBytesAttachView
|
|
}
|
|
return
|
|
}
|
|
|
|
func (d *decoderBase) mapStart(v int) int {
|
|
if v != containerLenNil {
|
|
d.depthIncr()
|
|
d.c = containerMapStart
|
|
}
|
|
return v
|
|
}
|
|
|
|
func (d *decoderBase) HandleName() string {
|
|
return d.hh.Name()
|
|
}
|
|
|
|
func (d *decoderBase) isBytes() bool {
|
|
return d.bytes
|
|
}
|
|
|
|
type decoderI interface {
|
|
Decode(v interface{}) (err error)
|
|
HandleName() string
|
|
MustDecode(v interface{})
|
|
NumBytesRead() int
|
|
Release() // deprecated
|
|
Reset(r io.Reader)
|
|
ResetBytes(in []byte)
|
|
ResetString(s string)
|
|
|
|
isBytes() bool
|
|
wrapErr(v error, err *error)
|
|
swallow()
|
|
|
|
nextValueBytes() []byte // wrapper method, for use in tests
|
|
// getDecDriver() decDriverI
|
|
|
|
decode(v interface{})
|
|
decodeAs(v interface{}, t reflect.Type, ext bool)
|
|
|
|
interfaceExtConvertAndDecode(v interface{}, ext InterfaceExt)
|
|
}
|
|
|
|
var errDecNoResetBytesWithReader = errors.New("cannot reset an Decoder reading from []byte with a io.Reader")
|
|
var errDecNoResetReaderWithBytes = errors.New("cannot reset an Decoder reading from io.Reader with a []byte")
|
|
|
|
func setZero(iv interface{}) {
|
|
rv, isnil := isNil(iv, false)
|
|
if isnil {
|
|
return
|
|
}
|
|
if !rv.IsValid() {
|
|
rv = reflect.ValueOf(iv)
|
|
}
|
|
if isnilBitset.isset(byte(rv.Kind())) && rvIsNil(rv) {
|
|
return
|
|
}
|
|
// var canDecode bool
|
|
switch v := iv.(type) {
|
|
case *string:
|
|
*v = ""
|
|
case *bool:
|
|
*v = false
|
|
case *int:
|
|
*v = 0
|
|
case *int8:
|
|
*v = 0
|
|
case *int16:
|
|
*v = 0
|
|
case *int32:
|
|
*v = 0
|
|
case *int64:
|
|
*v = 0
|
|
case *uint:
|
|
*v = 0
|
|
case *uint8:
|
|
*v = 0
|
|
case *uint16:
|
|
*v = 0
|
|
case *uint32:
|
|
*v = 0
|
|
case *uint64:
|
|
*v = 0
|
|
case *float32:
|
|
*v = 0
|
|
case *float64:
|
|
*v = 0
|
|
case *complex64:
|
|
*v = 0
|
|
case *complex128:
|
|
*v = 0
|
|
case *[]byte:
|
|
*v = nil
|
|
case *Raw:
|
|
*v = nil
|
|
case *time.Time:
|
|
*v = time.Time{}
|
|
case reflect.Value:
|
|
decSetNonNilRV2Zero(v)
|
|
default:
|
|
if !fastpathDecodeSetZeroTypeSwitch(iv) {
|
|
decSetNonNilRV2Zero(rv)
|
|
}
|
|
}
|
|
}
|
|
|
|
// decSetNonNilRV2Zero will set the non-nil value to its zero value.
|
|
func decSetNonNilRV2Zero(v reflect.Value) {
|
|
// If not decodeable (settable), we do not touch it.
|
|
// We considered empty'ing it if not decodeable e.g.
|
|
// - if chan, drain it
|
|
// - if map, clear it
|
|
// - if slice or array, zero all elements up to len
|
|
//
|
|
// However, we decided instead that we either will set the
|
|
// whole value to the zero value, or leave AS IS.
|
|
|
|
k := v.Kind()
|
|
if k == reflect.Interface {
|
|
decSetNonNilRV2Zero4Intf(v)
|
|
} else if k == reflect.Ptr {
|
|
decSetNonNilRV2Zero4Ptr(v)
|
|
} else if v.CanSet() {
|
|
rvSetDirectZero(v)
|
|
}
|
|
}
|
|
|
|
func decSetNonNilRV2Zero4Ptr(v reflect.Value) {
|
|
ve := v.Elem()
|
|
if ve.CanSet() {
|
|
rvSetZero(ve) // we can have a pointer to an interface
|
|
} else if v.CanSet() {
|
|
rvSetZero(v)
|
|
}
|
|
}
|
|
|
|
func decSetNonNilRV2Zero4Intf(v reflect.Value) {
|
|
ve := v.Elem()
|
|
if ve.CanSet() {
|
|
rvSetDirectZero(ve) // interfaces always have element as a non-interface
|
|
} else if v.CanSet() {
|
|
rvSetZero(v)
|
|
}
|
|
}
|
|
|
|
func (d *decoderBase) arrayCannotExpand(sliceLen, streamLen int) {
|
|
if d.h.ErrorIfNoArrayExpand {
|
|
halt.errorf("cannot expand array len during decode from %v to %v", any(sliceLen), any(streamLen))
|
|
}
|
|
}
|
|
|
|
//go:noinline
|
|
func (d *decoderBase) haltAsNotDecodeable(rv reflect.Value) {
|
|
if !rv.IsValid() {
|
|
halt.onerror(errCannotDecodeIntoNil)
|
|
}
|
|
// check if an interface can be retrieved, before grabbing an interface
|
|
if !rv.CanInterface() {
|
|
halt.errorf("cannot decode into a value without an interface: %v", rv)
|
|
}
|
|
halt.errorf("cannot decode into value of kind: %v, %#v", rv.Kind(), rv2i(rv))
|
|
}
|
|
|
|
func (d *decoderBase) depthIncr() {
|
|
d.depth++
|
|
if d.depth >= d.maxdepth {
|
|
halt.onerror(errMaxDepthExceeded)
|
|
}
|
|
}
|
|
|
|
func (d *decoderBase) depthDecr() {
|
|
d.depth--
|
|
}
|
|
|
|
func (d *decoderBase) arrayStart(v int) int {
|
|
if v != containerLenNil {
|
|
d.depthIncr()
|
|
d.c = containerArrayStart
|
|
}
|
|
return v
|
|
}
|
|
|
|
func (d *decoderBase) oneShotAddrRV(rvt reflect.Type, rvk reflect.Kind) reflect.Value {
|
|
// MARKER 2025: is this slow for calling oneShot?
|
|
if decUseTransient && d.h.getTypeInfo4RT(baseRT(rvt)).flagCanTransient {
|
|
return d.perType.TransientAddrK(rvt, rvk)
|
|
}
|
|
return rvZeroAddrK(rvt, rvk)
|
|
}
|
|
|
|
// decNegintPosintFloatNumberHelper is used for formats that are binary
|
|
// and have distinct ways of storing positive integers vs negative integers
|
|
// vs floats, which are uniquely identified by the byte descriptor.
|
|
//
|
|
// Currently, these formats are binc, cbor and simple.
|
|
type decNegintPosintFloatNumberHelper struct {
|
|
d decDriverI
|
|
}
|
|
|
|
func (x decNegintPosintFloatNumberHelper) uint64(ui uint64, neg, ok bool) uint64 {
|
|
if ok && !neg {
|
|
return ui
|
|
}
|
|
return x.uint64TryFloat(ok)
|
|
}
|
|
|
|
func (x decNegintPosintFloatNumberHelper) uint64TryFloat(neg bool) (ui uint64) {
|
|
if neg { // neg = true
|
|
halt.errorStr("assigning negative signed value to unsigned type")
|
|
}
|
|
f, ok := x.d.decFloat()
|
|
if !(ok && f >= 0 && noFrac64(math.Float64bits(f))) {
|
|
halt.errorStr2("invalid number loading uint64, with descriptor: ", x.d.descBd())
|
|
}
|
|
return uint64(f)
|
|
}
|
|
|
|
func (x decNegintPosintFloatNumberHelper) int64(ui uint64, neg, ok, cbor bool) (i int64) {
|
|
if ok {
|
|
return decNegintPosintFloatNumberHelperInt64v(ui, neg, cbor)
|
|
}
|
|
// return x.int64TryFloat()
|
|
// }
|
|
// func (x decNegintPosintFloatNumberHelper) int64TryFloat() (i int64) {
|
|
f, ok := x.d.decFloat()
|
|
if !(ok && noFrac64(math.Float64bits(f))) {
|
|
halt.errorf("invalid number loading uint64 (%v), with descriptor: %s", f, x.d.descBd())
|
|
}
|
|
return int64(f)
|
|
}
|
|
|
|
func (x decNegintPosintFloatNumberHelper) float64(f float64, ok, cbor bool) float64 {
|
|
if ok {
|
|
return f
|
|
}
|
|
return x.float64TryInteger(cbor)
|
|
}
|
|
|
|
func (x decNegintPosintFloatNumberHelper) float64TryInteger(cbor bool) float64 {
|
|
ui, neg, ok := x.d.decInteger()
|
|
if !ok {
|
|
halt.errorStr2("invalid descriptor for float: ", x.d.descBd())
|
|
}
|
|
return float64(decNegintPosintFloatNumberHelperInt64v(ui, neg, cbor))
|
|
}
|
|
|
|
func decNegintPosintFloatNumberHelperInt64v(ui uint64, neg, incrIfNeg bool) (i int64) {
|
|
if neg && incrIfNeg {
|
|
ui++
|
|
}
|
|
i = chkOvf.SignedIntV(ui)
|
|
if neg {
|
|
i = -i
|
|
}
|
|
return
|
|
}
|
|
|
|
// isDecodeable checks if value can be decoded into
|
|
//
|
|
// decode can take any reflect.Value that is a inherently addressable i.e.
|
|
// - non-nil chan (we will SEND to it)
|
|
// - non-nil slice (we will set its elements)
|
|
// - non-nil map (we will put into it)
|
|
// - non-nil pointer (we can "update" it)
|
|
// - func: no
|
|
// - interface: no
|
|
// - array: if canAddr=true
|
|
// - any other value pointer: if canAddr=true
|
|
func isDecodeable(rv reflect.Value) (canDecode bool, reason decNotDecodeableReason) {
|
|
switch rv.Kind() {
|
|
case reflect.Ptr, reflect.Slice, reflect.Chan, reflect.Map:
|
|
canDecode = !rvIsNil(rv)
|
|
reason = decNotDecodeableReasonNilReference
|
|
case reflect.Func, reflect.Interface, reflect.Invalid, reflect.UnsafePointer:
|
|
reason = decNotDecodeableReasonBadKind
|
|
default:
|
|
canDecode = rv.CanAddr()
|
|
reason = decNotDecodeableReasonNonAddrValue
|
|
}
|
|
return
|
|
}
|
|
|
|
// decInferLen will infer a sensible length, given the following:
|
|
// - clen: length wanted.
|
|
// - maxlen: max length to be returned.
|
|
// if <= 0, it is unset, and we infer it based on the unit size
|
|
// - unit: number of bytes for each element of the collection
|
|
func decInferLen(clen int, maxlen, unit uint) (n uint) {
|
|
// anecdotal testing showed increase in allocation with map length of 16.
|
|
// We saw same typical alloc from 0-8, then a 20% increase at 16.
|
|
// Thus, we set it to 8.
|
|
|
|
const (
|
|
minLenIfUnset = 8
|
|
maxMem = 1024 * 1024 // 1 MB Memory
|
|
)
|
|
|
|
// handle when maxlen is not set i.e. <= 0
|
|
|
|
// clen==0: use 0
|
|
// maxlen<=0, clen<0: use default
|
|
// maxlen> 0, clen<0: use default
|
|
// maxlen<=0, clen>0: infer maxlen, and cap on it
|
|
// maxlen> 0, clen>0: cap at maxlen
|
|
|
|
if clen == 0 || clen == containerLenNil {
|
|
return 0
|
|
}
|
|
if clen < 0 {
|
|
// if unspecified, return 64 for bytes, ... 8 for uint64, ... and everything else
|
|
return max(64/unit, minLenIfUnset)
|
|
}
|
|
if unit == 0 {
|
|
return uint(clen)
|
|
}
|
|
if maxlen == 0 {
|
|
maxlen = maxMem / unit
|
|
}
|
|
return min(uint(clen), maxlen)
|
|
}
|
|
|
|
type Decoder struct {
|
|
decoderI
|
|
}
|
|
|
|
// NewDecoder returns a Decoder for decoding a stream of bytes from an io.Reader.
|
|
//
|
|
// For efficiency, Users are encouraged to configure ReaderBufferSize on the handle
|
|
// OR pass in a memory buffered reader (eg bufio.Reader, bytes.Buffer).
|
|
func NewDecoder(r io.Reader, h Handle) *Decoder {
|
|
return &Decoder{h.newDecoder(r)}
|
|
}
|
|
|
|
// NewDecoderBytes returns a Decoder which efficiently decodes directly
|
|
// from a byte slice with zero copying.
|
|
func NewDecoderBytes(in []byte, h Handle) *Decoder {
|
|
return &Decoder{h.newDecoderBytes(in)}
|
|
}
|
|
|
|
// NewDecoderString returns a Decoder which efficiently decodes directly
|
|
// from a string with zero copying.
|
|
//
|
|
// It is a convenience function that calls NewDecoderBytes with a
|
|
// []byte view into the string.
|
|
//
|
|
// This can be an efficient zero-copy if using default mode i.e. without codec.safe tag.
|
|
func NewDecoderString(s string, h Handle) *Decoder {
|
|
return NewDecoderBytes(bytesView(s), h)
|
|
}
|
|
|
|
// ----
|
|
|
|
func sideDecode(h Handle, p *sync.Pool, fn func(decoderI)) {
|
|
var s decoderI
|
|
if usePoolForSideDecode {
|
|
s = p.Get().(decoderI)
|
|
defer p.Put(s)
|
|
} else {
|
|
// initialization cycle error
|
|
// s = NewDecoderBytes(nil, h).decoderI
|
|
s = p.New().(decoderI)
|
|
}
|
|
fn(s)
|
|
}
|
|
|
|
func oneOffDecode(sd decoderI, v interface{}, in []byte, basetype reflect.Type, ext bool) {
|
|
sd.ResetBytes(in)
|
|
sd.decodeAs(v, basetype, ext)
|
|
// d.sideDecoder(xbs)
|
|
// d.sideDecode(rv, basetype)
|
|
}
|
|
|
|
func bytesOKdbi(v []byte, _ dBytesIntoState) []byte {
|
|
return v
|
|
}
|
|
|
|
func bytesOKs(bs []byte, _ dBytesAttachState) []byte {
|
|
return bs
|
|
}
|