From 406e632e78c78ba803535cdb69f878e3e641f187 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Sat, 16 Oct 2021 16:39:23 +0100 Subject: [PATCH 1/5] Migrate to use go-JSON This PR switches to use GoCcyJSON by default. Signed-off-by: Andrew Thornton --- CONTRIBUTING.md | 1 - go.mod | 1 + go.sum | 3 +- modules/json/json.go | 59 ++++++++- modules/lfs/http_client.go | 2 +- vendor/github.com/goccy/go-json/CHANGELOG.md | 28 ++++ .../goccy/go-json/docker-compose.yml | 2 +- .../goccy/go-json/internal/decoder/bytes.go | 125 +++++------------- .../goccy/go-json/internal/decoder/func.go | 4 +- .../go-json/internal/decoder/interface.go | 4 +- .../goccy/go-json/internal/decoder/map.go | 49 ++++--- .../goccy/go-json/internal/decoder/number.go | 4 + .../goccy/go-json/internal/decoder/slice.go | 11 +- .../goccy/go-json/internal/decoder/string.go | 24 +++- .../goccy/go-json/internal/decoder/struct.go | 16 +-- .../go-json/internal/encoder/compiler.go | 5 +- .../goccy/go-json/internal/encoder/opcode.go | 24 ++-- .../goccy/go-json/internal/encoder/vm/util.go | 9 ++ .../goccy/go-json/internal/encoder/vm/vm.go | 35 +++-- .../go-json/internal/encoder/vm_color/util.go | 9 ++ .../go-json/internal/encoder/vm_color/vm.go | 35 +++-- .../internal/encoder/vm_color_indent/util.go | 9 ++ .../internal/encoder/vm_color_indent/vm.go | 35 +++-- .../internal/encoder/vm_indent/util.go | 9 ++ .../go-json/internal/encoder/vm_indent/vm.go | 35 +++-- .../goccy/go-json/internal/errors/error.go | 7 + vendor/modules.txt | 3 +- 27 files changed, 362 insertions(+), 186 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 026536868d50c..14044bfaf69a7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -142,7 +142,6 @@ For imports you should use the following format (_without_ the comments) ```go import ( // stdlib - "encoding/json" "fmt" // local packages diff --git a/go.mod b/go.mod index 7a4923e9e460b..638d76cfca4bc 100644 --- a/go.mod +++ b/go.mod @@ -48,6 +48,7 @@ require ( github.com/go-swagger/go-swagger v0.27.0 github.com/go-testfixtures/testfixtures/v3 v3.6.1 github.com/gobwas/glob v0.2.3 + github.com/goccy/go-json v0.7.9 github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 diff --git a/go.sum b/go.sum index d935b6b8495d0..332119645be35 100644 --- a/go.sum +++ b/go.sum @@ -493,8 +493,9 @@ github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY9 github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.4.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.7.4 h1:B44qRUFwz/vxPKPISQ1KhvzRi9kZ28RAf6YtjriBZ5k= github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.7.9 h1:mSp3uo1tr6MXQTYopSNhHTUnJhd2zQ4Yk+HdJZP+ZRY= +github.com/goccy/go-json v0.7.9/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= diff --git a/modules/json/json.go b/modules/json/json.go index be42b6ae6c441..d336694ec4ccc 100644 --- a/modules/json/json.go +++ b/modules/json/json.go @@ -8,7 +8,9 @@ import ( "bytes" "encoding/json" "io" + "strings" + goccy_json "github.com/goccy/go-json" jsoniter "github.com/json-iterator/go" ) @@ -31,14 +33,41 @@ type Interface interface { Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error } +// DefaultJSONHandlerType is the type of library used as the backend for the JSON library +var DefaultJSONHandlerType = "goccy" + var ( // DefaultJSONHandler default json handler - DefaultJSONHandler Interface = JSONiter{jsoniter.ConfigCompatibleWithStandardLibrary} + DefaultJSONHandler Interface _ Interface = StdJSON{} _ Interface = JSONiter{} + _ Interface = GoCcyJSON{} ) +func init() { + SelectDefaultJSONHandler(DefaultJSONHandlerType) +} + +// SelectDefaultJSONHandler selects the default JSON handler +// Note: this function is not race safe and would need to be run before other uses +func SelectDefaultJSONHandler(typ string) { + switch strings.ToLower(typ) { + case "std": + DefaultJSONHandler = StdJSON{} + DefaultJSONHandlerType = "std" + case "goccy": + DefaultJSONHandler = GoCcyJSON{} + DefaultJSONHandlerType = "goccy" + case "jsoniter": + DefaultJSONHandler = JSONiter{jsoniter.ConfigCompatibleWithStandardLibrary} + DefaultJSONHandlerType = "jsoniter" + default: + DefaultJSONHandler = JSONiter{jsoniter.ConfigCompatibleWithStandardLibrary} + DefaultJSONHandlerType = "jsoniter" + } +} + // StdJSON implements Interface via encoding/json type StdJSON struct{} @@ -97,6 +126,34 @@ func (j JSONiter) Indent(dst *bytes.Buffer, src []byte, prefix, indent string) e return json.Indent(dst, src, prefix, indent) } +// GoCcyJSON implements Interface +type GoCcyJSON struct{} + +// Marshal implements Interface +func (j GoCcyJSON) Marshal(v interface{}) ([]byte, error) { + return goccy_json.Marshal(v) +} + +// Unmarshal implements Interface +func (j GoCcyJSON) Unmarshal(data []byte, v interface{}) error { + return goccy_json.Unmarshal(data, v) +} + +// NewEncoder implements Interface +func (j GoCcyJSON) NewEncoder(writer io.Writer) Encoder { + return goccy_json.NewEncoder(writer) +} + +// NewDecoder implements Interface +func (j GoCcyJSON) NewDecoder(reader io.Reader) Decoder { + return goccy_json.NewDecoder(reader) +} + +// Indent implements Interface +func (j GoCcyJSON) Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { + return goccy_json.Indent(dst, src, prefix, indent) +} + // Marshal converts object as bytes func Marshal(v interface{}) ([]byte, error) { return DefaultJSONHandler.Marshal(v) diff --git a/modules/lfs/http_client.go b/modules/lfs/http_client.go index 5df5ed33a9ff0..e124824bff974 100644 --- a/modules/lfs/http_client.go +++ b/modules/lfs/http_client.go @@ -111,7 +111,7 @@ func (c *HTTPClient) batch(ctx context.Context, operation string, objects []Poin err = json.NewDecoder(res.Body).Decode(&response) if err != nil { log.Error("Error decoding json: %v", err) - return nil, err + return nil, fmt.Errorf("invalid json: %w", err) } if len(response.Transfer) == 0 { diff --git a/vendor/github.com/goccy/go-json/CHANGELOG.md b/vendor/github.com/goccy/go-json/CHANGELOG.md index fd6aa9d6c7f28..c1d02bb484323 100644 --- a/vendor/github.com/goccy/go-json/CHANGELOG.md +++ b/vendor/github.com/goccy/go-json/CHANGELOG.md @@ -1,3 +1,31 @@ +# v0.7.9 - 2021/09/28 + +* Fix encoding of nil value about interface type that has method ( #291 ) + +# v0.7.8 - 2021/09/01 + +* Fix mapassign_faststr for indirect struct type ( #283 ) +* Fix encoding of not empty interface type ( #284 ) +* Fix encoding of empty struct interface type ( #286 ) + +# v0.7.7 - 2021/08/25 + +* Fix invalid utf8 on stream decoder ( #279 ) +* Fix buffer length bug on string stream decoder ( #280 ) + +Thank you @orisano !! + +# v0.7.6 - 2021/08/13 + +* Fix nil slice assignment ( #276 ) +* Improve error message ( #277 ) + +# v0.7.5 - 2021/08/12 + +* Fix encoding of embedded struct with tags ( #265 ) +* Fix encoding of embedded struct that isn't first field ( #272 ) +* Fix decoding of binary type with escaped char ( #273 ) + # v0.7.4 - 2021/07/06 * Fix encoding of indirect layout structure ( #264 ) diff --git a/vendor/github.com/goccy/go-json/docker-compose.yml b/vendor/github.com/goccy/go-json/docker-compose.yml index e5106662464bf..48415e3d97c9d 100644 --- a/vendor/github.com/goccy/go-json/docker-compose.yml +++ b/vendor/github.com/goccy/go-json/docker-compose.yml @@ -1,7 +1,7 @@ version: '2' services: go-json: - image: golang:1.16 + image: golang:1.17 volumes: - '.:/go/src/go-json' deploy: diff --git a/vendor/github.com/goccy/go-json/internal/decoder/bytes.go b/vendor/github.com/goccy/go-json/internal/decoder/bytes.go index 0c4681a118c16..01a37fef4fa44 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/bytes.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/bytes.go @@ -9,10 +9,11 @@ import ( ) type bytesDecoder struct { - typ *runtime.Type - sliceDecoder Decoder - structName string - fieldName string + typ *runtime.Type + sliceDecoder Decoder + stringDecoder *stringDecoder + structName string + fieldName string } func byteUnmarshalerSliceDecoder(typ *runtime.Type, structName string, fieldName string) Decoder { @@ -31,10 +32,11 @@ func byteUnmarshalerSliceDecoder(typ *runtime.Type, structName string, fieldName func newBytesDecoder(typ *runtime.Type, structName string, fieldName string) *bytesDecoder { return &bytesDecoder{ - typ: typ, - sliceDecoder: byteUnmarshalerSliceDecoder(typ, structName, fieldName), - structName: structName, - fieldName: fieldName, + typ: typ, + sliceDecoder: byteUnmarshalerSliceDecoder(typ, structName, fieldName), + stringDecoder: newStringDecoder(structName, fieldName), + structName: structName, + fieldName: fieldName, } } @@ -77,101 +79,36 @@ func (d *bytesDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe return cursor, nil } -func binaryBytes(s *Stream) ([]byte, error) { - s.cursor++ - start := s.cursor - for { - switch s.char() { - case '"': - literal := s.buf[start:s.cursor] - s.cursor++ - return literal, nil - case nul: - if s.read() { - continue - } - goto ERROR - } - s.cursor++ - } -ERROR: - return nil, errors.ErrUnexpectedEndOfJSON("[]byte", s.totalOffset()) -} - func (d *bytesDecoder) decodeStreamBinary(s *Stream, depth int64, p unsafe.Pointer) ([]byte, error) { - for { - switch s.char() { - case ' ', '\n', '\t', '\r': - s.cursor++ - continue - case '"': - return binaryBytes(s) - case 'n': - if err := nullBytes(s); err != nil { - return nil, err - } - return nil, nil - case '[': - if d.sliceDecoder == nil { - return nil, &errors.UnmarshalTypeError{ - Type: runtime.RType2Type(d.typ), - Offset: s.totalOffset(), - } - } - if err := d.sliceDecoder.DecodeStream(s, depth, p); err != nil { - return nil, err - } - return nil, nil - case nul: - if s.read() { - continue + c := s.skipWhiteSpace() + if c == '[' { + if d.sliceDecoder == nil { + return nil, &errors.UnmarshalTypeError{ + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), } } - break + err := d.sliceDecoder.DecodeStream(s, depth, p) + return nil, err } - return nil, errors.ErrNotAtBeginningOfValue(s.totalOffset()) + return d.stringDecoder.decodeStreamByte(s) } func (d *bytesDecoder) decodeBinary(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) ([]byte, int64, error) { buf := ctx.Buf - for { - switch buf[cursor] { - case ' ', '\n', '\t', '\r': - cursor++ - case '"': - cursor++ - start := cursor - for { - switch buf[cursor] { - case '"': - literal := buf[start:cursor] - cursor++ - return literal, cursor, nil - case nul: - return nil, 0, errors.ErrUnexpectedEndOfJSON("[]byte", cursor) - } - cursor++ - } - case '[': - if d.sliceDecoder == nil { - return nil, 0, &errors.UnmarshalTypeError{ - Type: runtime.RType2Type(d.typ), - Offset: cursor, - } + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == '[' { + if d.sliceDecoder == nil { + return nil, 0, &errors.UnmarshalTypeError{ + Type: runtime.RType2Type(d.typ), + Offset: cursor, } - c, err := d.sliceDecoder.Decode(ctx, cursor, depth, p) - if err != nil { - return nil, 0, err - } - return nil, c, nil - case 'n': - if err := validateNull(buf, cursor); err != nil { - return nil, 0, err - } - cursor += 4 - return nil, cursor, nil - default: - return nil, 0, errors.ErrNotAtBeginningOfValue(cursor) } + c, err := d.sliceDecoder.Decode(ctx, cursor, depth, p) + if err != nil { + return nil, 0, err + } + return nil, c, nil } + return d.stringDecoder.decodeByte(buf, cursor) } diff --git a/vendor/github.com/goccy/go-json/internal/decoder/func.go b/vendor/github.com/goccy/go-json/internal/decoder/func.go index 75afe75cd87f6..ee35637115c8d 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/func.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/func.go @@ -76,7 +76,7 @@ func (d *funcDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) err } } } - return errors.ErrNotAtBeginningOfValue(start) + return errors.ErrInvalidBeginningOfValue(s.buf[s.cursor], s.totalOffset()) } func (d *funcDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { @@ -137,5 +137,5 @@ func (d *funcDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe. } } } - return 0, errors.ErrNotAtBeginningOfValue(start) + return cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor) } diff --git a/vendor/github.com/goccy/go-json/internal/decoder/interface.go b/vendor/github.com/goccy/go-json/internal/decoder/interface.go index ea1b4aa57984f..4dbb4be4ac82b 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/interface.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/interface.go @@ -277,7 +277,7 @@ func (d *interfaceDecoder) decodeStreamEmptyInterface(s *Stream, depth int64, p } break } - return errors.ErrNotAtBeginningOfValue(s.totalOffset()) + return errors.ErrInvalidBeginningOfValue(c, s.totalOffset()) } type emptyInterface struct { @@ -454,5 +454,5 @@ func (d *interfaceDecoder) decodeEmptyInterface(ctx *RuntimeContext, cursor, dep **(**interface{})(unsafe.Pointer(&p)) = nil return cursor, nil } - return cursor, errors.ErrNotAtBeginningOfValue(cursor) + return cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor) } diff --git a/vendor/github.com/goccy/go-json/internal/decoder/map.go b/vendor/github.com/goccy/go-json/internal/decoder/map.go index dd480e1681a07..bb18ef995d8c8 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/map.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/map.go @@ -9,29 +9,42 @@ import ( ) type mapDecoder struct { - mapType *runtime.Type - keyType *runtime.Type - valueType *runtime.Type - stringKeyType bool - keyDecoder Decoder - valueDecoder Decoder - structName string - fieldName string + mapType *runtime.Type + keyType *runtime.Type + valueType *runtime.Type + canUseAssignFaststrType bool + keyDecoder Decoder + valueDecoder Decoder + structName string + fieldName string } func newMapDecoder(mapType *runtime.Type, keyType *runtime.Type, keyDec Decoder, valueType *runtime.Type, valueDec Decoder, structName, fieldName string) *mapDecoder { return &mapDecoder{ - mapType: mapType, - keyDecoder: keyDec, - keyType: keyType, - stringKeyType: keyType.Kind() == reflect.String, - valueType: valueType, - valueDecoder: valueDec, - structName: structName, - fieldName: fieldName, + mapType: mapType, + keyDecoder: keyDec, + keyType: keyType, + canUseAssignFaststrType: canUseAssignFaststrType(keyType, valueType), + valueType: valueType, + valueDecoder: valueDec, + structName: structName, + fieldName: fieldName, } } +const ( + mapMaxElemSize = 128 +) + +// See detail: https://github.com/goccy/go-json/pull/283 +func canUseAssignFaststrType(key *runtime.Type, value *runtime.Type) bool { + indirectElem := value.Size() > mapMaxElemSize + if indirectElem { + return false + } + return key.Kind() == reflect.String +} + //go:linkname makemap reflect.makemap func makemap(*runtime.Type, int) unsafe.Pointer @@ -45,8 +58,8 @@ func mapassign_faststr(t *runtime.Type, m unsafe.Pointer, s string) unsafe.Point func mapassign(t *runtime.Type, m unsafe.Pointer, k, v unsafe.Pointer) func (d *mapDecoder) mapassign(t *runtime.Type, m, k, v unsafe.Pointer) { - if d.stringKeyType { - mapV := mapassign_faststr(d.mapType, m, *(*string)(k)) + if d.canUseAssignFaststrType { + mapV := mapassign_faststr(t, m, *(*string)(k)) typedmemmove(d.valueType, mapV, v) } else { mapassign(t, m, k, v) diff --git a/vendor/github.com/goccy/go-json/internal/decoder/number.go b/vendor/github.com/goccy/go-json/internal/decoder/number.go index c50d62b99fed4..bf63773e30ed1 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/number.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/number.go @@ -52,6 +52,7 @@ func (d *numberDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsaf } func (d *numberDecoder) decodeStreamByte(s *Stream) ([]byte, error) { + start := s.cursor for { switch s.char() { case ' ', '\n', '\t', '\r': @@ -76,6 +77,9 @@ func (d *numberDecoder) decodeStreamByte(s *Stream) ([]byte, error) { } } ERROR: + if s.cursor == start { + return nil, errors.ErrInvalidBeginningOfValue(s.char(), s.totalOffset()) + } return nil, errors.ErrUnexpectedEndOfJSON("json.Number", s.totalOffset()) } diff --git a/vendor/github.com/goccy/go-json/internal/decoder/slice.go b/vendor/github.com/goccy/go-json/internal/decoder/slice.go index 853a555ece402..85b6e1119e733 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/slice.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/slice.go @@ -9,6 +9,13 @@ import ( "github.com/goccy/go-json/internal/runtime" ) +var ( + sliceType = runtime.Type2RType( + reflect.TypeOf((*sliceHeader)(nil)).Elem(), + ) + nilSlice = unsafe.Pointer(&sliceHeader{}) +) + type sliceDecoder struct { elemType *runtime.Type isElemPointerType bool @@ -107,7 +114,7 @@ func (d *sliceDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) er if err := nullBytes(s); err != nil { return err } - *(*unsafe.Pointer)(p) = nil + typedmemmove(sliceType, p, nilSlice) return nil case '[': s.cursor++ @@ -216,7 +223,7 @@ func (d *sliceDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe return 0, err } cursor += 4 - *(*unsafe.Pointer)(p) = nil + typedmemmove(sliceType, p, nilSlice) return cursor, nil case '[': cursor++ diff --git a/vendor/github.com/goccy/go-json/internal/decoder/string.go b/vendor/github.com/goccy/go-json/internal/decoder/string.go index 1e1ce157d4cf7..65b1004889028 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/string.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/string.go @@ -170,6 +170,7 @@ RETRY: s.buf = append(s.buf[:s.cursor-1], s.buf[s.cursor:]...) s.length-- s.cursor-- + p = s.bufptr() return p, nil } @@ -238,14 +239,23 @@ func stringBytes(s *Stream) ([]byte, error) { fallthrough default: // multi bytes character - r, _ := utf8.DecodeRune(s.buf[cursor:]) - b := []byte(string(r)) + if !utf8.FullRune(s.buf[cursor : len(s.buf)-1]) { + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + continue + } + goto ERROR + } + r, size := utf8.DecodeRune(s.buf[cursor:]) if r == utf8.RuneError { - s.buf = append(append(append([]byte{}, s.buf[:cursor]...), b...), s.buf[cursor+1:]...) + s.buf = append(append(append([]byte{}, s.buf[:cursor]...), runeErrBytes...), s.buf[cursor+1:]...) + cursor += runeErrBytesLen + s.length += runeErrBytesLen _, _, p = s.stat() + } else { + cursor += int64(size) } - cursor += int64(len(b)) - s.length += int64(len(b)) continue } cursor++ @@ -280,7 +290,7 @@ func (d *stringDecoder) decodeStreamByte(s *Stream) ([]byte, error) { } break } - return nil, errors.ErrNotAtBeginningOfValue(s.totalOffset()) + return nil, errors.ErrInvalidBeginningOfValue(s.char(), s.totalOffset()) } func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { @@ -355,7 +365,7 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err cursor += 4 return nil, cursor, nil default: - return nil, 0, errors.ErrNotAtBeginningOfValue(cursor) + return nil, 0, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor) } } } diff --git a/vendor/github.com/goccy/go-json/internal/decoder/struct.go b/vendor/github.com/goccy/go-json/internal/decoder/struct.go index d467b0d25c3a5..2c64680458940 100644 --- a/vendor/github.com/goccy/go-json/internal/decoder/struct.go +++ b/vendor/github.com/goccy/go-json/internal/decoder/struct.go @@ -261,7 +261,7 @@ func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64, cursor++ } default: - return cursor, nil, errors.ErrNotAtBeginningOfValue(cursor) + return cursor, nil, errors.ErrInvalidBeginningOfValue(char(b, cursor), cursor) } } } @@ -324,7 +324,7 @@ func decodeKeyByBitmapUint16(d *structDecoder, buf []byte, cursor int64) (int64, cursor++ } default: - return cursor, nil, errors.ErrNotAtBeginningOfValue(cursor) + return cursor, nil, errors.ErrInvalidBeginningOfValue(char(b, cursor), cursor) } } } @@ -376,7 +376,7 @@ func decodeKeyByBitmapUint8Stream(d *structDecoder, s *Stream) (*structFieldSet, _, cursor, p = s.stat() continue } - return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) + return nil, "", errors.ErrInvalidBeginningOfValue(char(p, cursor), s.totalOffset()) case '"': cursor++ FIRST_CHAR: @@ -443,7 +443,7 @@ func decodeKeyByBitmapUint8Stream(d *structDecoder, s *Stream) (*structFieldSet, cursor++ } default: - return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) + return nil, "", errors.ErrInvalidBeginningOfValue(char(p, cursor), s.totalOffset()) } } } @@ -463,7 +463,7 @@ func decodeKeyByBitmapUint16Stream(d *structDecoder, s *Stream) (*structFieldSet _, cursor, p = s.stat() continue } - return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) + return nil, "", errors.ErrInvalidBeginningOfValue(char(p, cursor), s.totalOffset()) case '"': cursor++ FIRST_CHAR: @@ -530,7 +530,7 @@ func decodeKeyByBitmapUint16Stream(d *structDecoder, s *Stream) (*structFieldSet cursor++ } default: - return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) + return nil, "", errors.ErrInvalidBeginningOfValue(char(p, cursor), s.totalOffset()) } } } @@ -653,7 +653,7 @@ func (d *structDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) e return nil default: if s.char() != '{' { - return errors.ErrNotAtBeginningOfValue(s.totalOffset()) + return errors.ErrInvalidBeginningOfValue(s.char(), s.totalOffset()) } } s.cursor++ @@ -740,7 +740,7 @@ func (d *structDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsaf return cursor, nil case '{': default: - return 0, errors.ErrNotAtBeginningOfValue(cursor) + return 0, errors.ErrInvalidBeginningOfValue(char(b, cursor), cursor) } cursor++ cursor = skipWhiteSpace(buf, cursor) diff --git a/vendor/github.com/goccy/go-json/internal/encoder/compiler.go b/vendor/github.com/goccy/go-json/internal/encoder/compiler.go index 01a5d4b282c1c..c627ed307b7fe 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/compiler.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/compiler.go @@ -1417,7 +1417,7 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) { valueCode = code } - if field.Anonymous { + if field.Anonymous && !tag.IsTaggedKey { tagKey := "" if tag.IsTaggedKey { tagKey = tag.Key @@ -1425,6 +1425,7 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) { for k, v := range anonymousStructFieldPairMap(tags, tagKey, valueCode) { anonymousFields[k] = append(anonymousFields[k], v...) } + valueCode.decIndent() // fix issue144 @@ -1505,7 +1506,6 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) { structEndCode := &Opcode{ Op: OpStructEnd, - Next: newEndOp(ctx), Type: nil, Indent: ctx.indent, } @@ -1530,6 +1530,7 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) { structEndCode.DisplayIdx = ctx.opcodeIndex structEndCode.Idx = opcodeOffset(ctx.ptrIndex) ctx.incIndex() + structEndCode.Next = newEndOp(ctx) if prevField != nil && prevField.NextField == nil { prevField.NextField = structEndCode diff --git a/vendor/github.com/goccy/go-json/internal/encoder/opcode.go b/vendor/github.com/goccy/go-json/internal/encoder/opcode.go index c23a90b2e12d1..7c50eefae3c4f 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/opcode.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/opcode.go @@ -13,15 +13,16 @@ const uintptrSize = 4 << (^uintptr(0) >> 63) type OpFlags uint16 const ( - AnonymousHeadFlags OpFlags = 1 << 0 - AnonymousKeyFlags OpFlags = 1 << 1 - IndirectFlags OpFlags = 1 << 2 - IsTaggedKeyFlags OpFlags = 1 << 3 - NilCheckFlags OpFlags = 1 << 4 - AddrForMarshalerFlags OpFlags = 1 << 5 - IsNextOpPtrTypeFlags OpFlags = 1 << 6 - IsNilableTypeFlags OpFlags = 1 << 7 - MarshalerContextFlags OpFlags = 1 << 8 + AnonymousHeadFlags OpFlags = 1 << 0 + AnonymousKeyFlags OpFlags = 1 << 1 + IndirectFlags OpFlags = 1 << 2 + IsTaggedKeyFlags OpFlags = 1 << 3 + NilCheckFlags OpFlags = 1 << 4 + AddrForMarshalerFlags OpFlags = 1 << 5 + IsNextOpPtrTypeFlags OpFlags = 1 << 6 + IsNilableTypeFlags OpFlags = 1 << 7 + MarshalerContextFlags OpFlags = 1 << 8 + NonEmptyInterfaceFlags OpFlags = 1 << 9 ) type Opcode struct { @@ -743,6 +744,10 @@ func newMapEndCode(ctx *compileContext, head *Opcode) *Opcode { } func newInterfaceCode(ctx *compileContext) *Opcode { + var flag OpFlags + if ctx.typ.NumMethod() > 0 { + flag |= NonEmptyInterfaceFlags + } return &Opcode{ Op: OpInterface, Idx: opcodeOffset(ctx.ptrIndex), @@ -750,6 +755,7 @@ func newInterfaceCode(ctx *compileContext) *Opcode { Type: ctx.typ, DisplayIdx: ctx.opcodeIndex, Indent: ctx.indent, + Flags: flag, } } diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm/util.go b/vendor/github.com/goccy/go-json/internal/encoder/vm/util.go index c55944794b52a..f06f9c8c4fa8e 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/vm/util.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm/util.go @@ -33,6 +33,15 @@ type emptyInterface struct { ptr unsafe.Pointer } +type nonEmptyInterface struct { + itab *struct { + ityp *runtime.Type // static interface type + typ *runtime.Type // dynamic concrete type + // unused fields... + } + ptr unsafe.Pointer +} + func errUnimplementedOp(op encoder.OpType) error { return fmt.Errorf("encoder: opcode %s has not been implemented", op) } diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go index 78da5e449993a..6853dc4d57fb8 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go @@ -7,6 +7,7 @@ import ( "unsafe" "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" ) func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { @@ -185,16 +186,30 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b } } ctx.SeenPtr = append(ctx.SeenPtr, p) - iface := (*emptyInterface)(ptrToUnsafePtr(p)) - if iface.ptr == nil { + var ( + typ *runtime.Type + ifacePtr unsafe.Pointer + ) + up := ptrToUnsafePtr(p) + if code.Flags&encoder.NonEmptyInterfaceFlags != 0 { + iface := (*nonEmptyInterface)(up) + ifacePtr = iface.ptr + if iface.itab != nil { + typ = iface.itab.typ + } + } else { + iface := (*emptyInterface)(up) + ifacePtr = iface.ptr + typ = iface.typ + } + if ifacePtr == nil { b = appendNull(ctx, b) b = appendComma(ctx, b) code = code.Next break } - - ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) - ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + ctx.KeepRefs = append(ctx.KeepRefs, up) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(typ))) if err != nil { return nil, err } @@ -223,7 +238,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr end := ifaceCodeSet.EndCode - store(ctxptr, c.Idx, uintptr(iface.ptr)) + store(ctxptr, c.Idx, uintptr(ifacePtr)) store(ctxptr, end.Idx, oldOffset) store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) storeIndent(ctxptr, end, uintptr(oldBaseIndent)) @@ -578,8 +593,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b if code.Flags&encoder.AnonymousHeadFlags == 0 { b = appendStructHead(ctx, b) } - if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { - b = appendStructKey(ctx, code, b) + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } } p += uintptr(code.Offset) code = code.Next @@ -3437,7 +3454,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b code = code.Next } case encoder.OpStructField: - if code.Flags&encoder.AnonymousKeyFlags == 0 { + if code.Flags&encoder.IsTaggedKeyFlags != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { b = appendStructKey(ctx, code, b) } p := load(ctxptr, code.Idx) + uintptr(code.Offset) diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go index 516536d740fcd..710087f64efb3 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go @@ -26,6 +26,15 @@ type emptyInterface struct { ptr unsafe.Pointer } +type nonEmptyInterface struct { + itab *struct { + ityp *runtime.Type // static interface type + typ *runtime.Type // dynamic concrete type + // unused fields... + } + ptr unsafe.Pointer +} + func errUnimplementedOp(op encoder.OpType) error { return fmt.Errorf("encoder: opcode %s has not been implemented", op) } diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go index 0d4c472a5cd87..256781d8332cd 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go @@ -7,6 +7,7 @@ import ( "unsafe" "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" ) func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { @@ -185,16 +186,30 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b } } ctx.SeenPtr = append(ctx.SeenPtr, p) - iface := (*emptyInterface)(ptrToUnsafePtr(p)) - if iface.ptr == nil { + var ( + typ *runtime.Type + ifacePtr unsafe.Pointer + ) + up := ptrToUnsafePtr(p) + if code.Flags&encoder.NonEmptyInterfaceFlags != 0 { + iface := (*nonEmptyInterface)(up) + ifacePtr = iface.ptr + if iface.itab != nil { + typ = iface.itab.typ + } + } else { + iface := (*emptyInterface)(up) + ifacePtr = iface.ptr + typ = iface.typ + } + if ifacePtr == nil { b = appendNull(ctx, b) b = appendComma(ctx, b) code = code.Next break } - - ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) - ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + ctx.KeepRefs = append(ctx.KeepRefs, up) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(typ))) if err != nil { return nil, err } @@ -223,7 +238,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr end := ifaceCodeSet.EndCode - store(ctxptr, c.Idx, uintptr(iface.ptr)) + store(ctxptr, c.Idx, uintptr(ifacePtr)) store(ctxptr, end.Idx, oldOffset) store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) storeIndent(ctxptr, end, uintptr(oldBaseIndent)) @@ -578,8 +593,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b if code.Flags&encoder.AnonymousHeadFlags == 0 { b = appendStructHead(ctx, b) } - if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { - b = appendStructKey(ctx, code, b) + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } } p += uintptr(code.Offset) code = code.Next @@ -3437,7 +3454,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b code = code.Next } case encoder.OpStructField: - if code.Flags&encoder.AnonymousKeyFlags == 0 { + if code.Flags&encoder.IsTaggedKeyFlags != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { b = appendStructKey(ctx, code, b) } p := load(ctxptr, code.Idx) + uintptr(code.Offset) diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go index 9f98781b8b9a1..1399a25b67e3f 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go @@ -28,6 +28,15 @@ type emptyInterface struct { ptr unsafe.Pointer } +type nonEmptyInterface struct { + itab *struct { + ityp *runtime.Type // static interface type + typ *runtime.Type // dynamic concrete type + // unused fields... + } + ptr unsafe.Pointer +} + func errUnimplementedOp(op encoder.OpType) error { return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op) } diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go index de8b858f97e36..c9011c8670dbb 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go @@ -7,6 +7,7 @@ import ( "unsafe" "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" ) func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { @@ -185,16 +186,30 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b } } ctx.SeenPtr = append(ctx.SeenPtr, p) - iface := (*emptyInterface)(ptrToUnsafePtr(p)) - if iface.ptr == nil { + var ( + typ *runtime.Type + ifacePtr unsafe.Pointer + ) + up := ptrToUnsafePtr(p) + if code.Flags&encoder.NonEmptyInterfaceFlags != 0 { + iface := (*nonEmptyInterface)(up) + ifacePtr = iface.ptr + if iface.itab != nil { + typ = iface.itab.typ + } + } else { + iface := (*emptyInterface)(up) + ifacePtr = iface.ptr + typ = iface.typ + } + if ifacePtr == nil { b = appendNull(ctx, b) b = appendComma(ctx, b) code = code.Next break } - - ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) - ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + ctx.KeepRefs = append(ctx.KeepRefs, up) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(typ))) if err != nil { return nil, err } @@ -223,7 +238,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr end := ifaceCodeSet.EndCode - store(ctxptr, c.Idx, uintptr(iface.ptr)) + store(ctxptr, c.Idx, uintptr(ifacePtr)) store(ctxptr, end.Idx, oldOffset) store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) storeIndent(ctxptr, end, uintptr(oldBaseIndent)) @@ -578,8 +593,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b if code.Flags&encoder.AnonymousHeadFlags == 0 { b = appendStructHead(ctx, b) } - if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { - b = appendStructKey(ctx, code, b) + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } } p += uintptr(code.Offset) code = code.Next @@ -3437,7 +3454,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b code = code.Next } case encoder.OpStructField: - if code.Flags&encoder.AnonymousKeyFlags == 0 { + if code.Flags&encoder.IsTaggedKeyFlags != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { b = appendStructKey(ctx, code, b) } p := load(ctxptr, code.Idx) + uintptr(code.Offset) diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go index 5f5d8a58fd0ad..2e3c35fb97ee0 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go @@ -35,6 +35,15 @@ type emptyInterface struct { ptr unsafe.Pointer } +type nonEmptyInterface struct { + itab *struct { + ityp *runtime.Type // static interface type + typ *runtime.Type // dynamic concrete type + // unused fields... + } + ptr unsafe.Pointer +} + func errUnimplementedOp(op encoder.OpType) error { return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op) } diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go index d10ce75c28a7a..250221623a458 100644 --- a/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go @@ -7,6 +7,7 @@ import ( "unsafe" "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" ) func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { @@ -185,16 +186,30 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b } } ctx.SeenPtr = append(ctx.SeenPtr, p) - iface := (*emptyInterface)(ptrToUnsafePtr(p)) - if iface.ptr == nil { + var ( + typ *runtime.Type + ifacePtr unsafe.Pointer + ) + up := ptrToUnsafePtr(p) + if code.Flags&encoder.NonEmptyInterfaceFlags != 0 { + iface := (*nonEmptyInterface)(up) + ifacePtr = iface.ptr + if iface.itab != nil { + typ = iface.itab.typ + } + } else { + iface := (*emptyInterface)(up) + ifacePtr = iface.ptr + typ = iface.typ + } + if ifacePtr == nil { b = appendNull(ctx, b) b = appendComma(ctx, b) code = code.Next break } - - ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) - ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + ctx.KeepRefs = append(ctx.KeepRefs, up) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(typ))) if err != nil { return nil, err } @@ -223,7 +238,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr end := ifaceCodeSet.EndCode - store(ctxptr, c.Idx, uintptr(iface.ptr)) + store(ctxptr, c.Idx, uintptr(ifacePtr)) store(ctxptr, end.Idx, oldOffset) store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) storeIndent(ctxptr, end, uintptr(oldBaseIndent)) @@ -578,8 +593,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b if code.Flags&encoder.AnonymousHeadFlags == 0 { b = appendStructHead(ctx, b) } - if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { - b = appendStructKey(ctx, code, b) + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } } p += uintptr(code.Offset) code = code.Next @@ -3437,7 +3454,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b code = code.Next } case encoder.OpStructField: - if code.Flags&encoder.AnonymousKeyFlags == 0 { + if code.Flags&encoder.IsTaggedKeyFlags != 0 || code.Flags&encoder.AnonymousKeyFlags == 0 { b = appendStructKey(ctx, code, b) } p := load(ctxptr, code.Idx) + uintptr(code.Offset) diff --git a/vendor/github.com/goccy/go-json/internal/errors/error.go b/vendor/github.com/goccy/go-json/internal/errors/error.go index 329e2f12d293a..d58e39f4e1128 100644 --- a/vendor/github.com/goccy/go-json/internal/errors/error.go +++ b/vendor/github.com/goccy/go-json/internal/errors/error.go @@ -155,3 +155,10 @@ func ErrInvalidCharacter(c byte, context string, cursor int64) *SyntaxError { Offset: cursor, } } + +func ErrInvalidBeginningOfValue(c byte, cursor int64) *SyntaxError { + return &SyntaxError{ + msg: fmt.Sprintf("invalid character '%c' looking for beginning of value", c), + Offset: cursor, + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 82afbb6730753..bee5b50e09cb1 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -422,7 +422,8 @@ github.com/gobwas/glob/syntax/ast github.com/gobwas/glob/syntax/lexer github.com/gobwas/glob/util/runes github.com/gobwas/glob/util/strings -# github.com/goccy/go-json v0.7.4 +# github.com/goccy/go-json v0.7.9 +## explicit github.com/goccy/go-json github.com/goccy/go-json/internal/decoder github.com/goccy/go-json/internal/encoder From 396c033c6346ecb7b33c7c092e0075826848d54d Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 21 Oct 2021 19:08:44 +0100 Subject: [PATCH 2/5] Make json library configurable Signed-off-by: Andrew Thornton --- custom/conf/app.example.ini | 2 ++ .../doc/advanced/config-cheat-sheet.en-us.md | 2 ++ docs/content/doc/usage/command-line.en-us.md | 1 + main.go | 16 +++++++++++++++- modules/json/json.go | 8 +++++--- modules/setting/setting.go | 2 ++ options/locale/locale_en-US.ini | 1 + routers/web/admin/admin.go | 1 + templates/admin/config.tmpl | 2 ++ 9 files changed, 31 insertions(+), 4 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index bdc42480e443e..12a06552a5fe5 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -19,6 +19,8 @@ RUN_USER = ; git ;; ;; Application run mode, affects performance and debugging. Either "dev", "prod" or "test", default is "prod" RUN_MODE = ; prod +;; JSON library to use. Either "std", "goccy", or "jsoniter". Will default to "jsoniter" +; JSON_LIBRARY = jsoniter ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 251f6bd51a9df..92e9069292d48 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -39,6 +39,8 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `RUN_USER`: **git**: The user Gitea will run as. This should be a dedicated system (non-user) account. Setting this incorrectly will cause Gitea to not start. - `RUN_MODE`: **prod**: Application run mode, affects performance and debugging. Either "dev", "prod" or "test". +- `JSON_LIBRARY`: **jsoniter**: JSON library to use. Either "std", "goccy", or "jsoniter". Will default to "jsoniter" + ## Repository (`repository`) diff --git a/docs/content/doc/usage/command-line.en-us.md b/docs/content/doc/usage/command-line.en-us.md index b12400c57ec19..c74d0cc3ce107 100644 --- a/docs/content/doc/usage/command-line.en-us.md +++ b/docs/content/doc/usage/command-line.en-us.md @@ -32,6 +32,7 @@ All global options can be placed at the command level. - `--custom-path path`, `-C path`: Location of the Gitea custom folder. Optional. (default: `AppWorkPath`/custom or `$GITEA_CUSTOM`). - `--config path`, `-c path`: Gitea configuration file path. Optional. (default: `custom`/conf/app.ini). - `--work-path path`, `-w path`: Gitea `AppWorkPath`. Optional. (default: LOCATION_OF_GITEA_BINARY or `$GITEA_WORK_DIR`) +- `--json-library`: JSON library to use. Optional. (default: `jsoniter`, but may be: `std`, `goccy` or `jsoniter`) NB: The defaults custom-path, config and work-path can also be changed at build time (if preferred). diff --git a/main.go b/main.go index 6cbdc244018b4..9c2735ebbcb45 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,7 @@ import ( "time" "code.gitea.io/gitea/cmd" + "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -99,6 +100,11 @@ arguments - which can alternatively be run by running the subcommand web.` Value: setting.AppWorkPath, Usage: "Set the gitea working path", }, + cli.StringFlag{ + Name: "json-library", + Value: json.DefaultJSONHandlerType, + Usage: "Set the default json library type", + }, } // Set the default to be equivalent to cmdWeb and add the default flags @@ -130,10 +136,14 @@ func establishCustomPath(ctx *cli.Context) error { var providedCustom string var providedConf string var providedWorkPath string + var defaultJSONHandler string currentCtx := ctx for { - if len(providedCustom) != 0 && len(providedConf) != 0 && len(providedWorkPath) != 0 { + if len(providedCustom) != 0 && + len(providedConf) != 0 && + len(providedWorkPath) != 0 && + len(defaultJSONHandler) != 0 { break } if currentCtx == nil { @@ -148,9 +158,13 @@ func establishCustomPath(ctx *cli.Context) error { if currentCtx.IsSet("work-path") && len(providedWorkPath) == 0 { providedWorkPath = currentCtx.String("work-path") } + if currentCtx.IsSet("json-library") && len(defaultJSONHandler) == 0 { + defaultJSONHandler = currentCtx.String("json-library") + } currentCtx = currentCtx.Parent() } + json.SelectDefaultJSONHandler(defaultJSONHandler) setting.SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath) setAppHelpTemplates() diff --git a/modules/json/json.go b/modules/json/json.go index d336694ec4ccc..22bdad698850d 100644 --- a/modules/json/json.go +++ b/modules/json/json.go @@ -34,7 +34,7 @@ type Interface interface { } // DefaultJSONHandlerType is the type of library used as the backend for the JSON library -var DefaultJSONHandlerType = "goccy" +var DefaultJSONHandlerType = "jsoniter" var ( // DefaultJSONHandler default json handler @@ -52,6 +52,9 @@ func init() { // SelectDefaultJSONHandler selects the default JSON handler // Note: this function is not race safe and would need to be run before other uses func SelectDefaultJSONHandler(typ string) { + if typ == DefaultJSONHandlerType { + return + } switch strings.ToLower(typ) { case "std": DefaultJSONHandler = StdJSON{} @@ -60,8 +63,7 @@ func SelectDefaultJSONHandler(typ string) { DefaultJSONHandler = GoCcyJSON{} DefaultJSONHandlerType = "goccy" case "jsoniter": - DefaultJSONHandler = JSONiter{jsoniter.ConfigCompatibleWithStandardLibrary} - DefaultJSONHandlerType = "jsoniter" + fallthrough default: DefaultJSONHandler = JSONiter{jsoniter.ConfigCompatibleWithStandardLibrary} DefaultJSONHandlerType = "jsoniter" diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 2133184cfc40d..89fee7ca9b504 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -568,6 +568,8 @@ func NewContext() { } Cfg.NameMapper = ini.SnackCase + json.SelectDefaultJSONHandler(Cfg.Section("").Key("JSON_LIBRARY").MustString(json.DefaultJSONHandlerType)) + homeDir, err := com.HomeDir() if err != nil { log.Fatal("Failed to get home directory: %v", err) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 407ec9f84ee10..30f1f23d779d8 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2544,6 +2544,7 @@ config.offline_mode = Local Mode config.disable_router_log = Disable Router Log config.run_user = Run As Username config.run_mode = Run Mode +config.json_library = JSON library config.git_version = Git Version config.repo_root_path = Repository Root Path config.lfs_root_path = LFS Root Path diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index ca5b157523c50..21b4056e0cde6 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -316,6 +316,7 @@ func Config(ctx *context.Context) { ctx.Data["DisableRouterLog"] = setting.DisableRouterLog ctx.Data["EnableXORMLog"] = setting.EnableXORMLog ctx.Data["LogSQL"] = setting.Database.LogSQL + ctx.Data["JSONLibrary"] = json.DefaultJSONHandlerType ctx.HTML(http.StatusOK, tplConfig) } diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index b419d04a1b240..471223453be9f 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -29,6 +29,8 @@
{{.RunUser}}
{{.i18n.Tr "admin.config.run_mode"}}
{{.RunMode}}
+
{{.i18n.Tr "admin.config.json_library"}}
+
{{.JSONLibrary}}
From 3697880c89b98b799fa213cccd2f6345112503fa Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 21 Oct 2021 19:11:49 +0100 Subject: [PATCH 3/5] update the from-source document Signed-off-by: Andrew Thornton --- docs/content/doc/installation/from-source.en-us.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/doc/installation/from-source.en-us.md b/docs/content/doc/installation/from-source.en-us.md index 496111e956348..4fe49b85843a5 100644 --- a/docs/content/doc/installation/from-source.en-us.md +++ b/docs/content/doc/installation/from-source.en-us.md @@ -161,6 +161,7 @@ using the `LDFLAGS` environment variable for `make`. The appropriate settings ar - For `AppWorkPath` you should use `-X \"code.gitea.io/gitea/modules/setting.AppWorkPath=working-path\"` - For `StaticRootPath` you should use `-X \"code.gitea.io/gitea/modules/setting.StaticRootPath=static-root-path\"` - To change the default PID file location use `-X \"code.gitea.io/gitea/modules/setting.PIDFile=/run/gitea.pid\"` +- To change the default JSON library use `-X \"code.gitea.io/gitea/modules/json.DefaultJSONHandlerType=\"` Add as many of the strings with their preceding `-X` to the `LDFLAGS` variable and run `make build` with the appropriate `TAGS` as above. From b5a6bde858970356808c00523c8a51d29713a6f9 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 21 Oct 2021 19:35:02 +0100 Subject: [PATCH 4/5] oops Signed-off-by: Andrew Thornton --- modules/json/json.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/json/json.go b/modules/json/json.go index 22bdad698850d..5a72fcee22569 100644 --- a/modules/json/json.go +++ b/modules/json/json.go @@ -38,7 +38,7 @@ var DefaultJSONHandlerType = "jsoniter" var ( // DefaultJSONHandler default json handler - DefaultJSONHandler Interface + DefaultJSONHandler Interface = JSONiter{} _ Interface = StdJSON{} _ Interface = JSONiter{} From 4d2b1669a81ed64181ae0518db0bee64073c7a38 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 21 Oct 2021 20:43:53 +0100 Subject: [PATCH 5/5] oops (2) Signed-off-by: Andrew Thornton --- modules/json/json.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/json/json.go b/modules/json/json.go index 5a72fcee22569..30f46fa176496 100644 --- a/modules/json/json.go +++ b/modules/json/json.go @@ -38,7 +38,7 @@ var DefaultJSONHandlerType = "jsoniter" var ( // DefaultJSONHandler default json handler - DefaultJSONHandler Interface = JSONiter{} + DefaultJSONHandler Interface = JSONiter{jsoniter.ConfigCompatibleWithStandardLibrary} _ Interface = StdJSON{} _ Interface = JSONiter{}