From 5a024ca2f11703081c44cad38482d838c3e71cf1 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 3 Jun 2021 18:49:01 +0900 Subject: [PATCH] Fix package layout for decoder --- codec.go | 104 ---------- decode.go | 149 +++----------- export_test.go | 10 +- .../decoder/anonymous_field.go | 16 +- decode_array.go => internal/decoder/array.go | 27 +-- decode_bool.go => internal/decoder/bool.go | 12 +- decode_bytes.go => internal/decoder/bytes.go | 47 ++--- .../decoder/compile.go | 125 +++++++----- .../decoder/compile_norace.go | 14 +- .../decoder/compile_race.go | 6 +- .../decoder/context.go | 56 +++--- decode_float.go => internal/decoder/float.go | 22 ++- decode_int.go => internal/decoder/int.go | 23 ++- .../decoder/interface.go | 77 ++++---- decode_map.go => internal/decoder/map.go | 47 ++--- .../decoder/number.go | 27 +-- decode_ptr.go => internal/decoder/ptr.go | 18 +- decode_slice.go => internal/decoder/slice.go | 39 ++-- .../decoder/stream.go | 187 ++++++++++++++---- .../decoder/string.go | 40 ++-- .../decoder/struct.go | 86 ++++---- internal/decoder/type.go | 23 +++ decode_uint.go => internal/decoder/uint.go | 23 ++- .../decoder/unmarshal_json.go | 22 ++- .../decoder/unmarshal_text.go | 41 ++-- .../decoder/wrapped_string.go | 16 +- rtype.go | 27 --- 27 files changed, 640 insertions(+), 644 deletions(-) delete mode 100644 codec.go rename decode_anonymous_field.go => internal/decoder/anonymous_field.go (54%) rename decode_array.go => internal/decoder/array.go (73%) rename decode_bool.go => internal/decoder/bool.go (80%) rename decode_bytes.go => internal/decoder/bytes.go (65%) rename decode_compile.go => internal/decoder/compile.go (70%) rename decode_compile_norace.go => internal/decoder/compile_norace.go (57%) rename decode_compile_race.go => internal/decoder/compile_race.go (81%) rename decode_context.go => internal/decoder/context.go (64%) rename decode_float.go => internal/decoder/float.go (80%) rename decode_int.go => internal/decoder/int.go (86%) rename decode_interface.go => internal/decoder/interface.go (81%) rename decode_map.go => internal/decoder/map.go (62%) rename decode_number.go => internal/decoder/number.go (73%) rename decode_ptr.go => internal/decoder/ptr.go (73%) rename decode_slice.go => internal/decoder/slice.go (83%) rename decode_stream.go => internal/decoder/stream.go (62%) rename decode_string.go => internal/decoder/string.go (87%) rename decode_struct.go => internal/decoder/struct.go (80%) create mode 100644 internal/decoder/type.go rename decode_uint.go => internal/decoder/uint.go (83%) rename decode_unmarshal_json.go => internal/decoder/unmarshal_json.go (66%) rename decode_unmarshal_text.go => internal/decoder/unmarshal_text.go (83%) rename decode_wrapped_string.go => internal/decoder/wrapped_string.go (68%) delete mode 100644 rtype.go diff --git a/codec.go b/codec.go deleted file mode 100644 index e109d99..0000000 --- a/codec.go +++ /dev/null @@ -1,104 +0,0 @@ -package json - -import ( - "fmt" - "reflect" - "sync/atomic" - "unsafe" -) - -const ( - maxAcceptableTypeAddrRange = 1024 * 1024 * 2 // 2 Mib -) - -var ( - cachedDecoder []decoder - cachedDecoderMap unsafe.Pointer // map[uintptr]decoder - baseTypeAddr uintptr - maxTypeAddr uintptr - typeAddrShift uintptr -) - -//go:linkname typelinks reflect.typelinks -func typelinks() ([]unsafe.Pointer, [][]int32) - -//go:linkname rtypeOff reflect.rtypeOff -func rtypeOff(unsafe.Pointer, int32) unsafe.Pointer - -func setupCodec() error { - sections, offsets := typelinks() - if len(sections) != 1 { - return fmt.Errorf("failed to get sections") - } - if len(offsets) != 1 { - return fmt.Errorf("failed to get offsets") - } - section := sections[0] - offset := offsets[0] - var ( - min uintptr = uintptr(^uint(0)) - max uintptr = 0 - isAligned64 = true - isAligned32 = true - ) - for i := 0; i < len(offset); i++ { - typ := (*rtype)(rtypeOff(section, offset[i])) - addr := uintptr(unsafe.Pointer(typ)) - if min > addr { - min = addr - } - if max < addr { - max = addr - } - if typ.Kind() == reflect.Ptr { - addr = uintptr(unsafe.Pointer(typ.Elem())) - if min > addr { - min = addr - } - if max < addr { - max = addr - } - } - - // check every address is aligned from the base address - isAligned64 = isAligned64 && (addr-min)&63 == 0 - isAligned32 = isAligned32 && (addr-min)&31 == 0 - } - addrRange := max - min - if addrRange == 0 { - return fmt.Errorf("failed to get address range of types") - } - if isAligned64 { - typeAddrShift = 6 - } else if isAligned32 { - typeAddrShift = 5 - } - cacheSize := addrRange >> typeAddrShift - if cacheSize > maxAcceptableTypeAddrRange { - return fmt.Errorf("too big address range %d", addrRange) - } - cachedDecoder = make([]decoder, cacheSize) - baseTypeAddr = min - maxTypeAddr = max - return nil -} - -func init() { - _ = setupCodec() -} - -func loadDecoderMap() map[uintptr]decoder { - p := atomic.LoadPointer(&cachedDecoderMap) - return *(*map[uintptr]decoder)(unsafe.Pointer(&p)) -} - -func storeDecoder(typ uintptr, dec decoder, m map[uintptr]decoder) { - newDecoderMap := make(map[uintptr]decoder, len(m)+1) - newDecoderMap[typ] = dec - - for k, v := range m { - newDecoderMap[k] = v - } - - atomic.StorePointer(&cachedDecoderMap, *(*unsafe.Pointer)(unsafe.Pointer(&newDecoderMap))) -} diff --git a/decode.go b/decode.go index 14d1a33..82070d3 100644 --- a/decode.go +++ b/decode.go @@ -1,32 +1,27 @@ package json import ( - "encoding" "fmt" "io" "reflect" - "strconv" "unsafe" -) -type decoder interface { - decode([]byte, int64, int64, unsafe.Pointer) (int64, error) - decodeStream(*stream, int64, unsafe.Pointer) error -} + "github.com/goccy/go-json/internal/decoder" + "github.com/goccy/go-json/internal/runtime" +) type Decoder struct { - s *stream + s *decoder.Stream } -var ( - unmarshalJSONType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() - unmarshalTextType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() +const ( + nul = '\000' ) -const ( - nul = '\000' - maxDecodeNestingDepth = 10000 -) +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} func unmarshal(data []byte, v interface{}) error { src := make([]byte, len(data)+1) // append nul byte to the end @@ -37,11 +32,11 @@ func unmarshal(data []byte, v interface{}) error { if err := validateType(header.typ, uintptr(header.ptr)); err != nil { return err } - dec, err := decodeCompileToGetDecoder(header.typ) + dec, err := decoder.CompileToGetDecoder(header.typ) if err != nil { return err } - cursor, err := dec.decode(src, 0, 0, header.ptr) + cursor, err := dec.Decode(src, 0, 0, header.ptr) if err != nil { return err } @@ -57,11 +52,11 @@ func unmarshalNoEscape(data []byte, v interface{}) error { if err := validateType(header.typ, uintptr(header.ptr)); err != nil { return err } - dec, err := decodeCompileToGetDecoder(header.typ) + dec, err := decoder.CompileToGetDecoder(header.typ) if err != nil { return err } - cursor, err := dec.decode(src, 0, 0, noescape(header.ptr)) + cursor, err := dec.Decode(src, 0, 0, noescape(header.ptr)) if err != nil { return err } @@ -91,9 +86,9 @@ func noescape(p unsafe.Pointer) unsafe.Pointer { return unsafe.Pointer(x ^ 0) } -func validateType(typ *rtype, p uintptr) error { +func validateType(typ *runtime.Type, p uintptr) error { if typ == nil || typ.Kind() != reflect.Ptr || p == 0 { - return &InvalidUnmarshalError{Type: rtype2type(typ)} + return &InvalidUnmarshalError{Type: runtime.RType2Type(typ)} } return nil } @@ -103,7 +98,7 @@ func validateType(typ *rtype, p uintptr) error { // The decoder introduces its own buffering and may // read data from r beyond the JSON values requested. func NewDecoder(r io.Reader) *Decoder { - s := newStream(r) + s := decoder.NewStream(r) return &Decoder{ s: s, } @@ -112,28 +107,7 @@ func NewDecoder(r io.Reader) *Decoder { // Buffered returns a reader of the data remaining in the Decoder's // buffer. The reader is valid until the next call to Decode. func (d *Decoder) Buffered() io.Reader { - return d.s.buffered() -} - -func (d *Decoder) prepareForDecode() error { - s := d.s - for { - switch s.char() { - case ' ', '\t', '\r', '\n': - s.cursor++ - continue - case ',', ':': - s.cursor++ - return nil - case nul: - if s.read() { - continue - } - return io.EOF - } - break - } - return nil + return d.s.Buffered() } // Decode reads the next JSON-encoded value from its @@ -147,115 +121,48 @@ func (d *Decoder) Decode(v interface{}) error { ptr := uintptr(header.ptr) typeptr := uintptr(unsafe.Pointer(typ)) // noescape trick for header.typ ( reflect.*rtype ) - copiedType := *(**rtype)(unsafe.Pointer(&typeptr)) + copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr)) if err := validateType(copiedType, ptr); err != nil { return err } - dec, err := decodeCompileToGetDecoder(typ) + dec, err := decoder.CompileToGetDecoder(typ) if err != nil { return err } - if err := d.prepareForDecode(); err != nil { + if err := d.s.PrepareForDecode(); err != nil { return err } s := d.s - if err := dec.decodeStream(s, 0, header.ptr); err != nil { + if err := dec.DecodeStream(s, 0, header.ptr); err != nil { return err } - s.reset() - s.bufSize = initBufSize + s.Reset() return nil } func (d *Decoder) More() bool { - s := d.s - for { - switch s.char() { - case ' ', '\n', '\r', '\t': - s.cursor++ - continue - case '}', ']': - return false - case nul: - if s.read() { - continue - } - return false - } - break - } - return true + return d.s.More() } func (d *Decoder) Token() (Token, error) { - s := d.s - for { - c := s.char() - switch c { - case ' ', '\n', '\r', '\t': - s.cursor++ - case '{', '[', ']', '}': - s.cursor++ - return Delim(c), nil - case ',', ':': - s.cursor++ - case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - bytes := floatBytes(s) - s := *(*string)(unsafe.Pointer(&bytes)) - f64, err := strconv.ParseFloat(s, 64) - if err != nil { - return nil, err - } - return f64, nil - case '"': - bytes, err := stringBytes(s) - if err != nil { - return nil, err - } - return string(bytes), nil - case 't': - if err := trueBytes(s); err != nil { - return nil, err - } - return true, nil - case 'f': - if err := falseBytes(s); err != nil { - return nil, err - } - return false, nil - case 'n': - if err := nullBytes(s); err != nil { - return nil, err - } - return nil, nil - case nul: - if s.read() { - continue - } - goto END - default: - return nil, errInvalidCharacter(s.char(), "token", s.totalOffset()) - } - } -END: - return nil, io.EOF + return d.s.Token() } // DisallowUnknownFields causes the Decoder to return an error when the destination // is a struct and the input contains object keys which do not match any // non-ignored, exported fields in the destination. func (d *Decoder) DisallowUnknownFields() { - d.s.disallowUnknownFields = true + d.s.DisallowUnknownFields = true } func (d *Decoder) InputOffset() int64 { - return d.s.totalOffset() + return d.s.TotalOffset() } // UseNumber causes the Decoder to unmarshal a number into an interface{} as a // Number instead of as a float64. func (d *Decoder) UseNumber() { - d.s.useNumber = true + d.s.UseNumber = true } diff --git a/export_test.go b/export_test.go index b0e3532..526f9b2 100644 --- a/export_test.go +++ b/export_test.go @@ -1,6 +1,10 @@ package json -var ( - NewSyntaxError = errSyntax - NewMarshalerError = errMarshaler +import ( + "github.com/goccy/go-json/internal/errors" +) + +var ( + NewSyntaxError = errors.ErrSyntax + NewMarshalerError = errors.ErrMarshaler ) diff --git a/decode_anonymous_field.go b/internal/decoder/anonymous_field.go similarity index 54% rename from decode_anonymous_field.go rename to internal/decoder/anonymous_field.go index 77931f2..25af1d9 100644 --- a/decode_anonymous_field.go +++ b/internal/decoder/anonymous_field.go @@ -1,16 +1,18 @@ -package json +package decoder import ( "unsafe" + + "github.com/goccy/go-json/internal/runtime" ) type anonymousFieldDecoder struct { - structType *rtype + structType *runtime.Type offset uintptr dec decoder } -func newAnonymousFieldDecoder(structType *rtype, offset uintptr, dec decoder) *anonymousFieldDecoder { +func newAnonymousFieldDecoder(structType *runtime.Type, offset uintptr, dec decoder) *anonymousFieldDecoder { return &anonymousFieldDecoder{ structType: structType, offset: offset, @@ -18,18 +20,18 @@ func newAnonymousFieldDecoder(structType *rtype, offset uintptr, dec decoder) *a } } -func (d *anonymousFieldDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *anonymousFieldDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { if *(*unsafe.Pointer)(p) == nil { *(*unsafe.Pointer)(p) = unsafe_New(d.structType) } p = *(*unsafe.Pointer)(p) - return d.dec.decodeStream(s, depth, unsafe.Pointer(uintptr(p)+d.offset)) + return d.dec.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+d.offset)) } -func (d *anonymousFieldDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *anonymousFieldDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { if *(*unsafe.Pointer)(p) == nil { *(*unsafe.Pointer)(p) = unsafe_New(d.structType) } p = *(*unsafe.Pointer)(p) - return d.dec.decode(buf, cursor, depth, unsafe.Pointer(uintptr(p)+d.offset)) + return d.dec.Decode(buf, cursor, depth, unsafe.Pointer(uintptr(p)+d.offset)) } diff --git a/decode_array.go b/internal/decoder/array.go similarity index 73% rename from decode_array.go rename to internal/decoder/array.go index 508f097..f917fa3 100644 --- a/decode_array.go +++ b/internal/decoder/array.go @@ -1,11 +1,14 @@ -package json +package decoder import ( "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" ) type arrayDecoder struct { - elemType *rtype + elemType *runtime.Type size uintptr valueDecoder decoder alen int @@ -14,7 +17,7 @@ type arrayDecoder struct { zeroValue unsafe.Pointer } -func newArrayDecoder(dec decoder, elemType *rtype, alen int, structName, fieldName string) *arrayDecoder { +func newArrayDecoder(dec decoder, elemType *runtime.Type, alen int, structName, fieldName string) *arrayDecoder { zeroValue := *(*unsafe.Pointer)(unsafe_New(elemType)) return &arrayDecoder{ valueDecoder: dec, @@ -27,10 +30,10 @@ func newArrayDecoder(dec decoder, elemType *rtype, alen int, structName, fieldNa } } -func (d *arrayDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *arrayDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { depth++ if depth > maxDecodeNestingDepth { - return errExceededMaxDepth(s.char(), s.cursor) + return errors.ErrExceededMaxDepth(s.char(), s.cursor) } for { @@ -46,7 +49,7 @@ func (d *arrayDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er for { s.cursor++ if idx < d.alen { - if err := d.valueDecoder.decodeStream(s, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size)); err != nil { + if err := d.valueDecoder.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size)); err != nil { return err } } else { @@ -86,13 +89,13 @@ func (d *arrayDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er s.cursor++ } ERROR: - return errUnexpectedEndOfJSON("array", s.totalOffset()) + return errors.ErrUnexpectedEndOfJSON("array", s.totalOffset()) } -func (d *arrayDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *arrayDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { depth++ if depth > maxDecodeNestingDepth { - return 0, errExceededMaxDepth(buf[cursor], cursor) + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) } for { @@ -111,7 +114,7 @@ func (d *arrayDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) for { cursor++ if idx < d.alen { - c, err := d.valueDecoder.decode(buf, cursor, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size)) + c, err := d.valueDecoder.Decode(buf, cursor, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size)) if err != nil { return 0, err } @@ -136,11 +139,11 @@ func (d *arrayDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) case ',': continue default: - return 0, errInvalidCharacter(buf[cursor], "array", cursor) + return 0, errors.ErrInvalidCharacter(buf[cursor], "array", cursor) } } default: - return 0, errUnexpectedEndOfJSON("array", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("array", cursor) } } } diff --git a/decode_bool.go b/internal/decoder/bool.go similarity index 80% rename from decode_bool.go rename to internal/decoder/bool.go index 9efc1c1..b885ce0 100644 --- a/decode_bool.go +++ b/internal/decoder/bool.go @@ -1,7 +1,9 @@ -package json +package decoder import ( "unsafe" + + "github.com/goccy/go-json/internal/errors" ) type boolDecoder struct { @@ -13,7 +15,7 @@ func newBoolDecoder(structName, fieldName string) *boolDecoder { return &boolDecoder{structName: structName, fieldName: fieldName} } -func (d *boolDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *boolDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { s.skipWhiteSpace() for { switch s.char() { @@ -43,10 +45,10 @@ func (d *boolDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) err break } ERROR: - return errUnexpectedEndOfJSON("bool", s.totalOffset()) + return errors.ErrUnexpectedEndOfJSON("bool", s.totalOffset()) } -func (d *boolDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *boolDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { cursor = skipWhiteSpace(buf, cursor) switch buf[cursor] { case 't': @@ -70,5 +72,5 @@ func (d *boolDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) cursor += 4 return cursor, nil } - return 0, errUnexpectedEndOfJSON("bool", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("bool", cursor) } diff --git a/decode_bytes.go b/internal/decoder/bytes.go similarity index 65% rename from decode_bytes.go rename to internal/decoder/bytes.go index e0b8b8a..e8fcc91 100644 --- a/decode_bytes.go +++ b/internal/decoder/bytes.go @@ -1,24 +1,27 @@ -package json +package decoder import ( "encoding/base64" "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" ) type bytesDecoder struct { - typ *rtype + typ *runtime.Type sliceDecoder decoder structName string fieldName string } -func byteUnmarshalerSliceDecoder(typ *rtype, structName string, fieldName string) decoder { +func byteUnmarshalerSliceDecoder(typ *runtime.Type, structName string, fieldName string) decoder { var unmarshalDecoder decoder switch { - case rtype_ptrTo(typ).Implements(unmarshalJSONType): - unmarshalDecoder = newUnmarshalJSONDecoder(rtype_ptrTo(typ), structName, fieldName) - case rtype_ptrTo(typ).Implements(unmarshalTextType): - unmarshalDecoder = newUnmarshalTextDecoder(rtype_ptrTo(typ), structName, fieldName) + case runtime.PtrTo(typ).Implements(unmarshalJSONType): + unmarshalDecoder = newUnmarshalJSONDecoder(runtime.PtrTo(typ), structName, fieldName) + case runtime.PtrTo(typ).Implements(unmarshalTextType): + unmarshalDecoder = newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName) } if unmarshalDecoder == nil { return nil @@ -26,7 +29,7 @@ func byteUnmarshalerSliceDecoder(typ *rtype, structName string, fieldName string return newSliceDecoder(unmarshalDecoder, typ, 1, structName, fieldName) } -func newBytesDecoder(typ *rtype, structName string, fieldName string) *bytesDecoder { +func newBytesDecoder(typ *runtime.Type, structName string, fieldName string) *bytesDecoder { return &bytesDecoder{ typ: typ, sliceDecoder: byteUnmarshalerSliceDecoder(typ, structName, fieldName), @@ -35,7 +38,7 @@ func newBytesDecoder(typ *rtype, structName string, fieldName string) *bytesDeco } } -func (d *bytesDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *bytesDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { bytes, err := d.decodeStreamBinary(s, depth, p) if err != nil { return err @@ -54,7 +57,7 @@ func (d *bytesDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er return nil } -func (d *bytesDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *bytesDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { bytes, c, err := d.decodeBinary(buf, cursor, depth, p) if err != nil { return 0, err @@ -73,7 +76,7 @@ func (d *bytesDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) return cursor, nil } -func binaryBytes(s *stream) ([]byte, error) { +func binaryBytes(s *Stream) ([]byte, error) { s.cursor++ start := s.cursor for { @@ -91,10 +94,10 @@ func binaryBytes(s *stream) ([]byte, error) { s.cursor++ } ERROR: - return nil, errUnexpectedEndOfJSON("[]byte", s.totalOffset()) + return nil, errors.ErrUnexpectedEndOfJSON("[]byte", s.totalOffset()) } -func (d *bytesDecoder) decodeStreamBinary(s *stream, depth int64, p unsafe.Pointer) ([]byte, error) { +func (d *bytesDecoder) decodeStreamBinary(s *Stream, depth int64, p unsafe.Pointer) ([]byte, error) { for { switch s.char() { case ' ', '\n', '\t', '\r': @@ -109,12 +112,12 @@ func (d *bytesDecoder) decodeStreamBinary(s *stream, depth int64, p unsafe.Point return nil, nil case '[': if d.sliceDecoder == nil { - return nil, &UnmarshalTypeError{ - Type: rtype2type(d.typ), + return nil, &errors.UnmarshalTypeError{ + Type: runtime.RType2Type(d.typ), Offset: s.totalOffset(), } } - if err := d.sliceDecoder.decodeStream(s, depth, p); err != nil { + if err := d.sliceDecoder.DecodeStream(s, depth, p); err != nil { return nil, err } return nil, nil @@ -125,7 +128,7 @@ func (d *bytesDecoder) decodeStreamBinary(s *stream, depth int64, p unsafe.Point } break } - return nil, errNotAtBeginningOfValue(s.totalOffset()) + return nil, errors.ErrNotAtBeginningOfValue(s.totalOffset()) } func (d *bytesDecoder) decodeBinary(buf []byte, cursor, depth int64, p unsafe.Pointer) ([]byte, int64, error) { @@ -143,18 +146,18 @@ func (d *bytesDecoder) decodeBinary(buf []byte, cursor, depth int64, p unsafe.Po cursor++ return literal, cursor, nil case nul: - return nil, 0, errUnexpectedEndOfJSON("[]byte", cursor) + return nil, 0, errors.ErrUnexpectedEndOfJSON("[]byte", cursor) } cursor++ } case '[': if d.sliceDecoder == nil { - return nil, 0, &UnmarshalTypeError{ - Type: rtype2type(d.typ), + return nil, 0, &errors.UnmarshalTypeError{ + Type: runtime.RType2Type(d.typ), Offset: cursor, } } - c, err := d.sliceDecoder.decode(buf, cursor, depth, p) + c, err := d.sliceDecoder.Decode(buf, cursor, depth, p) if err != nil { return nil, 0, err } @@ -166,7 +169,7 @@ func (d *bytesDecoder) decodeBinary(buf []byte, cursor, depth int64, p unsafe.Po cursor += 4 return nil, cursor, nil default: - return nil, 0, errNotAtBeginningOfValue(cursor) + return nil, 0, errors.ErrNotAtBeginningOfValue(cursor) } } } diff --git a/decode_compile.go b/internal/decoder/compile.go similarity index 70% rename from decode_compile.go rename to internal/decoder/compile.go index 62f3a61..966f18e 100644 --- a/decode_compile.go +++ b/internal/decoder/compile.go @@ -1,21 +1,50 @@ -package json +package decoder import ( "encoding/json" "fmt" "reflect" "strings" + "sync/atomic" "unicode" "unsafe" + "github.com/goccy/go-json/internal/errors" "github.com/goccy/go-json/internal/runtime" ) var ( - jsonNumberType = reflect.TypeOf(json.Number("")) + jsonNumberType = reflect.TypeOf(json.Number("")) + typeAddr *runtime.TypeAddr + cachedDecoderMap unsafe.Pointer // map[uintptr]decoder + cachedDecoder []decoder ) -func decodeCompileToGetDecoderSlowPath(typeptr uintptr, typ *rtype) (decoder, error) { +func init() { + typeAddr = runtime.AnalyzeTypeAddr() + if typeAddr == nil { + typeAddr = &runtime.TypeAddr{} + } + cachedDecoder = make([]decoder, typeAddr.AddrRange>>typeAddr.AddrShift) +} + +func loadDecoderMap() map[uintptr]decoder { + p := atomic.LoadPointer(&cachedDecoderMap) + return *(*map[uintptr]decoder)(unsafe.Pointer(&p)) +} + +func storeDecoder(typ uintptr, dec decoder, m map[uintptr]decoder) { + newDecoderMap := make(map[uintptr]decoder, len(m)+1) + newDecoderMap[typ] = dec + + for k, v := range m { + newDecoderMap[k] = v + } + + atomic.StorePointer(&cachedDecoderMap, *(*unsafe.Pointer)(unsafe.Pointer(&newDecoderMap))) +} + +func decodeCompileToGetDecoderSlowPath(typeptr uintptr, typ *runtime.Type) (decoder, error) { decoderMap := loadDecoderMap() if dec, exists := decoderMap[typeptr]; exists { return dec, nil @@ -29,22 +58,22 @@ func decodeCompileToGetDecoderSlowPath(typeptr uintptr, typ *rtype) (decoder, er return dec, nil } -func decodeCompileHead(typ *rtype, structTypeToDecoder map[uintptr]decoder) (decoder, error) { +func decodeCompileHead(typ *runtime.Type, structTypeToDecoder map[uintptr]decoder) (decoder, error) { switch { - case rtype_ptrTo(typ).Implements(unmarshalJSONType): - return newUnmarshalJSONDecoder(rtype_ptrTo(typ), "", ""), nil - case rtype_ptrTo(typ).Implements(unmarshalTextType): - return newUnmarshalTextDecoder(rtype_ptrTo(typ), "", ""), nil + case runtime.PtrTo(typ).Implements(unmarshalJSONType): + return newUnmarshalJSONDecoder(runtime.PtrTo(typ), "", ""), nil + case runtime.PtrTo(typ).Implements(unmarshalTextType): + return newUnmarshalTextDecoder(runtime.PtrTo(typ), "", ""), nil } return decodeCompile(typ.Elem(), "", "", structTypeToDecoder) } -func decodeCompile(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { +func decodeCompile(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { switch { - case rtype_ptrTo(typ).Implements(unmarshalJSONType): - return newUnmarshalJSONDecoder(rtype_ptrTo(typ), structName, fieldName), nil - case rtype_ptrTo(typ).Implements(unmarshalTextType): - return newUnmarshalTextDecoder(rtype_ptrTo(typ), structName, fieldName), nil + case runtime.PtrTo(typ).Implements(unmarshalJSONType): + return newUnmarshalJSONDecoder(runtime.PtrTo(typ), structName, fieldName), nil + case runtime.PtrTo(typ).Implements(unmarshalTextType): + return newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName), nil } switch typ.Kind() { @@ -95,18 +124,18 @@ func decodeCompile(typ *rtype, structName, fieldName string, structTypeToDecoder case reflect.Float64: return decodeCompileFloat64(structName, fieldName) } - return nil, &UnmarshalTypeError{ + return nil, &errors.UnmarshalTypeError{ Value: "object", - Type: rtype2type(typ), + Type: runtime.RType2Type(typ), Offset: 0, } } -func isStringTagSupportedType(typ *rtype) bool { +func isStringTagSupportedType(typ *runtime.Type) bool { switch { - case rtype_ptrTo(typ).Implements(unmarshalJSONType): + case runtime.PtrTo(typ).Implements(unmarshalJSONType): return false - case rtype_ptrTo(typ).Implements(unmarshalTextType): + case runtime.PtrTo(typ).Implements(unmarshalTextType): return false } switch typ.Kind() { @@ -124,9 +153,9 @@ func isStringTagSupportedType(typ *rtype) bool { return true } -func decodeCompileMapKey(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { - if rtype_ptrTo(typ).Implements(unmarshalTextType) { - return newUnmarshalTextDecoder(rtype_ptrTo(typ), structName, fieldName), nil +func decodeCompileMapKey(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { + if runtime.PtrTo(typ).Implements(unmarshalTextType) { + return newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName), nil } dec, err := decodeCompile(typ, structName, fieldName, structTypeToDecoder) if err != nil { @@ -145,14 +174,14 @@ func decodeCompileMapKey(typ *rtype, structName, fieldName string, structTypeToD } } ERROR: - return nil, &UnmarshalTypeError{ + return nil, &errors.UnmarshalTypeError{ Value: "object", - Type: rtype2type(typ), + Type: runtime.RType2Type(typ), Offset: 0, } } -func decodeCompilePtr(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { +func decodeCompilePtr(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { dec, err := decodeCompile(typ.Elem(), structName, fieldName, structTypeToDecoder) if err != nil { return nil, err @@ -160,61 +189,61 @@ func decodeCompilePtr(typ *rtype, structName, fieldName string, structTypeToDeco return newPtrDecoder(dec, typ.Elem(), structName, fieldName), nil } -func decodeCompileInt(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileInt(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { *(*int)(p) = int(v) }), nil } -func decodeCompileInt8(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileInt8(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { *(*int8)(p) = int8(v) }), nil } -func decodeCompileInt16(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileInt16(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { *(*int16)(p) = int16(v) }), nil } -func decodeCompileInt32(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileInt32(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { *(*int32)(p) = int32(v) }), nil } -func decodeCompileInt64(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileInt64(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { *(*int64)(p) = v }), nil } -func decodeCompileUint(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileUint(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { *(*uint)(p) = uint(v) }), nil } -func decodeCompileUint8(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileUint8(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { *(*uint8)(p) = uint8(v) }), nil } -func decodeCompileUint16(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileUint16(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { *(*uint16)(p) = uint16(v) }), nil } -func decodeCompileUint32(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileUint32(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { *(*uint32)(p) = uint32(v) }), nil } -func decodeCompileUint64(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileUint64(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { *(*uint64)(p) = v }), nil @@ -232,10 +261,10 @@ func decodeCompileFloat64(structName, fieldName string) (decoder, error) { }), nil } -func decodeCompileString(typ *rtype, structName, fieldName string) (decoder, error) { - if typ == type2rtype(jsonNumberType) { - return newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v Number) { - *(*Number)(p) = v +func decodeCompileString(typ *runtime.Type, structName, fieldName string) (decoder, error) { + if typ == runtime.Type2RType(jsonNumberType) { + return newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) { + *(*json.Number)(p) = v }), nil } return newStringDecoder(structName, fieldName), nil @@ -245,11 +274,11 @@ func decodeCompileBool(structName, fieldName string) (decoder, error) { return newBoolDecoder(structName, fieldName), nil } -func decodeCompileBytes(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileBytes(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newBytesDecoder(typ, structName, fieldName), nil } -func decodeCompileSlice(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { +func decodeCompileSlice(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { elem := typ.Elem() decoder, err := decodeCompile(elem, structName, fieldName, structTypeToDecoder) if err != nil { @@ -258,7 +287,7 @@ func decodeCompileSlice(typ *rtype, structName, fieldName string, structTypeToDe return newSliceDecoder(decoder, elem, elem.Size(), structName, fieldName), nil } -func decodeCompileArray(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { +func decodeCompileArray(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { elem := typ.Elem() decoder, err := decodeCompile(elem, structName, fieldName, structTypeToDecoder) if err != nil { @@ -267,7 +296,7 @@ func decodeCompileArray(typ *rtype, structName, fieldName string, structTypeToDe return newArrayDecoder(decoder, elem, typ.Len(), structName, fieldName), nil } -func decodeCompileMap(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { +func decodeCompileMap(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { keyDec, err := decodeCompileMapKey(typ.Key(), structName, fieldName, structTypeToDecoder) if err != nil { return nil, err @@ -279,7 +308,7 @@ func decodeCompileMap(typ *rtype, structName, fieldName string, structTypeToDeco return newMapDecoder(typ, typ.Key(), keyDec, typ.Elem(), valueDec, structName, fieldName), nil } -func decodeCompileInterface(typ *rtype, structName, fieldName string) (decoder, error) { +func decodeCompileInterface(typ *runtime.Type, structName, fieldName string) (decoder, error) { return newInterfaceDecoder(typ, structName, fieldName), nil } @@ -338,7 +367,7 @@ func decodeRemoveConflictFields(fieldMap map[string]*structFieldSet, conflictedM } } -func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { +func decodeCompileStruct(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]decoder) (decoder, error) { fieldNum := typ.NumField() conflictedMap := map[string]struct{}{} fieldMap := map[string]*structFieldSet{} @@ -356,13 +385,13 @@ func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToD } isUnexportedField := unicode.IsLower([]rune(field.Name)[0]) tag := runtime.StructTagFromField(field) - dec, err := decodeCompile(type2rtype(field.Type), structName, field.Name, structTypeToDecoder) + dec, err := decodeCompile(runtime.Type2RType(field.Type), structName, field.Name, structTypeToDecoder) if err != nil { return nil, err } if field.Anonymous && !tag.IsTaggedKey { if stDec, ok := dec.(*structDecoder); ok { - if type2rtype(field.Type) == typ { + if runtime.Type2RType(field.Type) == typ { // recursive definition continue } @@ -438,8 +467,8 @@ func decodeCompileStruct(typ *rtype, structName, fieldName string, structTypeToD } } } else { - if tag.IsString && isStringTagSupportedType(type2rtype(field.Type)) { - dec = newWrappedStringDecoder(type2rtype(field.Type), dec, structName, field.Name) + if tag.IsString && isStringTagSupportedType(runtime.Type2RType(field.Type)) { + dec = newWrappedStringDecoder(runtime.Type2RType(field.Type), dec, structName, field.Name) } var key string if tag.Key != "" { diff --git a/decode_compile_norace.go b/internal/decoder/compile_norace.go similarity index 57% rename from decode_compile_norace.go rename to internal/decoder/compile_norace.go index 4a7670a..1f319d8 100644 --- a/decode_compile_norace.go +++ b/internal/decoder/compile_norace.go @@ -1,16 +1,20 @@ // +build !race -package json +package decoder -import "unsafe" +import ( + "unsafe" -func decodeCompileToGetDecoder(typ *rtype) (decoder, error) { + "github.com/goccy/go-json/internal/runtime" +) + +func CompileToGetDecoder(typ *runtime.Type) (decoder, error) { typeptr := uintptr(unsafe.Pointer(typ)) - if typeptr > maxTypeAddr { + if typeptr > typeAddr.MaxTypeAddr { return decodeCompileToGetDecoderSlowPath(typeptr, typ) } - index := (typeptr - baseTypeAddr) >> typeAddrShift + index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift if dec := cachedDecoder[index]; dec != nil { return dec, nil } diff --git a/decode_compile_race.go b/internal/decoder/compile_race.go similarity index 81% rename from decode_compile_race.go rename to internal/decoder/compile_race.go index a70850c..0ea22e4 100644 --- a/decode_compile_race.go +++ b/internal/decoder/compile_race.go @@ -1,15 +1,17 @@ // +build race -package json +package decoder import ( "sync" "unsafe" + + "github.com/goccy/go-json/internal/runtime" ) var decMu sync.RWMutex -func decodeCompileToGetDecoder(typ *rtype) (decoder, error) { +func CompileToGetDecoder(typ *runtime.Type) (decoder, error) { typeptr := uintptr(unsafe.Pointer(typ)) if typeptr > maxTypeAddr { return decodeCompileToGetDecoderSlowPath(typeptr, typ) diff --git a/decode_context.go b/internal/decoder/context.go similarity index 64% rename from decode_context.go rename to internal/decoder/context.go index a6ff091..380d73e 100644 --- a/decode_context.go +++ b/internal/decoder/context.go @@ -1,7 +1,9 @@ -package json +package decoder import ( "unsafe" + + "github.com/goccy/go-json/internal/errors" ) var ( @@ -34,7 +36,7 @@ func skipObject(buf []byte, cursor, depth int64) (int64, error) { braceCount++ depth++ if depth > maxDecodeNestingDepth { - return 0, errExceededMaxDepth(buf[cursor], cursor) + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) } case '}': depth-- @@ -45,7 +47,7 @@ func skipObject(buf []byte, cursor, depth int64) (int64, error) { case '[': depth++ if depth > maxDecodeNestingDepth { - return 0, errExceededMaxDepth(buf[cursor], cursor) + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) } case ']': depth-- @@ -56,16 +58,16 @@ func skipObject(buf []byte, cursor, depth int64) (int64, error) { case '\\': cursor++ if buf[cursor] == nul { - return 0, errUnexpectedEndOfJSON("string of object", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) } case '"': goto SWITCH_OUT case nul: - return 0, errUnexpectedEndOfJSON("string of object", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) } } case nul: - return 0, errUnexpectedEndOfJSON("object of object", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("object of object", cursor) } SWITCH_OUT: cursor++ @@ -80,7 +82,7 @@ func skipArray(buf []byte, cursor, depth int64) (int64, error) { bracketCount++ depth++ if depth > maxDecodeNestingDepth { - return 0, errExceededMaxDepth(buf[cursor], cursor) + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) } case ']': bracketCount-- @@ -91,7 +93,7 @@ func skipArray(buf []byte, cursor, depth int64) (int64, error) { case '{': depth++ if depth > maxDecodeNestingDepth { - return 0, errExceededMaxDepth(buf[cursor], cursor) + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) } case '}': depth-- @@ -102,16 +104,16 @@ func skipArray(buf []byte, cursor, depth int64) (int64, error) { case '\\': cursor++ if buf[cursor] == nul { - return 0, errUnexpectedEndOfJSON("string of object", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) } case '"': goto SWITCH_OUT case nul: - return 0, errUnexpectedEndOfJSON("string of object", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) } } case nul: - return 0, errUnexpectedEndOfJSON("array of object", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("array of object", cursor) } SWITCH_OUT: cursor++ @@ -135,12 +137,12 @@ func skipValue(buf []byte, cursor, depth int64) (int64, error) { case '\\': cursor++ if buf[cursor] == nul { - return 0, errUnexpectedEndOfJSON("string of object", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) } case '"': return cursor + 1, nil case nul: - return 0, errUnexpectedEndOfJSON("string of object", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) } } case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': @@ -171,58 +173,58 @@ func skipValue(buf []byte, cursor, depth int64) (int64, error) { cursor += 4 return cursor, nil default: - return cursor, errUnexpectedEndOfJSON("null", cursor) + return cursor, errors.ErrUnexpectedEndOfJSON("null", cursor) } } } func validateTrue(buf []byte, cursor int64) error { if cursor+3 >= int64(len(buf)) { - return errUnexpectedEndOfJSON("true", cursor) + return errors.ErrUnexpectedEndOfJSON("true", cursor) } if buf[cursor+1] != 'r' { - return errInvalidCharacter(buf[cursor+1], "true", cursor) + return errors.ErrInvalidCharacter(buf[cursor+1], "true", cursor) } if buf[cursor+2] != 'u' { - return errInvalidCharacter(buf[cursor+2], "true", cursor) + return errors.ErrInvalidCharacter(buf[cursor+2], "true", cursor) } if buf[cursor+3] != 'e' { - return errInvalidCharacter(buf[cursor+3], "true", cursor) + return errors.ErrInvalidCharacter(buf[cursor+3], "true", cursor) } return nil } func validateFalse(buf []byte, cursor int64) error { if cursor+4 >= int64(len(buf)) { - return errUnexpectedEndOfJSON("false", cursor) + return errors.ErrUnexpectedEndOfJSON("false", cursor) } if buf[cursor+1] != 'a' { - return errInvalidCharacter(buf[cursor+1], "false", cursor) + return errors.ErrInvalidCharacter(buf[cursor+1], "false", cursor) } if buf[cursor+2] != 'l' { - return errInvalidCharacter(buf[cursor+2], "false", cursor) + return errors.ErrInvalidCharacter(buf[cursor+2], "false", cursor) } if buf[cursor+3] != 's' { - return errInvalidCharacter(buf[cursor+3], "false", cursor) + return errors.ErrInvalidCharacter(buf[cursor+3], "false", cursor) } if buf[cursor+4] != 'e' { - return errInvalidCharacter(buf[cursor+4], "false", cursor) + return errors.ErrInvalidCharacter(buf[cursor+4], "false", cursor) } return nil } func validateNull(buf []byte, cursor int64) error { if cursor+3 >= int64(len(buf)) { - return errUnexpectedEndOfJSON("null", cursor) + return errors.ErrUnexpectedEndOfJSON("null", cursor) } if buf[cursor+1] != 'u' { - return errInvalidCharacter(buf[cursor+1], "null", cursor) + return errors.ErrInvalidCharacter(buf[cursor+1], "null", cursor) } if buf[cursor+2] != 'l' { - return errInvalidCharacter(buf[cursor+2], "null", cursor) + return errors.ErrInvalidCharacter(buf[cursor+2], "null", cursor) } if buf[cursor+3] != 'l' { - return errInvalidCharacter(buf[cursor+3], "null", cursor) + return errors.ErrInvalidCharacter(buf[cursor+3], "null", cursor) } return nil } diff --git a/decode_float.go b/internal/decoder/float.go similarity index 80% rename from decode_float.go rename to internal/decoder/float.go index d48c2c8..b53befb 100644 --- a/decode_float.go +++ b/internal/decoder/float.go @@ -1,8 +1,10 @@ -package json +package decoder import ( "strconv" "unsafe" + + "github.com/goccy/go-json/internal/errors" ) type floatDecoder struct { @@ -47,7 +49,7 @@ var ( } ) -func floatBytes(s *stream) []byte { +func floatBytes(s *Stream) []byte { start := s.cursor for { s.cursor++ @@ -64,7 +66,7 @@ func floatBytes(s *stream) []byte { return s.buf[start:s.cursor] } -func (d *floatDecoder) decodeStreamByte(s *stream) ([]byte, error) { +func (d *floatDecoder) decodeStreamByte(s *Stream) ([]byte, error) { for { switch s.char() { case ' ', '\n', '\t', '\r': @@ -87,7 +89,7 @@ func (d *floatDecoder) decodeStreamByte(s *stream) ([]byte, error) { } } ERROR: - return nil, errUnexpectedEndOfJSON("float", s.totalOffset()) + return nil, errors.ErrUnexpectedEndOfJSON("float", s.totalOffset()) } func (d *floatDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { @@ -111,12 +113,12 @@ func (d *floatDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, erro cursor += 4 return nil, cursor, nil default: - return nil, 0, errUnexpectedEndOfJSON("float", cursor) + return nil, 0, errors.ErrUnexpectedEndOfJSON("float", cursor) } } } -func (d *floatDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *floatDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { bytes, err := d.decodeStreamByte(s) if err != nil { return err @@ -127,13 +129,13 @@ func (d *floatDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er str := *(*string)(unsafe.Pointer(&bytes)) f64, err := strconv.ParseFloat(str, 64) if err != nil { - return errSyntax(err.Error(), s.totalOffset()) + return errors.ErrSyntax(err.Error(), s.totalOffset()) } d.op(p, f64) return nil } -func (d *floatDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *floatDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { bytes, c, err := d.decodeByte(buf, cursor) if err != nil { return 0, err @@ -143,12 +145,12 @@ func (d *floatDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) } cursor = c if !validEndNumberChar[buf[cursor]] { - return 0, errUnexpectedEndOfJSON("float", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("float", cursor) } s := *(*string)(unsafe.Pointer(&bytes)) f64, err := strconv.ParseFloat(s, 64) if err != nil { - return 0, errSyntax(err.Error(), cursor) + return 0, errors.ErrSyntax(err.Error(), cursor) } d.op(p, f64) return cursor, nil diff --git a/decode_int.go b/internal/decoder/int.go similarity index 86% rename from decode_int.go rename to internal/decoder/int.go index d351366..18cbd2a 100644 --- a/decode_int.go +++ b/internal/decoder/int.go @@ -1,20 +1,23 @@ -package json +package decoder import ( "fmt" "reflect" "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" ) type intDecoder struct { - typ *rtype + typ *runtime.Type kind reflect.Kind op func(unsafe.Pointer, int64) structName string fieldName string } -func newIntDecoder(typ *rtype, structName, fieldName string, op func(unsafe.Pointer, int64)) *intDecoder { +func newIntDecoder(typ *runtime.Type, structName, fieldName string, op func(unsafe.Pointer, int64)) *intDecoder { return &intDecoder{ typ: typ, kind: typ.Kind(), @@ -24,10 +27,10 @@ func newIntDecoder(typ *rtype, structName, fieldName string, op func(unsafe.Poin } } -func (d *intDecoder) typeError(buf []byte, offset int64) *UnmarshalTypeError { - return &UnmarshalTypeError{ +func (d *intDecoder) typeError(buf []byte, offset int64) *errors.UnmarshalTypeError { + return &errors.UnmarshalTypeError{ Value: fmt.Sprintf("number %s", string(buf)), - Type: rtype2type(d.typ), + Type: runtime.RType2Type(d.typ), Struct: d.structName, Field: d.fieldName, Offset: offset, @@ -83,7 +86,7 @@ var ( numZeroBuf = []byte{'0'} ) -func (d *intDecoder) decodeStreamByte(s *stream) ([]byte, error) { +func (d *intDecoder) decodeStreamByte(s *Stream) ([]byte, error) { for { switch s.char() { case ' ', '\n', '\t', '\r': @@ -142,7 +145,7 @@ func (d *intDecoder) decodeStreamByte(s *stream) ([]byte, error) { } } ERROR: - return nil, errUnexpectedEndOfJSON("number(integer)", s.totalOffset()) + return nil, errors.ErrUnexpectedEndOfJSON("number(integer)", s.totalOffset()) } func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { @@ -175,7 +178,7 @@ func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) } } -func (d *intDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *intDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { bytes, err := d.decodeStreamByte(s) if err != nil { return err @@ -206,7 +209,7 @@ func (d *intDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) erro return nil } -func (d *intDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *intDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { bytes, c, err := d.decodeByte(buf, cursor) if err != nil { return 0, err diff --git a/decode_interface.go b/internal/decoder/interface.go similarity index 81% rename from decode_interface.go rename to internal/decoder/interface.go index e7e96b8..a22ac35 100644 --- a/decode_interface.go +++ b/internal/decoder/interface.go @@ -1,14 +1,18 @@ -package json +package decoder import ( "bytes" "encoding" + "encoding/json" "reflect" "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" ) type interfaceDecoder struct { - typ *rtype + typ *runtime.Type structName string fieldName string sliceDecoder *sliceDecoder @@ -26,7 +30,7 @@ func newEmptyInterfaceDecoder(structName, fieldName string) *interfaceDecoder { floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { *(*interface{})(p) = v }), - numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v Number) { + numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) { *(*interface{})(p) = v }), stringDecoder: newStringDecoder(structName, fieldName), @@ -49,7 +53,7 @@ func newEmptyInterfaceDecoder(structName, fieldName string) *interfaceDecoder { return ifaceDecoder } -func newInterfaceDecoder(typ *rtype, structName, fieldName string) *interfaceDecoder { +func newInterfaceDecoder(typ *runtime.Type, structName, fieldName string) *interfaceDecoder { emptyIfaceDecoder := newEmptyInterfaceDecoder(structName, fieldName) stringDecoder := newStringDecoder(structName, fieldName) return &interfaceDecoder{ @@ -74,31 +78,31 @@ func newInterfaceDecoder(typ *rtype, structName, fieldName string) *interfaceDec floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { *(*interface{})(p) = v }), - numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v Number) { + numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) { *(*interface{})(p) = v }), stringDecoder: stringDecoder, } } -func (d *interfaceDecoder) numDecoder(s *stream) decoder { - if s.useNumber { +func (d *interfaceDecoder) numDecoder(s *Stream) decoder { + if s.UseNumber { return d.numberDecoder } return d.floatDecoder } var ( - emptyInterfaceType = type2rtype(reflect.TypeOf((*interface{})(nil)).Elem()) - interfaceMapType = type2rtype( + emptyInterfaceType = runtime.Type2RType(reflect.TypeOf((*interface{})(nil)).Elem()) + interfaceMapType = runtime.Type2RType( reflect.TypeOf((*map[string]interface{})(nil)).Elem(), ) - stringType = type2rtype( + stringType = runtime.Type2RType( reflect.TypeOf(""), ) ) -func decodeStreamUnmarshaler(s *stream, depth int64, unmarshaler Unmarshaler) error { +func decodeStreamUnmarshaler(s *Stream, depth int64, unmarshaler json.Unmarshaler) error { start := s.cursor if err := s.skipValue(depth); err != nil { return err @@ -113,7 +117,7 @@ func decodeStreamUnmarshaler(s *stream, depth int64, unmarshaler Unmarshaler) er return nil } -func decodeUnmarshaler(buf []byte, cursor, depth int64, unmarshaler Unmarshaler) (int64, error) { +func decodeUnmarshaler(buf []byte, cursor, depth int64, unmarshaler json.Unmarshaler) (int64, error) { cursor = skipWhiteSpace(buf, cursor) start := cursor end, err := skipValue(buf, cursor, depth) @@ -130,7 +134,7 @@ func decodeUnmarshaler(buf []byte, cursor, depth int64, unmarshaler Unmarshaler) return end, nil } -func decodeStreamTextUnmarshaler(s *stream, depth int64, unmarshaler encoding.TextUnmarshaler, p unsafe.Pointer) error { +func decodeStreamTextUnmarshaler(s *Stream, depth int64, unmarshaler encoding.TextUnmarshaler, p unsafe.Pointer) error { start := s.cursor if err := s.skipValue(depth); err != nil { return err @@ -171,14 +175,14 @@ func decodeTextUnmarshaler(buf []byte, cursor, depth int64, unmarshaler encoding return end, nil } -func (d *interfaceDecoder) decodeStreamEmptyInterface(s *stream, depth int64, p unsafe.Pointer) error { +func (d *interfaceDecoder) decodeStreamEmptyInterface(s *Stream, depth int64, p unsafe.Pointer) error { s.skipWhiteSpace() for { switch s.char() { case '{': var v map[string]interface{} ptr := unsafe.Pointer(&v) - if err := d.mapDecoder.decodeStream(s, depth, ptr); err != nil { + if err := d.mapDecoder.DecodeStream(s, depth, ptr); err != nil { return err } *(*interface{})(p) = v @@ -186,13 +190,13 @@ func (d *interfaceDecoder) decodeStreamEmptyInterface(s *stream, depth int64, p case '[': var v []interface{} ptr := unsafe.Pointer(&v) - if err := d.sliceDecoder.decodeStream(s, depth, ptr); err != nil { + if err := d.sliceDecoder.DecodeStream(s, depth, ptr); err != nil { return err } *(*interface{})(p) = v return nil case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return d.numDecoder(s).decodeStream(s, depth, p) + return d.numDecoder(s).DecodeStream(s, depth, p) case '"': s.cursor++ start := s.cursor @@ -211,7 +215,7 @@ func (d *interfaceDecoder) decodeStreamEmptyInterface(s *stream, depth int64, p if s.read() { continue } - return errUnexpectedEndOfJSON("string", s.totalOffset()) + return errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) } s.cursor++ } @@ -240,17 +244,22 @@ func (d *interfaceDecoder) decodeStreamEmptyInterface(s *stream, depth int64, p } break } - return errNotAtBeginningOfValue(s.totalOffset()) + return errors.ErrNotAtBeginningOfValue(s.totalOffset()) } -func (d *interfaceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func (d *interfaceDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{ typ: d.typ, ptr: p, })) rv := reflect.ValueOf(runtimeInterfaceValue) if rv.NumMethod() > 0 && rv.CanInterface() { - if u, ok := rv.Interface().(Unmarshaler); ok { + if u, ok := rv.Interface().(json.Unmarshaler); ok { return decodeStreamUnmarshaler(s, depth, u) } if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok { @@ -284,15 +293,15 @@ func (d *interfaceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer *(*interface{})(p) = nil return nil } - decoder, err := decodeCompileToGetDecoder(typ) + decoder, err := CompileToGetDecoder(typ) if err != nil { return err } - return decoder.decodeStream(s, depth, ifaceHeader.ptr) + return decoder.DecodeStream(s, depth, ifaceHeader.ptr) } -func (d *interfaceDecoder) errUnmarshalType(typ reflect.Type, offset int64) *UnmarshalTypeError { - return &UnmarshalTypeError{ +func (d *interfaceDecoder) errUnmarshalType(typ reflect.Type, offset int64) *errors.UnmarshalTypeError { + return &errors.UnmarshalTypeError{ Value: typ.String(), Type: typ, Offset: offset, @@ -301,14 +310,14 @@ func (d *interfaceDecoder) errUnmarshalType(typ reflect.Type, offset int64) *Unm } } -func (d *interfaceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *interfaceDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{ typ: d.typ, ptr: p, })) rv := reflect.ValueOf(runtimeInterfaceValue) if rv.NumMethod() > 0 && rv.CanInterface() { - if u, ok := rv.Interface().(Unmarshaler); ok { + if u, ok := rv.Interface().(json.Unmarshaler); ok { return decodeUnmarshaler(buf, cursor, depth, u) } if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok { @@ -345,11 +354,11 @@ func (d *interfaceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Poin **(**interface{})(unsafe.Pointer(&p)) = nil return cursor, nil } - decoder, err := decodeCompileToGetDecoder(typ) + decoder, err := CompileToGetDecoder(typ) if err != nil { return 0, err } - return decoder.decode(buf, cursor, depth, ifaceHeader.ptr) + return decoder.Decode(buf, cursor, depth, ifaceHeader.ptr) } func (d *interfaceDecoder) decodeEmptyInterface(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { @@ -358,7 +367,7 @@ func (d *interfaceDecoder) decodeEmptyInterface(buf []byte, cursor, depth int64, case '{': var v map[string]interface{} ptr := unsafe.Pointer(&v) - cursor, err := d.mapDecoder.decode(buf, cursor, depth, ptr) + cursor, err := d.mapDecoder.Decode(buf, cursor, depth, ptr) if err != nil { return 0, err } @@ -367,18 +376,18 @@ func (d *interfaceDecoder) decodeEmptyInterface(buf []byte, cursor, depth int64, case '[': var v []interface{} ptr := unsafe.Pointer(&v) - cursor, err := d.sliceDecoder.decode(buf, cursor, depth, ptr) + cursor, err := d.sliceDecoder.Decode(buf, cursor, depth, ptr) if err != nil { return 0, err } **(**interface{})(unsafe.Pointer(&p)) = v return cursor, nil case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return d.floatDecoder.decode(buf, cursor, depth, p) + return d.floatDecoder.Decode(buf, cursor, depth, p) case '"': var v string ptr := unsafe.Pointer(&v) - cursor, err := d.stringDecoder.decode(buf, cursor, depth, ptr) + cursor, err := d.stringDecoder.Decode(buf, cursor, depth, ptr) if err != nil { return 0, err } @@ -406,5 +415,5 @@ func (d *interfaceDecoder) decodeEmptyInterface(buf []byte, cursor, depth int64, **(**interface{})(unsafe.Pointer(&p)) = nil return cursor, nil } - return cursor, errNotAtBeginningOfValue(cursor) + return cursor, errors.ErrNotAtBeginningOfValue(cursor) } diff --git a/decode_map.go b/internal/decoder/map.go similarity index 62% rename from decode_map.go rename to internal/decoder/map.go index 91af50e..f3a60de 100644 --- a/decode_map.go +++ b/internal/decoder/map.go @@ -1,20 +1,23 @@ -package json +package decoder import ( "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" ) type mapDecoder struct { - mapType *rtype - keyType *rtype - valueType *rtype + mapType *runtime.Type + keyType *runtime.Type + valueType *runtime.Type keyDecoder decoder valueDecoder decoder structName string fieldName string } -func newMapDecoder(mapType *rtype, keyType *rtype, keyDec decoder, valueType *rtype, valueDec decoder, structName, fieldName string) *mapDecoder { +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, @@ -27,16 +30,16 @@ func newMapDecoder(mapType *rtype, keyType *rtype, keyDec decoder, valueType *rt } //go:linkname makemap reflect.makemap -func makemap(*rtype, int) unsafe.Pointer +func makemap(*runtime.Type, int) unsafe.Pointer //go:linkname mapassign reflect.mapassign //go:noescape -func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer) +func mapassign(t *runtime.Type, m unsafe.Pointer, key, val unsafe.Pointer) -func (d *mapDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { depth++ if depth > maxDecodeNestingDepth { - return errExceededMaxDepth(s.char(), s.cursor) + return errors.ErrExceededMaxDepth(s.char(), s.cursor) } s.skipWhiteSpace() @@ -49,7 +52,7 @@ func (d *mapDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) erro return nil case '{': default: - return errExpected("{ character for map value", s.totalOffset()) + return errors.ErrExpected("{ character for map value", s.totalOffset()) } s.skipWhiteSpace() mapValue := *(*unsafe.Pointer)(p) @@ -64,16 +67,16 @@ func (d *mapDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) erro for { s.cursor++ k := unsafe_New(d.keyType) - if err := d.keyDecoder.decodeStream(s, depth, k); err != nil { + if err := d.keyDecoder.DecodeStream(s, depth, k); err != nil { return err } s.skipWhiteSpace() if !s.equalChar(':') { - return errExpected("colon after object key", s.totalOffset()) + return errors.ErrExpected("colon after object key", s.totalOffset()) } s.cursor++ v := unsafe_New(d.valueType) - if err := d.valueDecoder.decodeStream(s, depth, v); err != nil { + if err := d.valueDecoder.DecodeStream(s, depth, v); err != nil { return err } mapassign(d.mapType, mapValue, k, v) @@ -84,21 +87,21 @@ func (d *mapDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) erro return nil } if !s.equalChar(',') { - return errExpected("comma after object value", s.totalOffset()) + return errors.ErrExpected("comma after object value", s.totalOffset()) } } } -func (d *mapDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *mapDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { depth++ if depth > maxDecodeNestingDepth { - return 0, errExceededMaxDepth(buf[cursor], cursor) + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) } cursor = skipWhiteSpace(buf, cursor) buflen := int64(len(buf)) if buflen < 2 { - return 0, errExpected("{} for map", cursor) + return 0, errors.ErrExpected("{} for map", cursor) } switch buf[cursor] { case 'n': @@ -110,7 +113,7 @@ func (d *mapDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) ( return cursor, nil case '{': default: - return 0, errExpected("{ character for map value", cursor) + return 0, errors.ErrExpected("{ character for map value", cursor) } cursor++ cursor = skipWhiteSpace(buf, cursor) @@ -125,17 +128,17 @@ func (d *mapDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) ( } for { k := unsafe_New(d.keyType) - keyCursor, err := d.keyDecoder.decode(buf, cursor, depth, k) + keyCursor, err := d.keyDecoder.Decode(buf, cursor, depth, k) if err != nil { return 0, err } cursor = skipWhiteSpace(buf, keyCursor) if buf[cursor] != ':' { - return 0, errExpected("colon after object key", cursor) + return 0, errors.ErrExpected("colon after object key", cursor) } cursor++ v := unsafe_New(d.valueType) - valueCursor, err := d.valueDecoder.decode(buf, cursor, depth, v) + valueCursor, err := d.valueDecoder.Decode(buf, cursor, depth, v) if err != nil { return 0, err } @@ -147,7 +150,7 @@ func (d *mapDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) ( return cursor, nil } if buf[cursor] != ',' { - return 0, errExpected("comma after object value", cursor) + return 0, errors.ErrExpected("comma after object value", cursor) } cursor++ } diff --git a/decode_number.go b/internal/decoder/number.go similarity index 73% rename from decode_number.go rename to internal/decoder/number.go index 6c8720b..20e5fe7 100644 --- a/decode_number.go +++ b/internal/decoder/number.go @@ -1,18 +1,21 @@ -package json +package decoder import ( + "encoding/json" "strconv" "unsafe" + + "github.com/goccy/go-json/internal/errors" ) type numberDecoder struct { stringDecoder *stringDecoder - op func(unsafe.Pointer, Number) + op func(unsafe.Pointer, json.Number) structName string fieldName string } -func newNumberDecoder(structName, fieldName string, op func(unsafe.Pointer, Number)) *numberDecoder { +func newNumberDecoder(structName, fieldName string, op func(unsafe.Pointer, json.Number)) *numberDecoder { return &numberDecoder{ stringDecoder: newStringDecoder(structName, fieldName), op: op, @@ -21,34 +24,34 @@ func newNumberDecoder(structName, fieldName string, op func(unsafe.Pointer, Numb } } -func (d *numberDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *numberDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { bytes, err := d.decodeStreamByte(s) if err != nil { return err } if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil { - return errSyntax(err.Error(), s.totalOffset()) + return errors.ErrSyntax(err.Error(), s.totalOffset()) } - d.op(p, Number(string(bytes))) + d.op(p, json.Number(string(bytes))) s.reset() return nil } -func (d *numberDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *numberDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { bytes, c, err := d.decodeByte(buf, cursor) if err != nil { return 0, err } if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil { - return 0, errSyntax(err.Error(), c) + return 0, errors.ErrSyntax(err.Error(), c) } cursor = c s := *(*string)(unsafe.Pointer(&bytes)) - d.op(p, Number(s)) + d.op(p, json.Number(s)) return cursor, nil } -func (d *numberDecoder) decodeStreamByte(s *stream) ([]byte, error) { +func (d *numberDecoder) decodeStreamByte(s *Stream) ([]byte, error) { for { switch s.char() { case ' ', '\n', '\t', '\r': @@ -73,7 +76,7 @@ func (d *numberDecoder) decodeStreamByte(s *stream) ([]byte, error) { } } ERROR: - return nil, errUnexpectedEndOfJSON("json.Number", s.totalOffset()) + return nil, errors.ErrUnexpectedEndOfJSON("json.Number", s.totalOffset()) } func (d *numberDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { @@ -99,7 +102,7 @@ func (d *numberDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err case '"': return d.stringDecoder.decodeByte(buf, cursor) default: - return nil, 0, errUnexpectedEndOfJSON("json.Number", cursor) + return nil, 0, errors.ErrUnexpectedEndOfJSON("json.Number", cursor) } } } diff --git a/decode_ptr.go b/internal/decoder/ptr.go similarity index 73% rename from decode_ptr.go rename to internal/decoder/ptr.go index 40997c5..133cc7c 100644 --- a/decode_ptr.go +++ b/internal/decoder/ptr.go @@ -1,17 +1,19 @@ -package json +package decoder import ( "unsafe" + + "github.com/goccy/go-json/internal/runtime" ) type ptrDecoder struct { dec decoder - typ *rtype + typ *runtime.Type structName string fieldName string } -func newPtrDecoder(dec decoder, typ *rtype, structName, fieldName string) *ptrDecoder { +func newPtrDecoder(dec decoder, typ *runtime.Type, structName, fieldName string) *ptrDecoder { return &ptrDecoder{ dec: dec, typ: typ, @@ -30,9 +32,9 @@ func (d *ptrDecoder) contentDecoder() decoder { //nolint:golint //go:linkname unsafe_New reflect.unsafe_New -func unsafe_New(*rtype) unsafe.Pointer +func unsafe_New(*runtime.Type) unsafe.Pointer -func (d *ptrDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *ptrDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { s.skipWhiteSpace() if s.char() == nul { s.read() @@ -51,13 +53,13 @@ func (d *ptrDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) erro } else { newptr = *(*unsafe.Pointer)(p) } - if err := d.dec.decodeStream(s, depth, newptr); err != nil { + if err := d.dec.DecodeStream(s, depth, newptr); err != nil { return err } return nil } -func (d *ptrDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *ptrDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { cursor = skipWhiteSpace(buf, cursor) if buf[cursor] == 'n' { if err := validateNull(buf, cursor); err != nil { @@ -76,7 +78,7 @@ func (d *ptrDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) ( } else { newptr = *(*unsafe.Pointer)(p) } - c, err := d.dec.decode(buf, cursor, depth, newptr) + c, err := d.dec.Decode(buf, cursor, depth, newptr) if err != nil { return 0, err } diff --git a/decode_slice.go b/internal/decoder/slice.go similarity index 83% rename from decode_slice.go rename to internal/decoder/slice.go index 01f9dfe..376d0f1 100644 --- a/decode_slice.go +++ b/internal/decoder/slice.go @@ -1,13 +1,16 @@ -package json +package decoder import ( "reflect" "sync" "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" ) type sliceDecoder struct { - elemType *rtype + elemType *runtime.Type isElemPointerType bool valueDecoder decoder size uintptr @@ -29,7 +32,7 @@ const ( defaultSliceCapacity = 2 ) -func newSliceDecoder(dec decoder, elemType *rtype, size uintptr, structName, fieldName string) *sliceDecoder { +func newSliceDecoder(dec decoder, elemType *runtime.Type, size uintptr, structName, fieldName string) *sliceDecoder { return &sliceDecoder{ valueDecoder: dec, elemType: elemType, @@ -71,28 +74,28 @@ func (d *sliceDecoder) releaseSlice(p *sliceHeader) { } //go:linkname copySlice reflect.typedslicecopy -func copySlice(elemType *rtype, dst, src sliceHeader) int +func copySlice(elemType *runtime.Type, dst, src sliceHeader) int //go:linkname newArray reflect.unsafe_NewArray -func newArray(*rtype, int) unsafe.Pointer +func newArray(*runtime.Type, int) unsafe.Pointer //go:linkname typedmemmove reflect.typedmemmove -func typedmemmove(t *rtype, dst, src unsafe.Pointer) +func typedmemmove(t *runtime.Type, dst, src unsafe.Pointer) -func (d *sliceDecoder) errNumber(offset int64) *UnmarshalTypeError { - return &UnmarshalTypeError{ +func (d *sliceDecoder) errNumber(offset int64) *errors.UnmarshalTypeError { + return &errors.UnmarshalTypeError{ Value: "number", - Type: reflect.SliceOf(rtype2type(d.elemType)), + Type: reflect.SliceOf(runtime.RType2Type(d.elemType)), Struct: d.structName, Field: d.fieldName, Offset: offset, } } -func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *sliceDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { depth++ if depth > maxDecodeNestingDepth { - return errExceededMaxDepth(s.char(), s.cursor) + return errors.ErrExceededMaxDepth(s.char(), s.cursor) } for { @@ -144,7 +147,7 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er } } - if err := d.valueDecoder.decodeStream(s, depth, ep); err != nil { + if err := d.valueDecoder.DecodeStream(s, depth, ep); err != nil { return err } s.skipWhiteSpace() @@ -194,13 +197,13 @@ func (d *sliceDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) er } } ERROR: - return errUnexpectedEndOfJSON("slice", s.totalOffset()) + return errors.ErrUnexpectedEndOfJSON("slice", s.totalOffset()) } -func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *sliceDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { depth++ if depth > maxDecodeNestingDepth { - return 0, errExceededMaxDepth(buf[cursor], cursor) + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) } for { @@ -251,7 +254,7 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) typedmemmove(d.elemType, ep, unsafe_New(d.elemType)) } } - c, err := d.valueDecoder.decode(buf, cursor, depth, ep) + c, err := d.valueDecoder.Decode(buf, cursor, depth, ep) if err != nil { return 0, err } @@ -278,14 +281,14 @@ func (d *sliceDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) slice.cap = capacity slice.data = data d.releaseSlice(slice) - return 0, errInvalidCharacter(buf[cursor], "slice", cursor) + return 0, errors.ErrInvalidCharacter(buf[cursor], "slice", cursor) } cursor++ } case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': return 0, d.errNumber(cursor) default: - return 0, errUnexpectedEndOfJSON("slice", cursor) + return 0, errors.ErrUnexpectedEndOfJSON("slice", cursor) } } } diff --git a/decode_stream.go b/internal/decoder/stream.go similarity index 62% rename from decode_stream.go rename to internal/decoder/stream.go index da75e8f..a08bfee 100644 --- a/decode_stream.go +++ b/internal/decoder/stream.go @@ -1,16 +1,20 @@ -package json +package decoder import ( "bytes" + "encoding/json" "io" + "strconv" "unsafe" + + "github.com/goccy/go-json/internal/errors" ) const ( initBufSize = 512 ) -type stream struct { +type Stream struct { buf []byte bufSize int64 length int64 @@ -19,19 +23,23 @@ type stream struct { cursor int64 filledBuffer bool allRead bool - useNumber bool - disallowUnknownFields bool + UseNumber bool + DisallowUnknownFields bool } -func newStream(r io.Reader) *stream { - return &stream{ +func NewStream(r io.Reader) *Stream { + return &Stream{ r: r, bufSize: initBufSize, buf: []byte{nul}, } } -func (s *stream) buffered() io.Reader { +func (s *Stream) TotalOffset() int64 { + return s.totalOffset() +} + +func (s *Stream) Buffered() io.Reader { buflen := int64(len(s.buf)) for i := s.cursor; i < buflen; i++ { if s.buf[i] == nul { @@ -41,15 +49,35 @@ func (s *stream) buffered() io.Reader { return bytes.NewReader(s.buf[s.cursor:]) } -func (s *stream) totalOffset() int64 { +func (s *Stream) PrepareForDecode() error { + for { + switch s.char() { + case ' ', '\t', '\r', '\n': + s.cursor++ + continue + case ',', ':': + s.cursor++ + return nil + case nul: + if s.read() { + continue + } + return io.EOF + } + break + } + return nil +} + +func (s *Stream) totalOffset() int64 { return s.offset + s.cursor } -func (s *stream) char() byte { +func (s *Stream) char() byte { return s.buf[s.cursor] } -func (s *stream) equalChar(c byte) bool { +func (s *Stream) equalChar(c byte) bool { cur := s.buf[s.cursor] if cur == nul { s.read() @@ -58,23 +86,100 @@ func (s *stream) equalChar(c byte) bool { return cur == c } -func (s *stream) stat() ([]byte, int64, unsafe.Pointer) { +func (s *Stream) stat() ([]byte, int64, unsafe.Pointer) { return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data } -func (s *stream) statForRetry() ([]byte, int64, unsafe.Pointer) { +func (s *Stream) statForRetry() ([]byte, int64, unsafe.Pointer) { s.cursor-- // for retry ( because caller progress cursor position in each loop ) return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data } -func (s *stream) reset() { +func (s *Stream) Reset() { + s.reset() + s.bufSize = initBufSize +} + +func (s *Stream) More() bool { + for { + switch s.char() { + case ' ', '\n', '\r', '\t': + s.cursor++ + continue + case '}', ']': + return false + case nul: + if s.read() { + continue + } + return false + } + break + } + return true +} + +func (s *Stream) Token() (interface{}, error) { + for { + c := s.char() + switch c { + case ' ', '\n', '\r', '\t': + s.cursor++ + case '{', '[', ']', '}': + s.cursor++ + return json.Delim(c), nil + case ',', ':': + s.cursor++ + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + bytes := floatBytes(s) + s := *(*string)(unsafe.Pointer(&bytes)) + f64, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, err + } + return f64, nil + case '"': + bytes, err := stringBytes(s) + if err != nil { + return nil, err + } + return string(bytes), nil + case 't': + if err := trueBytes(s); err != nil { + return nil, err + } + return true, nil + case 'f': + if err := falseBytes(s); err != nil { + return nil, err + } + return false, nil + case 'n': + if err := nullBytes(s); err != nil { + return nil, err + } + return nil, nil + case nul: + if s.read() { + continue + } + goto END + default: + return nil, errors.ErrInvalidCharacter(s.char(), "token", s.totalOffset()) + } + } +END: + return nil, io.EOF +} + +func (s *Stream) reset() { s.offset += s.cursor s.buf = s.buf[s.cursor:] s.length -= s.cursor s.cursor = 0 } -func (s *stream) readBuf() []byte { +func (s *Stream) readBuf() []byte { if s.filledBuffer { s.bufSize *= 2 remainBuf := s.buf @@ -92,7 +197,7 @@ func (s *stream) readBuf() []byte { return s.buf[s.cursor+remainNotNulCharNum:] } -func (s *stream) read() bool { +func (s *Stream) read() bool { if s.allRead { return false } @@ -114,7 +219,7 @@ func (s *stream) read() bool { return true } -func (s *stream) skipWhiteSpace() { +func (s *Stream) skipWhiteSpace() { LOOP: switch s.char() { case ' ', '\n', '\t', '\r': @@ -127,7 +232,7 @@ LOOP: } } -func (s *stream) skipObject(depth int64) error { +func (s *Stream) skipObject(depth int64) error { braceCount := 1 _, cursor, p := s.stat() for { @@ -136,7 +241,7 @@ func (s *stream) skipObject(depth int64) error { braceCount++ depth++ if depth > maxDecodeNestingDepth { - return errExceededMaxDepth(s.char(), s.cursor) + return errors.ErrExceededMaxDepth(s.char(), s.cursor) } case '}': braceCount-- @@ -148,7 +253,7 @@ func (s *stream) skipObject(depth int64) error { case '[': depth++ if depth > maxDecodeNestingDepth { - return errExceededMaxDepth(s.char(), s.cursor) + return errors.ErrExceededMaxDepth(s.char(), s.cursor) } case ']': depth-- @@ -164,7 +269,7 @@ func (s *stream) skipObject(depth int64) error { _, cursor, p = s.statForRetry() continue } - return errUnexpectedEndOfJSON("string of object", cursor) + return errors.ErrUnexpectedEndOfJSON("string of object", cursor) } case '"': goto SWITCH_OUT @@ -174,7 +279,7 @@ func (s *stream) skipObject(depth int64) error { _, cursor, p = s.statForRetry() continue } - return errUnexpectedEndOfJSON("string of object", cursor) + return errors.ErrUnexpectedEndOfJSON("string of object", cursor) } } case nul: @@ -183,14 +288,14 @@ func (s *stream) skipObject(depth int64) error { _, cursor, p = s.stat() continue } - return errUnexpectedEndOfJSON("object of object", cursor) + return errors.ErrUnexpectedEndOfJSON("object of object", cursor) } SWITCH_OUT: cursor++ } } -func (s *stream) skipArray(depth int64) error { +func (s *Stream) skipArray(depth int64) error { bracketCount := 1 _, cursor, p := s.stat() for { @@ -199,7 +304,7 @@ func (s *stream) skipArray(depth int64) error { bracketCount++ depth++ if depth > maxDecodeNestingDepth { - return errExceededMaxDepth(s.char(), s.cursor) + return errors.ErrExceededMaxDepth(s.char(), s.cursor) } case ']': bracketCount-- @@ -211,7 +316,7 @@ func (s *stream) skipArray(depth int64) error { case '{': depth++ if depth > maxDecodeNestingDepth { - return errExceededMaxDepth(s.char(), s.cursor) + return errors.ErrExceededMaxDepth(s.char(), s.cursor) } case '}': depth-- @@ -227,7 +332,7 @@ func (s *stream) skipArray(depth int64) error { _, cursor, p = s.statForRetry() continue } - return errUnexpectedEndOfJSON("string of object", cursor) + return errors.ErrUnexpectedEndOfJSON("string of object", cursor) } case '"': goto SWITCH_OUT @@ -237,7 +342,7 @@ func (s *stream) skipArray(depth int64) error { _, cursor, p = s.statForRetry() continue } - return errUnexpectedEndOfJSON("string of object", cursor) + return errors.ErrUnexpectedEndOfJSON("string of object", cursor) } } case nul: @@ -246,14 +351,14 @@ func (s *stream) skipArray(depth int64) error { _, cursor, p = s.stat() continue } - return errUnexpectedEndOfJSON("array of object", cursor) + return errors.ErrUnexpectedEndOfJSON("array of object", cursor) } SWITCH_OUT: cursor++ } } -func (s *stream) skipValue(depth int64) error { +func (s *Stream) skipValue(depth int64) error { _, cursor, p := s.stat() for { switch char(p, cursor) { @@ -266,7 +371,7 @@ func (s *stream) skipValue(depth int64) error { _, cursor, p = s.stat() continue } - return errUnexpectedEndOfJSON("value of object", s.totalOffset()) + return errors.ErrUnexpectedEndOfJSON("value of object", s.totalOffset()) case '{': s.cursor = cursor + 1 return s.skipObject(depth + 1) @@ -285,7 +390,7 @@ func (s *stream) skipValue(depth int64) error { _, cursor, p = s.statForRetry() continue } - return errUnexpectedEndOfJSON("value of string", s.totalOffset()) + return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset()) } case '"': s.cursor = cursor + 1 @@ -296,7 +401,7 @@ func (s *stream) skipValue(depth int64) error { _, cursor, p = s.statForRetry() continue } - return errUnexpectedEndOfJSON("value of string", s.totalOffset()) + return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset()) } } case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': @@ -338,7 +443,7 @@ func (s *stream) skipValue(depth int64) error { } } -func nullBytes(s *stream) error { +func nullBytes(s *Stream) error { // current cursor's character is 'n' s.cursor++ if s.char() != 'u' { @@ -362,14 +467,14 @@ func nullBytes(s *stream) error { return nil } -func retryReadNull(s *stream) error { +func retryReadNull(s *Stream) error { if s.char() == nul && s.read() { return nil } - return errInvalidCharacter(s.char(), "null", s.totalOffset()) + return errors.ErrInvalidCharacter(s.char(), "null", s.totalOffset()) } -func trueBytes(s *stream) error { +func trueBytes(s *Stream) error { // current cursor's character is 't' s.cursor++ if s.char() != 'r' { @@ -393,14 +498,14 @@ func trueBytes(s *stream) error { return nil } -func retryReadTrue(s *stream) error { +func retryReadTrue(s *Stream) error { if s.char() == nul && s.read() { return nil } - return errInvalidCharacter(s.char(), "bool(true)", s.totalOffset()) + return errors.ErrInvalidCharacter(s.char(), "bool(true)", s.totalOffset()) } -func falseBytes(s *stream) error { +func falseBytes(s *Stream) error { // current cursor's character is 'f' s.cursor++ if s.char() != 'a' { @@ -430,9 +535,9 @@ func falseBytes(s *stream) error { return nil } -func retryReadFalse(s *stream) error { +func retryReadFalse(s *Stream) error { if s.char() == nul && s.read() { return nil } - return errInvalidCharacter(s.char(), "bool(false)", s.totalOffset()) + return errors.ErrInvalidCharacter(s.char(), "bool(false)", s.totalOffset()) } diff --git a/decode_string.go b/internal/decoder/string.go similarity index 87% rename from decode_string.go rename to internal/decoder/string.go index 3ca1710..d470806 100644 --- a/decode_string.go +++ b/internal/decoder/string.go @@ -1,4 +1,4 @@ -package json +package decoder import ( "reflect" @@ -6,6 +6,8 @@ import ( "unicode/utf16" "unicode/utf8" "unsafe" + + "github.com/goccy/go-json/internal/errors" ) type stringDecoder struct { @@ -20,8 +22,8 @@ func newStringDecoder(structName, fieldName string) *stringDecoder { } } -func (d *stringDecoder) errUnmarshalType(typeName string, offset int64) *UnmarshalTypeError { - return &UnmarshalTypeError{ +func (d *stringDecoder) errUnmarshalType(typeName string, offset int64) *errors.UnmarshalTypeError { + return &errors.UnmarshalTypeError{ Value: typeName, Type: reflect.TypeOf(""), Offset: offset, @@ -30,7 +32,7 @@ func (d *stringDecoder) errUnmarshalType(typeName string, offset int64) *Unmarsh } } -func (d *stringDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *stringDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { bytes, err := d.decodeStreamByte(s) if err != nil { return err @@ -43,7 +45,7 @@ func (d *stringDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) e return nil } -func (d *stringDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *stringDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { bytes, c, err := d.decodeByte(buf, cursor) if err != nil { return 0, err @@ -91,13 +93,13 @@ func unicodeToRune(code []byte) rune { return r } -func decodeUnicodeRune(s *stream) (rune, int64, error) { +func decodeUnicodeRune(s *Stream) (rune, int64, error) { const defaultOffset = 5 const surrogateOffset = 11 if s.cursor+defaultOffset >= s.length { if !s.read() { - return rune(0), 0, errInvalidCharacter(s.char(), "escaped string", s.totalOffset()) + return rune(0), 0, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset()) } } @@ -117,7 +119,7 @@ func decodeUnicodeRune(s *stream) (rune, int64, error) { return r, defaultOffset, nil } -func decodeUnicode(s *stream) error { +func decodeUnicode(s *Stream) error { const backSlashAndULen = 2 // length of \u r, offset, err := decodeUnicodeRune(s) @@ -133,7 +135,7 @@ func decodeUnicode(s *stream) error { return nil } -func decodeEscapeString(s *stream) error { +func decodeEscapeString(s *Stream) error { s.cursor++ RETRY: switch s.buf[s.cursor] { @@ -157,11 +159,11 @@ RETRY: return decodeUnicode(s) case nul: if !s.read() { - return errInvalidCharacter(s.char(), "escaped string", s.totalOffset()) + return errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset()) } goto RETRY default: - return errUnexpectedEndOfJSON("string", s.totalOffset()) + return errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) } s.buf = append(s.buf[:s.cursor-1], s.buf[s.cursor:]...) s.length-- @@ -174,7 +176,7 @@ var ( runeErrBytesLen = int64(len(runeErrBytes)) ) -func stringBytes(s *stream) ([]byte, error) { +func stringBytes(s *Stream) ([]byte, error) { _, cursor, p := s.stat() cursor++ // skip double quote char start := cursor @@ -245,10 +247,10 @@ func stringBytes(s *stream) ([]byte, error) { cursor++ } ERROR: - return nil, errUnexpectedEndOfJSON("string", s.totalOffset()) + return nil, errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) } -func (d *stringDecoder) decodeStreamByte(s *stream) ([]byte, error) { +func (d *stringDecoder) decodeStreamByte(s *Stream) ([]byte, error) { for { switch s.char() { case ' ', '\n', '\t', '\r': @@ -274,7 +276,7 @@ func (d *stringDecoder) decodeStreamByte(s *stream) ([]byte, error) { } break } - return nil, errNotAtBeginningOfValue(s.totalOffset()) + return nil, errors.ErrNotAtBeginningOfValue(s.totalOffset()) } func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { @@ -324,13 +326,13 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err case 'u': buflen := int64(len(buf)) if cursor+5 >= buflen { - return nil, 0, errUnexpectedEndOfJSON("escaped string", cursor) + return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor) } code := unicodeToRune(buf[cursor+1 : cursor+5]) unicode := []byte(string(code)) buf = append(append(buf[:cursor-1], unicode...), buf[cursor+5:]...) default: - return nil, 0, errUnexpectedEndOfJSON("escaped string", cursor) + return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor) } continue case '"': @@ -338,7 +340,7 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err cursor++ return literal, cursor, nil case nul: - return nil, 0, errUnexpectedEndOfJSON("string", cursor) + return nil, 0, errors.ErrUnexpectedEndOfJSON("string", cursor) } cursor++ } @@ -349,7 +351,7 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err cursor += 4 return nil, cursor, nil default: - return nil, 0, errNotAtBeginningOfValue(cursor) + return nil, 0, errors.ErrNotAtBeginningOfValue(cursor) } } } diff --git a/decode_struct.go b/internal/decoder/struct.go similarity index 80% rename from decode_struct.go rename to internal/decoder/struct.go index f857bfc..95e10c2 100644 --- a/decode_struct.go +++ b/internal/decoder/struct.go @@ -1,4 +1,4 @@ -package json +package decoder import ( "fmt" @@ -7,6 +7,8 @@ import ( "sort" "strings" "unsafe" + + "github.com/goccy/go-json/internal/errors" ) type structFieldSet struct { @@ -28,7 +30,7 @@ type structDecoder struct { keyBitmapUint16 [][256]uint16 sortedFieldSets []*structFieldSet keyDecoder func(*structDecoder, []byte, int64) (int64, *structFieldSet, error) - keyStreamDecoder func(*structDecoder, *stream) (*structFieldSet, string, error) + keyStreamDecoder func(*structDecoder, *Stream) (*structFieldSet, string, error) } var ( @@ -154,7 +156,7 @@ func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64, cursor++ return cursor, field, nil case nul: - return 0, nil, errUnexpectedEndOfJSON("string", cursor) + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) } keyIdx := 0 bitmap := d.keyBitmapUint8 @@ -173,7 +175,7 @@ func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64, } return cursor, field, nil case nul: - return 0, nil, errUnexpectedEndOfJSON("string", cursor) + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) default: curBit &= bitmap[keyIdx][largeToSmallTable[c]] if curBit == 0 { @@ -186,10 +188,10 @@ func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64, case '\\': cursor++ if char(b, cursor) == nul { - return 0, nil, errUnexpectedEndOfJSON("string", cursor) + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) } case nul: - return 0, nil, errUnexpectedEndOfJSON("string", cursor) + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) } } } @@ -198,7 +200,7 @@ func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64, cursor++ } default: - return cursor, nil, errNotAtBeginningOfValue(cursor) + return cursor, nil, errors.ErrNotAtBeginningOfValue(cursor) } } } @@ -221,7 +223,7 @@ func decodeKeyByBitmapUint16(d *structDecoder, buf []byte, cursor int64) (int64, cursor++ return cursor, field, nil case nul: - return 0, nil, errUnexpectedEndOfJSON("string", cursor) + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) } keyIdx := 0 bitmap := d.keyBitmapUint16 @@ -240,7 +242,7 @@ func decodeKeyByBitmapUint16(d *structDecoder, buf []byte, cursor int64) (int64, } return cursor, field, nil case nul: - return 0, nil, errUnexpectedEndOfJSON("string", cursor) + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) default: curBit &= bitmap[keyIdx][largeToSmallTable[c]] if curBit == 0 { @@ -253,10 +255,10 @@ func decodeKeyByBitmapUint16(d *structDecoder, buf []byte, cursor int64) (int64, case '\\': cursor++ if char(b, cursor) == nul { - return 0, nil, errUnexpectedEndOfJSON("string", cursor) + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) } case nul: - return 0, nil, errUnexpectedEndOfJSON("string", cursor) + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) } } } @@ -265,7 +267,7 @@ func decodeKeyByBitmapUint16(d *structDecoder, buf []byte, cursor int64) (int64, cursor++ } default: - return cursor, nil, errNotAtBeginningOfValue(cursor) + return cursor, nil, errors.ErrNotAtBeginningOfValue(cursor) } } } @@ -284,7 +286,7 @@ func decodeKey(d *structDecoder, buf []byte, cursor int64) (int64, *structFieldS return cursor, field, nil } -func decodeKeyByBitmapUint8Stream(d *structDecoder, s *stream) (*structFieldSet, string, error) { +func decodeKeyByBitmapUint8Stream(d *structDecoder, s *Stream) (*structFieldSet, string, error) { var ( field *structFieldSet curBit uint8 = math.MaxUint8 @@ -300,7 +302,7 @@ func decodeKeyByBitmapUint8Stream(d *structDecoder, s *stream) (*structFieldSet, buf, cursor, p = s.stat() continue } - return nil, "", errNotAtBeginningOfValue(s.totalOffset()) + return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) case '"': cursor++ FIRST_CHAR: @@ -316,7 +318,7 @@ func decodeKeyByBitmapUint8Stream(d *structDecoder, s *stream) (*structFieldSet, buf, cursor, p = s.stat() goto FIRST_CHAR } - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) } keyIdx := 0 bitmap := d.keyBitmapUint8 @@ -340,7 +342,7 @@ func decodeKeyByBitmapUint8Stream(d *structDecoder, s *stream) (*structFieldSet, buf, cursor, p = s.stat() continue } - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) default: curBit &= bitmap[keyIdx][largeToSmallTable[c]] if curBit == 0 { @@ -358,14 +360,14 @@ func decodeKeyByBitmapUint8Stream(d *structDecoder, s *stream) (*structFieldSet, if char(p, cursor) == nul { s.cursor = cursor if !s.read() { - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) } buf, cursor, p = s.statForRetry() } case nul: s.cursor = cursor if !s.read() { - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) } buf, cursor, p = s.statForRetry() } @@ -376,12 +378,12 @@ func decodeKeyByBitmapUint8Stream(d *structDecoder, s *stream) (*structFieldSet, cursor++ } default: - return nil, "", errNotAtBeginningOfValue(s.totalOffset()) + return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) } } } -func decodeKeyByBitmapUint16Stream(d *structDecoder, s *stream) (*structFieldSet, string, error) { +func decodeKeyByBitmapUint16Stream(d *structDecoder, s *Stream) (*structFieldSet, string, error) { var ( field *structFieldSet curBit uint16 = math.MaxUint16 @@ -397,7 +399,7 @@ func decodeKeyByBitmapUint16Stream(d *structDecoder, s *stream) (*structFieldSet buf, cursor, p = s.stat() continue } - return nil, "", errNotAtBeginningOfValue(s.totalOffset()) + return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) case '"': cursor++ FIRST_CHAR: @@ -413,7 +415,7 @@ func decodeKeyByBitmapUint16Stream(d *structDecoder, s *stream) (*structFieldSet buf, cursor, p = s.stat() goto FIRST_CHAR } - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) } keyIdx := 0 bitmap := d.keyBitmapUint16 @@ -437,7 +439,7 @@ func decodeKeyByBitmapUint16Stream(d *structDecoder, s *stream) (*structFieldSet buf, cursor, p = s.stat() continue } - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) default: curBit &= bitmap[keyIdx][largeToSmallTable[c]] if curBit == 0 { @@ -455,14 +457,14 @@ func decodeKeyByBitmapUint16Stream(d *structDecoder, s *stream) (*structFieldSet if char(p, cursor) == nul { s.cursor = cursor if !s.read() { - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) } buf, cursor, p = s.statForRetry() } case nul: s.cursor = cursor if !s.read() { - return nil, "", errUnexpectedEndOfJSON("string", s.totalOffset()) + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) } buf, cursor, p = s.statForRetry() } @@ -473,12 +475,12 @@ func decodeKeyByBitmapUint16Stream(d *structDecoder, s *stream) (*structFieldSet cursor++ } default: - return nil, "", errNotAtBeginningOfValue(s.totalOffset()) + return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) } } } -func decodeKeyStream(d *structDecoder, s *stream) (*structFieldSet, string, error) { +func decodeKeyStream(d *structDecoder, s *Stream) (*structFieldSet, string, error) { key, err := d.stringDecoder.decodeStreamByte(s) if err != nil { return nil, "", err @@ -487,10 +489,10 @@ func decodeKeyStream(d *structDecoder, s *stream) (*structFieldSet, string, erro return d.fieldMap[k], k, nil } -func (d *structDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *structDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { depth++ if depth > maxDecodeNestingDepth { - return errExceededMaxDepth(s.char(), s.cursor) + return errors.ErrExceededMaxDepth(s.char(), s.cursor) } s.skipWhiteSpace() @@ -504,7 +506,7 @@ func (d *structDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) e s.read() default: if s.char() != '{' { - return errNotAtBeginningOfValue(s.totalOffset()) + return errors.ErrNotAtBeginningOfValue(s.totalOffset()) } } s.cursor++ @@ -521,22 +523,22 @@ func (d *structDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) e } s.skipWhiteSpace() if s.char() != ':' { - return errExpected("colon after object key", s.totalOffset()) + return errors.ErrExpected("colon after object key", s.totalOffset()) } s.cursor++ if s.char() == nul { if !s.read() { - return errExpected("object value after colon", s.totalOffset()) + return errors.ErrExpected("object value after colon", s.totalOffset()) } } if field != nil { if field.err != nil { return field.err } - if err := field.dec.decodeStream(s, depth, unsafe.Pointer(uintptr(p)+field.offset)); err != nil { + if err := field.dec.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+field.offset)); err != nil { return err } - } else if s.disallowUnknownFields { + } else if s.DisallowUnknownFields { return fmt.Errorf("json: unknown field %q", key) } else { if err := s.skipValue(depth); err != nil { @@ -550,16 +552,16 @@ func (d *structDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) e return nil } if c != ',' { - return errExpected("comma after object element", s.totalOffset()) + return errors.ErrExpected("comma after object element", s.totalOffset()) } s.cursor++ } } -func (d *structDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *structDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { depth++ if depth > maxDecodeNestingDepth { - return 0, errExceededMaxDepth(buf[cursor], cursor) + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) } buflen := int64(len(buf)) cursor = skipWhiteSpace(buf, cursor) @@ -573,7 +575,7 @@ func (d *structDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer return cursor, nil case '{': default: - return 0, errNotAtBeginningOfValue(cursor) + return 0, errors.ErrNotAtBeginningOfValue(cursor) } cursor++ cursor = skipWhiteSpace(buf, cursor) @@ -588,17 +590,17 @@ func (d *structDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer } cursor = skipWhiteSpace(buf, c) if char(b, cursor) != ':' { - return 0, errExpected("colon after object key", cursor) + return 0, errors.ErrExpected("colon after object key", cursor) } cursor++ if cursor >= buflen { - return 0, errExpected("object value after colon", cursor) + return 0, errors.ErrExpected("object value after colon", cursor) } if field != nil { if field.err != nil { return 0, field.err } - c, err := field.dec.decode(buf, cursor, depth, unsafe.Pointer(uintptr(p)+field.offset)) + c, err := field.dec.Decode(buf, cursor, depth, unsafe.Pointer(uintptr(p)+field.offset)) if err != nil { return 0, err } @@ -616,7 +618,7 @@ func (d *structDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer return cursor, nil } if char(b, cursor) != ',' { - return 0, errExpected("comma after object element", cursor) + return 0, errors.ErrExpected("comma after object element", cursor) } cursor++ } diff --git a/internal/decoder/type.go b/internal/decoder/type.go new file mode 100644 index 0000000..89695a2 --- /dev/null +++ b/internal/decoder/type.go @@ -0,0 +1,23 @@ +package decoder + +import ( + "encoding" + "encoding/json" + "reflect" + "unsafe" +) + +type decoder interface { + Decode([]byte, int64, int64, unsafe.Pointer) (int64, error) + DecodeStream(*Stream, int64, unsafe.Pointer) error +} + +const ( + nul = '\000' + maxDecodeNestingDepth = 10000 +) + +var ( + unmarshalJSONType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() + unmarshalTextType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() +) diff --git a/decode_uint.go b/internal/decoder/uint.go similarity index 83% rename from decode_uint.go rename to internal/decoder/uint.go index f6c19e4..064c196 100644 --- a/decode_uint.go +++ b/internal/decoder/uint.go @@ -1,20 +1,23 @@ -package json +package decoder import ( "fmt" "reflect" "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" ) type uintDecoder struct { - typ *rtype + typ *runtime.Type kind reflect.Kind op func(unsafe.Pointer, uint64) structName string fieldName string } -func newUintDecoder(typ *rtype, structName, fieldName string, op func(unsafe.Pointer, uint64)) *uintDecoder { +func newUintDecoder(typ *runtime.Type, structName, fieldName string, op func(unsafe.Pointer, uint64)) *uintDecoder { return &uintDecoder{ typ: typ, kind: typ.Kind(), @@ -24,10 +27,10 @@ func newUintDecoder(typ *rtype, structName, fieldName string, op func(unsafe.Poi } } -func (d *uintDecoder) typeError(buf []byte, offset int64) *UnmarshalTypeError { - return &UnmarshalTypeError{ +func (d *uintDecoder) typeError(buf []byte, offset int64) *errors.UnmarshalTypeError { + return &errors.UnmarshalTypeError{ Value: fmt.Sprintf("number %s", string(buf)), - Type: rtype2type(d.typ), + Type: runtime.RType2Type(d.typ), Offset: offset, } } @@ -54,7 +57,7 @@ func (d *uintDecoder) parseUint(b []byte) (uint64, error) { return sum, nil } -func (d *uintDecoder) decodeStreamByte(s *stream) ([]byte, error) { +func (d *uintDecoder) decodeStreamByte(s *Stream) ([]byte, error) { for { switch s.char() { case ' ', '\n', '\t', '\r': @@ -93,7 +96,7 @@ func (d *uintDecoder) decodeStreamByte(s *stream) ([]byte, error) { } break } - return nil, errUnexpectedEndOfJSON("number(unsigned integer)", s.totalOffset()) + return nil, errors.ErrUnexpectedEndOfJSON("number(unsigned integer)", s.totalOffset()) } func (d *uintDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { @@ -125,7 +128,7 @@ func (d *uintDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error } } -func (d *uintDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *uintDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { bytes, err := d.decodeStreamByte(s) if err != nil { return err @@ -155,7 +158,7 @@ func (d *uintDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) err return nil } -func (d *uintDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *uintDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { bytes, c, err := d.decodeByte(buf, cursor) if err != nil { return 0, err diff --git a/decode_unmarshal_json.go b/internal/decoder/unmarshal_json.go similarity index 66% rename from decode_unmarshal_json.go rename to internal/decoder/unmarshal_json.go index faa593b..3676eab 100644 --- a/decode_unmarshal_json.go +++ b/internal/decoder/unmarshal_json.go @@ -1,16 +1,20 @@ -package json +package decoder import ( + "encoding/json" "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" ) type unmarshalJSONDecoder struct { - typ *rtype + typ *runtime.Type structName string fieldName string } -func newUnmarshalJSONDecoder(typ *rtype, structName, fieldName string) *unmarshalJSONDecoder { +func newUnmarshalJSONDecoder(typ *runtime.Type, structName, fieldName string) *unmarshalJSONDecoder { return &unmarshalJSONDecoder{ typ: typ, structName: structName, @@ -20,15 +24,15 @@ func newUnmarshalJSONDecoder(typ *rtype, structName, fieldName string) *unmarsha func (d *unmarshalJSONDecoder) annotateError(cursor int64, err error) { switch e := err.(type) { - case *UnmarshalTypeError: + case *errors.UnmarshalTypeError: e.Struct = d.structName e.Field = d.fieldName - case *SyntaxError: + case *errors.SyntaxError: e.Offset = cursor } } -func (d *unmarshalJSONDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *unmarshalJSONDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { s.skipWhiteSpace() start := s.cursor if err := s.skipValue(depth); err != nil { @@ -42,14 +46,14 @@ func (d *unmarshalJSONDecoder) decodeStream(s *stream, depth int64, p unsafe.Poi typ: d.typ, ptr: p, })) - if err := v.(Unmarshaler).UnmarshalJSON(dst); err != nil { + if err := v.(json.Unmarshaler).UnmarshalJSON(dst); err != nil { d.annotateError(s.cursor, err) return err } return nil } -func (d *unmarshalJSONDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *unmarshalJSONDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { cursor = skipWhiteSpace(buf, cursor) start := cursor end, err := skipValue(buf, cursor, depth) @@ -64,7 +68,7 @@ func (d *unmarshalJSONDecoder) decode(buf []byte, cursor, depth int64, p unsafe. typ: d.typ, ptr: p, })) - if err := v.(Unmarshaler).UnmarshalJSON(dst); err != nil { + if err := v.(json.Unmarshaler).UnmarshalJSON(dst); err != nil { d.annotateError(cursor, err) return 0, err } diff --git a/decode_unmarshal_text.go b/internal/decoder/unmarshal_text.go similarity index 83% rename from decode_unmarshal_text.go rename to internal/decoder/unmarshal_text.go index cd30e16..709ae56 100644 --- a/decode_unmarshal_text.go +++ b/internal/decoder/unmarshal_text.go @@ -1,4 +1,4 @@ -package json +package decoder import ( "bytes" @@ -7,15 +7,18 @@ import ( "unicode/utf16" "unicode/utf8" "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" ) type unmarshalTextDecoder struct { - typ *rtype + typ *runtime.Type structName string fieldName string } -func newUnmarshalTextDecoder(typ *rtype, structName, fieldName string) *unmarshalTextDecoder { +func newUnmarshalTextDecoder(typ *runtime.Type, structName, fieldName string) *unmarshalTextDecoder { return &unmarshalTextDecoder{ typ: typ, structName: structName, @@ -25,10 +28,10 @@ func newUnmarshalTextDecoder(typ *rtype, structName, fieldName string) *unmarsha func (d *unmarshalTextDecoder) annotateError(cursor int64, err error) { switch e := err.(type) { - case *UnmarshalTypeError: + case *errors.UnmarshalTypeError: e.Struct = d.structName e.Field = d.fieldName - case *SyntaxError: + case *errors.SyntaxError: e.Offset = cursor } } @@ -37,7 +40,7 @@ var ( nullbytes = []byte(`null`) ) -func (d *unmarshalTextDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *unmarshalTextDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { s.skipWhiteSpace() start := s.cursor if err := s.skipValue(depth); err != nil { @@ -47,21 +50,21 @@ func (d *unmarshalTextDecoder) decodeStream(s *stream, depth int64, p unsafe.Poi if len(src) > 0 { switch src[0] { case '[': - return &UnmarshalTypeError{ + return &errors.UnmarshalTypeError{ Value: "array", - Type: rtype2type(d.typ), + Type: runtime.RType2Type(d.typ), Offset: s.totalOffset(), } case '{': - return &UnmarshalTypeError{ + return &errors.UnmarshalTypeError{ Value: "object", - Type: rtype2type(d.typ), + Type: runtime.RType2Type(d.typ), Offset: s.totalOffset(), } case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return &UnmarshalTypeError{ + return &errors.UnmarshalTypeError{ Value: "number", - Type: rtype2type(d.typ), + Type: runtime.RType2Type(d.typ), Offset: s.totalOffset(), } case 'n': @@ -88,7 +91,7 @@ func (d *unmarshalTextDecoder) decodeStream(s *stream, depth int64, p unsafe.Poi return nil } -func (d *unmarshalTextDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *unmarshalTextDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { cursor = skipWhiteSpace(buf, cursor) start := cursor end, err := skipValue(buf, cursor, depth) @@ -99,21 +102,21 @@ func (d *unmarshalTextDecoder) decode(buf []byte, cursor, depth int64, p unsafe. if len(src) > 0 { switch src[0] { case '[': - return 0, &UnmarshalTypeError{ + return 0, &errors.UnmarshalTypeError{ Value: "array", - Type: rtype2type(d.typ), + Type: runtime.RType2Type(d.typ), Offset: start, } case '{': - return 0, &UnmarshalTypeError{ + return 0, &errors.UnmarshalTypeError{ Value: "object", - Type: rtype2type(d.typ), + Type: runtime.RType2Type(d.typ), Offset: start, } case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return 0, &UnmarshalTypeError{ + return 0, &errors.UnmarshalTypeError{ Value: "number", - Type: rtype2type(d.typ), + Type: runtime.RType2Type(d.typ), Offset: start, } case 'n': diff --git a/decode_wrapped_string.go b/internal/decoder/wrapped_string.go similarity index 68% rename from decode_wrapped_string.go rename to internal/decoder/wrapped_string.go index 7f63c59..5015db3 100644 --- a/decode_wrapped_string.go +++ b/internal/decoder/wrapped_string.go @@ -1,12 +1,14 @@ -package json +package decoder import ( "reflect" "unsafe" + + "github.com/goccy/go-json/internal/runtime" ) type wrappedStringDecoder struct { - typ *rtype + typ *runtime.Type dec decoder stringDecoder *stringDecoder structName string @@ -14,7 +16,7 @@ type wrappedStringDecoder struct { isPtrType bool } -func newWrappedStringDecoder(typ *rtype, dec decoder, structName, fieldName string) *wrappedStringDecoder { +func newWrappedStringDecoder(typ *runtime.Type, dec decoder, structName, fieldName string) *wrappedStringDecoder { return &wrappedStringDecoder{ typ: typ, dec: dec, @@ -25,7 +27,7 @@ func newWrappedStringDecoder(typ *rtype, dec decoder, structName, fieldName stri } } -func (d *wrappedStringDecoder) decodeStream(s *stream, depth int64, p unsafe.Pointer) error { +func (d *wrappedStringDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { bytes, err := d.stringDecoder.decodeStreamByte(s) if err != nil { return err @@ -38,13 +40,13 @@ func (d *wrappedStringDecoder) decodeStream(s *stream, depth int64, p unsafe.Poi } b := make([]byte, len(bytes)+1) copy(b, bytes) - if _, err := d.dec.decode(b, 0, depth, p); err != nil { + if _, err := d.dec.Decode(b, 0, depth, p); err != nil { return err } return nil } -func (d *wrappedStringDecoder) decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { +func (d *wrappedStringDecoder) Decode(buf []byte, cursor, depth int64, p unsafe.Pointer) (int64, error) { bytes, c, err := d.stringDecoder.decodeByte(buf, cursor) if err != nil { return 0, err @@ -56,7 +58,7 @@ func (d *wrappedStringDecoder) decode(buf []byte, cursor, depth int64, p unsafe. return c, nil } bytes = append(bytes, nul) - if _, err := d.dec.decode(bytes, 0, depth, p); err != nil { + if _, err := d.dec.Decode(bytes, 0, depth, p); err != nil { return 0, err } return c, nil diff --git a/rtype.go b/rtype.go deleted file mode 100644 index 3459884..0000000 --- a/rtype.go +++ /dev/null @@ -1,27 +0,0 @@ -package json - -import ( - "reflect" - "unsafe" - - "github.com/goccy/go-json/internal/runtime" -) - -type rtype = runtime.Type - -type emptyInterface struct { - typ *rtype - ptr unsafe.Pointer -} - -func rtype_ptrTo(t *rtype) *rtype { - return runtime.PtrTo(t) -} - -func rtype2type(t *rtype) reflect.Type { - return runtime.RType2Type(t) -} - -func type2rtype(t reflect.Type) *rtype { - return runtime.Type2RType(t) -}