diff options
| author | 2025-06-30 15:19:09 +0200 | |
|---|---|---|
| committer | 2025-06-30 15:19:09 +0200 | |
| commit | 8b0ea560279a5bf4479555d3924c763ddeecfcad (patch) | |
| tree | 005e26d4a658e565594fb259cc17948659195822 /vendor/github.com/ugorji/go/codec/encode.base.go | |
| parent | [chore] bumps ncruces/go-sqlite3 v0.26.1 => v0.26.3 (#4302) (diff) | |
| download | gotosocial-8b0ea560279a5bf4479555d3924c763ddeecfcad.tar.xz | |
[chore] update go dependencies (#4304)
- 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>
Diffstat (limited to 'vendor/github.com/ugorji/go/codec/encode.base.go')
| -rw-r--r-- | vendor/github.com/ugorji/go/codec/encode.base.go | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/vendor/github.com/ugorji/go/codec/encode.base.go b/vendor/github.com/ugorji/go/codec/encode.base.go new file mode 100644 index 000000000..0ded90465 --- /dev/null +++ b/vendor/github.com/ugorji/go/codec/encode.base.go @@ -0,0 +1,461 @@ +// 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 ( + "cmp" + "errors" + "io" + "reflect" + "slices" + "sync" + "time" +) + +var errEncoderNotInitialized = errors.New("encoder not initialized") + +var encBuiltinRtids []uintptr + +func init() { + for _, v := range []interface{}{ + (string)(""), + (bool)(false), + (int)(0), + (int8)(0), + (int16)(0), + (int32)(0), + (int64)(0), + (uint)(0), + (uint8)(0), + (uint16)(0), + (uint32)(0), + (uint64)(0), + (uintptr)(0), + (float32)(0), + (float64)(0), + (complex64)(0), + (complex128)(0), + (time.Time{}), + ([]byte)(nil), + (Raw{}), + // (interface{})(nil), + } { + t := reflect.TypeOf(v) + encBuiltinRtids = append(encBuiltinRtids, rt2id(t), rt2id(reflect.PointerTo(t))) + } + slices.Sort(encBuiltinRtids) +} + +// encDriver abstracts the actual codec (binc vs msgpack, etc) +type encDriverI interface { + EncodeNil() + EncodeInt(i int64) + EncodeUint(i uint64) + EncodeBool(b bool) + EncodeFloat32(f float32) + EncodeFloat64(f float64) + // re is never nil + EncodeRawExt(re *RawExt) + // ext is never nil + EncodeExt(v interface{}, basetype reflect.Type, xtag uint64, ext Ext) + // EncodeString using cUTF8, honor'ing StringToRaw flag + EncodeString(v string) + EncodeStringNoEscape4Json(v string) + // encode a non-nil []byte + EncodeStringBytesRaw(v []byte) + // encode a []byte as nil, empty or encoded sequence of bytes depending on context + EncodeBytes(v []byte) + EncodeTime(time.Time) + WriteArrayStart(length int) + WriteArrayEnd() + WriteMapStart(length int) + WriteMapEnd() + + // these write a zero-len map or array into the stream + WriteMapEmpty() + WriteArrayEmpty() + + writeNilMap() + writeNilArray() + writeNilBytes() + + // these are no-op except for json + encDriverContainerTracker + + // reset will reset current encoding runtime state, and cached information from the handle + reset() + + atEndOfEncode() + writerEnd() + + writeBytesAsis(b []byte) + // writeStringAsisDblQuoted(v string) + + resetOutBytes(out *[]byte) + resetOutIO(out io.Writer) + + init(h Handle, shared *encoderBase, enc encoderI) (fp interface{}) + + // driverStateManager +} + +type encInit2er struct{} + +func (encInit2er) init2(enc encoderI) {} + +type encDriverContainerTracker interface { + WriteArrayElem(firstTime bool) + WriteMapElemKey(firstTime bool) + WriteMapElemValue() +} + +type encDriverNoState struct{} + +// func (encDriverNoState) captureState() interface{} { return nil } +// func (encDriverNoState) resetState() {} +// func (encDriverNoState) restoreState(v interface{}) {} +func (encDriverNoState) reset() {} + +type encDriverNoopContainerWriter struct{} + +func (encDriverNoopContainerWriter) WriteArrayStart(length int) {} +func (encDriverNoopContainerWriter) WriteArrayEnd() {} +func (encDriverNoopContainerWriter) WriteMapStart(length int) {} +func (encDriverNoopContainerWriter) WriteMapEnd() {} +func (encDriverNoopContainerWriter) atEndOfEncode() {} + +// encStructFieldObj[Slice] is used for sorting when there are missing fields and canonical flag is set +type encStructFieldObj struct { + key string + rv reflect.Value + intf interface{} + isRv bool + noEsc4json bool + builtin bool +} + +type encStructFieldObjSlice []encStructFieldObj + +func (p encStructFieldObjSlice) Len() int { return len(p) } +func (p encStructFieldObjSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } +func (p encStructFieldObjSlice) Less(i, j int) bool { + return p[uint(i)].key < p[uint(j)].key +} + +// ---- + +type orderedRv[T cmp.Ordered] struct { + v T + r reflect.Value +} + +func cmpOrderedRv[T cmp.Ordered](v1, v2 orderedRv[T]) int { + return cmp.Compare(v1.v, v2.v) +} + +// ---- + +type encFnInfo struct { + ti *typeInfo + xfFn Ext + xfTag uint64 + addrE bool + // addrEf bool // force: if addrE, then encode function MUST take a ptr +} + +// ---- + +// EncodeOptions captures configuration options during encode. +type EncodeOptions struct { + // WriterBufferSize is the size of the buffer used when writing. + // + // if > 0, we use a smart buffer internally for performance purposes. + WriterBufferSize int + + // ChanRecvTimeout is the timeout used when selecting from a chan. + // + // Configuring this controls how we receive from a chan during the encoding process. + // - If ==0, we only consume the elements currently available in the chan. + // - if <0, we consume until the chan is closed. + // - If >0, we consume until this timeout. + ChanRecvTimeout time.Duration + + // StructToArray specifies to encode a struct as an array, and not as a map + StructToArray bool + + // Canonical representation means that encoding a value will always result in the same + // sequence of bytes. + // + // This only affects maps, as the iteration order for maps is random. + // + // The implementation MAY use the natural sort order for the map keys if possible: + // + // - If there is a natural sort order (ie for number, bool, string or []byte keys), + // then the map keys are first sorted in natural order and then written + // with corresponding map values to the strema. + // - If there is no natural sort order, then the map keys will first be + // encoded into []byte, and then sorted, + // before writing the sorted keys and the corresponding map values to the stream. + // + Canonical bool + + // CheckCircularRef controls whether we check for circular references + // and error fast during an encode. + // + // If enabled, an error is received if a pointer to a struct + // references itself either directly or through one of its fields (iteratively). + // + // This is opt-in, as there may be a performance hit to checking circular references. + CheckCircularRef bool + + // RecursiveEmptyCheck controls how we determine whether a value is empty. + // + // If true, we descend into interfaces and pointers to reursively check if value is empty. + // + // We *might* check struct fields one by one to see if empty + // (if we cannot directly check if a struct value is equal to its zero value). + // If so, we honor IsZero, Comparable, IsCodecEmpty(), etc. + // Note: This *may* make OmitEmpty more expensive due to the large number of reflect calls. + // + // If false, we check if the value is equal to its zero value (newly allocated state). + RecursiveEmptyCheck bool + + // Raw controls whether we encode Raw values. + // This is a "dangerous" option and must be explicitly set. + // If set, we blindly encode Raw values as-is, without checking + // if they are a correct representation of a value in that format. + // If unset, we error out. + Raw bool + + // StringToRaw controls how strings are encoded. + // + // As a go string is just an (immutable) sequence of bytes, + // it can be encoded either as raw bytes or as a UTF string. + // + // By default, strings are encoded as UTF-8. + // but can be treated as []byte during an encode. + // + // Note that things which we know (by definition) to be UTF-8 + // are ALWAYS encoded as UTF-8 strings. + // These include encoding.TextMarshaler, time.Format calls, struct field names, etc. + StringToRaw bool + + // OptimumSize controls whether we optimize for the smallest size. + // + // Some formats will use this flag to determine whether to encode + // in the smallest size possible, even if it takes slightly longer. + // + // For example, some formats that support half-floats might check if it is possible + // to store a float64 as a half float. Doing this check has a small performance cost, + // but the benefit is that the encoded message will be smaller. + OptimumSize bool + + // NoAddressableReadonly controls whether we try to force a non-addressable value + // to be addressable so we can call a pointer method on it e.g. for types + // that support Selfer, json.Marshaler, etc. + // + // Use it in the very rare occurrence that your types modify a pointer value when calling + // an encode callback function e.g. JsonMarshal, TextMarshal, BinaryMarshal or CodecEncodeSelf. + NoAddressableReadonly bool + + // NilCollectionToZeroLength controls whether we encode nil collections (map, slice, chan) + // as nil (e.g. null if using JSON) or as zero length collections (e.g. [] or {} if using JSON). + // + // This is useful in many scenarios e.g. + // - encoding in go, but decoding the encoded stream in python + // where context of the type is missing but needed + // + // Note: this flag ignores the MapBySlice tag, and will encode nil slices, maps and chan + // in their natural zero-length formats e.g. a slice in json encoded as [] + // (and not nil or {} if MapBySlice tag). + NilCollectionToZeroLength bool +} + +// --------------------------------------------- + +// encoderBase is shared as a field between Encoder and its encDrivers. +// This way, encDrivers need not hold a referece to the Encoder itself. +type encoderBase struct { + perType encPerType + + h *BasicHandle + + // MARKER: these fields below should belong directly in Encoder. + // There should not be any pointers here - just values. + // we pack them here for space efficiency and cache-line optimization. + + rtidFn, rtidFnNoExt *atomicRtidFnSlice + + // se encoderI + err error + + blist bytesFreeList + + // js bool // is json encoder? + // be bool // is binary encoder? + + bytes bool + + c containerState + + calls uint16 + seq uint16 // sequencer (e.g. used by binc for symbols, etc) + + // ---- cpu cache line boundary + hh Handle + + // ---- cpu cache line boundary + + // ---- writable fields during execution --- *try* to keep in sep cache line + + ci circularRefChecker + + slist sfiRvFreeList +} + +func (e *encoderBase) HandleName() string { + return e.hh.Name() +} + +// Release is a no-op. +// +// Deprecated: Pooled resources are not used with an Encoder. +// This method is kept for compatibility reasons only. +func (e *encoderBase) Release() { +} + +func (e *encoderBase) setContainerState(cs containerState) { + if cs != 0 { + e.c = cs + } +} + +func (e *encoderBase) haltOnMbsOddLen(length int) { + if length&1 != 0 { // similar to &1==1 or %2 == 1 + halt.errorInt("mapBySlice requires even slice length, but got ", int64(length)) + } +} + +// addrRV returns a addressable value given that rv is not addressable +func (e *encoderBase) addrRV(rv reflect.Value, typ, ptrType reflect.Type) (rva reflect.Value) { + // if rv.CanAddr() { + // return rvAddr(rv, ptrType) + // } + if e.h.NoAddressableReadonly { + rva = reflect.New(typ) + rvSetDirect(rva.Elem(), rv) + return + } + return rvAddr(e.perType.AddressableRO(rv), ptrType) +} + +func (e *encoderBase) wrapErr(v error, err *error) { + *err = wrapCodecErr(v, e.hh.Name(), 0, true) +} + +func (e *encoderBase) kErr(_ *encFnInfo, rv reflect.Value) { + halt.errorf("unsupported encoding kind: %s, for %#v", rv.Kind(), any(rv)) +} + +func chanToSlice(rv reflect.Value, rtslice reflect.Type, timeout time.Duration) (rvcs reflect.Value) { + rvcs = rvZeroK(rtslice, reflect.Slice) + if timeout < 0 { // consume until close + for { + recv, recvOk := rv.Recv() + if !recvOk { + break + } + rvcs = reflect.Append(rvcs, recv) + } + } else { + cases := make([]reflect.SelectCase, 2) + cases[0] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: rv} + if timeout == 0 { + cases[1] = reflect.SelectCase{Dir: reflect.SelectDefault} + } else { + tt := time.NewTimer(timeout) + cases[1] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(tt.C)} + } + for { + chosen, recv, recvOk := reflect.Select(cases) + if chosen == 1 || !recvOk { + break + } + rvcs = reflect.Append(rvcs, recv) + } + } + return +} + +type encoderI interface { + Encode(v interface{}) error + MustEncode(v interface{}) + Release() + Reset(w io.Writer) + ResetBytes(out *[]byte) + + wrapErr(v error, err *error) + atEndOfEncode() + writerEnd() + + encodeI(v interface{}) + encodeR(v reflect.Value) + encodeAs(v interface{}, t reflect.Type, ext bool) + + setContainerState(cs containerState) // needed for canonical encoding via side encoder +} + +var errEncNoResetBytesWithWriter = errors.New("cannot reset an Encoder which outputs to []byte with a io.Writer") +var errEncNoResetWriterWithBytes = errors.New("cannot reset an Encoder which outputs to io.Writer with a []byte") + +type encDriverContainerNoTrackerT struct{} + +func (encDriverContainerNoTrackerT) WriteArrayElem(firstTime bool) {} +func (encDriverContainerNoTrackerT) WriteMapElemKey(firstTime bool) {} +func (encDriverContainerNoTrackerT) WriteMapElemValue() {} + +type Encoder struct { + encoderI +} + +// NewEncoder returns an Encoder for encoding into an io.Writer. +// +// For efficiency, Users are encouraged to configure WriterBufferSize on the handle +// OR pass in a memory buffered writer (eg bufio.Writer, bytes.Buffer). +func NewEncoder(w io.Writer, h Handle) *Encoder { + return &Encoder{h.newEncoder(w)} +} + +// NewEncoderBytes returns an encoder for encoding directly and efficiently +// into a byte slice, using zero-copying to temporary slices. +// +// It will potentially replace the output byte slice pointed to. +// After encoding, the out parameter contains the encoded contents. +func NewEncoderBytes(out *[]byte, h Handle) *Encoder { + return &Encoder{h.newEncoderBytes(out)} +} + +// ---- + +func sideEncode(h Handle, p *sync.Pool, fn func(encoderI)) { + var s encoderI + if usePoolForSideEncode { + s = p.Get().(encoderI) + defer p.Put(s) + } else { + // initialization cycle error + // s = NewEncoderBytes(nil, h).encoderI + s = p.New().(encoderI) + } + fn(s) +} + +func oneOffEncode(se encoderI, v interface{}, out *[]byte, basetype reflect.Type, ext bool) { + se.ResetBytes(out) + se.encodeAs(v, basetype, ext) + se.atEndOfEncode() + se.writerEnd() + // e.sideEncoder(&bs) + // e.sideEncode(v, basetype, 0) +} |
