diff options
author | 2023-02-25 13:12:40 +0100 | |
---|---|---|
committer | 2023-02-25 12:12:40 +0000 | |
commit | ecdc8379fa8f9d88faca626e7de748c2afbe4910 (patch) | |
tree | 8c20a5826db2136fc89bee45e15355c5899fa65b /vendor/github.com/ugorji/go/codec/encode.go | |
parent | [bugfix] Fix deleted status causing issues when getting bookmark (#1551) (diff) | |
download | gotosocial-ecdc8379fa8f9d88faca626e7de748c2afbe4910.tar.xz |
[chore] Update gin to v1.9.0 (#1553)
Diffstat (limited to 'vendor/github.com/ugorji/go/codec/encode.go')
-rw-r--r-- | vendor/github.com/ugorji/go/codec/encode.go | 165 |
1 files changed, 105 insertions, 60 deletions
diff --git a/vendor/github.com/ugorji/go/codec/encode.go b/vendor/github.com/ugorji/go/codec/encode.go index e411bdb81..53389b085 100644 --- a/vendor/github.com/ugorji/go/codec/encode.go +++ b/vendor/github.com/ugorji/go/codec/encode.go @@ -686,15 +686,11 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) { var rvv = mapAddrLoopvarRV(f.ti.elem, vtypeKind) - if e.h.Canonical { - e.kMapCanonical(f.ti, rv, rvv, valFn) - e.mapEnd() - return - } - rtkey := f.ti.key var keyTypeIsString = stringTypId == rt2id(rtkey) // rtkeyid - if !keyTypeIsString { + if keyTypeIsString { + keyFn = e.h.fn(rtkey) + } else { for rtkey.Kind() == reflect.Ptr { rtkey = rtkey.Elem() } @@ -703,6 +699,12 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) { } } + if e.h.Canonical { + e.kMapCanonical(f.ti, rv, rvv, keyFn, valFn) + e.mapEnd() + return + } + var rvk = mapAddrLoopvarRV(f.ti.key, ktypeKind) var it mapIter @@ -723,11 +725,14 @@ func (e *Encoder) kMap(f *codecFnInfo, rv reflect.Value) { e.mapEnd() } -func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *codecFn) { - // we previously did out-of-band if an extension was registered. - // This is not necessary, as the natural kind is sufficient for ordering. - +func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, keyFn, valFn *codecFn) { + // The base kind of the type of the map key is sufficient for ordering. + // We only do out of band if that kind is not ordered (number or string), bool or time.Time. + // If the key is a predeclared type, directly call methods on encDriver e.g. EncodeString + // but if not, call encodeValue, in case it has an extension registered or otherwise. rtkey := ti.key + rtkeydecl := rtkey.PkgPath() == "" && rtkey.Name() != "" // key type is predeclared + mks := rv.MapKeys() rtkeyKind := rtkey.Kind() kfast := mapKeyFastKindFor(rtkeyKind) @@ -736,18 +741,24 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code switch rtkeyKind { case reflect.Bool: - mksv := make([]boolRv, len(mks)) - for i, k := range mks { - v := &mksv[i] - v.r = k - v.v = k.Bool() + // though bool keys make no sense in a map, it *could* happen. + // in that case, we MUST support it in reflection mode, + // as that is the fallback for even codecgen and others. + + // sort the keys so that false comes before true + // ie if 2 keys in order (true, false), then swap them + if len(mks) == 2 && mks[0].Bool() { + mks[0], mks[1] = mks[1], mks[0] } - sort.Sort(boolRvSlice(mksv)) - for i := range mksv { + for i := range mks { e.mapElemKey() - e.e.EncodeBool(mksv[i].v) + if rtkeydecl { + e.e.EncodeBool(mks[i].Bool()) + } else { + e.encodeValueNonNil(mks[i], keyFn) + } e.mapElemValue() - e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) + e.encodeValue(mapGet(rv, mks[i], rvv, kfast, visindirect, visref), valFn) } case reflect.String: mksv := make([]stringRv, len(mks)) @@ -759,7 +770,11 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code sort.Sort(stringRvSlice(mksv)) for i := range mksv { e.mapElemKey() - e.e.EncodeString(mksv[i].v) + if rtkeydecl { + e.e.EncodeString(mksv[i].v) + } else { + e.encodeValueNonNil(mksv[i].r, keyFn) + } e.mapElemValue() e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) } @@ -773,7 +788,11 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code sort.Sort(uint64RvSlice(mksv)) for i := range mksv { e.mapElemKey() - e.e.EncodeUint(mksv[i].v) + if rtkeydecl { + e.e.EncodeUint(mksv[i].v) + } else { + e.encodeValueNonNil(mksv[i].r, keyFn) + } e.mapElemValue() e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) } @@ -787,7 +806,11 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code sort.Sort(int64RvSlice(mksv)) for i := range mksv { e.mapElemKey() - e.e.EncodeInt(mksv[i].v) + if rtkeydecl { + e.e.EncodeInt(mksv[i].v) + } else { + e.encodeValueNonNil(mksv[i].r, keyFn) + } e.mapElemValue() e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) } @@ -801,7 +824,11 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code sort.Sort(float64RvSlice(mksv)) for i := range mksv { e.mapElemKey() - e.e.EncodeFloat32(float32(mksv[i].v)) + if rtkeydecl { + e.e.EncodeFloat32(float32(mksv[i].v)) + } else { + e.encodeValueNonNil(mksv[i].r, keyFn) + } e.mapElemValue() e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) } @@ -815,11 +842,15 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code sort.Sort(float64RvSlice(mksv)) for i := range mksv { e.mapElemKey() - e.e.EncodeFloat64(mksv[i].v) + if rtkeydecl { + e.e.EncodeFloat64(mksv[i].v) + } else { + e.encodeValueNonNil(mksv[i].r, keyFn) + } e.mapElemValue() e.encodeValue(mapGet(rv, mksv[i].r, rvv, kfast, visindirect, visref), valFn) } - case reflect.Struct: + default: if rtkey == timeTyp { mksv := make([]timeRv, len(mks)) for i, k := range mks { @@ -836,8 +867,7 @@ func (e *Encoder) kMapCanonical(ti *typeInfo, rv, rvv reflect.Value, valFn *code } break } - fallthrough - default: + // out-of-band // first encode each key to a []byte first, then sort them, then record bs0 := e.blist.get(len(mks) * 16) @@ -1010,16 +1040,17 @@ func (e *Encoder) ResetBytes(out *[]byte) { // To set an option on all fields (e.g. omitempty on all fields), you // can create a field called _struct, and set flags on it. The options // which can be set on _struct are: -// - omitempty: so all fields are omitted if empty -// - toarray: so struct is encoded as an array -// - int: so struct key names are encoded as signed integers (instead of strings) -// - uint: so struct key names are encoded as unsigned integers (instead of strings) -// - float: so struct key names are encoded as floats (instead of strings) +// - omitempty: so all fields are omitted if empty +// - toarray: so struct is encoded as an array +// - int: so struct key names are encoded as signed integers (instead of strings) +// - uint: so struct key names are encoded as unsigned integers (instead of strings) +// - float: so struct key names are encoded as floats (instead of strings) +// // More details on these below. // // Struct values "usually" encode as maps. Each exported struct field is encoded unless: -// - the field's tag is "-", OR -// - the field is empty (empty or the zero value) and its tag specifies the "omitempty" option. +// - the field's tag is "-", OR +// - the field is empty (empty or the zero value) and its tag specifies the "omitempty" option. // // When encoding as a map, the first string in the tag (before the comma) // is the map key string to use when encoding. @@ -1032,8 +1063,9 @@ func (e *Encoder) ResetBytes(out *[]byte) { // This is done with the int,uint or float option on the _struct field (see above). // // However, struct values may encode as arrays. This happens when: -// - StructToArray Encode option is set, OR -// - the tag on the _struct field sets the "toarray" option +// - StructToArray Encode option is set, OR +// - the tag on the _struct field sets the "toarray" option +// // Note that omitempty is ignored when encoding struct values as arrays, // as an entry must be encoded for each field, to maintain its position. // @@ -1043,33 +1075,33 @@ func (e *Encoder) ResetBytes(out *[]byte) { // or interface value, and any array, slice, map, or string of length zero. // // Anonymous fields are encoded inline except: -// - the struct tag specifies a replacement name (first value) -// - the field is of an interface type +// - the struct tag specifies a replacement name (first value) +// - the field is of an interface type // // Examples: // -// // NOTE: 'json:' can be used as struct tag key, in place 'codec:' below. -// type MyStruct struct { -// _struct bool `codec:",omitempty"` //set omitempty for every field -// Field1 string `codec:"-"` //skip this field -// Field2 int `codec:"myName"` //Use key "myName" in encode stream -// Field3 int32 `codec:",omitempty"` //use key "Field3". Omit if empty. -// Field4 bool `codec:"f4,omitempty"` //use key "f4". Omit if empty. -// io.Reader //use key "Reader". -// MyStruct `codec:"my1" //use key "my1". -// MyStruct //inline it -// ... -// } +// // NOTE: 'json:' can be used as struct tag key, in place 'codec:' below. +// type MyStruct struct { +// _struct bool `codec:",omitempty"` //set omitempty for every field +// Field1 string `codec:"-"` //skip this field +// Field2 int `codec:"myName"` //Use key "myName" in encode stream +// Field3 int32 `codec:",omitempty"` //use key "Field3". Omit if empty. +// Field4 bool `codec:"f4,omitempty"` //use key "f4". Omit if empty. +// io.Reader //use key "Reader". +// MyStruct `codec:"my1" //use key "my1". +// MyStruct //inline it +// ... +// } // -// type MyStruct struct { -// _struct bool `codec:",toarray"` //encode struct as an array -// } +// type MyStruct struct { +// _struct bool `codec:",toarray"` //encode struct as an array +// } // -// type MyStruct struct { -// _struct bool `codec:",uint"` //encode struct with "unsigned integer" keys -// Field1 string `codec:"1"` //encode Field1 key using: EncodeInt(1) -// Field2 string `codec:"2"` //encode Field2 key using: EncodeInt(2) -// } +// type MyStruct struct { +// _struct bool `codec:",uint"` //encode struct with "unsigned integer" keys +// Field1 string `codec:"1"` //encode Field1 key using: EncodeInt(1) +// Field2 string `codec:"2"` //encode Field2 key using: EncodeInt(2) +// } // // The mode of encoding is based on the type of the value. When a value is seen: // - If a Selfer, call its CodecEncodeSelf method @@ -1293,7 +1325,7 @@ TOP: } if fn == nil { - fn = e.h.fn(rvType(rv)) + fn = e.h.fn(rv.Type()) } if !fn.i.addrE { // typically, addrE = false, so check it first @@ -1310,6 +1342,19 @@ TOP: } } +// encodeValueNonNil can encode a number, bool, or string +// OR non-nil values of kind map, slice and chan. +func (e *Encoder) encodeValueNonNil(rv reflect.Value, fn *codecFn) { + if fn == nil { + fn = e.h.fn(rv.Type()) + } + + if fn.i.addrE { // typically, addrE = false, so check it first + rv = e.addrRV(rv, fn.i.ti.rt, fn.i.ti.ptr) + } + fn.fe(e, &fn.i, rv) +} + // addrRV returns a addressable value which may be readonly func (e *Encoder) addrRV(rv reflect.Value, typ, ptrType reflect.Type) (rva reflect.Value) { if rv.CanAddr() { |