diff --git a/api_test.go b/api_test.go index 612ce7b76..014c0f675 100644 --- a/api_test.go +++ b/api_test.go @@ -63,6 +63,11 @@ func TestApiUseNumber(t *testing.T) { err := cfg.UnmarshalFromString("123", &i) assert.NoError(t, err) assert.Equal(t, i, interface{}(json.Number("123"))) + + var i2 int + err = cfg.UnmarshalFromString("123", &i2) + assert.NoError(t, err) + assert.Equal(t, i2, 123) } func TestApiUseInt64(t *testing.T) { @@ -81,6 +86,7 @@ func TestApiDefaultNoCopy(t *testing.T) { // not copy the string cfg := Config{ }.Froze() + var i string data := "\"123\"" ptr0 := (*reflect.StringHeader)(unsafe.Pointer(&data)).Data + 1 diff --git a/decode_test.go b/decode_test.go index 0815be6d0..21bc13ae7 100644 --- a/decode_test.go +++ b/decode_test.go @@ -2028,10 +2028,10 @@ var decodeMismatchErrorTests = []struct { dest interface{} src string }{ - {new(int), `{}`}, - {new(string), `{}`}, - {new(bool), `{}`}, - {new([]byte), `{}`}, + {new(int), `{}`}, + {new(string), `{}`}, + {new(bool), `{}`}, + {new([]byte), `{}`}, } func TestMismatchTypeError(t *testing.T) { diff --git a/dev/decoder/compile_struct.go b/dev/decoder/compile_struct.go index 1f8c91e60..76acd8486 100644 --- a/dev/decoder/compile_struct.go +++ b/dev/decoder/compile_struct.go @@ -141,5 +141,6 @@ func (c *compiler) compileStructBody(vt reflect.Type) decFunc { fieldMap: fm, fields: entries, structName: vt.Name(), + typ: vt, } } diff --git a/dev/decoder/compiler.go b/dev/decoder/compiler.go index b8c0ea417..9026c9349 100644 --- a/dev/decoder/compiler.go +++ b/dev/decoder/compiler.go @@ -197,6 +197,7 @@ func (c *compiler) compileArray(vt reflect.Type) decFunc { len: vt.Len(), elemType: rt.UnpackType(vt.Elem()), elemDec: c.compile(vt.Elem()), + typ: vt, } } @@ -215,6 +216,7 @@ func (c *compiler) tryCompileSliceUnmarshaler(vt reflect.Type) decFunc { return &sliceDecoder{ elemType: rt.UnpackType(vt.Elem()), elemDec: c.compile(vt.Elem()), + typ: vt, } } @@ -222,6 +224,7 @@ func (c *compiler) tryCompileSliceUnmarshaler(vt reflect.Type) decFunc { return &sliceDecoder{ elemType: rt.UnpackType(vt.Elem()), elemDec: c.compile(vt.Elem()), + typ: vt, } } return nil @@ -266,6 +269,7 @@ func (c *compiler) compileSlice(vt reflect.Type) decFunc { return &sliceDecoder{ elemType: rt.UnpackType(vt.Elem()), elemDec: c.compile(vt.Elem()), + typ: vt, } } @@ -276,6 +280,7 @@ func (c *compiler) compileSliceBytes(vt reflect.Type) decFunc { return &sliceBytesUnmarshalerDecoder{ elemType: rt.UnpackType(vt.Elem()), elemDec: c.compile(vt.Elem()), + typ: vt, } } @@ -283,6 +288,7 @@ func (c *compiler) compileSliceBytes(vt reflect.Type) decFunc { return &sliceBytesUnmarshalerDecoder{ elemType: rt.UnpackType(vt.Elem()), elemDec: c.compile(vt.Elem()), + typ: vt, } } diff --git a/dev/decoder/errors.go b/dev/decoder/errors.go index 9006cbac4..2afdb0b86 100644 --- a/dev/decoder/errors.go +++ b/dev/decoder/errors.go @@ -118,9 +118,11 @@ func error_type(vt *rt.GoType) error { } type MismatchTypeError struct { - Pos int - Src string - Type reflect.Type + Pos int + Src string + Type reflect.Type + Struct string + Field string } func swithchJSONType(src string, pos int) string { @@ -143,11 +145,7 @@ func swithchJSONType(src string, pos int) string { } func (self MismatchTypeError) Error() string { - se := SyntaxError{ - Pos: self.Pos, - Src: self.Src, - } - return fmt.Sprintf("Mismatch type %s with value %s %q", self.Type.String(), swithchJSONType(self.Src, self.Pos), se.description()) + return self.Description() } func (self MismatchTypeError) Description() string { @@ -155,14 +153,19 @@ func (self MismatchTypeError) Description() string { Pos: self.Pos, Src: self.Src, } - return fmt.Sprintf("Mismatch type %s with value %s %s", self.Type.String(), swithchJSONType(self.Src, self.Pos), se.description()) + if self.Struct != "" { + return fmt.Sprintf("Mismatch type `%s` in struct `%s` field `%s` with value `%s` %s", self.Type.String(), self.Struct, self.Field, swithchJSONType(self.Src, self.Pos), se.description()) + } else { + return fmt.Sprintf("Mismatch type `%s` with value `%s` %s", self.Type.String(), swithchJSONType(self.Src, self.Pos), se.description()) + } + } -func error_mismatch(src string, pos int, vt *rt.GoType) error { +func error_mismatch(node internal.Node, ctx *context, typ reflect.Type) error { return &MismatchTypeError{ - Pos: pos, - Src: src, - Type: vt.Pack(), + Pos: node.Position(&ctx.Context), + Src: ctx.Json, + Type: typ, } } @@ -187,23 +190,12 @@ func error_parse_internal(err error, src string) error { } if e, ok := err.(*internal.UnmatchedError); ok { - return SyntaxError{ + return &MismatchTypeError { Pos: int(e.Offset), Src: src, - Msg: e.Msg, + Type: e.Type.Pack(), } } return err } - -func error_mismatch_internal(err error, vt reflect.Type, src string) error { - if _, ok := err.(*internal.UnmatchedError); ok { - return MismatchTypeError{ - Pos: 0, - Src: src, - Type: vt, - } - } - return err -} diff --git a/dev/decoder/errors_test.go b/dev/decoder/errors_test.go index 7b469cbc7..201085622 100644 --- a/dev/decoder/errors_test.go +++ b/dev/decoder/errors_test.go @@ -18,20 +18,129 @@ package decoder import ( "testing" + "encoding/json" + + "github.com/stretchr/testify/assert" ) +type errTest struct { + in string + ptr interface{} + pos int +} + + func TestErrors_ParseError(t *testing.T) { - var got interface{} - err := NewDecoder(`{123}`).Decode(&got) - println(err.(SyntaxError).Description()) + testCases := []errTest { + { + in: `{123}`, + pos: 1, + }, + { + in: `{}1`, + pos: 2, + }, + { + in: `tru`, + pos: 3, + }, + { + in: ` fx`, + pos: 3, + }, + { + in: `{"12" 12}`, + pos: 6, + }, + } + + for _, tt := range testCases { + var v1, v2 interface{} + got := NewDecoder(tt.in).Decode(&v1) + exp := json.Unmarshal([]byte(tt.in), &v2) + assert.Error(t, exp) + e := got.(SyntaxError); + assert.Equal(t, tt.pos, e.Pos) + println(e.Description()) + + } } type A struct { A string } + +type B struct { + A int `json:"a,string"` +} + func TestErrors_MismatchType(t *testing.T) { - var got A - err := NewDecoder(`{"a": 123}`).Decode(&got) - println(err.(MismatchTypeError).Description()) + testCases := []errTest { + { + in: `{"a": 123}`, + ptr: &A{}, + pos: 6, + }, + { + in: ` {"a": true}`, + ptr: &A{}, + pos: 7, + }, + { + in: ` {"a": true}`, + ptr: &B{}, + pos: 7, + }, + { + in: ` {"a": "true"}`, + ptr: &B{}, + pos: 7, + }, + { + in: ` [1, 2, "3", 4]`, + ptr: &[4]int{}, + pos: 8, + }, + { + in: ` [1, 2, "3", 4]`, + ptr: &[]int{}, + pos: 8, + }, + { + in: ` [1, 256, "3", 4]`, + ptr: &[]int8{}, + pos: 5, + }, + { + in: ` [1, 256, "3", 4]`, + ptr: &[]byte{}, // []byte is special + pos: 1, + }, + { + in: ` {"key": 123}`, + ptr: &map[string]string{}, + pos: 9, + }, + { + in: ` {"key": 123}`, + ptr: &map[int64]interface{}{}, + pos: 2, + }, + { + in: ` "key"`, + ptr: new(json.Number), + pos: 1, + }, + } + + for _, tt := range testCases { + got := NewDecoder(tt.in).Decode(tt.ptr) + e := got.(*MismatchTypeError); + assert.Equal(t, tt.pos, e.Pos) + println(e.Description()) + + exp := json.Unmarshal([]byte(tt.in), tt.ptr) + assert.Error(t, exp) + } } diff --git a/dev/decoder/functor.go b/dev/decoder/functor.go index 0ed3637af..2b3890f8b 100644 --- a/dev/decoder/functor.go +++ b/dev/decoder/functor.go @@ -63,13 +63,9 @@ func (d *i8Decoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context) return nil } - ret, err := node.AsI64() - if err != nil { - return err - } - - if ret > math.MaxInt8 || ret < math.MinInt8 { - return error_value(node.AsRaw(&ctx.Context), int8Type) + ret, ok := node.AsI64(&ctx.Context) + if !ok || ret > math.MaxInt8 || ret < math.MinInt8 { + return error_mismatch(node, ctx, int8Type) } *(*int8)(vp) = int8(ret) @@ -83,13 +79,9 @@ func (d *i16Decoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context return nil } - ret, err := node.AsI64() - if err != nil { - return err - } - - if ret > math.MaxInt16 || ret < math.MinInt16 { - return error_value(node.AsRaw(&ctx.Context), int16Type) + ret, ok := node.AsI64(&ctx.Context) + if !ok || ret > math.MaxInt16 || ret < math.MinInt16 { + return error_mismatch(node, ctx, int16Type) } *(*int16)(vp) = int16(ret) @@ -103,13 +95,9 @@ func (d *i32Decoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context return nil } - ret, err := node.AsI64() - if err != nil { - return err - } - - if ret > math.MaxInt32 || ret < math.MinInt32 { - return error_value(node.AsRaw(&ctx.Context), int32Type) + ret, ok := node.AsI64(&ctx.Context) + if !ok || ret > math.MaxInt32 || ret < math.MinInt32 { + return error_mismatch(node, ctx, int32Type) } *(*int32)(vp) = int32(ret) @@ -123,9 +111,9 @@ func (d *i64Decoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context return nil } - ret, err := node.AsI64() - if err != nil { - return err + ret, ok := node.AsI64(&ctx.Context) + if !ok { + return error_mismatch(node, ctx, int64Type) } *(*int64)(vp) = int64(ret) @@ -139,14 +127,13 @@ func (d *u8Decoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context) return nil } - ret, err := node.AsU64() - if err != nil { + ret, ok := node.AsU64(&ctx.Context) + if !ok || ret > math.MaxUint8 { + err := error_mismatch(node, ctx, uint8Type) + println("err is ", err.Error()) return err } - if ret > math.MaxUint8 { - return error_value(node.AsRaw(&ctx.Context), uint8Type) - } *(*uint8)(vp) = uint8(ret) return nil } @@ -158,12 +145,9 @@ func (d *u16Decoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context return nil } - ret, err := node.AsU64() - if err != nil { - return err - } - if ret > math.MaxUint16 { - return error_value(node.AsRaw(&ctx.Context), uint16Type) + ret, ok := node.AsU64(&ctx.Context) + if !ok || ret > math.MaxUint16 { + return error_mismatch(node, ctx, uint16Type) } *(*uint16)(vp) = uint16(ret) return nil @@ -176,13 +160,11 @@ func (d *u32Decoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context return nil } - ret, err := node.AsU64() - if err != nil { - return err - } - if ret > math.MaxUint32 { - return error_value(node.AsRaw(&ctx.Context), uint32Type) + ret, ok := node.AsU64(&ctx.Context) + if !ok || ret > math.MaxUint32 { + return error_mismatch(node, ctx, uint32Type) } + *(*uint32)(vp) = uint32(ret) return nil } @@ -194,10 +176,11 @@ func (d *u64Decoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context return nil } - ret, err := node.AsU64() - if err != nil { - return err + ret, ok := node.AsU64(&ctx.Context) + if !ok { + return error_mismatch(node, ctx, uint64Type) } + *(*uint64)(vp) = uint64(ret) return nil } @@ -209,13 +192,9 @@ func (d *f32Decoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context return nil } - ret, err := node.AsF64() - if err != nil { - return err - } - - if ret > math.MaxFloat32 || ret < -math.MaxFloat32 { - return error_value(node.AsRaw(&ctx.Context), float32Type) + ret, ok := node.AsF64(&ctx.Context) + if !ok || ret > math.MaxFloat32 || ret < -math.MaxFloat32 { + return error_mismatch(node, ctx, float32Type) } *(*float32)(vp) = float32(ret) @@ -229,10 +208,11 @@ func (d *f64Decoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context return nil } - ret, err := node.AsF64() - if err != nil { - return err + ret, ok := node.AsF64(&ctx.Context) + if !ok { + return error_mismatch(node, ctx, float64Type) } + *(*float64)(vp) = float64(ret) return nil } @@ -245,10 +225,11 @@ func (d *boolDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *contex return nil } - ret, err := node.AsBool() - if err != nil { - return err + ret, ok := node.AsBool() + if !ok { + return error_mismatch(node, ctx, boolType) } + *(*bool)(vp) = bool(ret) return nil } @@ -261,9 +242,9 @@ func (d *stringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *cont return nil } - ret, err := node.AsStr(&ctx.Context) - if err != nil { - return err + ret, ok := node.AsStr(&ctx.Context) + if !ok { + return error_mismatch(node, ctx, stringType) } *(*string)(vp) = ret return nil @@ -277,9 +258,9 @@ func (d *numberDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *cont return nil } - num, err := node.AsNumber(&ctx.Context) - if err != nil { - return err + num, ok := node.AsNumber(&ctx.Context) + if !ok { + return error_mismatch(node, ctx, jsonNumberType) } *(*json.Number)(vp) = num return nil diff --git a/dev/decoder/interface.go b/dev/decoder/interface.go index 2974b189f..b7b54d5f7 100644 --- a/dev/decoder/interface.go +++ b/dev/decoder/interface.go @@ -127,9 +127,9 @@ func (d *unmarshalTextDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct return nil } - s, err := node.AsStringCopy() - if err != nil { - return err + s, ok := node.AsStringCopy() + if !ok { + return error_mismatch(node, ctx, d.typ.Pack()) } v := *(*interface{})(unsafe.Pointer(&rt.GoEface{ diff --git a/dev/decoder/map.go b/dev/decoder/map.go index 48004d09e..0992b87de 100644 --- a/dev/decoder/map.go +++ b/dev/decoder/map.go @@ -49,6 +49,7 @@ func (d *mapStringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *c type mapStrKeyFastDecoder struct { mapType *rt.GoMapType elemDec decFunc + typ reflect.Type } func (d *mapStrKeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context) error { @@ -57,9 +58,9 @@ func (d *mapStrKeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) } // allocate map @@ -72,19 +73,11 @@ func (d *mapStrKeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct next := obj.Children() for i := 0; i < obj.Len(); i++ { keyn := internal.NewNode(next) - key, err := keyn.AsStr(&ctx.Context) - if err != nil { - if gerr == nil { - gerr = err - } - valn := internal.NewNode(internal.PtrOffset(next, 1)) - next = valn.Next() - continue - } + key, _ := keyn.AsStr(&ctx.Context) valn := internal.NewNode(internal.PtrOffset(next, 1)) valp := mapassign_faststr(d.mapType, m, key) - err = d.elemDec.FromDom(valp, valn, ctx) + err := d.elemDec.FromDom(valp, valn, ctx) if gerr == nil && err != nil { gerr = err } @@ -106,9 +99,9 @@ func (d *mapStrKeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) } // allocate map @@ -121,19 +114,11 @@ func (d *mapStrKeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx next := obj.Children() for i := 0; i < obj.Len(); i++ { keyn := internal.NewNode(next) - key, err := keyn.AsStr(&ctx.Context) - if err != nil { - if gerr == nil { - gerr = err - } - valn := internal.NewNode(internal.PtrOffset(next, 1)) - next = valn.Next() - continue - } + key, _ := keyn.AsStr(&ctx.Context) valn := internal.NewNode(internal.PtrOffset(next, 1)) valp := mapassign(d.mapType, m, unsafe.Pointer(&key)) - err = d.elemDec.FromDom(valp, valn, ctx) + err := d.elemDec.FromDom(valp, valn, ctx) if gerr == nil && err != nil { gerr = err } @@ -157,9 +142,9 @@ func (d *mapI32KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) } // allocate map @@ -172,14 +157,10 @@ func (d *mapI32KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct var gerr error for i := 0; i < obj.Len(); i++ { keyn := internal.NewNode(next) - k, err := keyn.ParseI64(&ctx.Context) - if k > math.MaxInt32 || k < math.MinInt32 { - err = error_value(keyn.AsRaw(&ctx.Context), d.mapType.Key.Pack()) - } - - if err != nil { + k, ok := keyn.ParseI64(&ctx.Context) + if !ok || k > math.MaxInt32 || k < math.MinInt32 { if gerr == nil { - gerr = err + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) } valn := internal.NewNode(internal.PtrOffset(next, 1)) next = valn.Next() @@ -190,7 +171,7 @@ func (d *mapI32KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct ku32 := *(*uint32)(unsafe.Pointer(&key)) valn := internal.NewNode(internal.PtrOffset(next, 1)) valp := mapassign_fast32(d.mapType, m, ku32) - err = d.elemDec.FromDom(valp, valn, ctx) + err := d.elemDec.FromDom(valp, valn, ctx) if gerr == nil && err != nil { gerr = err } @@ -213,9 +194,9 @@ func (d *mapI32KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) } // allocate map @@ -228,17 +209,11 @@ func (d *mapI32KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx next := obj.Children() for i := 0; i < obj.Len(); i++ { keyn := internal.NewNode(next) - k, err := keyn.ParseI64(&ctx.Context) - if err != nil { - return err - } - if k > math.MaxInt32 || k < math.MinInt32 { - err = error_value(keyn.AsRaw(&ctx.Context), d.mapType.Key.Pack()) - } + k, ok := keyn.ParseI64(&ctx.Context) - if err != nil { + if !ok || k > math.MaxInt32 || k < math.MinInt32 { if gerr == nil { - gerr = err + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) } valn := internal.NewNode(internal.PtrOffset(next, 1)) next = valn.Next() @@ -246,10 +221,9 @@ func (d *mapI32KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx } key := int32(k) - valn := internal.NewNode(internal.PtrOffset(next, 1)) valp := mapassign(d.mapType, m, unsafe.Pointer(&key)) - err = d.elemDec.FromDom(valp, valn, ctx) + err := d.elemDec.FromDom(valp, valn, ctx) if gerr == nil && err != nil { gerr = err } @@ -271,9 +245,9 @@ func (d *mapI64KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) } // allocate map @@ -286,11 +260,11 @@ func (d *mapI64KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct next := obj.Children() for i := 0; i < obj.Len(); i++ { keyn := internal.NewNode(next) - key, err := keyn.ParseI64(&ctx.Context) + key, ok := keyn.ParseI64(&ctx.Context) - if err != nil { + if !ok { if gerr == nil { - gerr = err + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) } valn := internal.NewNode(internal.PtrOffset(next, 1)) next = valn.Next() @@ -300,7 +274,7 @@ func (d *mapI64KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct ku64 := *(*uint64)(unsafe.Pointer(&key)) valn := internal.NewNode(internal.PtrOffset(next, 1)) valp := mapassign_fast64(d.mapType, m, ku64) - err = d.elemDec.FromDom(valp, valn, ctx) + err := d.elemDec.FromDom(valp, valn, ctx) if gerr == nil && err != nil { gerr = err } @@ -322,9 +296,9 @@ func (d *mapI64KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) } // allocate map @@ -337,11 +311,11 @@ func (d *mapI64KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx next := obj.Children() for i := 0; i < obj.Len(); i++ { keyn := internal.NewNode(next) - key, err := keyn.ParseI64(&ctx.Context) + key, ok := keyn.ParseI64(&ctx.Context) - if err != nil { + if !ok { if gerr == nil { - gerr = err + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) } valn := internal.NewNode(internal.PtrOffset(next, 1)) next = valn.Next() @@ -350,7 +324,7 @@ func (d *mapI64KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx valn := internal.NewNode(internal.PtrOffset(next, 1)) valp := mapassign(d.mapType, m, unsafe.Pointer(&key)) - err = d.elemDec.FromDom(valp, valn, ctx) + err := d.elemDec.FromDom(valp, valn, ctx) if gerr == nil && err != nil { gerr = err } @@ -374,9 +348,9 @@ func (d *mapU32KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) } // allocate map @@ -389,14 +363,10 @@ func (d *mapU32KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct next := obj.Children() for i := 0; i < obj.Len(); i++ { keyn := internal.NewNode(next) - k, err := keyn.ParseU64(&ctx.Context) - if k > math.MaxUint32 { - err = error_value(keyn.AsRaw(&ctx.Context), d.mapType.Key.Pack()) - } - - if err != nil { + k, ok := keyn.ParseU64(&ctx.Context) + if !ok || k > math.MaxUint32 { if gerr == nil { - gerr = err + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) } valn := internal.NewNode(internal.PtrOffset(next, 1)) next = valn.Next() @@ -404,10 +374,9 @@ func (d *mapU32KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct } key := uint32(k) - valn := internal.NewNode(internal.PtrOffset(next, 1)) valp := mapassign_fast32(d.mapType, m, key) - err = d.elemDec.FromDom(valp, valn, ctx) + err := d.elemDec.FromDom(valp, valn, ctx) if gerr == nil && err != nil { gerr = err } @@ -429,9 +398,9 @@ func (d *mapU32KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) } // allocate map @@ -444,14 +413,10 @@ func (d *mapU32KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx var gerr error for i := 0; i < obj.Len(); i++ { keyn := internal.NewNode(next) - k, err := keyn.ParseU64(&ctx.Context) - if k > math.MaxUint32 { - err = error_value(keyn.AsRaw(&ctx.Context), d.mapType.Key.Pack()) - } - - if err != nil { + k, ok := keyn.ParseU64(&ctx.Context) + if !ok || k > math.MaxUint32 { if gerr == nil { - gerr = err + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) } valn := internal.NewNode(internal.PtrOffset(next, 1)) next = valn.Next() @@ -459,10 +424,9 @@ func (d *mapU32KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx } key := uint32(k) - valn := internal.NewNode(internal.PtrOffset(next, 1)) valp := mapassign(d.mapType, m, unsafe.Pointer(&key)) - err = d.elemDec.FromDom(valp, valn, ctx) + err := d.elemDec.FromDom(valp, valn, ctx) if gerr == nil && err != nil { gerr = err } @@ -485,11 +449,10 @@ func (d *mapU64KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) } - // allocate map m := *(*unsafe.Pointer)(vp) if m == nil { @@ -499,10 +462,11 @@ func (d *mapU64KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct var gerr error next := obj.Children() for i := 0; i < obj.Len(); i++ { - key, err := internal.NewNode(next).ParseU64(&ctx.Context) - if err != nil { + keyn := internal.NewNode(next) + key, ok := keyn.ParseU64(&ctx.Context) + if !ok { if gerr == nil { - gerr = err + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) } valn := internal.NewNode(internal.PtrOffset(next, 1)) next = valn.Next() @@ -511,7 +475,7 @@ func (d *mapU64KeyFastDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ct valn := internal.NewNode(internal.PtrOffset(next, 1)) valp := mapassign_fast64(d.mapType, m, key) - err = d.elemDec.FromDom(valp, valn, ctx) + err := d.elemDec.FromDom(valp, valn, ctx) if gerr == nil && err != nil { gerr = err } @@ -533,9 +497,9 @@ func (d *mapU64KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) } // allocate map @@ -548,10 +512,10 @@ func (d *mapU64KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx var gerr error for i := 0; i < obj.Len(); i++ { keyn := internal.NewNode(next) - key, err := keyn.ParseU64(&ctx.Context) - if err != nil { + key, ok := keyn.ParseU64(&ctx.Context) + if !ok { if gerr == nil { - gerr = err + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) } valn := internal.NewNode(internal.PtrOffset(next, 1)) next = valn.Next() @@ -560,7 +524,7 @@ func (d *mapU64KeyStdDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx valn := internal.NewNode(internal.PtrOffset(next, 1)) valp := mapassign(d.mapType, m, unsafe.Pointer(&key)) - err = d.elemDec.FromDom(valp, valn, ctx) + err := d.elemDec.FromDom(valp, valn, ctx) if gerr == nil && err != nil { gerr = err } @@ -670,9 +634,9 @@ func (d *mapDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) } // allocate map @@ -684,11 +648,12 @@ func (d *mapDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context next := obj.Children() var gerr error for i := 0; i < obj.Len(); i++ { - raw := internal.NewNode(next).AsRaw(&ctx.Context) + keyn := internal.NewNode(next) + raw := keyn.AsRaw(&ctx.Context) key, err := d.keyDec(d, raw, ctx) if err != nil { if gerr == nil { - gerr = err + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) } valn := internal.NewNode(internal.PtrOffset(next, 1)) next = valn.Next() diff --git a/dev/decoder/slice.go b/dev/decoder/slice.go index cb7dc4e31..d8fbe38fa 100644 --- a/dev/decoder/slice.go +++ b/dev/decoder/slice.go @@ -1,15 +1,17 @@ package decoder import ( + "reflect" "unsafe" - "github.com/bytedance/sonic/dev/internal/rt" "github.com/bytedance/sonic/dev/internal" + "github.com/bytedance/sonic/dev/internal/rt" ) type sliceDecoder struct { elemType *rt.GoType elemDec decFunc + typ reflect.Type } var ( @@ -22,21 +24,20 @@ func (d *sliceDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *conte return nil } - arr, err := node.AsArr() - if err != nil { - return err + arr, ok := node.AsArr() + if !ok { + return error_mismatch(node, ctx, d.typ) } slice := internal.MakeSlice(vp, d.elemType, arr.Len()) elems := slice.Ptr - next := arr.Children() var gerr error for i := 0; i < arr.Len(); i++ { val := internal.NewNode(next) elem := unsafe.Pointer(uintptr(elems) + uintptr(i)*d.elemType.Size) - err = d.elemDec.FromDom(elem, val, ctx) + err := d.elemDec.FromDom(elem, val, ctx) if gerr == nil && err != nil { gerr = err } @@ -51,6 +52,7 @@ type arrayDecoder struct { len int elemType *rt.GoType elemDec decFunc + typ reflect.Type } //go:nocheckptr @@ -59,19 +61,21 @@ func (d *arrayDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *conte return nil } - arr, err := node.AsArr() - if err != nil { - return err + arr, ok := node.AsArr() + if !ok { + return error_mismatch(node, ctx, d.typ) } next := arr.Children() i := 0 + + var gerr error for ; i < d.len && i < arr.Len(); i++ { elem := unsafe.Pointer(uintptr(vp) + uintptr(i)*d.elemType.Size) val := internal.NewNode(next) - err = d.elemDec.FromDom(elem, val, ctx) - if err != nil { - return err + err := d.elemDec.FromDom(elem, val, ctx) + if gerr == nil && err != nil { + gerr = err } next = val.Next() } @@ -80,7 +84,7 @@ func (d *arrayDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *conte ptr := unsafe.Pointer(uintptr(vp) + uintptr(i)*d.elemType.Size) n := uintptr(d.len-i) * d.elemType.Size internal.ClearMemory(d.elemType, ptr, n) - return nil + return gerr } type sliceEfaceDecoder struct { @@ -184,6 +188,7 @@ func (d *sliceBytesDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx * type sliceBytesUnmarshalerDecoder struct { elemType *rt.GoType elemDec decFunc + typ reflect.Type } func (d *sliceBytesUnmarshalerDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context) error { @@ -203,25 +208,26 @@ func (d *sliceBytesUnmarshalerDecoder) FromDom(vp unsafe.Pointer, node internal. } /* parse JSON array into `[]byte` */ - arr, err := node.AsArr() - if err != nil { - return err + arr, ok := node.AsArr() + if !ok { + return error_mismatch(node, ctx, d.typ) } slice := internal.MakeSlice(vp, d.elemType, arr.Len()) elems := slice.Ptr + var gerr error next := arr.Children() for i := 0; i < arr.Len(); i++ { child := internal.NewNode(next) elem := unsafe.Pointer(uintptr(elems) + uintptr(i)*d.elemType.Size) - err = d.elemDec.FromDom(elem, child, ctx) - if err != nil { - return err + err := d.elemDec.FromDom(elem, child, ctx) + if gerr == nil && err != nil { + gerr = err } next = child.Next() } *(*rt.GoSlice)(vp) = *slice - return nil + return gerr } diff --git a/dev/decoder/stringopts.go b/dev/decoder/stringopts.go index 195462c07..2991e3ab2 100644 --- a/dev/decoder/stringopts.go +++ b/dev/decoder/stringopts.go @@ -21,10 +21,14 @@ func (d *ptrStrDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *cont return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { + s, ok := node.AsStrRef(&ctx.Context) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { *(*unsafe.Pointer)(vp) = nil - return err + return nil } if *(*unsafe.Pointer)(vp) == nil { @@ -42,17 +46,12 @@ func (d *boolStringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx * return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { - return err + b, ok := node.ParseBool(&ctx.Context) + if !ok { + return error_mismatch(node, ctx, boolType) } - ret, err := internal.ParseBool(s) - if err != nil { - return err - } - - *(*bool)(vp) = ret + *(*bool)(vp) = b return nil } @@ -63,18 +62,9 @@ func (d *i8StringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *co return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { - return err - } - - ret, err := internal.ParseI64(s) - if err != nil { - return err - } - - if ret > math.MaxInt8 || ret < math.MinInt8 { - return error_value(node.AsRaw(&ctx.Context), int8Type) + ret, ok := node.ParseI64(&ctx.Context) + if !ok || ret > math.MaxInt8 || ret < math.MinInt8 { + return error_mismatch(node, ctx, int8Type) } *(*int8)(vp) = int8(ret) @@ -88,18 +78,9 @@ func (d *i16StringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *c return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { - return err - } - - ret, err := internal.ParseI64(s) - if err != nil { - return err - } - - if ret > math.MaxInt16 || ret < math.MinInt16 { - return error_value(node.AsRaw(&ctx.Context), int16Type) + ret, ok := node.ParseI64(&ctx.Context) + if !ok || ret > math.MaxInt16 || ret < math.MinInt16 { + return error_mismatch(node, ctx, int16Type) } *(*int16)(vp) = int16(ret) @@ -113,18 +94,9 @@ func (d *i32StringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *c return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { - return err - } - - ret, err := internal.ParseI64(s) - if err != nil { - return err - } - - if ret > math.MaxInt32 || ret < math.MinInt32 { - return error_value(node.AsRaw(&ctx.Context), int32Type) + ret, ok := node.ParseI64(&ctx.Context) + if !ok || ret > math.MaxInt32 || ret < math.MinInt32 { + return error_mismatch(node, ctx, int32Type) } *(*int32)(vp) = int32(ret) @@ -138,14 +110,9 @@ func (d *i64StringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *c return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { - return err - } - - ret, err := internal.ParseI64(s) - if err != nil { - return err + ret, ok := node.ParseI64(&ctx.Context) + if !ok { + return error_mismatch(node, ctx, int64Type) } *(*int64)(vp) = int64(ret) @@ -159,18 +126,9 @@ func (d *u8StringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *co return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { - return err - } - - ret, err := internal.ParseU64(s) - if err != nil { - return err - } - - if ret > math.MaxUint8 { - return error_value(node.AsRaw(&ctx.Context), uint8Type) + ret, ok := node.ParseU64(&ctx.Context) + if !ok || ret > math.MaxUint8 { + return error_mismatch(node, ctx, uint8Type) } *(*uint8)(vp) = uint8(ret) @@ -184,18 +142,9 @@ func (d *u16StringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *c return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { - return err - } - - ret, err := internal.ParseU64(s) - if err != nil { - return err - } - - if ret > math.MaxUint16 { - return error_value(node.AsRaw(&ctx.Context), uint16Type) + ret, ok := node.ParseU64(&ctx.Context) + if !ok || ret > math.MaxUint16 { + return error_mismatch(node, ctx, uint16Type) } *(*uint16)(vp) = uint16(ret) @@ -209,18 +158,9 @@ func (d *u32StringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *c return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { - return err - } - - ret, err := internal.ParseU64(s) - if err != nil { - return err - } - - if ret > math.MaxUint32 { - return error_value(node.AsRaw(&ctx.Context), uint32Type) + ret, ok := node.ParseU64(&ctx.Context) + if !ok || ret > math.MaxUint32 { + return error_mismatch(node, ctx, uint32Type) } *(*uint32)(vp) = uint32(ret) @@ -234,14 +174,9 @@ func (d *u64StringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *c return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { - return err - } - - ret, err := internal.ParseU64(s) - if err != nil { - return err + ret, ok := node.ParseU64(&ctx.Context) + if !ok { + return error_mismatch(node, ctx, uint64Type) } *(*uint64)(vp) = uint64(ret) @@ -255,17 +190,8 @@ func (d *f32StringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *c return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { - return err - } - - ret, err := internal.ParseF64(s) - if err != nil { - return err - } - - if ret > math.MaxFloat32 || ret < -math.MaxFloat32 { + ret, ok := node.ParseF64(&ctx.Context) + if !ok || ret > math.MaxFloat32 || ret < -math.MaxFloat32 { return error_value(node.AsRaw(&ctx.Context), float32Type) } @@ -281,14 +207,9 @@ func (d *f64StringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *c return nil } - s, err := node.AsStrRef(&ctx.Context) - if err != nil || s == "null" { - return err - } - - ret, err := internal.ParseF64(s) - if err != nil { - return err + ret, ok := node.ParseF64(&ctx.Context) + if !ok { + return error_value(node.AsRaw(&ctx.Context), float64Type) } *(*float64)(vp) = float64(ret) @@ -303,18 +224,12 @@ func (d *strStringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *c return nil } - s, err := node.AsStrRef(&ctx.Context) - /* deal with empty string */ - if err != nil || s == "null" { - return err - } - - ret, err := internal.Unquote(s) - if err != nil { - return err + s, ok := node.ParseString(&ctx.Context) + if !ok { + return error_value(node.AsRaw(&ctx.Context), stringType) } - *(*string)(vp) = ret + *(*string)(vp) = s return nil } @@ -325,16 +240,11 @@ func (d *numberStringDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx return nil } - s, err := node.AsStr(&ctx.Context) - if err != nil || s == "null" { - return err - } - - end, err := internal.SkipNumberFast(s, 0) - if err != nil { - return err + num, ok := node.ParseNumber(&ctx.Context) + if !ok { + return error_value(node.AsRaw(&ctx.Context), jsonNumberType) } - *(*json.Number)(vp) = json.Number(s[:end]) + *(*json.Number)(vp) = json.Number(num) return nil } diff --git a/dev/decoder/structs.go b/dev/decoder/structs.go index 2b2201dc4..1043ca01e 100644 --- a/dev/decoder/structs.go +++ b/dev/decoder/structs.go @@ -1,11 +1,12 @@ package decoder import ( + "reflect" "unsafe" - "github.com/bytedance/sonic/internal/resolver" "github.com/bytedance/sonic/dev/internal" "github.com/bytedance/sonic/dev/internal/caching" + "github.com/bytedance/sonic/internal/resolver" ) type fieldEntry struct { @@ -17,6 +18,7 @@ type structDecoder struct { fieldMap *caching.FieldMap fields []fieldEntry structName string + typ reflect.Type } func (d *structDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *context) error { @@ -25,20 +27,18 @@ func (d *structDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *cont } var gerr error - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.typ) } next := obj.Children() for i := 0; i < obj.Len(); i++ { - key, err := internal.NewNode(next).AsStrRef(&ctx.Context) + key, _ := internal.NewNode(next).AsStrRef(&ctx.Context) val := internal.NewNode(internal.PtrOffset(next, 1)) next = val.Next() - if err != nil { - return err - } + // find field idx idx := d.fieldMap.TryGet(key, i) if idx == -1 { idx = d.fieldMap.Get(key) @@ -55,12 +55,24 @@ func (d *structDecoder) FromDom(vp unsafe.Pointer, node internal.Node, ctx *cont offset := d.fields[idx].Path[0].Size elem := unsafe.Pointer(uintptr(vp) + offset) - err = d.fields[idx].fieldDec.FromDom(elem, val, ctx) + err := d.fields[idx].fieldDec.FromDom(elem, val, ctx) // deal with mismatch type errors if gerr == nil && err != nil { - gerr = error_mismatch_internal(err, d.fields[idx].Type, ctx.Json) + gerr = d.wrapper_error(err, idx) } } return gerr } + +//go:noinline +func (d *structDecoder) wrapper_error(err error, idx int) error { + if e, ok := err.(*MismatchTypeError); ok { + e.Struct = d.structName + e.Field = d.fields[idx].Name + return e + } + return err +} + + diff --git a/dev/decoder/types.go b/dev/decoder/types.go index 784fb2a37..626bbcf60 100644 --- a/dev/decoder/types.go +++ b/dev/decoder/types.go @@ -27,6 +27,7 @@ import ( ) var ( + boolType = reflect.TypeOf(bool(false)) byteType = reflect.TypeOf(byte(0)) intType = reflect.TypeOf(int(0)) int8Type = reflect.TypeOf(int8(0)) diff --git a/dev/dev_decode_test.go b/dev/dev_decode_test.go index 56a855a34..489f96c29 100644 --- a/dev/dev_decode_test.go +++ b/dev/dev_decode_test.go @@ -1177,7 +1177,7 @@ func TestUnmarshal(t *testing.T) { dec.CopyString() if err := dec.Decode(v.Interface()); (err == nil) != (tt.err == nil) { spew.Dump(tt, v) - t.Fatalf("#%d: %v, want %v", i, err, tt.err) + t.Fatalf("#%d: %v, want %v for json %v", i, err, tt.err, tt.in) continue } else if err != nil { continue diff --git a/dev/dev_test.go b/dev/dev_test.go index 5fc739e32..fbf661333 100644 --- a/dev/dev_test.go +++ b/dev/dev_test.go @@ -2,6 +2,7 @@ package dev_test import ( "encoding/json" + "errors" "testing" "unsafe" @@ -108,17 +109,20 @@ var fieldMap = map[string]int{ "indics": 11, } +var decodeError = errors.New("decode failed") + func unmarshalSearchMetadata(data string) (searchMetadata, error) { var ret searchMetadata + var ok bool ctx, err := internal.NewContext(data, 0) if err != nil { - return ret, nil + return ret, err } node := ctx.Dom.Root() - obj, err := node.AsObj() - if err != nil { - return ret, err + obj, ok := node.AsObj() + if !ok { + return ret, decodeError } size := obj.Len() @@ -130,59 +134,59 @@ func unmarshalSearchMetadata(data string) (searchMetadata, error) { switch idx { case 10: { - ret.MaxID, err = val.AsI64() - if err != nil { - return ret, err + ret.MaxID, ok = val.AsI64(&ctx) + if !ok { + return ret, decodeError } } case 1: - id, err := val.AsI64() + id, ok := val.AsI64(&ctx) id2 := &id id3 := &id2 - if err != nil { - return ret, err + if !ok { + return ret, decodeError } ret.SinceID = &id3 case 2: - ret.RefreshURL, err = val.AsStr(&ctx) - if err != nil { - return ret, err + ret.RefreshURL, ok = val.AsStr(&ctx) + if !ok { + return ret, decodeError } case 3: - ret.NextResults, err = val.AsStr(&ctx) - if err != nil { - return ret, err + ret.NextResults, ok = val.AsStr(&ctx) + if !ok { + return ret, decodeError } case 4: - count, err := val.AsI64() + count, ok := val.AsI64(&ctx) ret.Count = int(count) - if err != nil { - return ret, err + if !ok { + return ret, decodeError } case 5: - ret.Bool, err = val.AsBool() - if err != nil { - return ret, err + ret.Bool, ok = val.AsBool() + if !ok { + return ret, decodeError } case 6: - ret.CompletedIn, err = val.AsF64() - if err != nil { - return ret, err + ret.CompletedIn, ok = val.AsF64(&ctx) + if !ok { + return ret, decodeError } case 7: - ret.SinceIDStr, err = val.AsStr(&ctx) - if err != nil { - return ret, err + ret.SinceIDStr, ok = val.AsStr(&ctx) + if !ok { + return ret, decodeError } case 8: - ret.Query, err = val.AsStr(&ctx) - if err != nil { - return ret, err + ret.Query, ok = val.AsStr(&ctx) + if !ok { + return ret, decodeError } case 9: - s, err := val.AsStr(&ctx) - if err != nil { - return ret, err + s, ok := val.AsStr(&ctx) + if !ok { + return ret, decodeError } ret.MaxIDStr = &s case 11: diff --git a/dev/internal/errors.go b/dev/internal/errors.go index add79e3be..100342fb2 100644 --- a/dev/internal/errors.go +++ b/dev/internal/errors.go @@ -2,14 +2,16 @@ package internal import ( "fmt" + + "github.com/bytedance/sonic/dev/internal/rt" ) type ParseError struct { - Offset int64 + Offset int Msg string } -func newError(msg string, offset int64) error { +func newError(msg string, offset int) error { return &ParseError{ Offset: offset, Msg: msg, @@ -18,14 +20,13 @@ func newError(msg string, offset int64) error { type UnmatchedError struct { Offset int - Msg string - Backtrace string + Type *rt.GoType } -func newUnmatched(msg string) error { +func newUnmatched(pos int, typ *rt.GoType) error { return &UnmatchedError{ - Offset: 0, - Msg: msg, + Offset: pos, + Type: typ, } } @@ -34,5 +35,5 @@ func (e *ParseError) Error() string { } func (e *UnmatchedError) Error() string { - return fmt.Sprintf("Internal Unmatched Error: %v\n", e.Msg) + return fmt.Sprintf("Internal Unmatched Error for Type %v\n", e.Type) } diff --git a/dev/internal/helper.go b/dev/internal/helper.go index 26075d0b6..f47b178be 100644 --- a/dev/internal/helper.go +++ b/dev/internal/helper.go @@ -14,7 +14,7 @@ func SkipNumberFast(json string, start int) (int, error) { if json[pos] >= '0' && json[pos] <= '9' || json[pos] == '.' || json[pos] == '-' || json[pos] == '+' || json[pos] == 'e' || json[pos] == 'E' { pos += 1 } else { - return pos, newError("invalid number", int64(pos)) + return pos, newError("invalid number",pos) } } return pos, nil @@ -27,7 +27,7 @@ func ValidNumberFast(json string) error { if json[pos] >= '0' && json[pos] <= '9' || json[pos] == '.' || json[pos] == '-' || json[pos] == '+' || json[pos] == 'e' || json[pos] == 'E' { pos += 1 } else { - return newError("invalid number", int64(pos)) + return newError("invalid number",pos) } } return nil @@ -37,7 +37,7 @@ func SkipOneFast2(json string, pos *int) (int, error) { // find the number ending, we pasred in sonic-cpp, it alway valid start := native.SkipOneFast(&json, pos) if start < 0 { - return -1, newError("invalid json", int64(-start)) + return -1, newError("invalid json", -start) } return start, nil } @@ -47,7 +47,7 @@ func SkipOneFast(json string, pos int) (string, error) { // find the number ending, we pasred in sonic-cpp, it alway valid start := native.SkipOneFast(&json, &pos) if start < 0 { - return "", newError("invalid json", int64(pos)) + return "", newError("invalid json",pos) } return json[start:pos], nil } diff --git a/dev/internal/link/libsonic_rs_x86_64-unknown-linux-gnu.so b/dev/internal/link/libsonic_rs_x86_64-unknown-linux-gnu.so index 35874c179..27e84e0f2 100755 Binary files a/dev/internal/link/libsonic_rs_x86_64-unknown-linux-gnu.so and b/dev/internal/link/libsonic_rs_x86_64-unknown-linux-gnu.so differ diff --git a/dev/internal/sonic_rs.go b/dev/internal/sonic_rs.go index a62547841..d2c9eb93e 100644 --- a/dev/internal/sonic_rs.go +++ b/dev/internal/sonic_rs.go @@ -142,7 +142,7 @@ func Parse(data string, opt uint64) (*Dom, error) { } // parse error - if offset := int64(cdom.error_offset); offset != -1 { + if offset := int(cdom.error_offset); offset != -1 { msg := C.GoStringN(cdom.error_msg, C.int(cdom.error_msg_len)) err := newError(msg, offset) sonic_rs_ffi_free(&cdom) @@ -197,23 +197,28 @@ func (val Node) Bool() bool { return ctype.t == KTrue } -func (val Node) AsU64() (uint64, error) { - if val.Type() != KUint { - return 0, newUnmatched("expect uint64") +func (self Node) AsU64(ctx *Context) (uint64, bool) { + if self.Type() == KUint { + return self.U64(), true + } else if self.Type() == KRawNumber { + num, err := ParseU64(self.Raw(ctx)) + if err != nil { + return 0, false + } + return num, true + } else { + return 0, false } - - cnum := (*C.Number)(unsafe.Pointer(val.cptr)) - return *(*uint64)((unsafe.Pointer)(&(cnum.num))), nil } -func (val *Node) AsObj() (Object, error) { +func (val *Node) AsObj() (Object, bool) { var ret Object if val.Type() != KObject { - return ret, newUnmatched("expect object") + return ret, false } return Object{ cptr: val.cptr, - }, nil + }, true } func (val Node) Obj() Object { @@ -224,135 +229,191 @@ func (val Node) Arr() Array { return Array{cptr: val.cptr} } -func (val *Node) AsArr() (Array, error) { +func (val *Node) AsArr() (Array, bool) { var ret Array if val.Type() != KArray { - return ret, newUnmatched("expect array") + return ret, false } return Array{ cptr: val.cptr, - }, nil + }, true } -func (val Node) AsI64() (int64, error) { - if val.Type() == KUint && val.U64() <= math.MaxInt64 { - return int64(val.U64()), nil +func (self Node) AsI64(ctx *Context) (int64, bool) { + typ := self.Type() + if typ == KUint && self.U64() <= math.MaxInt64 { + return int64(self.U64()), true + } else if typ == KSint { + return self.I64(), true + } else if typ == KRawNumber { + val, err := self.Number(ctx).Int64() + if err != nil { + return 0, false + } + return val, true + } else { + return 0, false } +} - if val.Type() == KSint { - return val.I64(), nil - } +/********* Parse Node String into Value ***************/ - return 0, newUnmatched("expect int64") -} +func (val Node) ParseI64(ctx *Context) (int64, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return 0, false + } -func (val Node) ParseI64(ctx *Context) (int64, error) { - s, err := val.AsStrRef(ctx) - if err != nil { - return 0, err + if s == "null" { + return 0, true } i, err := ParseI64(s) if err != nil { - return 0, err + return 0, false } - return i, nil + return i, true } -func (val Node) ParseBool(ctx *Context) (bool, error) { - s, err := val.AsStrRef(ctx) - if err != nil { - return false, err +func (val Node) ParseBool(ctx *Context) (bool, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return false, false + } + + if s == "null" { + return false, true } b, err := ParseBool(s) if err != nil { - return false, err + return false, false } - return b, nil + return b, true } -func (val Node) ParseU64(ctx *Context) (uint64, error) { - s, err := val.AsStrRef(ctx) - if err != nil { - return 0, err +func (val Node) ParseU64(ctx *Context) (uint64, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return 0, false + } + + if s == "null" { + return 0, true } i, err := ParseU64(s) if err != nil { - return 0, err + return 0, false } - return i, nil + return i, true } -func (val Node) ParseF64(ctx *Context) (float64, error) { - s, err := val.AsStrRef(ctx) - if err != nil { - return 0, err +func (val Node) ParseF64(ctx *Context) (float64, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return 0, false + } + + if s == "null" { + return 0, true } i, err := ParseF64(s) if err != nil { - return 0, err + return 0, false } - return i, nil + return i, true } -func (val Node) AsF64() (float64, error) { - if val.Type() == KUint { - return float64(val.U64()), nil +func (val Node) ParseString(ctx *Context) (string, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return "", false } - if val.Type() == KSint { - return float64(val.I64()), nil + + if s == "null" { + return "", true } - if val.Type() == KReal { - return float64(val.F64()), nil + + s, err := Unquote(s) + if err != nil { + return "", false } - return 0, newUnmatched("expect float64") + return s, true } -func (val Node) AsBool() (bool, error) { - if val.Type() == KTrue { - return true, nil + +func (val Node) ParseNumber(ctx *Context) (json.Number, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return json.Number(""), false } - if val.Type() == KFalse { - return false, nil + + if s == "null" { + return json.Number(""), true + } + + end, err := SkipNumberFast(s, 0) + // has error or trailing chars + if err != nil || end != len(s) { + return json.Number(""), false + } + return json.Number(s), true +} + + + +func (val Node) AsF64(ctx *Context) (float64, bool) { + switch val.Type() { + case KUint: return float64(val.U64()), true + case KSint: return float64(val.I64()), true + case KReal: return float64(val.F64()), true + case KRawNumber: f, err := val.Number(ctx).Float64(); return f, err == nil + default: return 0, false + } +} + +func (val Node) AsBool() (bool, bool) { + switch val.Type() { + case KTrue: return true, true + case KFalse: return false, true + default: return false, false } - return false, newUnmatched("expect bool") } -func (val Node) AsStr(ctx *Context) (string, error) { +func (val Node) AsStr(ctx *Context) (string, bool) { if !val.IsStr() { - return "", newUnmatched("expect string") + return "", false } if (ctx.Options & (1 << _F_copy_string) == 0) && val.Type() == KStringCommon { - return val.String(ctx), nil + return val.String(ctx), true } - return val.StringCopy(), nil + return val.StringCopy(), true } -func (val Node) AsStrRef(ctx *Context) (string, error) { +func (val Node) AsStrRef(ctx *Context) (string, bool) { switch val.Type() { case KStringHasEscaped: - return val.StringCopy(), nil + return val.StringCopy(), true case KStringCommon: - return val.String(ctx), nil + return val.String(ctx), true default: - return "", newUnmatched("expect string") + return "", false } } -func (val Node) AsStringCopy() (string, error) { +func (val Node) AsStringCopy() (string, bool) { if !val.IsStr() { - return "", newUnmatched("expect string") + return "", false } cstr := (*C.String)(unsafe.Pointer(val.cptr)) len := cstr.len >> PosBits ret := C.GoStringN(cstr.p, C.int(len)) - return ret, nil + return ret, true } func (val Node) IsStr() bool { @@ -364,11 +425,15 @@ func (val Node) IsRawNumber() bool { } func (val Node) Number(ctx *Context) json.Number { + return json.Number(val.Raw(ctx)) +} + +func (val Node) Raw(ctx *Context) string { cnum := (*C.RawNumber)(unsafe.Pointer(val.cptr)) len := int(cnum.len >> PosBits) offset := int(uintptr(unsafe.Pointer(cnum.p)) - ctx.Start) ref := rt.Str2Mem(ctx.Json)[offset:int(offset+len)] - return json.Number(rt.Mem2Str(ref)) + return rt.Mem2Str(ref) } func (val Node) Position(ctx *Context) int { @@ -382,30 +447,37 @@ func (val Node) Position(ctx *Context) int { } } -func (val Node) AsNumber(ctx *Context) (json.Number, error) { +func (val Node) AsNumber(ctx *Context) (json.Number, bool) { + // parse JSON string as number if val.IsStr() { s, _ := val.AsStr(ctx) err := ValidNumberFast(s) if err != nil { - return "", err + return "", false } - return json.Number(s), nil + return json.Number(s), true } - if !val.IsNumber() { - return json.Number(""), newUnmatched("expect number") - } + return val.NonstrAsNumber(ctx) +} +func (val Node) NonstrAsNumber(ctx *Context) (json.Number, bool) { + // deal with raw number if val.IsRawNumber() { - return val.Number(ctx), nil + return val.Number(ctx), true + } + + // deal with parse number + if !val.IsNumber() { + return json.Number(""), false } start := val.Position(ctx) end, err := SkipNumberFast(ctx.Json, start) if err != nil { - return "", err + return "", false } - return json.Number(ctx.Json[start:end]), nil + return json.Number(ctx.Json[start:end]), true } func (val Node) AsRaw(ctx *Context) string { @@ -424,6 +496,8 @@ func (val Node) AsRaw(ctx *Context) string { // add start abd end quote ref := rt.Str2Mem(ctx.Json)[offset-1 : int(offset+len)+1] return rt.Mem2Str(ref) + case KRawNumber: fallthrough + case KRaw: return val.Raw(ctx) default: raw, err := SkipOneFast(ctx.Json, val.Position(ctx)) if err != nil { @@ -485,9 +559,9 @@ func (node *Node) AsMapEface(ctx *Context, vp unsafe.Pointer) error { return nil } - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return newUnmatched(node.Position(ctx), mapEfaceType) } size := obj.Len() @@ -498,15 +572,12 @@ func (node *Node) AsMapEface(ctx *Context, vp unsafe.Pointer) error { m = *(*map[string]interface{})(vp) } - var gerr error + var gerr, err error + next := obj.Children() for i := 0; i < size; i++ { knode := NewNode(next) - key, err := knode.AsStr(ctx) - if err != nil { - return err - } - + key, _ := knode.AsStr(ctx) val := NewNode(PtrOffset(next, 1)) m[key], err = val.AsEface(ctx) if gerr == nil && err != nil { @@ -520,9 +591,9 @@ func (node *Node) AsMapEface(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsMapEfaceUseNumber(ctx *Context, vp unsafe.Pointer) error { - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return newUnmatched(node.Position(ctx), mapEfaceType) } size := obj.Len() @@ -534,19 +605,17 @@ func (node *Node) AsMapEfaceUseNumber(ctx *Context, vp unsafe.Pointer) error { m = *(*map[string]interface{})(vp) } - var gerr error - *node = NewNode(obj.Children()) + var gerr, err error + next := obj.Children() for i := 0; i < size; i++ { - key, err := node.AsStr(ctx) - if err != nil { - return err - } - - *node = NewNode(PtrOffset(node.cptr, 1)) - m[key], err = node.AsEfaceUseNumber(ctx) + knode := NewNode(next) + key, _ := knode.AsStr(ctx) + val := NewNode(PtrOffset(next, 1)) + m[key], err = val.AsEfaceUseNumber(ctx) if gerr == nil && err != nil { gerr = err } + next = val.cptr } *(*map[string]interface{})(vp) = m @@ -554,33 +623,31 @@ func (node *Node) AsMapEfaceUseNumber(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsMapEfaceUseInt64(ctx *Context, vp unsafe.Pointer) error { - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return newUnmatched(node.Position(ctx), mapEfaceType) } size := obj.Len() var m map[string]interface{} - var gerr error if *(*unsafe.Pointer)(vp) == nil { m = make(map[string]interface{}, size) } else { m = *(*map[string]interface{})(vp) } - *node = NewNode(obj.Children()) + var gerr, err error + next := obj.Children() for i := 0; i < size; i++ { - key, err := node.AsStr(ctx) - if err != nil { - return err - } - - *node = NewNode(PtrOffset(node.cptr, 1)) - m[key], err = node.AsEfaceUseInt64(ctx) + knode := NewNode(next) + key, _ := knode.AsStr(ctx) + val := NewNode(PtrOffset(next, 1)) + m[key], err = val.AsEfaceUseInt64(ctx) if gerr == nil && err != nil { gerr = err } + next = val.cptr } *(*map[string]interface{})(vp) = m @@ -588,9 +655,9 @@ func (node *Node) AsMapEfaceUseInt64(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsMapString(ctx *Context, vp unsafe.Pointer) error { - obj, err := node.AsObj() - if err != nil { - return err + obj, ok := node.AsObj() + if !ok { + return newUnmatched(node.Position(ctx), mapStringType) } size := obj.Len() @@ -602,21 +669,21 @@ func (node *Node) AsMapString(ctx *Context, vp unsafe.Pointer) error { m = *(*map[string]string)(vp) } - next := obj.Children() var gerr error + next := obj.Children() for i := 0; i < size; i++ { knode := NewNode(next) - key, err := knode.AsStr(ctx) - if err != nil { - return err - } - + key, _ := knode.AsStr(ctx) val := NewNode(PtrOffset(next, 1)) - m[key], err = val.AsStr(ctx) - if gerr == nil && err != nil { - gerr = err + m[key], ok = val.AsStr(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(ctx), stringType) + } + next = val.Next() + } else { + next = PtrOffset(val.cptr, 1) } - next = val.Next() } *(*map[string]string)(vp) = m @@ -624,24 +691,21 @@ func (node *Node) AsMapString(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsSliceEface(ctx *Context, vp unsafe.Pointer) error { - arr, err := node.AsArr() - if err != nil { - return err + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(ctx), sliceEfaceType) } size := arr.Len() - s := *(*[]interface{})((unsafe.Pointer)(MakeSlice(vp, anyType, size))) - next := arr.Children() + *node = NewNode(arr.Children()) - var gerr error + var gerr, err error for i := 0; i < size; i++ { - val := NewNode(next) - s[i], err = val.AsEface(ctx) + s[i], err = node.AsEface(ctx) if gerr == nil && err != nil { gerr = err } - next = val.cptr } *(*[]interface{})(vp) = s @@ -649,17 +713,16 @@ func (node *Node) AsSliceEface(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsSliceEfaceUseNumber(ctx *Context, vp unsafe.Pointer) error { - arr, err := node.AsArr() - if err != nil { - return err + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(ctx), sliceEfaceType) } size := arr.Len() - s := *(*[]interface{})((unsafe.Pointer)(MakeSlice(vp, anyType, size))) *node = NewNode(arr.Children()) - var gerr error + var gerr, err error for i := 0; i < size; i++ { s[i], err = node.AsEfaceUseNumber(ctx) if gerr == nil && err != nil { @@ -672,17 +735,16 @@ func (node *Node) AsSliceEfaceUseNumber(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsSliceEfaceUseInt64(ctx *Context, vp unsafe.Pointer) error { - arr, err := node.AsArr() - if err != nil { - return err + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(ctx), sliceEfaceType) } size := arr.Len() - s := *(*[]interface{})((unsafe.Pointer)(MakeSlice(vp, anyType, size))) *node = NewNode(arr.Children()) - var gerr error + var gerr, err error for i := 0; i < size; i++ { s[i], err = node.AsEfaceUseInt64(ctx) if gerr == nil && err != nil { @@ -695,33 +757,28 @@ func (node *Node) AsSliceEfaceUseInt64(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsSliceI32(ctx *Context, vp unsafe.Pointer) error { - arr, err := node.AsArr() - if err != nil { - return err + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(ctx), sliceI32Type) } size := arr.Len() - s := *(*[]int32)((unsafe.Pointer)(MakeSlice(vp, int32Type, size))) next := arr.Children() var gerr error for i := 0; i < size; i++ { val := NewNode(next) - ret, err := val.AsI64() - if gerr == nil && err != nil { - gerr = err - } - - if ret > math.MaxInt32 || ret < math.MinInt32 { + ret, ok := val.AsI64(ctx) + if !ok || ret > math.MaxInt32 || ret < math.MinInt32 { if gerr == nil { - gerr = newUnmatched("expect int32") + gerr = newUnmatched(val.Position(ctx), int32Type) } - ret = 0 + next = val.Next() + } else { + s[i] = int32(ret) + next = PtrOffset(val.cptr, 1) } - - next = val.Next() - s[i] = int32(ret) } *(*[]int32)(vp) = s @@ -729,27 +786,29 @@ func (node *Node) AsSliceI32(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsSliceI64(ctx *Context, vp unsafe.Pointer) error { - arr, err := node.AsArr() - if err != nil { - return err + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(ctx), sliceI64Type) } size := arr.Len() - next := arr.Children() - s := *(*[]int64)((unsafe.Pointer)(MakeSlice(vp, int64Type, size))) + next := arr.Children() var gerr error for i := 0; i < size; i++ { val := NewNode(next) - ret, err := val.AsI64() - if gerr == nil && err != nil { - gerr = err + ret, ok := val.AsI64(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(ctx), int64Type) + } + next = val.Next() + } else { + s[i] = ret + next = PtrOffset(val.cptr, 1) } - - s[i] = ret - next = val.Next() } *(*[]int64)(vp) = s @@ -757,32 +816,28 @@ func (node *Node) AsSliceI64(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsSliceU32(ctx *Context, vp unsafe.Pointer) error { - arr, err := node.AsArr() - if err != nil { - return err + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(ctx), sliceU32Type) } size := arr.Len() next := arr.Children() - s := *(*[]uint32)((unsafe.Pointer)(MakeSlice(vp, uint32Type, size))) + var gerr error for i := 0; i < size; i++ { val := NewNode(next) - ret, err := val.AsU64() - if gerr == nil && err != nil { - gerr = err - } - - if ret > math.MaxUint32 { + ret, ok := val.AsU64(ctx) + if !ok || ret > math.MaxUint32 { if gerr == nil { - gerr = newUnmatched("expect uint32") + gerr = newUnmatched(val.Position(ctx), uint32Type) } - ret = 0 + next = val.Next() + } else { + s[i] = uint32(ret) + next = PtrOffset(val.cptr, 1) } - - s[i] = uint32(ret) - next = val.Next() } *(*[]uint32)(vp) = s @@ -790,9 +845,9 @@ func (node *Node) AsSliceU32(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsSliceU64(ctx *Context, vp unsafe.Pointer) error { - arr, err := node.AsArr() - if err != nil { - return err + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(ctx), sliceU64Type) } size := arr.Len() @@ -802,14 +857,16 @@ func (node *Node) AsSliceU64(ctx *Context, vp unsafe.Pointer) error { var gerr error for i := 0; i < size; i++ { val := NewNode(next) - - ret, err := val.AsU64() - if gerr == nil && err != nil { - gerr = err + ret, ok := val.AsU64(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(ctx), uint64Type) + } + next = val.Next() + } else { + s[i] = ret + next = PtrOffset(val.cptr, 1) } - - s[i] = ret - next = val.Next() } *(*[]uint64)(vp) = s @@ -817,25 +874,28 @@ func (node *Node) AsSliceU64(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsSliceString(ctx *Context, vp unsafe.Pointer) error { - arr, err := node.AsArr() - if err != nil { - return err + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(ctx), sliceStringType) } + size := arr.Len() next := arr.Children() + s := *(*[]string)((unsafe.Pointer)(MakeSlice(vp, stringType, size))) - s := *(*[]string)((unsafe.Pointer)(MakeSlice(vp, strType, size))) var gerr error for i := 0; i < size; i++ { val := NewNode(next) - - ret, err := val.AsStr(ctx) - if gerr == nil && err != nil { - gerr = err + ret, ok := val.AsStr(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(ctx), stringType) + } + next = val.Next() + } else { + s[i] = ret + next = PtrOffset(val.cptr, 1) } - - s[i] = ret - next = val.Next() } *(*[]string)(vp) = s @@ -843,14 +903,14 @@ func (node *Node) AsSliceString(ctx *Context, vp unsafe.Pointer) error { } func (node *Node) AsSliceBytes(ctx *Context) ([]byte, error) { - s, err := node.AsStrRef(ctx) - if err != nil { - return nil, err + s, ok := node.AsStrRef(ctx) + if !ok { + return nil, newUnmatched(node.Position(ctx), bytesType) } b64, err := decodeBase64(s) if err != nil { - return nil, err + return nil, newUnmatched(node.Position(ctx), bytesType) } return b64, nil @@ -862,40 +922,30 @@ func (node *Node) AsEface(ctx *Context) (interface{}, error) { obj := node.Object() size := obj.Len() m := make(map[string]interface{}, size) - *node = NewNode(obj.Children()) - var key string - var err error - + var gerr, err error for i := 0; i < size; i++ { - switch node.Type() { - case KStringHasEscaped: - key = node.StringCopy() - case KStringCommon: - key = node.String(ctx) - default: - return nil, newUnmatched("expect string") - } + key, _ := node.AsStr(ctx) *node = NewNode(PtrOffset(node.cptr, 1)) m[key], err = node.AsEface(ctx) - if err != nil { - return nil, err + if gerr == nil && err != nil { + gerr = err } } - return m, nil + return m, gerr case KArray: arr := node.Array() size := arr.Len() - garr := make([]interface{}, size) + a := make([]interface{}, size) *node = NewNode(arr.Children()) - var err error + var gerr, err error for i := 0; i < size; i++ { - garr[i], err = node.AsEface(ctx) - if err != nil { - return nil, err + a[i], err = node.AsEface(ctx) + if gerr == nil && err != nil { + gerr = err } } - return garr, nil + return a, gerr case KStringCommon: str := node.String(ctx) *node = NewNode(PtrOffset(node.cptr, 1)) @@ -904,18 +954,6 @@ func (node *Node) AsEface(ctx *Context) (interface{}, error) { str := node.StringCopy() *node = NewNode(PtrOffset(node.cptr, 1)) return str, nil - case KUint: - f := (float64)(node.U64()) - *node = NewNode(PtrOffset(node.cptr, 1)) - return f, nil - case KReal: - f := (float64)(node.F64()) - *node = NewNode(PtrOffset(node.cptr, 1)) - return f, nil - case KSint: - f := (float64)(node.I64()) - *node = NewNode(PtrOffset(node.cptr, 1)) - return f, nil case KTrue: *node = NewNode(PtrOffset(node.cptr, 1)) return true, nil @@ -926,7 +964,15 @@ func (node *Node) AsEface(ctx *Context) (interface{}, error) { *node = NewNode(PtrOffset(node.cptr, 1)) return nil, nil default: - return nil, newUnmatched("invalid JSON type") + num, ok := node.AsF64(ctx) + if !ok { + // skip the unmacthed type + *node = NewNode(node.Next()) + return nil, newUnmatched(node.Position(ctx), float64Type) + } else { + *node = NewNode(PtrOffset(node.cptr, 1)) + return num, nil + } } } @@ -937,40 +983,29 @@ func (node *Node) AsEfaceUseNumber(ctx *Context) (interface{}, error) { size := obj.Len() m := make(map[string]interface{}, size) *node = NewNode(obj.Children()) - - var key string - var err error + var gerr, err error for i := 0; i < size; i++ { - switch node.Type() { - case KStringHasEscaped: - key = node.StringCopy() - case KStringCommon: - key = node.String(ctx) - default: - return nil, newUnmatched("expect string") - } - + key, _ := node.AsStr(ctx) *node = NewNode(PtrOffset(node.cptr, 1)) m[key], err = node.AsEfaceUseNumber(ctx) - if err != nil { - return nil, err + if gerr == nil && err != nil { + gerr = err } } - return m, nil + return m, gerr case KArray: arr := node.Array() size := arr.Len() - garr := make([]interface{}, size) + a := make([]interface{}, size) *node = NewNode(arr.Children()) - - var err error + var gerr, err error for i := 0; i < size; i++ { - garr[i], err = node.AsEfaceUseNumber(ctx) - if err != nil { - return nil, err + a[i], err = node.AsEfaceUseNumber(ctx) + if gerr == nil && err != nil { + gerr = err } } - return garr, nil + return a, gerr case KStringCommon: str := node.String(ctx) *node = NewNode(PtrOffset(node.cptr, 1)) @@ -993,58 +1028,48 @@ func (node *Node) AsEfaceUseNumber(ctx *Context) (interface{}, error) { *node = NewNode(PtrOffset(node.cptr, 1)) return nil, nil default: - num, err := node.AsNumber(ctx) - if err != nil { - return nil, err + num, ok := node.NonstrAsNumber(ctx) + if !ok { + // skip the unmacthed type + *node = NewNode(node.Next()) + return nil, newUnmatched(node.Position(ctx), jsonNumberType) + } else { + *node = NewNode(PtrOffset(node.cptr, 1)) + return num, nil } - - *node = NewNode(PtrOffset(node.cptr, 1)) - return num, nil } } func (node *Node) AsEfaceUseInt64(ctx *Context) (interface{}, error) { switch node.Type() { case KObject: - { - obj := node.Object() - size := obj.Len() - m := make(map[string]interface{}, size) - *node = NewNode(obj.Children()) - - var key string - var err error - for i := 0; i < size; i++ { - switch node.Type() { - case KStringHasEscaped: - key = node.StringCopy() - case KStringCommon: - key = node.String(ctx) - default: - return nil, newUnmatched("expect string") - } - - *node = NewNode(PtrOffset(node.cptr, 1)) - m[key], err = node.AsEfaceUseInt64(ctx) - if err != nil { - return nil, err - } + obj := node.Object() + size := obj.Len() + m := make(map[string]interface{}, size) + *node = NewNode(obj.Children()) + var gerr, err error + for i := 0; i < size; i++ { + key, _ := node.AsStr(ctx) + *node = NewNode(PtrOffset(node.cptr, 1)) + m[key], err = node.AsEfaceUseInt64(ctx) + if gerr == nil && err != nil { + gerr = err } - return m, nil } + return m, gerr case KArray: arr := node.Array() size := arr.Len() - garr := make([]interface{}, size) + a := make([]interface{}, size) *node = NewNode(arr.Children()) - var err error + var gerr, err error for i := 0; i < size; i++ { - garr[i], err = node.AsEfaceUseInt64(ctx) - if err != nil { - return nil, err + a[i], err = node.AsEfaceUseInt64(ctx) + if gerr == nil && err != nil { + gerr = err } } - return garr, nil + return a, gerr case KStringCommon: str := node.String(ctx) *node = NewNode(PtrOffset(node.cptr, 1)) @@ -1063,9 +1088,15 @@ func (node *Node) AsEfaceUseInt64(ctx *Context) (interface{}, error) { *node = NewNode(PtrOffset(node.cptr, 1)) return nil, nil default: - val, err := node.AsI64() - *node = NewNode(PtrOffset(node.cptr, 1)) - return val, err + num, ok := node.AsI64(ctx) + if !ok { + // skip the unmacthed type + *node = NewNode(node.Next()) + return nil, newUnmatched(node.Position(ctx), jsonNumberType) + } else { + *node = NewNode(PtrOffset(node.cptr, 1)) + return num, nil + } } } diff --git a/dev/internal/types.go b/dev/internal/types.go index 4556395e0..001084c29 100644 --- a/dev/internal/types.go +++ b/dev/internal/types.go @@ -3,16 +3,40 @@ package internal import ( "reflect" "unsafe" + "encoding/json" "github.com/bytedance/sonic/dev/internal/rt" ) var ( - int32Type = rt.UnpackType(reflect.TypeOf(int32(0))) - int64Type = rt.UnpackType(reflect.TypeOf(int64(0))) - uint32Type = rt.UnpackType(reflect.TypeOf(uint32(0))) - uint64Type = rt.UnpackType(reflect.TypeOf(uint64(0))) - strType = rt.UnpackType(reflect.TypeOf("")) - anyType = rt.UnpackType(reflect.TypeOf((*interface{})(nil)).Elem()) + byteType = rt.UnpackType(reflect.TypeOf(byte(0))) + intType = rt.UnpackType(reflect.TypeOf(int(0))) + int8Type = rt.UnpackType(reflect.TypeOf(int8(0))) + int16Type = rt.UnpackType(reflect.TypeOf(int16(0))) + int32Type = rt.UnpackType(reflect.TypeOf(int32(0))) + int64Type = rt.UnpackType(reflect.TypeOf(int64(0))) + uintType = rt.UnpackType(reflect.TypeOf(uint(0))) + uint8Type = rt.UnpackType(reflect.TypeOf(uint8(0))) + uint16Type = rt.UnpackType(reflect.TypeOf(uint16(0))) + uint32Type = rt.UnpackType(reflect.TypeOf(uint32(0))) + uint64Type = rt.UnpackType(reflect.TypeOf(uint64(0))) + float32Type = rt.UnpackType(reflect.TypeOf(float32(0))) + float64Type = rt.UnpackType(reflect.TypeOf(float64(0))) + + stringType = rt.UnpackType(reflect.TypeOf("")) + bytesType = rt.UnpackType(reflect.TypeOf([]byte(nil))) + jsonNumberType = rt.UnpackType(reflect.TypeOf(json.Number(""))) + + sliceEfaceType = rt.UnpackType(reflect.TypeOf([]interface{}(nil))) + sliceStringType = rt.UnpackType(reflect.TypeOf([]string(nil))) + sliceI32Type = rt.UnpackType(reflect.TypeOf([]int32(nil))) + sliceI64Type = rt.UnpackType(reflect.TypeOf([]int64(nil))) + sliceU32Type = rt.UnpackType(reflect.TypeOf([]uint32(nil))) + sliceU64Type = rt.UnpackType(reflect.TypeOf([]uint64(nil))) + + anyType = rt.UnpackType(reflect.TypeOf((*interface{})(nil)).Elem()) + mapEfaceType = rt.UnpackType(reflect.TypeOf(map[string]interface{}(nil))) + mapStringType = rt.UnpackType(reflect.TypeOf(map[string]string(nil))) + _ZSTPtr = unsafe.Pointer(&struct{}{}) ) diff --git a/tools/asm2asm b/tools/asm2asm index ab01a6d91..4782e4f71 160000 --- a/tools/asm2asm +++ b/tools/asm2asm @@ -1 +1 @@ -Subproject commit ab01a6d91fb198f8f48685bbbbd8c00350f87090 +Subproject commit 4782e4f71a7ec26b181456f1ad737f673cfea386