This commit is contained in:
Marcellus Tavares 2024-11-22 06:54:38 +00:00 committed by GitHub
commit b18db1095d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 66 additions and 32 deletions

View File

@ -208,10 +208,18 @@ func Test_Decoder(t *testing.T) {
t.Run("interface", func(t *testing.T) { t.Run("interface", func(t *testing.T) {
t.Run("number", func(t *testing.T) { t.Run("number", func(t *testing.T) {
var v interface{} var v interface{}
assertErr(t, json.Unmarshal([]byte(`10`), &v)) assertErr(t, json.Unmarshal([]byte(`10.0`), &v))
assertEq(t, "interface.kind", "float64", reflect.TypeOf(v).Kind().String()) assertEq(t, "interface.kind", "float64", reflect.TypeOf(v).Kind().String())
assertEq(t, "interface", `10`, fmt.Sprint(v)) assertEq(t, "interface", `10`, fmt.Sprint(v))
}) })
t.Run("int64", func(t *testing.T) {
type StructValueLayout struct {
Values []interface{} `json:"values"`
}
var structLayout StructValueLayout
assertErr(t, json.Unmarshal([]byte(`{"values":[2074546971352916989, "test"]}`), &structLayout))
assertEq(t, "int64", int64(2074546971352916989), structLayout.Values[0].(int64))
})
t.Run("string", func(t *testing.T) { t.Run("string", func(t *testing.T) {
var v interface{} var v interface{}
assertErr(t, json.Unmarshal([]byte(`"hello"`), &v)) assertErr(t, json.Unmarshal([]byte(`"hello"`), &v))

View File

@ -18,6 +18,7 @@ type intDecoder struct {
} }
func newIntDecoder(typ *runtime.Type, structName, fieldName string, op func(unsafe.Pointer, int64)) *intDecoder { func newIntDecoder(typ *runtime.Type, structName, fieldName string, op func(unsafe.Pointer, int64)) *intDecoder {
if typ != nil {
return &intDecoder{ return &intDecoder{
typ: typ, typ: typ,
kind: typ.Kind(), kind: typ.Kind(),
@ -25,6 +26,13 @@ func newIntDecoder(typ *runtime.Type, structName, fieldName string, op func(unsa
structName: structName, structName: structName,
fieldName: fieldName, fieldName: fieldName,
} }
} else {
return &intDecoder{
op: op,
structName: structName,
fieldName: fieldName,
}
}
} }
func (d *intDecoder) typeError(buf []byte, offset int64) *errors.UnmarshalTypeError { func (d *intDecoder) typeError(buf []byte, offset int64) *errors.UnmarshalTypeError {
@ -190,6 +198,7 @@ func (d *intDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) erro
if err != nil { if err != nil {
return d.typeError(bytes, s.totalOffset()) return d.typeError(bytes, s.totalOffset())
} }
if d.typ != nil {
switch d.kind { switch d.kind {
case reflect.Int8: case reflect.Int8:
if i64 < -1*(1<<7) || (1<<7) <= i64 { if i64 < -1*(1<<7) || (1<<7) <= i64 {
@ -204,6 +213,7 @@ func (d *intDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) erro
return d.typeError(bytes, s.totalOffset()) return d.typeError(bytes, s.totalOffset())
} }
} }
}
d.op(p, i64) d.op(p, i64)
s.reset() s.reset()
return nil return nil
@ -223,6 +233,7 @@ func (d *intDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.P
if err != nil { if err != nil {
return 0, d.typeError(bytes, cursor) return 0, d.typeError(bytes, cursor)
} }
if d.typ != nil {
switch d.kind { switch d.kind {
case reflect.Int8: case reflect.Int8:
if i64 < -1*(1<<7) || (1<<7) <= i64 { if i64 < -1*(1<<7) || (1<<7) <= i64 {
@ -237,6 +248,7 @@ func (d *intDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.P
return 0, d.typeError(bytes, cursor) return 0, d.typeError(bytes, cursor)
} }
} }
}
d.op(p, i64) d.op(p, i64)
return cursor, nil return cursor, nil
} }

View File

@ -5,6 +5,7 @@ import (
"encoding" "encoding"
"encoding/json" "encoding/json"
"reflect" "reflect"
"strings"
"unsafe" "unsafe"
"github.com/goccy/go-json/internal/errors" "github.com/goccy/go-json/internal/errors"
@ -18,6 +19,7 @@ type interfaceDecoder struct {
sliceDecoder *sliceDecoder sliceDecoder *sliceDecoder
mapDecoder *mapDecoder mapDecoder *mapDecoder
floatDecoder *floatDecoder floatDecoder *floatDecoder
intDecoder *intDecoder
numberDecoder *numberDecoder numberDecoder *numberDecoder
stringDecoder *stringDecoder stringDecoder *stringDecoder
} }
@ -30,6 +32,9 @@ func newEmptyInterfaceDecoder(structName, fieldName string) *interfaceDecoder {
floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
*(*interface{})(p) = v *(*interface{})(p) = v
}), }),
intDecoder: newIntDecoder(nil, structName, fieldName, func(p unsafe.Pointer, v int64) {
*(*interface{})(p) = v
}),
numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) { numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) {
*(*interface{})(p) = v *(*interface{})(p) = v
}), }),
@ -78,6 +83,9 @@ func newInterfaceDecoder(typ *runtime.Type, structName, fieldName string) *inter
floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) {
*(*interface{})(p) = v *(*interface{})(p) = v
}), }),
intDecoder: newIntDecoder(nil, structName, fieldName, func(p unsafe.Pointer, v int64) {
*(*interface{})(p) = v
}),
numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) { numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) {
*(*interface{})(p) = v *(*interface{})(p) = v
}), }),
@ -423,7 +431,13 @@ func (d *interfaceDecoder) decodeEmptyInterface(ctx *RuntimeContext, cursor, dep
**(**interface{})(unsafe.Pointer(&p)) = v **(**interface{})(unsafe.Pointer(&p)) = v
return cursor, nil return cursor, nil
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
bytes, _, _ := d.numberDecoder.decodeByte(ctx.Buf, cursor)
numberStr := *(*string)(unsafe.Pointer(&bytes))
if strings.Contains(numberStr, ".") {
return d.floatDecoder.Decode(ctx, cursor, depth, p) return d.floatDecoder.Decode(ctx, cursor, depth, p)
} else {
return d.intDecoder.Decode(ctx, cursor, depth, p)
}
case '"': case '"':
var v string var v string
ptr := unsafe.Pointer(&v) ptr := unsafe.Pointer(&v)