summaryrefslogtreecommitdiff
path: root/vendor/github.com/bytedance/sonic/internal/decoder/optdec
diff options
context:
space:
mode:
authorLibravatar dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>2025-01-14 13:10:39 +0000
committerLibravatar GitHub <noreply@github.com>2025-01-14 13:10:39 +0000
commit4d423102c14de9e9328f1852db539d9561a3cad9 (patch)
tree6df5905f53ad7eadbfa9840939989253bfb4b199 /vendor/github.com/bytedance/sonic/internal/decoder/optdec
parent[bugfix] migration to cleanup dropped status edits (#3637) (diff)
downloadgotosocial-4d423102c14de9e9328f1852db539d9561a3cad9.tar.xz
[chore]: Bump github.com/gin-contrib/gzip from 1.0.1 to 1.1.0 (#3639)
Bumps [github.com/gin-contrib/gzip](https://github.com/gin-contrib/gzip) from 1.0.1 to 1.1.0. - [Release notes](https://github.com/gin-contrib/gzip/releases) - [Changelog](https://github.com/gin-contrib/gzip/blob/master/.goreleaser.yaml) - [Commits](https://github.com/gin-contrib/gzip/compare/v1.0.1...v1.1.0) --- updated-dependencies: - dependency-name: github.com/gin-contrib/gzip dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Diffstat (limited to 'vendor/github.com/bytedance/sonic/internal/decoder/optdec')
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go174
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go449
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go60
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go3
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go160
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go73
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go281
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go110
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go169
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go430
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go269
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go1278
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go224
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go360
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go61
-rw-r--r--vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go60
16 files changed, 4161 insertions, 0 deletions
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go
new file mode 100644
index 000000000..713fb6561
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go
@@ -0,0 +1,174 @@
+package optdec
+
+import (
+ "fmt"
+ "reflect"
+
+ caching "github.com/bytedance/sonic/internal/optcaching"
+ "github.com/bytedance/sonic/internal/rt"
+ "github.com/bytedance/sonic/internal/resolver"
+)
+
+const (
+ _MAX_FIELDS = 50 // cutoff at 50 fields struct
+)
+
+func (c *compiler) compileIntStringOption(vt reflect.Type) decFunc {
+ switch vt.Size() {
+ case 4:
+ switch vt.Kind() {
+ case reflect.Uint:
+ fallthrough
+ case reflect.Uintptr:
+ return &u32StringDecoder{}
+ case reflect.Int:
+ return &i32StringDecoder{}
+ }
+ case 8:
+ switch vt.Kind() {
+ case reflect.Uint:
+ fallthrough
+ case reflect.Uintptr:
+ return &u64StringDecoder{}
+ case reflect.Int:
+ return &i64StringDecoder{}
+ }
+ default:
+ panic("not supported pointer size: " + fmt.Sprint(vt.Size()))
+ }
+ panic("unreachable")
+}
+
+func isInteger(vt reflect.Type) bool {
+ switch vt.Kind() {
+ case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr, reflect.Int: return true
+ default: return false
+ }
+}
+
+func (c *compiler) assertStringOptTypes(vt reflect.Type) {
+ if c.depth > _CompileMaxDepth {
+ panic(*stackOverflow)
+ }
+
+ c.depth += 1
+ defer func () {
+ c.depth -= 1
+ }()
+
+ if isInteger(vt) {
+ return
+ }
+
+ switch vt.Kind() {
+ case reflect.String, reflect.Bool, reflect.Float32, reflect.Float64:
+ return
+ case reflect.Ptr: c.assertStringOptTypes(vt.Elem())
+ default:
+ panicForInvalidStrType(vt)
+ }
+}
+
+func (c *compiler) compileFieldStringOption(vt reflect.Type) decFunc {
+ c.assertStringOptTypes(vt)
+ unmDec := c.tryCompilePtrUnmarshaler(vt, true)
+ if unmDec != nil {
+ return unmDec
+ }
+
+ switch vt.Kind() {
+ case reflect.String:
+ if vt == jsonNumberType {
+ return &numberStringDecoder{}
+ }
+ return &strStringDecoder{}
+ case reflect.Bool:
+ return &boolStringDecoder{}
+ case reflect.Int8:
+ return &i8StringDecoder{}
+ case reflect.Int16:
+ return &i16StringDecoder{}
+ case reflect.Int32:
+ return &i32StringDecoder{}
+ case reflect.Int64:
+ return &i64StringDecoder{}
+ case reflect.Uint8:
+ return &u8StringDecoder{}
+ case reflect.Uint16:
+ return &u16StringDecoder{}
+ case reflect.Uint32:
+ return &u32StringDecoder{}
+ case reflect.Uint64:
+ return &u64StringDecoder{}
+ case reflect.Float32:
+ return &f32StringDecoder{}
+ case reflect.Float64:
+ return &f64StringDecoder{}
+ case reflect.Uint:
+ fallthrough
+ case reflect.Uintptr:
+ fallthrough
+ case reflect.Int:
+ return c.compileIntStringOption(vt)
+ case reflect.Ptr:
+ return &ptrStrDecoder{
+ typ: rt.UnpackType(vt.Elem()),
+ deref: c.compileFieldStringOption(vt.Elem()),
+ }
+ default:
+ panicForInvalidStrType(vt)
+ return nil
+ }
+}
+
+func (c *compiler) compileStruct(vt reflect.Type) decFunc {
+ c.enter(vt)
+ defer c.exit(vt)
+ if c.namedPtr {
+ c.namedPtr = false
+ return c.compileStructBody(vt)
+ }
+
+ if c.depth >= c.opts.MaxInlineDepth + 1 || (c.counts > 0 && vt.NumField() >= _MAX_FIELDS) {
+ return &recuriveDecoder{
+ typ: rt.UnpackType(vt),
+ }
+ } else {
+ return c.compileStructBody(vt)
+ }
+}
+
+func (c *compiler) compileStructBody(vt reflect.Type) decFunc {
+ fv := resolver.ResolveStruct(vt)
+ entries := make([]fieldEntry, 0, len(fv))
+
+ for _, f := range fv {
+ var dec decFunc
+ /* dealt with field tag options */
+ if f.Opts&resolver.F_stringize != 0 {
+ dec = c.compileFieldStringOption(f.Type)
+ } else {
+ dec = c.compile(f.Type)
+ }
+
+ /* deal with embedded pointer fields */
+ if f.Path[0].Kind == resolver.F_deref {
+ dec = &embeddedFieldPtrDecoder{
+ field: f,
+ fieldDec: dec,
+ fieldName: f.Name,
+ }
+ }
+
+ entries = append(entries, fieldEntry{
+ FieldMeta: f,
+ fieldDec: dec,
+ })
+ }
+ return &structDecoder{
+ fieldMap: caching.NewFieldLookup(fv),
+ fields: entries,
+ structName: vt.Name(),
+ typ: vt,
+ }
+}
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go
new file mode 100644
index 000000000..fd164af93
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go
@@ -0,0 +1,449 @@
+package optdec
+
+import (
+ "encoding/json"
+ "fmt"
+ "reflect"
+
+ "github.com/bytedance/sonic/option"
+ "github.com/bytedance/sonic/internal/rt"
+ "github.com/bytedance/sonic/internal/caching"
+)
+
+var (
+ programCache = caching.CreateProgramCache()
+)
+
+func findOrCompile(vt *rt.GoType) (decFunc, error) {
+ makeDecoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) {
+ ret, err := newCompiler().compileType(vt.Pack())
+ return ret, err
+ }
+ if val := programCache.Get(vt); val != nil {
+ return val.(decFunc), nil
+ } else if ret, err := programCache.Compute(vt, makeDecoder); err == nil {
+ return ret.(decFunc), nil
+ } else {
+ return nil, err
+ }
+}
+
+type compiler struct {
+ visited map[reflect.Type]bool
+ depth int
+ counts int
+ opts option.CompileOptions
+ namedPtr bool
+}
+
+func newCompiler() *compiler {
+ return &compiler{
+ visited: make(map[reflect.Type]bool),
+ opts: option.DefaultCompileOptions(),
+ }
+}
+
+func (self *compiler) apply(opts option.CompileOptions) *compiler {
+ self.opts = opts
+ return self
+}
+
+const _CompileMaxDepth = 4096
+
+func (c *compiler) enter(vt reflect.Type) {
+ c.visited[vt] = true
+ c.depth += 1
+
+ if c.depth > _CompileMaxDepth {
+ panic(*stackOverflow)
+ }
+}
+
+func (c *compiler) exit(vt reflect.Type) {
+ c.visited[vt] = false
+ c.depth -= 1
+}
+
+func (c *compiler) compileInt(vt reflect.Type) decFunc {
+ switch vt.Size() {
+ case 4:
+ switch vt.Kind() {
+ case reflect.Uint:
+ fallthrough
+ case reflect.Uintptr:
+ return &u32Decoder{}
+ case reflect.Int:
+ return &i32Decoder{}
+ }
+ case 8:
+ switch vt.Kind() {
+ case reflect.Uint:
+ fallthrough
+ case reflect.Uintptr:
+ return &u64Decoder{}
+ case reflect.Int:
+ return &i64Decoder{}
+ }
+ default:
+ panic("not supported pointer size: " + fmt.Sprint(vt.Size()))
+ }
+ panic("unreachable")
+}
+
+func (c *compiler) rescue(ep *error) {
+ if val := recover(); val != nil {
+ if err, ok := val.(error); ok {
+ *ep = err
+ } else {
+ panic(val)
+ }
+ }
+}
+
+func (c *compiler) compileType(vt reflect.Type) (rt decFunc, err error) {
+ defer c.rescue(&err)
+ rt = c.compile(vt)
+ return rt, err
+}
+
+func (c *compiler) compile(vt reflect.Type) decFunc {
+ if c.visited[vt] {
+ return &recuriveDecoder{
+ typ: rt.UnpackType(vt),
+ }
+ }
+
+ dec := c.tryCompilePtrUnmarshaler(vt, false)
+ if dec != nil {
+ return dec
+ }
+
+ return c.compileBasic(vt)
+}
+
+func (c *compiler) compileBasic(vt reflect.Type) decFunc {
+ defer func() {
+ c.counts += 1
+ }()
+ switch vt.Kind() {
+ case reflect.Bool:
+ return &boolDecoder{}
+ case reflect.Int8:
+ return &i8Decoder{}
+ case reflect.Int16:
+ return &i16Decoder{}
+ case reflect.Int32:
+ return &i32Decoder{}
+ case reflect.Int64:
+ return &i64Decoder{}
+ case reflect.Uint8:
+ return &u8Decoder{}
+ case reflect.Uint16:
+ return &u16Decoder{}
+ case reflect.Uint32:
+ return &u32Decoder{}
+ case reflect.Uint64:
+ return &u64Decoder{}
+ case reflect.Float32:
+ return &f32Decoder{}
+ case reflect.Float64:
+ return &f64Decoder{}
+ case reflect.Uint:
+ fallthrough
+ case reflect.Uintptr:
+ fallthrough
+ case reflect.Int:
+ return c.compileInt(vt)
+ case reflect.String:
+ return c.compileString(vt)
+ case reflect.Array:
+ return c.compileArray(vt)
+ case reflect.Interface:
+ return c.compileInterface(vt)
+ case reflect.Map:
+ return c.compileMap(vt)
+ case reflect.Ptr:
+ return c.compilePtr(vt)
+ case reflect.Slice:
+ return c.compileSlice(vt)
+ case reflect.Struct:
+ return c.compileStruct(vt)
+ default:
+ panic(&json.UnmarshalTypeError{Type: vt})
+ }
+}
+
+func (c *compiler) compilePtr(vt reflect.Type) decFunc {
+ c.enter(vt)
+ defer c.exit(vt)
+
+ // specail logic for Named Ptr, issue 379
+ if reflect.PtrTo(vt.Elem()) != vt {
+ c.namedPtr = true
+ return &ptrDecoder{
+ typ: rt.UnpackType(vt.Elem()),
+ deref: c.compileBasic(vt.Elem()),
+ }
+ }
+
+ return &ptrDecoder{
+ typ: rt.UnpackType(vt.Elem()),
+ deref: c.compile(vt.Elem()),
+ }
+}
+
+func (c *compiler) compileArray(vt reflect.Type) decFunc {
+ c.enter(vt)
+ defer c.exit(vt)
+ return &arrayDecoder{
+ len: vt.Len(),
+ elemType: rt.UnpackType(vt.Elem()),
+ elemDec: c.compile(vt.Elem()),
+ typ: vt,
+ }
+}
+
+func (c *compiler) compileString(vt reflect.Type) decFunc {
+ if vt == jsonNumberType {
+ return &numberDecoder{}
+ }
+ return &stringDecoder{}
+
+}
+
+func (c *compiler) tryCompileSliceUnmarshaler(vt reflect.Type) decFunc {
+ pt := reflect.PtrTo(vt.Elem())
+ if pt.Implements(jsonUnmarshalerType) {
+ return &sliceDecoder{
+ elemType: rt.UnpackType(vt.Elem()),
+ elemDec: c.compile(vt.Elem()),
+ typ: vt,
+ }
+ }
+
+ if pt.Implements(encodingTextUnmarshalerType) {
+ return &sliceDecoder{
+ elemType: rt.UnpackType(vt.Elem()),
+ elemDec: c.compile(vt.Elem()),
+ typ: vt,
+ }
+ }
+ return nil
+}
+
+func (c *compiler) compileSlice(vt reflect.Type) decFunc {
+ c.enter(vt)
+ defer c.exit(vt)
+
+ // Some common slice, use a decoder, to avoid function calls
+ et := rt.UnpackType(vt.Elem())
+
+ /* first checking `[]byte` */
+ if et.Kind() == reflect.Uint8 /* []byte */ {
+ return c.compileSliceBytes(vt)
+ }
+
+ dec := c.tryCompileSliceUnmarshaler(vt)
+ if dec != nil {
+ return dec
+ }
+
+ if vt == reflect.TypeOf([]interface{}{}) {
+ return &sliceEfaceDecoder{}
+ }
+ if et.IsInt32() {
+ return &sliceI32Decoder{}
+ }
+ if et.IsInt64() {
+ return &sliceI64Decoder{}
+ }
+ if et.IsUint32() {
+ return &sliceU32Decoder{}
+ }
+ if et.IsUint64() {
+ return &sliceU64Decoder{}
+ }
+ if et.Kind() == reflect.String {
+ return &sliceStringDecoder{}
+ }
+
+ return &sliceDecoder{
+ elemType: rt.UnpackType(vt.Elem()),
+ elemDec: c.compile(vt.Elem()),
+ typ: vt,
+ }
+}
+
+func (c *compiler) compileSliceBytes(vt reflect.Type) decFunc {
+ ep := reflect.PtrTo(vt.Elem())
+
+ if ep.Implements(jsonUnmarshalerType) {
+ return &sliceBytesUnmarshalerDecoder{
+ elemType: rt.UnpackType(vt.Elem()),
+ elemDec: c.compile(vt.Elem()),
+ typ: vt,
+ }
+ }
+
+ if ep.Implements(encodingTextUnmarshalerType) {
+ return &sliceBytesUnmarshalerDecoder{
+ elemType: rt.UnpackType(vt.Elem()),
+ elemDec: c.compile(vt.Elem()),
+ typ: vt,
+ }
+ }
+
+ return &sliceBytesDecoder{}
+}
+
+func (c *compiler) compileInterface(vt reflect.Type) decFunc {
+ c.enter(vt)
+ defer c.exit(vt)
+ if vt.NumMethod() == 0 {
+ return &efaceDecoder{}
+ }
+
+ if vt.Implements(jsonUnmarshalerType) {
+ return &unmarshalJSONDecoder{
+ typ: rt.UnpackType(vt),
+ }
+ }
+
+ if vt.Implements(encodingTextUnmarshalerType) {
+ return &unmarshalTextDecoder{
+ typ: rt.UnpackType(vt),
+ }
+ }
+
+ return &ifaceDecoder{
+ typ: rt.UnpackType(vt),
+ }
+}
+
+func (c *compiler) compileMap(vt reflect.Type) decFunc {
+ c.enter(vt)
+ defer c.exit(vt)
+ // check the key unmarshaler at first
+ decKey := tryCompileKeyUnmarshaler(vt)
+ if decKey != nil {
+ return &mapDecoder{
+ mapType: rt.MapType(rt.UnpackType(vt)),
+ keyDec: decKey,
+ elemDec: c.compile(vt.Elem()),
+ }
+ }
+
+ // Most common map, use a decoder, to avoid function calls
+ if vt == reflect.TypeOf(map[string]interface{}{}) {
+ return &mapEfaceDecoder{}
+ } else if vt == reflect.TypeOf(map[string]string{}) {
+ return &mapStringDecoder{}
+ }
+
+ // Some common integer map later
+ mt := rt.MapType(rt.UnpackType(vt))
+
+ if mt.Key.Kind() == reflect.String {
+ return &mapStrKeyDecoder{
+ mapType: mt,
+ assign: rt.GetMapStrAssign(vt),
+ elemDec: c.compile(vt.Elem()),
+ }
+ }
+
+ if mt.Key.IsInt64() {
+ return &mapI64KeyDecoder{
+ mapType: mt,
+ elemDec: c.compile(vt.Elem()),
+ assign: rt.GetMap64Assign(vt),
+ }
+ }
+
+ if mt.Key.IsInt32() {
+ return &mapI32KeyDecoder{
+ mapType: mt,
+ elemDec: c.compile(vt.Elem()),
+ assign: rt.GetMap32Assign(vt),
+ }
+ }
+
+ if mt.Key.IsUint64() {
+ return &mapU64KeyDecoder{
+ mapType: mt,
+ elemDec: c.compile(vt.Elem()),
+ assign: rt.GetMap64Assign(vt),
+ }
+ }
+
+ if mt.Key.IsUint32() {
+ return &mapU32KeyDecoder{
+ mapType: mt,
+ elemDec: c.compile(vt.Elem()),
+ assign: rt.GetMap32Assign(vt),
+ }
+ }
+
+ // Generic map
+ return &mapDecoder{
+ mapType: mt,
+ keyDec: c.compileMapKey(vt),
+ elemDec: c.compile(vt.Elem()),
+ }
+}
+
+func tryCompileKeyUnmarshaler(vt reflect.Type) decKey {
+ pt := reflect.PtrTo(vt.Key())
+
+ /* check for `encoding.TextUnmarshaler` with pointer receiver */
+ if pt.Implements(encodingTextUnmarshalerType) {
+ return decodeKeyTextUnmarshaler
+ }
+
+ /* not support map key with `json.Unmarshaler` */
+ return nil
+}
+
+func (c *compiler) compileMapKey(vt reflect.Type) decKey {
+ switch vt.Key().Kind() {
+ case reflect.Int8:
+ return decodeKeyI8
+ case reflect.Int16:
+ return decodeKeyI16
+ case reflect.Uint8:
+ return decodeKeyU8
+ case reflect.Uint16:
+ return decodeKeyU16
+ default:
+ panic(&json.UnmarshalTypeError{Type: vt})
+ }
+}
+
+// maybe vt is a named type, and not a pointer receiver, see issue 379
+func (c *compiler) tryCompilePtrUnmarshaler(vt reflect.Type, strOpt bool) decFunc {
+ pt := reflect.PtrTo(vt)
+
+ /* check for `json.Unmarshaler` with pointer receiver */
+ if pt.Implements(jsonUnmarshalerType) {
+ return &unmarshalJSONDecoder{
+ typ: rt.UnpackType(pt),
+ strOpt: strOpt,
+ }
+ }
+
+ /* check for `encoding.TextMarshaler` with pointer receiver */
+ if pt.Implements(encodingTextUnmarshalerType) {
+ /* TextUnmarshal not support ,strig tag */
+ if strOpt {
+ panicForInvalidStrType(vt)
+ }
+ return &unmarshalTextDecoder{
+ typ: rt.UnpackType(pt),
+ }
+ }
+
+ return nil
+}
+
+func panicForInvalidStrType(vt reflect.Type) {
+ panic(error_type(rt.UnpackType(vt)))
+}
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go
new file mode 100644
index 000000000..77879fafe
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go
@@ -0,0 +1,60 @@
+package optdec
+
+import "math"
+
+/*
+Copied from sonic-rs
+// JSON Value Type
+const NULL: u64 = 0;
+const BOOL: u64 = 2;
+const FALSE: u64 = BOOL;
+const TRUE: u64 = (1 << 3) | BOOL;
+const NUMBER: u64 = 3;
+const UINT: u64 = NUMBER;
+const SINT: u64 = (1 << 3) | NUMBER;
+const REAL: u64 = (2 << 3) | NUMBER;
+const RAWNUMBER: u64 = (3 << 3) | NUMBER;
+const STRING: u64 = 4;
+const STRING_COMMON: u64 = STRING;
+const STRING_HASESCAPED: u64 = (1 << 3) | STRING;
+const OBJECT: u64 = 6;
+const ARRAY: u64 = 7;
+
+/// JSON Type Mask
+const POS_MASK: u64 = (!0) << 32;
+const POS_BITS: u64 = 32;
+const TYPE_MASK: u64 = 0xFF;
+const TYPE_BITS: u64 = 8;
+
+*/
+
+const (
+ // BasicType: 3 bits
+ KNull = 0 // xxxxx000
+ KBool = 2 // xxxxx010
+ KNumber = 3 // xxxxx011
+ KString = 4 // xxxxx100
+ KRaw = 5 // xxxxx101
+ KObject = 6 // xxxxx110
+ KArray = 7 // xxxxx111
+
+ // SubType: 2 bits
+ KFalse = (0 << 3) | KBool // xxx00_010, 2
+ KTrue = (1 << 3) | KBool // xxx01_010, 10
+ KUint = (0 << 3) | KNumber // xxx00_011, 3
+ KSint = (1 << 3) | KNumber // xxx01_011, 11
+ KReal = (2 << 3) | KNumber // xxx10_011, 19
+ KRawNumber = (3 << 3) | KNumber // xxx11_011, 27
+ KStringCommon = KString // xxx00_100, 4
+ KStringEscaped = (1 << 3) | KString // xxx01_100, 12
+)
+
+const (
+ PosMask = math.MaxUint64 << 32
+ PosBits = 32
+ TypeMask = 0xFF
+ TypeBits = 8
+
+ ConLenMask = uint64(math.MaxUint32)
+ ConLenBits = 32
+)
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go
new file mode 100644
index 000000000..93ed9b7e0
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go
@@ -0,0 +1,3 @@
+package optdec
+
+type context = Context
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go
new file mode 100644
index 000000000..81eed34ea
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go
@@ -0,0 +1,160 @@
+package optdec
+
+import (
+ "reflect"
+ "unsafe"
+
+ "encoding/json"
+ "github.com/bytedance/sonic/internal/rt"
+ "github.com/bytedance/sonic/option"
+ "github.com/bytedance/sonic/internal/decoder/errors"
+ "github.com/bytedance/sonic/internal/decoder/consts"
+)
+
+
+type (
+ MismatchTypeError = errors.MismatchTypeError
+ SyntaxError = errors.SyntaxError
+)
+
+const (
+ _F_allow_control = consts.F_allow_control
+ _F_copy_string = consts.F_copy_string
+ _F_disable_unknown = consts.F_disable_unknown
+ _F_disable_urc = consts.F_disable_urc
+ _F_use_int64 = consts.F_use_int64
+ _F_use_number = consts.F_use_number
+ _F_validate_string = consts.F_validate_string
+)
+
+type Options = consts.Options
+
+const (
+ OptionUseInt64 = consts.OptionUseInt64
+ OptionUseNumber = consts.OptionUseNumber
+ OptionUseUnicodeErrors = consts.OptionUseUnicodeErrors
+ OptionDisableUnknown = consts.OptionDisableUnknown
+ OptionCopyString = consts.OptionCopyString
+ OptionValidateString = consts.OptionValidateString
+)
+
+
+func Decode(s *string, i *int, f uint64, val interface{}) error {
+ vv := rt.UnpackEface(val)
+ vp := vv.Value
+
+ /* check for nil type */
+ if vv.Type == nil {
+ return &json.InvalidUnmarshalError{}
+ }
+
+ /* must be a non-nil pointer */
+ if vp == nil || vv.Type.Kind() != reflect.Ptr {
+ return &json.InvalidUnmarshalError{Type: vv.Type.Pack()}
+ }
+
+ etp := rt.PtrElem(vv.Type)
+
+ /* check the defined pointer type for issue 379 */
+ if vv.Type.IsNamed() {
+ newp := vp
+ etp = vv.Type
+ vp = unsafe.Pointer(&newp)
+ }
+
+ dec, err := findOrCompile(etp)
+ if err != nil {
+ return err
+ }
+
+ /* parse into document */
+ ctx, err := NewContext(*s, *i, uint64(f), etp)
+ defer ctx.Delete()
+ if ctx.Parser.Utf8Inv {
+ *s = ctx.Parser.Json
+ }
+ if err != nil {
+ goto fix_error;
+ }
+ err = dec.FromDom(vp, ctx.Root(), &ctx)
+
+fix_error:
+ err = fix_error(*s, *i, err)
+
+ // update position at last
+ *i += ctx.Parser.Pos()
+ return err
+}
+
+func fix_error(json string, pos int, err error) error {
+ if e, ok := err.(SyntaxError); ok {
+ return SyntaxError{
+ Pos: int(e.Pos) + pos,
+ Src: json,
+ Msg: e.Msg,
+ }
+ }
+
+ if e, ok := err.(MismatchTypeError); ok {
+ return &MismatchTypeError {
+ Pos: int(e.Pos) + pos,
+ Src: json,
+ Type: e.Type,
+ }
+ }
+
+ return err
+}
+
+// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
+// order to reduce the first-hit latency.
+//
+// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is
+// a compile option to set the depth of recursive compile for the nested struct type.
+func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
+ cfg := option.DefaultCompileOptions()
+ for _, opt := range opts {
+ opt(&cfg)
+ }
+ return pretouchRec(map[reflect.Type]bool{vt:true}, cfg)
+}
+
+func pretouchType(_vt reflect.Type, opts option.CompileOptions) (map[reflect.Type]bool, error) {
+ /* compile function */
+ compiler := newCompiler().apply(opts)
+ decoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) {
+ if f, err := compiler.compileType(_vt); err != nil {
+ return nil, err
+ } else {
+ return f, nil
+ }
+ }
+
+ /* find or compile */
+ vt := rt.UnpackType(_vt)
+ if val := programCache.Get(vt); val != nil {
+ return nil, nil
+ } else if _, err := programCache.Compute(vt, decoder); err == nil {
+ return compiler.visited, nil
+ } else {
+ return nil, err
+ }
+}
+
+func pretouchRec(vtm map[reflect.Type]bool, opts option.CompileOptions) error {
+ if opts.RecursiveDepth < 0 || len(vtm) == 0 {
+ return nil
+ }
+ next := make(map[reflect.Type]bool)
+ for vt := range(vtm) {
+ sub, err := pretouchType(vt, opts)
+ if err != nil {
+ return err
+ }
+ for svt := range(sub) {
+ next[svt] = true
+ }
+ }
+ opts.RecursiveDepth -= 1
+ return pretouchRec(next, opts)
+}
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go
new file mode 100644
index 000000000..db0af547b
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2021 ByteDance Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package optdec
+
+ import (
+ "encoding/json"
+ "errors"
+ "reflect"
+ "strconv"
+
+ "github.com/bytedance/sonic/internal/rt"
+ )
+
+ /** JIT Error Helpers **/
+
+ var stackOverflow = &json.UnsupportedValueError{
+ Str: "Value nesting too deep",
+ Value: reflect.ValueOf("..."),
+ }
+
+ func error_type(vt *rt.GoType) error {
+ return &json.UnmarshalTypeError{Type: vt.Pack()}
+ }
+
+ func error_mismatch(node Node, ctx *context, typ reflect.Type) error {
+ return MismatchTypeError{
+ Pos: node.Position(),
+ Src: ctx.Parser.Json,
+ Type: typ,
+ }
+ }
+
+ func newUnmatched(pos int, vt *rt.GoType) error {
+ return MismatchTypeError{
+ Pos: pos,
+ Src: "",
+ Type: vt.Pack(),
+ }
+ }
+
+ func error_field(name string) error {
+ return errors.New("json: unknown field " + strconv.Quote(name))
+ }
+
+ func error_value(value string, vtype reflect.Type) error {
+ return &json.UnmarshalTypeError{
+ Type: vtype,
+ Value: value,
+ }
+ }
+
+ func error_syntax(pos int, src string, msg string) error {
+ return SyntaxError{
+ Pos: pos,
+ Src: src,
+ Msg: msg,
+ }
+ }
+ \ No newline at end of file
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go
new file mode 100644
index 000000000..2a0523d5e
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go
@@ -0,0 +1,281 @@
+package optdec
+
+import (
+ "encoding/json"
+ "math"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/rt"
+ "github.com/bytedance/sonic/internal/resolver"
+)
+
+type decFunc interface {
+ FromDom(vp unsafe.Pointer, node Node, ctx *context) error
+}
+
+type ptrDecoder struct {
+ typ *rt.GoType
+ deref decFunc
+}
+
+// Pointer Value is allocated in the Caller
+func (d *ptrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*unsafe.Pointer)(vp) = nil
+ return nil
+ }
+
+ if *(*unsafe.Pointer)(vp) == nil {
+ *(*unsafe.Pointer)(vp) = rt.Mallocgc(d.typ.Size, d.typ, true)
+ }
+
+ return d.deref.FromDom(*(*unsafe.Pointer)(vp), node, ctx)
+}
+
+type embeddedFieldPtrDecoder struct {
+ field resolver.FieldMeta
+ fieldDec decFunc
+ fieldName string
+}
+
+// Pointer Value is allocated in the Caller
+func (d *embeddedFieldPtrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ // seek into the pointer
+ vp = unsafe.Pointer(uintptr(vp) - uintptr(d.field.Path[0].Size))
+ for _, f := range d.field.Path {
+ deref := rt.UnpackType(f.Type)
+ vp = unsafe.Pointer(uintptr(vp) + f.Size)
+ if f.Kind == resolver.F_deref {
+ if *(*unsafe.Pointer)(vp) == nil {
+ *(*unsafe.Pointer)(vp) = rt.Mallocgc(deref.Size, deref, true)
+ }
+ vp = *(*unsafe.Pointer)(vp)
+ }
+ }
+ return d.fieldDec.FromDom(vp, node, ctx)
+}
+
+type i8Decoder struct{}
+
+func (d *i8Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsI64(ctx)
+ if !ok || ret > math.MaxInt8 || ret < math.MinInt8 {
+ return error_mismatch(node, ctx, int8Type)
+ }
+
+ *(*int8)(vp) = int8(ret)
+ return nil
+}
+
+type i16Decoder struct{}
+
+func (d *i16Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsI64(ctx)
+ if !ok || ret > math.MaxInt16 || ret < math.MinInt16 {
+ return error_mismatch(node, ctx, int16Type)
+ }
+
+ *(*int16)(vp) = int16(ret)
+ return nil
+}
+
+type i32Decoder struct{}
+
+func (d *i32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsI64(ctx)
+ if !ok || ret > math.MaxInt32 || ret < math.MinInt32 {
+ return error_mismatch(node, ctx, int32Type)
+ }
+
+ *(*int32)(vp) = int32(ret)
+ return nil
+}
+
+type i64Decoder struct{}
+
+func (d *i64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsI64(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, int64Type)
+ }
+
+ *(*int64)(vp) = int64(ret)
+ return nil
+}
+
+type u8Decoder struct{}
+
+func (d *u8Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsU64(ctx)
+ if !ok || ret > math.MaxUint8 {
+ err := error_mismatch(node, ctx, uint8Type)
+ return err
+ }
+
+ *(*uint8)(vp) = uint8(ret)
+ return nil
+}
+
+type u16Decoder struct{}
+
+func (d *u16Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsU64(ctx)
+ if !ok || ret > math.MaxUint16 {
+ return error_mismatch(node, ctx, uint16Type)
+ }
+ *(*uint16)(vp) = uint16(ret)
+ return nil
+}
+
+type u32Decoder struct{}
+
+func (d *u32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsU64(ctx)
+ if !ok || ret > math.MaxUint32 {
+ return error_mismatch(node, ctx, uint32Type)
+ }
+
+ *(*uint32)(vp) = uint32(ret)
+ return nil
+}
+
+type u64Decoder struct{}
+
+func (d *u64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsU64(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, uint64Type)
+ }
+
+ *(*uint64)(vp) = uint64(ret)
+ return nil
+}
+
+type f32Decoder struct{}
+
+func (d *f32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsF64(ctx)
+ if !ok || ret > math.MaxFloat32 || ret < -math.MaxFloat32 {
+ return error_mismatch(node, ctx, float32Type)
+ }
+
+ *(*float32)(vp) = float32(ret)
+ return nil
+}
+
+type f64Decoder struct{}
+
+func (d *f64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsF64(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, float64Type)
+ }
+
+ *(*float64)(vp) = float64(ret)
+ return nil
+}
+
+type boolDecoder struct {
+}
+
+func (d *boolDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsBool()
+ if !ok {
+ return error_mismatch(node, ctx, boolType)
+ }
+
+ *(*bool)(vp) = bool(ret)
+ return nil
+}
+
+type stringDecoder struct {
+}
+
+func (d *stringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ ret, ok := node.AsStr(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, stringType)
+ }
+ *(*string)(vp) = ret
+ return nil
+}
+
+type numberDecoder struct {
+}
+
+func (d *numberDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ num, ok := node.AsNumber(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, jsonNumberType)
+ }
+ *(*json.Number)(vp) = num
+ return nil
+}
+
+type recuriveDecoder struct {
+ typ *rt.GoType
+}
+
+func (d *recuriveDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ dec, err := findOrCompile(d.typ)
+ if err != nil {
+ return err
+ }
+ return dec.FromDom(vp, node, ctx)
+}
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go
new file mode 100644
index 000000000..7bf8a8f39
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go
@@ -0,0 +1,110 @@
+package optdec
+
+import (
+ "encoding/json"
+ "strconv"
+
+ "github.com/bytedance/sonic/internal/native"
+ "github.com/bytedance/sonic/internal/utils"
+ "github.com/bytedance/sonic/internal/native/types"
+)
+
+
+func SkipNumberFast(json string, start int) (int, bool) {
+ // find the number ending, we pasred in native, it alway valid
+ pos := start
+ for pos < len(json) && json[pos] != ']' && json[pos] != '}' && json[pos] != ',' {
+ if json[pos] >= '0' && json[pos] <= '9' || json[pos] == '.' || json[pos] == '-' || json[pos] == '+' || json[pos] == 'e' || json[pos] == 'E' {
+ pos += 1
+ } else {
+ break
+ }
+ }
+
+ // if not found number, return false
+ if pos == start {
+ return pos, false
+ }
+ return pos, true
+}
+
+
+func isSpace(c byte) bool {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r'
+}
+
+// pos is the start index of the raw
+func ValidNumberFast(raw string) bool {
+ ret := utils.SkipNumber(raw, 0)
+ if ret < 0 {
+ return false
+ }
+
+ // check trainling chars
+ for ret < len(raw) {
+ return false
+ }
+
+ return true
+}
+
+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, error_syntax(*pos, json, types.ParsingError(-start).Error())
+ }
+ return start, nil
+}
+
+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 {
+ // TODO: details error code
+ return "", error_syntax(pos, json, types.ParsingError(-start).Error())
+ }
+ return json[start:pos], nil
+}
+
+func ParseI64(raw string) (int64, error) {
+ i64, err := strconv.ParseInt(raw, 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ return i64, nil
+}
+
+func ParseBool(raw string) (bool, error) {
+ var b bool
+ err := json.Unmarshal([]byte(raw), &b)
+ if err != nil {
+ return false, err
+ }
+ return b, nil
+}
+
+func ParseU64(raw string) (uint64, error) {
+ u64, err := strconv.ParseUint(raw, 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ return u64, nil
+}
+
+func ParseF64(raw string) (float64, error) {
+ f64, err := strconv.ParseFloat(raw, 64)
+ if err != nil {
+ return 0, err
+ }
+ return f64, nil
+}
+
+func Unquote(raw string) (string, error) {
+ var u string
+ err := json.Unmarshal([]byte(raw), &u)
+ if err != nil {
+ return "", err
+ }
+ return u, nil
+}
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go
new file mode 100644
index 000000000..0c063d55f
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go
@@ -0,0 +1,169 @@
+package optdec
+
+import (
+ "encoding"
+ "encoding/json"
+ "unsafe"
+ "reflect"
+
+ "github.com/bytedance/sonic/internal/rt"
+)
+
+type efaceDecoder struct {
+}
+
+func (d *efaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*interface{})(vp) = interface{}(nil)
+ return nil
+ }
+
+ eface := *(*rt.GoEface)(vp)
+
+ // not pointer type, or nil pointer, or *interface{}
+ if eface.Value == nil || eface.Type.Kind() != reflect.Ptr || rt.PtrElem(eface.Type) == anyType {
+ ret, err := node.AsEface(ctx)
+ if err != nil {
+ return err
+ }
+
+ *(*interface{})(vp) = ret
+ return nil
+ }
+
+ etp := rt.PtrElem(eface.Type)
+ vp = eface.Value
+
+ /* check the defined pointer type for issue 379 */
+ if eface.Type.IsNamed() {
+ newp := vp
+ etp = eface.Type
+ vp = unsafe.Pointer(&newp)
+ }
+
+ dec, err := findOrCompile(etp)
+ if err != nil {
+ return err
+ }
+
+ return dec.FromDom(vp, node, ctx)
+}
+
+type ifaceDecoder struct {
+ typ *rt.GoType
+}
+
+func (d *ifaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*unsafe.Pointer)(vp) = nil
+ return nil
+ }
+
+ iface := *(*rt.GoIface)(vp)
+ if iface.Itab == nil {
+ return error_type(d.typ)
+ }
+
+ vt := iface.Itab.Vt
+
+ // not pointer type, or nil pointer, or *interface{}
+ if vp == nil || vt.Kind() != reflect.Ptr || rt.PtrElem(vt) == anyType {
+ ret, err := node.AsEface(ctx)
+ if err != nil {
+ return err
+ }
+
+ *(*interface{})(vp) = ret
+ return nil
+ }
+
+
+ etp := rt.PtrElem(vt)
+ vp = iface.Value
+
+ /* check the defined pointer type for issue 379 */
+ if vt.IsNamed() {
+ newp := vp
+ etp = vt
+ vp = unsafe.Pointer(&newp)
+ }
+
+ dec, err := findOrCompile(etp)
+ if err != nil {
+ return err
+ }
+
+ return dec.FromDom(vp, node, ctx)
+}
+
+type unmarshalTextDecoder struct {
+ typ *rt.GoType
+}
+
+func (d *unmarshalTextDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*unsafe.Pointer)(vp) = nil
+ return nil
+ }
+
+ txt, ok := node.AsStringText(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, d.typ.Pack())
+ }
+
+ v := *(*interface{})(unsafe.Pointer(&rt.GoEface{
+ Type: d.typ,
+ Value: vp,
+ }))
+
+ // fast path
+ if u, ok := v.(encoding.TextUnmarshaler); ok {
+ return u.UnmarshalText(txt)
+ }
+
+ // slow path
+ rv := reflect.ValueOf(v)
+ if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok {
+ return u.UnmarshalText(txt)
+ }
+
+ return error_type(d.typ)
+}
+
+type unmarshalJSONDecoder struct {
+ typ *rt.GoType
+ strOpt bool
+}
+
+func (d *unmarshalJSONDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ v := *(*interface{})(unsafe.Pointer(&rt.GoEface{
+ Type: d.typ,
+ Value: vp,
+ }))
+
+ var input []byte
+ if d.strOpt && node.IsNull() {
+ input = []byte("null")
+ } else if d.strOpt {
+ s, ok := node.AsStringText(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, d.typ.Pack())
+ }
+ input = s
+ } else {
+ input = []byte(node.AsRaw(ctx))
+ }
+
+ // fast path
+ if u, ok := v.(json.Unmarshaler); ok {
+ return u.UnmarshalJSON((input))
+ }
+
+ // slow path
+ rv := reflect.ValueOf(v)
+ if u, ok := rv.Interface().(json.Unmarshaler); ok {
+ return u.UnmarshalJSON(input)
+ }
+
+ return error_type(d.typ)
+}
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go
new file mode 100644
index 000000000..1a2bda8f3
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go
@@ -0,0 +1,430 @@
+package optdec
+
+import (
+ "encoding"
+ "encoding/json"
+ "math"
+ "reflect"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/rt"
+)
+
+/** Decoder for most common map types: map[string]interface{}, map[string]string **/
+
+type mapEfaceDecoder struct {
+}
+
+func (d *mapEfaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*map[string]interface{})(vp) = nil
+ return nil
+ }
+
+ return node.AsMapEface(ctx, vp)
+}
+
+type mapStringDecoder struct {
+}
+
+func (d *mapStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*map[string]string)(vp) = nil
+ return nil
+ }
+
+ return node.AsMapString(ctx, vp)
+}
+
+/** Decoder for map with string key **/
+
+type mapStrKeyDecoder struct {
+ mapType *rt.GoMapType
+ elemDec decFunc
+ assign rt.MapStrAssign
+ typ reflect.Type
+}
+
+func (d *mapStrKeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*unsafe.Pointer)(vp) = nil
+ return nil
+ }
+
+ obj, ok := node.AsObj()
+ if !ok {
+ return error_mismatch(node, ctx, d.mapType.Pack())
+ }
+
+ // allocate map
+ m := *(*unsafe.Pointer)(vp)
+ if m == nil {
+ m = rt.Makemap(&d.mapType.GoType, obj.Len())
+ }
+
+ var gerr error
+ next := obj.Children()
+ for i := 0; i < obj.Len(); i++ {
+ keyn := NewNode(next)
+ key, _ := keyn.AsStr(ctx)
+
+ valn := NewNode(PtrOffset(next, 1))
+ valp := d.assign(d.mapType, m, key)
+ err := d.elemDec.FromDom(valp, valn, ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+ next = valn.Next()
+ }
+
+ *(*unsafe.Pointer)(vp) = m
+ return gerr
+}
+
+/** Decoder for map with int32 or int64 key **/
+
+type mapI32KeyDecoder struct {
+ mapType *rt.GoMapType
+ elemDec decFunc
+ assign rt.Map32Assign
+}
+
+func (d *mapI32KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*unsafe.Pointer)(vp) = nil
+ return nil
+ }
+
+ obj, ok := node.AsObj()
+ if !ok {
+ return error_mismatch(node, ctx, d.mapType.Pack())
+ }
+
+ // allocate map
+ m := *(*unsafe.Pointer)(vp)
+ if m == nil {
+ m = rt.Makemap(&d.mapType.GoType, obj.Len())
+ }
+
+ next := obj.Children()
+ var gerr error
+ for i := 0; i < obj.Len(); i++ {
+ keyn := NewNode(next)
+ k, ok := keyn.ParseI64(ctx)
+ if !ok || k > math.MaxInt32 || k < math.MinInt32 {
+ if gerr == nil {
+ gerr = error_mismatch(keyn, ctx, d.mapType.Pack())
+ }
+ valn := NewNode(PtrOffset(next, 1))
+ next = valn.Next()
+ continue
+ }
+
+ key := int32(k)
+ ku32 := *(*uint32)(unsafe.Pointer(&key))
+ valn := NewNode(PtrOffset(next, 1))
+ valp := d.assign(d.mapType, m, ku32)
+ err := d.elemDec.FromDom(valp, valn, ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+
+ next = valn.Next()
+ }
+
+ *(*unsafe.Pointer)(vp) = m
+ return gerr
+}
+
+type mapI64KeyDecoder struct {
+ mapType *rt.GoMapType
+ elemDec decFunc
+ assign rt.Map64Assign
+}
+
+func (d *mapI64KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*unsafe.Pointer)(vp) = nil
+ return nil
+ }
+
+ obj, ok := node.AsObj()
+ if !ok {
+ return error_mismatch(node, ctx, d.mapType.Pack())
+ }
+
+ // allocate map
+ m := *(*unsafe.Pointer)(vp)
+ if m == nil {
+ m = rt.Makemap(&d.mapType.GoType, obj.Len())
+ }
+
+ var gerr error
+ next := obj.Children()
+ for i := 0; i < obj.Len(); i++ {
+ keyn := NewNode(next)
+ key, ok := keyn.ParseI64(ctx)
+
+ if !ok {
+ if gerr == nil {
+ gerr = error_mismatch(keyn, ctx, d.mapType.Pack())
+ }
+ valn := NewNode(PtrOffset(next, 1))
+ next = valn.Next()
+ continue
+ }
+
+ ku64 := *(*uint64)(unsafe.Pointer(&key))
+ valn := NewNode(PtrOffset(next, 1))
+ valp := d.assign(d.mapType, m, ku64)
+ err := d.elemDec.FromDom(valp, valn, ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+ next = valn.Next()
+ }
+
+ *(*unsafe.Pointer)(vp) = m
+ return gerr
+}
+
+/** Decoder for map with unt32 or uint64 key **/
+
+type mapU32KeyDecoder struct {
+ mapType *rt.GoMapType
+ elemDec decFunc
+ assign rt.Map32Assign
+}
+
+func (d *mapU32KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*unsafe.Pointer)(vp) = nil
+ return nil
+ }
+
+ obj, ok := node.AsObj()
+ if !ok {
+ return error_mismatch(node, ctx, d.mapType.Pack())
+ }
+
+ // allocate map
+ m := *(*unsafe.Pointer)(vp)
+ if m == nil {
+ m = rt.Makemap(&d.mapType.GoType, obj.Len())
+ }
+
+ var gerr error
+ next := obj.Children()
+ for i := 0; i < obj.Len(); i++ {
+ keyn := NewNode(next)
+ k, ok := keyn.ParseU64(ctx)
+ if !ok || k > math.MaxUint32 {
+ if gerr == nil {
+ gerr = error_mismatch(keyn, ctx, d.mapType.Pack())
+ }
+ valn := NewNode(PtrOffset(next, 1))
+ next = valn.Next()
+ continue
+ }
+
+ key := uint32(k)
+ valn := NewNode(PtrOffset(next, 1))
+ valp := d.assign(d.mapType, m, key)
+ err := d.elemDec.FromDom(valp, valn, ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+ next = valn.Next()
+ }
+
+ *(*unsafe.Pointer)(vp) = m
+ return gerr
+}
+
+type mapU64KeyDecoder struct {
+ mapType *rt.GoMapType
+ elemDec decFunc
+ assign rt.Map64Assign
+}
+
+func (d *mapU64KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*unsafe.Pointer)(vp) = nil
+ return nil
+ }
+
+ obj, ok := node.AsObj()
+ if !ok {
+ return error_mismatch(node, ctx, d.mapType.Pack())
+ }
+ // allocate map
+ m := *(*unsafe.Pointer)(vp)
+ if m == nil {
+ m = rt.Makemap(&d.mapType.GoType, obj.Len())
+ }
+
+ var gerr error
+ next := obj.Children()
+ for i := 0; i < obj.Len(); i++ {
+ keyn := NewNode(next)
+ key, ok := keyn.ParseU64(ctx)
+ if !ok {
+ if gerr == nil {
+ gerr = error_mismatch(keyn, ctx, d.mapType.Pack())
+ }
+ valn := NewNode(PtrOffset(next, 1))
+ next = valn.Next()
+ continue
+ }
+
+ valn := NewNode(PtrOffset(next, 1))
+ valp := d.assign(d.mapType, m, key)
+ err := d.elemDec.FromDom(valp, valn, ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+ next = valn.Next()
+ }
+
+ *(*unsafe.Pointer)(vp) = m
+ return gerr
+}
+
+/** Decoder for generic cases */
+
+type decKey func(dec *mapDecoder, raw string, ctx *context) (interface{}, error)
+
+func decodeKeyU8(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
+ key, err := Unquote(raw)
+ if err != nil {
+ return nil, err
+ }
+ ret, err := ParseU64(key)
+ if err != nil {
+ return nil, err
+ }
+ if ret > math.MaxUint8 {
+ return nil, error_value(key, dec.mapType.Key.Pack())
+ }
+ return uint8(ret), nil
+}
+
+func decodeKeyU16(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
+ key, err := Unquote(raw)
+ if err != nil {
+ return nil, err
+ }
+ ret, err := ParseU64(key)
+ if err != nil {
+ return nil, err
+ }
+ if ret > math.MaxUint16 {
+ return nil, error_value(key, dec.mapType.Key.Pack())
+ }
+ return uint16(ret), nil
+}
+
+func decodeKeyI8(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
+ key, err := Unquote(raw)
+ if err != nil {
+ return nil, err
+ }
+ ret, err := ParseI64(key)
+ if err != nil {
+ return nil, err
+ }
+ if ret > math.MaxInt8 || ret < math.MinInt8 {
+ return nil, error_value(key, dec.mapType.Key.Pack())
+ }
+ return int8(ret), nil
+}
+
+func decodeKeyI16(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
+ key, err := Unquote(raw)
+ if err != nil {
+ return nil, err
+ }
+ ret, err := ParseI64(key)
+ if err != nil {
+ return nil, err
+ }
+ if ret > math.MaxInt16 || ret < math.MinInt16 {
+ return nil, error_value(key, dec.mapType.Key.Pack())
+ }
+ return int16(ret), nil
+}
+
+func decodeKeyJSONUnmarshaler(dec *mapDecoder, raw string, _ *context) (interface{}, error) {
+ ret := reflect.New(dec.mapType.Key.Pack()).Interface()
+ err := ret.(json.Unmarshaler).UnmarshalJSON([]byte(raw))
+ if err != nil {
+ return nil, err
+ }
+ return ret, nil
+}
+
+func decodeKeyTextUnmarshaler(dec *mapDecoder, raw string, ctx *context) (interface{}, error) {
+ key, err := Unquote(raw)
+ if err != nil {
+ return nil, err
+ }
+ ret := reflect.New(dec.mapType.Key.Pack()).Interface()
+ err = ret.(encoding.TextUnmarshaler).UnmarshalText([]byte(key))
+ if err != nil {
+ return nil, err
+ }
+ return ret, nil
+}
+
+type mapDecoder struct {
+ mapType *rt.GoMapType
+ keyDec decKey
+ elemDec decFunc
+}
+
+func (d *mapDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*unsafe.Pointer)(vp) = nil
+ return nil
+ }
+
+ obj, ok := node.AsObj()
+ if !ok {
+ return error_mismatch(node, ctx, d.mapType.Pack())
+ }
+
+ // allocate map
+ m := *(*unsafe.Pointer)(vp)
+ if m == nil {
+ m = rt.Makemap(&d.mapType.GoType, obj.Len())
+ }
+
+ next := obj.Children()
+ var gerr error
+ for i := 0; i < obj.Len(); i++ {
+ keyn := NewNode(next)
+ raw := keyn.AsRaw(ctx)
+ key, err := d.keyDec(d, raw, ctx)
+ if err != nil {
+ if gerr == nil {
+ gerr = error_mismatch(keyn, ctx, d.mapType.Pack())
+ }
+ valn := NewNode(PtrOffset(next, 1))
+ next = valn.Next()
+ continue
+ }
+
+ valn := NewNode(PtrOffset(next, 1))
+ keyp := rt.UnpackEface(key).Value
+ valp := rt.Mapassign(d.mapType, m, keyp)
+ err = d.elemDec.FromDom(valp, valn, ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+
+ next = valn.Next()
+ }
+
+ *(*unsafe.Pointer)(vp) = m
+ return gerr
+}
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go
new file mode 100644
index 000000000..29a0136ae
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go
@@ -0,0 +1,269 @@
+package optdec
+
+import (
+ "fmt"
+ "reflect"
+ "unsafe"
+
+ "sync"
+
+ "github.com/bytedance/sonic/internal/native"
+ "github.com/bytedance/sonic/internal/native/types"
+ "github.com/bytedance/sonic/internal/rt"
+ "github.com/bytedance/sonic/utf8"
+)
+
+
+type ErrorCode int
+
+const (
+ SONIC_OK = 0;
+ SONIC_CONTROL_CHAR = 1;
+ SONIC_INVALID_ESCAPED = 2;
+ SONIC_INVALID_NUM = 3;
+ SONIC_FLOAT_INF = 4;
+ SONIC_EOF = 5;
+ SONIC_INVALID_CHAR = 6;
+ SONIC_EXPECT_KEY = 7;
+ SONIC_EXPECT_COLON = 8;
+ SONIC_EXPECT_OBJ_COMMA_OR_END = 9;
+ SONIC_EXPECT_ARR_COMMA_OR_END = 10;
+ SONIC_VISIT_FAILED = 11;
+ SONIC_INVALID_ESCAPED_UTF = 12;
+ SONIC_INVALID_LITERAL = 13;
+ SONIC_STACK_OVERFLOW = 14;
+)
+
+var ParsingErrors = []string{
+ SONIC_OK : "ok",
+ SONIC_CONTROL_CHAR : "control chars in string",
+ SONIC_INVALID_ESCAPED : "invalid escaped chars in string",
+ SONIC_INVALID_NUM : "invalid number",
+ SONIC_FLOAT_INF : "float infinity",
+ SONIC_EOF : "eof",
+ SONIC_INVALID_CHAR : "invalid chars",
+ SONIC_EXPECT_KEY : "expect a json key",
+ SONIC_EXPECT_COLON : "expect a `:`",
+ SONIC_EXPECT_OBJ_COMMA_OR_END : "expect a `,` or `}`",
+ SONIC_EXPECT_ARR_COMMA_OR_END : "expect a `,` or `]`",
+ SONIC_VISIT_FAILED : "failed in json visitor",
+ SONIC_INVALID_ESCAPED_UTF : "invalid escaped unicodes",
+ SONIC_INVALID_LITERAL : "invalid literal(true/false/null)",
+ SONIC_STACK_OVERFLOW : "json is exceeded max depth 4096, cause stack overflow",
+}
+
+func (code ErrorCode) Error() string {
+ return ParsingErrors[code]
+}
+
+type node struct {
+ typ uint64
+ val uint64
+}
+
+// should consitent with native/parser.c
+type _nospaceBlock struct {
+ _ [8]byte
+ _ [8]byte
+}
+
+// should consitent with native/parser.c
+type nodeBuf struct {
+ ncur uintptr
+ parent int64
+ depth uint64
+ nstart uintptr
+ nend uintptr
+ stat jsonStat
+}
+
+func (self *nodeBuf) init(nodes []node) {
+ self.ncur = uintptr(unsafe.Pointer(&nodes[0]))
+ self.nstart = self.ncur
+ self.nend = self.ncur + uintptr(cap(nodes)) * unsafe.Sizeof(node{})
+ self.parent = -1
+}
+
+// should consitent with native/parser.c
+type Parser struct {
+ Json string
+ padded []byte
+ nodes []node
+ dbuf []byte
+ backup []node
+
+ options uint64
+ // JSON cursor
+ start uintptr
+ cur uintptr
+ end uintptr
+ _nbk _nospaceBlock
+
+ // node buffer cursor
+ nbuf nodeBuf
+ Utf8Inv bool
+ isEface bool
+}
+
+// only when parse non-empty object/array are needed.
+type jsonStat struct {
+ object uint32
+ array uint32
+ str uint32
+ number uint32
+ array_elems uint32
+ object_keys uint32
+ max_depth uint32
+}
+
+
+var (
+ defaultJsonPaddedCap uintptr = 1 << 20 // 1 Mb
+ defaultNodesCap uintptr = (1 << 20) / unsafe.Sizeof(node{}) // 1 Mb
+)
+
+var parsePool sync.Pool = sync.Pool {
+ New: func () interface{} {
+ return &Parser{
+ options: 0,
+ padded: make([]byte, 0, defaultJsonPaddedCap),
+ nodes: make([]node, defaultNodesCap, defaultNodesCap),
+ dbuf: make([]byte, types.MaxDigitNums, types.MaxDigitNums),
+ }
+ },
+}
+
+var padding string = "x\"x\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+
+func newParser(data string, pos int, opt uint64) *Parser {
+ p := parsePool.Get().(*Parser)
+
+ /* validate json if needed */
+ if (opt & (1 << _F_validate_string)) != 0 && !utf8.ValidateString(data){
+ dbuf := utf8.CorrectWith(nil, rt.Str2Mem(data[pos:]), "\ufffd")
+ dbuf = append(dbuf, padding...)
+ p.Json = rt.Mem2Str(dbuf[:len(dbuf) - len(padding)])
+ p.Utf8Inv = true
+ p.start = uintptr((*rt.GoString)(unsafe.Pointer(&p.Json)).Ptr)
+ } else {
+ p.Json = data
+ // TODO: prevent too large JSON
+ p.padded = append(p.padded, data[pos:]...)
+ p.padded = append(p.padded, padding...)
+ p.start = uintptr((*rt.GoSlice)(unsafe.Pointer(&p.padded)).Ptr)
+ }
+
+ p.cur = p.start
+ p.end = p.cur + uintptr(len(p.Json))
+ p.options = opt
+ p.nbuf.init(p.nodes)
+ return p
+}
+
+
+func (p *Parser) Pos() int {
+ return int(p.cur - p.start)
+}
+
+func (p *Parser) JsonBytes() []byte {
+ if p.Utf8Inv {
+ return (rt.Str2Mem(p.Json))
+ } else {
+ return p.padded
+ }
+}
+
+var nodeType = rt.UnpackType(reflect.TypeOf(node{}))
+
+//go:inline
+func calMaxNodeCap(jsonSize int) int {
+ return jsonSize / 2 + 2
+}
+
+func (p *Parser) parse() ErrorCode {
+ // when decode into struct, we should decode number as possible
+ old := p.options
+ if !p.isEface {
+ p.options &^= 1 << _F_use_number
+ }
+
+ // fast path with limited node buffer
+ err := ErrorCode(native.ParseWithPadding(unsafe.Pointer(p)))
+ if err != SONIC_VISIT_FAILED {
+ p.options = old
+ return err
+ }
+
+ // check OoB here
+ offset := p.nbuf.ncur - p.nbuf.nstart
+ curLen := offset / unsafe.Sizeof(node{})
+ if curLen != uintptr(len(p.nodes)) {
+ panic(fmt.Sprintf("current len: %d, real len: %d cap: %d", curLen, len(p.nodes), cap(p.nodes)))
+ }
+
+ // node buf is not enough, continue parse
+ // the maxCap is always meet all valid JSON
+ maxCap := calMaxNodeCap(len(p.Json))
+ slice := rt.GoSlice{
+ Ptr: rt.Mallocgc(uintptr(maxCap) * nodeType.Size, nodeType, false),
+ Len: maxCap,
+ Cap: maxCap,
+ }
+ rt.Memmove(unsafe.Pointer(slice.Ptr), unsafe.Pointer(&p.nodes[0]), offset)
+ p.backup = p.nodes
+ p.nodes = *(*[]node)(unsafe.Pointer(&slice))
+
+ // update node cursor
+ p.nbuf.nstart = uintptr(unsafe.Pointer(&p.nodes[0]))
+ p.nbuf.nend = p.nbuf.nstart + uintptr(cap(p.nodes)) * unsafe.Sizeof(node{})
+ p.nbuf.ncur = p.nbuf.nstart + offset
+
+ // continue parse json
+ err = ErrorCode(native.ParseWithPadding(unsafe.Pointer(p)))
+ p.options = old
+ return err
+}
+
+func (p *Parser) reset() {
+ p.options = 0
+ p.padded = p.padded[:0]
+ // nodes is too large here, we will not reset it and use small backup nodes buffer
+ if p.backup != nil {
+ p.nodes = p.backup
+ p.backup = nil
+ }
+ p.start = 0
+ p.cur = 0
+ p.end = 0
+ p.Json = ""
+ p.nbuf = nodeBuf{}
+ p._nbk = _nospaceBlock{}
+ p.Utf8Inv = false
+ p.isEface = false
+}
+
+func (p *Parser) free() {
+ p.reset()
+ parsePool.Put(p)
+}
+
+//go:noinline
+func (p *Parser) fixError(code ErrorCode) error {
+ if code == SONIC_OK {
+ return nil
+ }
+
+ if p.Pos() == 0 {
+ code = SONIC_EOF;
+ }
+
+ pos := p.Pos() - 1
+ return error_syntax(pos, p.Json, ParsingErrors[code])
+}
+
+func Parse(data string, opt uint64) error {
+ p := newParser(data, 0, opt)
+ err := p.parse()
+ p.free()
+ return err
+}
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go
new file mode 100644
index 000000000..3f60a3368
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go
@@ -0,0 +1,1278 @@
+package optdec
+
+import (
+ "encoding/json"
+ "math"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/envs"
+ "github.com/bytedance/sonic/internal/rt"
+)
+
+type Context struct {
+ Parser *Parser
+ efacePool *efacePool
+ Stack bounedStack
+ Utf8Inv bool
+}
+
+func (ctx *Context) Options() uint64 {
+ return ctx.Parser.options
+}
+
+/************************* Stack and Pool Helper *******************/
+
+type parentStat struct {
+ con unsafe.Pointer
+ remain uint64
+}
+type bounedStack struct {
+ stack []parentStat
+ index int
+}
+
+func newStack(size int) bounedStack {
+ return bounedStack{
+ stack: make([]parentStat, size + 2),
+ index: 0,
+ }
+}
+
+//go:nosplit
+func (s *bounedStack) Pop() (unsafe.Pointer, int, bool){
+ s.index--
+ con := s.stack[s.index].con
+ remain := s.stack[s.index].remain &^ (uint64(1) << 63)
+ isObj := (s.stack[s.index].remain & (uint64(1) << 63)) != 0
+ s.stack[s.index].con = nil
+ s.stack[s.index].remain = 0
+ return con, int(remain), isObj
+}
+
+//go:nosplit
+func (s *bounedStack) Push(p unsafe.Pointer, remain int, isObj bool) {
+ s.stack[s.index].con = p
+ s.stack[s.index].remain = uint64(remain)
+ if isObj {
+ s.stack[s.index].remain |= (uint64(1) << 63)
+ }
+ s.index++
+}
+
+type efacePool struct{
+ t64 rt.T64Pool
+ tslice rt.TslicePool
+ tstring rt.TstringPool
+ efaceSlice rt.SlicePool
+}
+
+func newEfacePool(stat *jsonStat, useNumber bool) *efacePool {
+ strs := int(stat.str)
+ nums := 0
+ if useNumber {
+ strs += int(stat.number)
+ } else {
+ nums = int(stat.number)
+ }
+
+ return &efacePool{
+ t64: rt.NewT64Pool(nums),
+ tslice: rt.NewTslicePool(int(stat.array)),
+ tstring: rt.NewTstringPool(strs),
+ efaceSlice: rt.NewPool(rt.AnyType, int(stat.array_elems)),
+ }
+}
+
+func (self *efacePool) GetMap(hint int) unsafe.Pointer {
+ m := make(map[string]interface{}, hint)
+ return *(*unsafe.Pointer)(unsafe.Pointer(&m))
+}
+
+func (self *efacePool) GetSlice(hint int) unsafe.Pointer {
+ return unsafe.Pointer(self.efaceSlice.GetSlice(hint))
+}
+
+func (self *efacePool) ConvTSlice(val rt.GoSlice, typ *rt.GoType, dst unsafe.Pointer) {
+ self.tslice.Conv(val, typ, (*interface{})(dst))
+}
+
+func (self *efacePool) ConvF64(val float64, dst unsafe.Pointer) {
+ self.t64.Conv(castU64(val), rt.Float64Type, (*interface{})(dst))
+}
+
+func (self *efacePool) ConvTstring(val string, dst unsafe.Pointer) {
+ self.tstring.Conv(val, (*interface{})(dst))
+}
+
+func (self *efacePool) ConvTnum(val json.Number, dst unsafe.Pointer) {
+ self.tstring.ConvNum(val, (*interface{})(dst))
+}
+
+/********************************************************/
+
+func canUseFastMap( opts uint64, root *rt.GoType) bool {
+ return envs.UseFastMap && (opts & (1 << _F_copy_string)) == 0 && (opts & (1 << _F_use_int64)) == 0 && (root == rt.AnyType || root == rt.MapEfaceType || root == rt.SliceEfaceType)
+}
+
+func NewContext(json string, pos int, opts uint64, root *rt.GoType) (Context, error) {
+ ctx := Context{
+ Parser: newParser(json, pos, opts),
+ }
+ if root == rt.AnyType || root == rt.MapEfaceType || root == rt.SliceEfaceType {
+ ctx.Parser.isEface = true
+ }
+
+ ecode := ctx.Parser.parse()
+
+ if ecode != 0 {
+ return ctx, ctx.Parser.fixError(ecode)
+ }
+
+ useNumber := (opts & (1 << _F_use_number )) != 0
+ if canUseFastMap(opts, root) {
+ ctx.efacePool = newEfacePool(&ctx.Parser.nbuf.stat, useNumber)
+ ctx.Stack = newStack(int(ctx.Parser.nbuf.stat.max_depth))
+ }
+
+ return ctx, nil
+}
+
+func (ctx *Context) Delete() {
+ ctx.Parser.free()
+ ctx.Parser = nil
+}
+
+type Node struct {
+ cptr uintptr
+}
+
+func NewNode(cptr uintptr) Node {
+ return Node{cptr: cptr}
+}
+
+type Dom struct {
+ cdom uintptr
+}
+
+func (ctx *Context) Root() Node {
+ root := (uintptr)(((*rt.GoSlice)(unsafe.Pointer(&ctx.Parser.nodes))).Ptr)
+ return Node{cptr: root}
+}
+
+type Array struct {
+ cptr uintptr
+}
+
+type Object struct {
+ cptr uintptr
+}
+
+func (obj Object) Len() int {
+ cobj := ptrCast(obj.cptr)
+ return int(uint64(cobj.val) & ConLenMask)
+}
+
+func (arr Array) Len() int {
+ carr := ptrCast(arr.cptr)
+ return int(uint64(carr.val) & ConLenMask)
+}
+
+// / Helper functions to eliminate CGO calls
+func (val Node) Type() uint8 {
+ ctype := ptrCast(val.cptr)
+ return uint8(ctype.typ & TypeMask)
+}
+
+func (val Node) Next() uintptr {
+ if val.Type() != KObject && val.Type() != KArray {
+ return PtrOffset(val.cptr, 1)
+ }
+ cobj := ptrCast(val.cptr)
+ offset := int64(uint64(cobj.val) >> ConLenBits)
+ return PtrOffset(val.cptr, offset)
+}
+
+func (val *Node) next() {
+ *val = NewNode(val.Next())
+}
+
+type NodeIter struct {
+ next uintptr
+}
+
+func NewNodeIter(node Node) NodeIter {
+ return NodeIter{next: node.cptr}
+}
+
+func (iter *NodeIter) Next() Node {
+ ret := NewNode(iter.next)
+ iter.next = PtrOffset(iter.next, 1)
+ return ret
+}
+
+
+func (iter *NodeIter) Peek() Node {
+ return NewNode(iter.next)
+}
+
+func (val Node) U64() uint64 {
+ cnum := ptrCast(val.cptr)
+ return *(*uint64)((unsafe.Pointer)(&(cnum.val)))
+}
+
+func (val Node) I64() int64 {
+ cnum := ptrCast(val.cptr)
+ return *(*int64)((unsafe.Pointer)(&(cnum.val)))
+}
+
+func (val Node) IsNull() bool {
+ return val.Type() == KNull
+}
+
+func (val Node) IsNumber() bool {
+ return val.Type() & KNumber != 0
+}
+
+func (val Node) F64() float64 {
+ cnum := ptrCast(val.cptr)
+ return *(*float64)((unsafe.Pointer)(&(cnum.val)))
+}
+
+func (val Node) Bool() bool {
+ return val.Type() == KTrue
+}
+
+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
+ }
+}
+
+func (val *Node) AsObj() (Object, bool) {
+ var ret Object
+ if val.Type() != KObject {
+ return ret, false
+ }
+ return Object{
+ cptr: val.cptr,
+ }, true
+}
+
+func (val Node) Obj() Object {
+ return Object{cptr: val.cptr}
+}
+
+func (val Node) Arr() Array {
+ return Array{cptr: val.cptr}
+}
+
+func (val *Node) AsArr() (Array, bool) {
+ var ret Array
+ if val.Type() != KArray {
+ return ret, false
+ }
+ return Array{
+ cptr: val.cptr,
+ }, true
+}
+
+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
+ }
+}
+
+/********* Parse Node String into Value ***************/
+
+func (val Node) ParseI64(ctx *Context) (int64, bool) {
+ s, ok := val.AsStrRef(ctx)
+ if !ok {
+ return 0, false
+ }
+
+ if s == "null" {
+ return 0, true
+ }
+
+ i, err := ParseI64(s)
+ if err != nil {
+ return 0, false
+ }
+ return i, true
+}
+
+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, false
+ }
+ return b, true
+}
+
+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, false
+ }
+ return i, true
+}
+
+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, false
+ }
+ return i, true
+}
+
+func (val Node) ParseString(ctx *Context) (string, bool) {
+ // shoud not use AsStrRef
+ s, ok := val.AsStr(ctx)
+ if !ok {
+ return "", false
+ }
+
+ if s == "null" {
+ return "", true
+ }
+
+ s, err := Unquote(s)
+ if err != nil {
+ return "", false
+ }
+ return s, true
+}
+
+
+func (val Node) ParseNumber(ctx *Context) (json.Number, bool) {
+ // shoud not use AsStrRef
+ s, ok := val.AsStr(ctx)
+ if !ok {
+ return json.Number(""), false
+ }
+
+ if s == "null" {
+ return json.Number(""), true
+ }
+
+ end, ok := SkipNumberFast(s, 0)
+ // has error or trailing chars
+ if !ok || 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
+ }
+}
+
+func (val Node) AsStr(ctx *Context) (string, bool) {
+ switch val.Type() {
+ case KStringCommon:
+ s := val.StringRef(ctx)
+ if (ctx.Options() & (1 << _F_copy_string) == 0) {
+ return s, true
+ }
+ return string(rt.Str2Mem(s)), true
+ case KStringEscaped:
+ return val.StringCopyEsc(ctx), true
+ default: return "", false
+ }
+}
+
+func (val Node) AsStrRef(ctx *Context) (string, bool) {
+ switch val.Type() {
+ case KStringEscaped:
+ node := ptrCast(val.cptr)
+ offset := val.Position()
+ len := int(node.val)
+ return rt.Mem2Str(ctx.Parser.JsonBytes()[offset : offset + len]), true
+ case KStringCommon:
+ return val.StringRef(ctx), true
+ default:
+ return "", false
+ }
+}
+
+func (val Node) AsBytesRef(ctx *Context) ([]byte, bool) {
+ switch val.Type() {
+ case KStringEscaped:
+ node := ptrCast(val.cptr)
+ offset := val.Position()
+ len := int(node.val)
+ return ctx.Parser.JsonBytes()[offset : offset + len], true
+ case KStringCommon:
+ return rt.Str2Mem(val.StringRef(ctx)), true
+ default:
+ return nil, false
+ }
+}
+
+func (val Node) AsStringText(ctx *Context) ([]byte, bool) {
+ if !val.IsStr() {
+ return nil, false
+ }
+
+ // clone to new bytes
+ s, b := val.AsStrRef(ctx)
+ return []byte(s), b
+}
+
+func (val Node) IsStr() bool {
+ return (val.Type() == KStringCommon) || (val.Type() == KStringEscaped)
+}
+
+func (val Node) IsRawNumber() bool {
+ return val.Type() == KRawNumber
+}
+
+func (val Node) Number(ctx *Context) json.Number {
+ return json.Number(val.Raw(ctx))
+}
+
+func (val Node) Raw(ctx *Context) string {
+ node := ptrCast(val.cptr)
+ len := int(node.val)
+ offset := val.Position()
+ return ctx.Parser.Json[offset:int(offset+len)]
+}
+
+func (val Node) Position() int {
+ node := ptrCast(val.cptr)
+ return int(node.typ >> PosBits)
+}
+
+func (val Node) AsNumber(ctx *Context) (json.Number, bool) {
+ // parse JSON string as number
+ if val.IsStr() {
+ s, _ := val.AsStr(ctx)
+ if !ValidNumberFast(s) {
+ return "", false
+ } else {
+ return json.Number(s), true
+ }
+ }
+
+ return val.NonstrAsNumber(ctx)
+}
+
+func (val Node) NonstrAsNumber(ctx *Context) (json.Number, bool) {
+ // deal with raw number
+ if val.IsRawNumber() {
+ return val.Number(ctx), true
+ }
+
+ // deal with parse number
+ if !val.IsNumber() {
+ return json.Number(""), false
+ }
+
+ start := val.Position()
+ end, ok := SkipNumberFast(ctx.Parser.Json, start)
+ if !ok {
+ return "", false
+ }
+ return json.Number(ctx.Parser.Json[start:end]), true
+}
+
+func (val Node) AsRaw(ctx *Context) string {
+ // fast path for unescaped strings
+ switch val.Type() {
+ case KNull:
+ return "null"
+ case KTrue:
+ return "true"
+ case KFalse:
+ return "false"
+ case KStringCommon:
+ node := ptrCast(val.cptr)
+ len := int(node.val)
+ offset := val.Position()
+ // add start abd end quote
+ ref := rt.Str2Mem(ctx.Parser.Json)[offset-1 : offset+len+1]
+ return rt.Mem2Str(ref)
+ case KRawNumber: fallthrough
+ case KRaw: return val.Raw(ctx)
+ case KStringEscaped:
+ raw, _ := SkipOneFast(ctx.Parser.Json, val.Position() - 1)
+ return raw
+ default:
+ raw, err := SkipOneFast(ctx.Parser.Json, val.Position())
+ if err != nil {
+ break
+ }
+ return raw
+ }
+ panic("should always be valid json here")
+}
+
+// reference from the input JSON as possible
+func (val Node) StringRef(ctx *Context) string {
+ return val.Raw(ctx)
+}
+
+//go:nocheckptr
+func ptrCast(p uintptr) *node {
+ return (*node)(unsafe.Pointer(p))
+}
+
+func (val Node) StringCopyEsc(ctx *Context) string {
+ // check whether there are in padded
+ node := ptrCast(val.cptr)
+ len := int(node.val)
+ offset := val.Position()
+ return string(ctx.Parser.JsonBytes()[offset : offset + len])
+}
+
+func (val Node) Object() Object {
+ return Object{cptr: val.cptr}
+}
+
+func (val Node) Array() Array {
+ return Array{cptr: val.cptr}
+}
+
+func (val *Array) Children() uintptr {
+ return PtrOffset(val.cptr, 1)
+}
+
+func (val *Object) Children() uintptr {
+ return PtrOffset(val.cptr, 1)
+}
+
+func (val *Node) Equal(ctx *Context, lhs string) bool {
+ // check whether escaped
+ cstr := ptrCast(val.cptr)
+ offset := int(val.Position())
+ len := int(cstr.val)
+ return lhs == ctx.Parser.Json[offset:offset+len]
+}
+
+func (node *Node) AsMapEface(ctx *Context, vp unsafe.Pointer) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ obj, ok := node.AsObj()
+ if !ok {
+ return newUnmatched(node.Position(), rt.MapEfaceType)
+ }
+
+ var err, gerr error
+ size := obj.Len()
+
+ var m map[string]interface{}
+ if *(*unsafe.Pointer)(vp) == nil {
+ if ctx.efacePool != nil {
+ p := ctx.efacePool.GetMap(size)
+ m = *(*map[string]interface{})(unsafe.Pointer(&p))
+ } else {
+ m = make(map[string]interface{}, size)
+ }
+ } else {
+ m = *(*map[string]interface{})(vp)
+ }
+
+ next := obj.Children()
+ for i := 0; i < size; i++ {
+ knode := NewNode(next)
+ key, _ := knode.AsStr(ctx)
+ val := NewNode(PtrOffset(next, 1))
+ m[key], err = val.AsEface(ctx)
+ next = val.cptr
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+ }
+
+ *(*map[string]interface{})(vp) = m
+ return gerr
+}
+
+func (node *Node) AsMapString(ctx *Context, vp unsafe.Pointer) error {
+ obj, ok := node.AsObj()
+ if !ok {
+ return newUnmatched(node.Position(), rt.MapStringType)
+ }
+
+ size := obj.Len()
+
+ var m map[string]string
+ if *(*unsafe.Pointer)(vp) == nil {
+ m = make(map[string]string, size)
+ } else {
+ m = *(*map[string]string)(vp)
+ }
+
+ var gerr error
+ next := obj.Children()
+ for i := 0; i < size; i++ {
+ knode := NewNode(next)
+ key, _ := knode.AsStr(ctx)
+ val := NewNode(PtrOffset(next, 1))
+ m[key], ok = val.AsStr(ctx)
+ if !ok {
+ if gerr == nil {
+ gerr = newUnmatched(val.Position(), rt.StringType)
+ }
+ next = val.Next()
+ } else {
+ next = PtrOffset(val.cptr, 1)
+ }
+ }
+
+ *(*map[string]string)(vp) = m
+ return gerr
+}
+
+func (node *Node) AsSliceEface(ctx *Context, vp unsafe.Pointer) error {
+ arr, ok := node.AsArr()
+ if !ok {
+ return newUnmatched(node.Position(), rt.SliceEfaceType)
+ }
+
+ size := arr.Len()
+ var s []interface{}
+ if size != 0 && ctx.efacePool != nil {
+ slice := rt.GoSlice {
+ Ptr: ctx.efacePool.GetSlice(size),
+ Len: size,
+ Cap: size,
+ }
+ *(*rt.GoSlice)(unsafe.Pointer(&s)) = slice
+ } else {
+ s = *(*[]interface{})((unsafe.Pointer)(rt.MakeSlice(vp, rt.AnyType, size)))
+ }
+
+ *node = NewNode(arr.Children())
+
+ var err, gerr error
+ for i := 0; i < size; i++ {
+ s[i], err = node.AsEface(ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+ }
+
+ *(*[]interface{})(vp) = s
+ return nil
+}
+
+func (node *Node) AsSliceI32(ctx *Context, vp unsafe.Pointer) error {
+ arr, ok := node.AsArr()
+ if !ok {
+ return newUnmatched(node.Position(), rt.SliceI32Type)
+ }
+
+ size := arr.Len()
+ s := *(*[]int32)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Int32Type, size)))
+ next := arr.Children()
+
+ var gerr error
+ for i := 0; i < size; i++ {
+ val := NewNode(next)
+ ret, ok := val.AsI64(ctx)
+ if !ok || ret > math.MaxInt32 || ret < math.MinInt32 {
+ if gerr == nil {
+ gerr = newUnmatched(val.Position(), rt.Int32Type)
+ }
+ next = val.Next()
+ } else {
+ s[i] = int32(ret)
+ next = PtrOffset(val.cptr, 1)
+ }
+ }
+
+ *(*[]int32)(vp) = s
+ return gerr
+}
+
+func (node *Node) AsSliceI64(ctx *Context, vp unsafe.Pointer) error {
+ arr, ok := node.AsArr()
+ if !ok {
+ return newUnmatched(node.Position(), rt.SliceI64Type)
+ }
+
+ size := arr.Len()
+ s := *(*[]int64)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Int64Type, size)))
+ next := arr.Children()
+
+ var gerr error
+ for i := 0; i < size; i++ {
+ val := NewNode(next)
+
+ ret, ok := val.AsI64(ctx)
+ if !ok {
+ if gerr == nil {
+ gerr = newUnmatched(val.Position(), rt.Int64Type)
+ }
+ next = val.Next()
+ } else {
+ s[i] = ret
+ next = PtrOffset(val.cptr, 1)
+ }
+ }
+
+ *(*[]int64)(vp) = s
+ return gerr
+}
+
+func (node *Node) AsSliceU32(ctx *Context, vp unsafe.Pointer) error {
+ arr, ok := node.AsArr()
+ if !ok {
+ return newUnmatched(node.Position(), rt.SliceU32Type)
+ }
+
+ size := arr.Len()
+ next := arr.Children()
+ s := *(*[]uint32)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Uint32Type, size)))
+
+ var gerr error
+ for i := 0; i < size; i++ {
+ val := NewNode(next)
+ ret, ok := val.AsU64(ctx)
+ if !ok || ret > math.MaxUint32 {
+ if gerr == nil {
+ gerr = newUnmatched(val.Position(), rt.Uint32Type)
+ }
+ next = val.Next()
+ } else {
+ s[i] = uint32(ret)
+ next = PtrOffset(val.cptr, 1)
+ }
+ }
+
+ *(*[]uint32)(vp) = s
+ return gerr
+}
+
+func (node *Node) AsSliceU64(ctx *Context, vp unsafe.Pointer) error {
+ arr, ok := node.AsArr()
+ if !ok {
+ return newUnmatched(node.Position(), rt.SliceU64Type)
+ }
+
+ size := arr.Len()
+ next := arr.Children()
+
+ s := *(*[]uint64)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Uint64Type, size)))
+ var gerr error
+ for i := 0; i < size; i++ {
+ val := NewNode(next)
+ ret, ok := val.AsU64(ctx)
+ if !ok {
+ if gerr == nil {
+ gerr = newUnmatched(val.Position(), rt.Uint64Type)
+ }
+ next = val.Next()
+ } else {
+ s[i] = ret
+ next = PtrOffset(val.cptr, 1)
+ }
+ }
+
+ *(*[]uint64)(vp) = s
+ return gerr
+}
+
+func (node *Node) AsSliceString(ctx *Context, vp unsafe.Pointer) error {
+ arr, ok := node.AsArr()
+ if !ok {
+ return newUnmatched(node.Position(), rt.SliceStringType)
+ }
+
+ size := arr.Len()
+ next := arr.Children()
+ s := *(*[]string)((unsafe.Pointer)(rt.MakeSlice(vp, rt.StringType, size)))
+
+ var gerr error
+ for i := 0; i < size; i++ {
+ val := NewNode(next)
+ ret, ok := val.AsStr(ctx)
+ if !ok {
+ if gerr == nil {
+ gerr = newUnmatched(val.Position(), rt.StringType)
+ }
+ next = val.Next()
+ } else {
+ s[i] = ret
+ next = PtrOffset(val.cptr, 1)
+ }
+ }
+
+ *(*[]string)(vp) = s
+ return gerr
+}
+
+func (node *Node) AsSliceBytes(ctx *Context) ([]byte, error) {
+ b, ok := node.AsBytesRef(ctx)
+ if !ok {
+ return nil, newUnmatched(node.Position(), rt.BytesType)
+ }
+
+ b64, err := rt.DecodeBase64(b)
+ if err != nil {
+ return nil, newUnmatched(node.Position(), rt.BytesType)
+ }
+ return b64, nil
+}
+
+// AsEface will always ok, because we have parse in native.
+func (node *Node) AsEface(ctx *Context) (interface{}, error) {
+ if ctx.efacePool != nil {
+ iter := NewNodeIter(*node)
+ v := AsEfaceFast(&iter, ctx)
+ *node = iter.Peek()
+ return v, nil
+ } else {
+ return node.AsEfaceFallback(ctx)
+ }
+}
+
+func parseSingleNode(node Node, ctx *Context) interface{} {
+ var v interface{}
+ switch node.Type() {
+ case KObject: v = map[string]interface{}{}
+ case KArray: v = []interface{}{}
+ case KStringCommon: v = node.StringRef(ctx)
+ case KStringEscaped: v = node.StringCopyEsc(ctx)
+ case KTrue: v = true
+ case KFalse: v = false
+ case KNull: v = nil
+ case KUint: v = float64(node.U64())
+ case KSint: v = float64(node.I64())
+ case KReal: v = float64(node.F64())
+ case KRawNumber: v = node.Number(ctx)
+ default: panic("unreachable for as eface")
+ }
+ return v
+}
+
+func castU64(val float64) uint64 {
+ return *((*uint64)(unsafe.Pointer((&val))))
+}
+
+func AsEfaceFast(iter *NodeIter, ctx *Context) interface{} {
+ var mp, sp, parent unsafe.Pointer // current container pointer
+ var node Node
+ var size int
+ var isObj bool
+ var slice rt.GoSlice
+ var val unsafe.Pointer
+ var vt **rt.GoType
+ var vp *unsafe.Pointer
+ var rootM unsafe.Pointer
+ var rootS rt.GoSlice
+ var root interface{}
+ var key string
+
+ node = iter.Next()
+
+ switch node.Type() {
+ case KObject:
+ size = node.Object().Len()
+ if size != 0 {
+ ctx.Stack.Push(nil, 0, true)
+ mp = ctx.efacePool.GetMap(size)
+ rootM = mp
+ isObj = true
+ goto _object_key
+ } else {
+ return rt.GoEface {
+ Type: rt.MapEfaceType,
+ Value: ctx.efacePool.GetMap(0),
+ }.Pack()
+ }
+ case KArray:
+ size = node.Array().Len()
+ if size != 0 {
+ ctx.Stack.Push(nil, 0, false)
+ sp = ctx.efacePool.GetSlice(size)
+ slice = rt.GoSlice {
+ Ptr: sp,
+ Len: size,
+ Cap: size,
+ }
+ rootS = slice
+ isObj = false
+ val = sp
+ goto _arr_val;
+ } else {
+ ctx.efacePool.ConvTSlice(rt.EmptySlice, rt.SliceEfaceType, unsafe.Pointer(&root))
+ }
+ case KStringCommon: ctx.efacePool.ConvTstring(node.StringRef(ctx), unsafe.Pointer(&root))
+ case KStringEscaped: ctx.efacePool.ConvTstring(node.StringCopyEsc(ctx), unsafe.Pointer(&root))
+ case KTrue: root = true
+ case KFalse: root = false
+ case KNull: root = nil
+ case KUint: ctx.efacePool.ConvF64(float64(node.U64()), unsafe.Pointer(&root))
+ case KSint: ctx.efacePool.ConvF64(float64(node.I64()), unsafe.Pointer(&root))
+ case KReal: ctx.efacePool.ConvF64(node.F64(), unsafe.Pointer(&root))
+ case KRawNumber: ctx.efacePool.ConvTnum(node.Number(ctx), unsafe.Pointer(&root))
+ default: panic("unreachable for as eface")
+ }
+ return root
+
+_object_key:
+ node = iter.Next()
+ if node.Type() == KStringCommon {
+ key = node.StringRef(ctx)
+ } else {
+ key = node.StringCopyEsc(ctx)
+ }
+
+ // interface{} slot in map bucket
+ val = rt.Mapassign_faststr(rt.MapEfaceMapType, mp, key)
+ vt = &(*rt.GoEface)(val).Type
+ vp = &(*rt.GoEface)(val).Value
+
+ // parse value node
+ node = iter.Next()
+ switch node.Type() {
+ case KObject:
+ newSize := node.Object().Len()
+ newMp := ctx.efacePool.GetMap(newSize)
+ *vt = rt.MapEfaceType
+ *vp = newMp
+ remain := size - 1
+ isObj = true
+ if newSize != 0 {
+ if remain > 0 {
+ ctx.Stack.Push(mp, remain, true)
+ }
+ mp = newMp
+ size = newSize
+ goto _object_key;
+ }
+ case KArray:
+ newSize := node.Array().Len()
+ if newSize == 0 {
+ ctx.efacePool.ConvTSlice(rt.EmptySlice, rt.SliceEfaceType, val)
+ break;
+ }
+
+ newSp := ctx.efacePool.GetSlice(newSize)
+ // pack to []interface{}
+ ctx.efacePool.ConvTSlice(rt.GoSlice{
+ Ptr: newSp,
+ Len: newSize,
+ Cap: newSize,
+ }, rt.SliceEfaceType, val)
+ remain := size - 1
+ if remain > 0 {
+ ctx.Stack.Push(mp, remain, true)
+ }
+ val = newSp
+ isObj = false
+ size = newSize
+ goto _arr_val;
+ case KStringCommon:
+ ctx.efacePool.ConvTstring(node.StringRef(ctx), val)
+ case KStringEscaped:
+ ctx.efacePool.ConvTstring(node.StringCopyEsc(ctx), val)
+ case KTrue:
+ rt.ConvTBool(true, (*interface{})(val))
+ case KFalse:
+ rt.ConvTBool(false, (*interface{})(val))
+ case KNull: /* skip */
+ case KUint:
+ ctx.efacePool.ConvF64(float64(node.U64()), val)
+ case KSint:
+ ctx.efacePool.ConvF64(float64(node.I64()), val)
+ case KReal:
+ ctx.efacePool.ConvF64(node.F64(), val)
+ case KRawNumber:
+ ctx.efacePool.ConvTnum(node.Number(ctx), val)
+ default:
+ panic("unreachable for as eface")
+ }
+
+ // check size
+ size -= 1
+ if size != 0 {
+ goto _object_key;
+ }
+
+ parent, size, isObj = ctx.Stack.Pop()
+
+ // parent is empty
+ if parent == nil {
+ if isObj {
+ return rt.GoEface {
+ Type: rt.MapEfaceType,
+ Value: rootM,
+ }.Pack()
+ } else {
+ ctx.efacePool.ConvTSlice(rootS, rt.SliceEfaceType, (unsafe.Pointer)(&root))
+ return root
+ }
+ }
+
+ // continue to parse parent
+ if isObj {
+ mp = parent
+ goto _object_key;
+ } else {
+ val = rt.PtrAdd(parent, rt.AnyType.Size)
+ goto _arr_val;
+ }
+
+_arr_val:
+ // interface{} slot in slice
+ vt = &(*rt.GoEface)(val).Type
+ vp = &(*rt.GoEface)(val).Value
+
+ // parse value node
+ node = iter.Next()
+ switch node.Type() {
+ case KObject:
+ newSize := node.Object().Len()
+ newMp := ctx.efacePool.GetMap(newSize)
+ *vt = rt.MapEfaceType
+ *vp = newMp
+ remain := size - 1
+ if newSize != 0 {
+ // push next array elem into stack
+ if remain > 0 {
+ ctx.Stack.Push(val, remain, false)
+ }
+ mp = newMp
+ size = newSize
+ isObj = true
+ goto _object_key;
+ }
+ case KArray:
+ newSize := node.Array().Len()
+ if newSize == 0 {
+ ctx.efacePool.ConvTSlice(rt.EmptySlice, rt.SliceEfaceType, val)
+ break;
+ }
+
+ newSp := ctx.efacePool.GetSlice(newSize)
+ // pack to []interface{}
+ ctx.efacePool.ConvTSlice(rt.GoSlice {
+ Ptr: newSp,
+ Len: newSize,
+ Cap: newSize,
+ }, rt.SliceEfaceType, val)
+
+ remain := size - 1
+ if remain > 0 {
+ ctx.Stack.Push(val, remain, false)
+ }
+
+ val = newSp
+ isObj = false
+ size = newSize
+ goto _arr_val;
+ case KStringCommon:
+ ctx.efacePool.ConvTstring(node.StringRef(ctx), val)
+ case KStringEscaped:
+ ctx.efacePool.ConvTstring(node.StringCopyEsc(ctx), val)
+ case KTrue:
+ rt.ConvTBool(true, (*interface{})(val))
+ case KFalse:
+ rt.ConvTBool(false, (*interface{})(val))
+ case KNull: /* skip */
+ case KUint:
+ ctx.efacePool.ConvF64(float64(node.U64()), val)
+ case KSint:
+ ctx.efacePool.ConvF64(float64(node.I64()), val)
+ case KReal:
+ ctx.efacePool.ConvF64(node.F64(), val)
+ case KRawNumber:
+ ctx.efacePool.ConvTnum(node.Number(ctx), val)
+ default: panic("unreachable for as eface")
+ }
+
+ // check size
+ size -= 1
+ if size != 0 {
+ val = rt.PtrAdd(val, rt.AnyType.Size)
+ goto _arr_val;
+ }
+
+
+ parent, size, isObj = ctx.Stack.Pop()
+
+ // parent is empty
+ if parent == nil {
+ if isObj {
+ return rt.GoEface {
+ Type: rt.MapEfaceType,
+ Value: rootM,
+ }.Pack()
+ } else {
+ ctx.efacePool.ConvTSlice(rootS, rt.SliceEfaceType, unsafe.Pointer(&root))
+ return root
+ }
+ }
+
+ // continue to parse parent
+ if isObj {
+ mp = parent
+ goto _object_key;
+ } else {
+ val = rt.PtrAdd(parent, rt.AnyType.Size)
+ goto _arr_val;
+ }
+}
+
+func (node *Node) AsEfaceFallback(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 gerr, err error
+ for i := 0; i < size; i++ {
+ key, _ := node.AsStr(ctx)
+ *node = NewNode(PtrOffset(node.cptr, 1))
+ m[key], err = node.AsEfaceFallback(ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+ }
+ return m, gerr
+ case KArray:
+ arr := node.Array()
+ size := arr.Len()
+ a := make([]interface{}, size)
+ *node = NewNode(arr.Children())
+ var gerr, err error
+ for i := 0; i < size; i++ {
+ a[i], err = node.AsEfaceFallback(ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+ }
+ return a, gerr
+ case KStringCommon:
+ str, _ := node.AsStr(ctx)
+ *node = NewNode(PtrOffset(node.cptr, 1))
+ return str, nil
+ case KStringEscaped:
+ str := node.StringCopyEsc(ctx)
+ *node = NewNode(PtrOffset(node.cptr, 1))
+ return str, nil
+ case KTrue:
+ *node = NewNode(PtrOffset(node.cptr, 1))
+ return true, nil
+ case KFalse:
+ *node = NewNode(PtrOffset(node.cptr, 1))
+ return false, nil
+ case KNull:
+ *node = NewNode(PtrOffset(node.cptr, 1))
+ return nil, nil
+ default:
+ // use float64
+ if ctx.Parser.options & (1 << _F_use_number) != 0 {
+ num, ok := node.AsNumber(ctx)
+ if !ok {
+ // skip the unmacthed type
+ *node = NewNode(node.Next())
+ return nil, newUnmatched(node.Position(), rt.JsonNumberType)
+ } else {
+ *node = NewNode(PtrOffset(node.cptr, 1))
+ return num, nil
+ }
+ } else if ctx.Parser.options & (1 << _F_use_int64) != 0 {
+ // first try int64
+ i, ok := node.AsI64(ctx)
+ if ok {
+ *node = NewNode(PtrOffset(node.cptr, 1))
+ return i, nil
+ }
+
+ // is not integer, then use float64
+ f, ok := node.AsF64(ctx)
+ if ok {
+ *node = NewNode(PtrOffset(node.cptr, 1))
+ return f, nil
+ }
+
+ // skip the unmacthed type
+ *node = NewNode(node.Next())
+ return nil, newUnmatched(node.Position(), rt.Int64Type)
+ } else {
+ num, ok := node.AsF64(ctx)
+ if !ok {
+ // skip the unmacthed type
+ *node = NewNode(node.Next())
+ return nil, newUnmatched(node.Position(), rt.Float64Type)
+ } else {
+ *node = NewNode(PtrOffset(node.cptr, 1))
+ return num, nil
+ }
+ }
+ }
+}
+
+//go:nosplit
+func PtrOffset(ptr uintptr, off int64) uintptr {
+ return uintptr(int64(ptr) + off * int64(unsafe.Sizeof(node{})))
+}
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go
new file mode 100644
index 000000000..a94e422b3
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go
@@ -0,0 +1,224 @@
+package optdec
+
+import (
+ "reflect"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/rt"
+)
+
+type sliceDecoder struct {
+ elemType *rt.GoType
+ elemDec decFunc
+ typ reflect.Type
+}
+
+var (
+ emptyPtr = &struct{}{}
+)
+
+func (d *sliceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*rt.GoSlice)(vp) = rt.GoSlice{}
+ return nil
+ }
+
+ arr, ok := node.AsArr()
+ if !ok {
+ return error_mismatch(node, ctx, d.typ)
+ }
+
+ slice := rt.MakeSlice(vp, d.elemType, arr.Len())
+ elems := slice.Ptr
+ next := arr.Children()
+
+ var gerr error
+ for i := 0; i < arr.Len(); i++ {
+ val := NewNode(next)
+ elem := unsafe.Pointer(uintptr(elems) + uintptr(i)*d.elemType.Size)
+ err := d.elemDec.FromDom(elem, val, ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+ next = val.Next()
+ }
+
+ *(*rt.GoSlice)(vp) = *slice
+ return gerr
+}
+
+type arrayDecoder struct {
+ len int
+ elemType *rt.GoType
+ elemDec decFunc
+ typ reflect.Type
+}
+
+//go:nocheckptr
+func (d *arrayDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ 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 := NewNode(next)
+ err := d.elemDec.FromDom(elem, val, ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+ next = val.Next()
+ }
+
+ /* zero rest of array */
+ ptr := unsafe.Pointer(uintptr(vp) + uintptr(i)*d.elemType.Size)
+ n := uintptr(d.len-i) * d.elemType.Size
+ rt.ClearMemory(d.elemType, ptr, n)
+ return gerr
+}
+
+type sliceEfaceDecoder struct {
+}
+
+func (d *sliceEfaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*rt.GoSlice)(vp) = rt.GoSlice{}
+ return nil
+ }
+
+ return node.AsSliceEface(ctx, vp)
+}
+
+type sliceI32Decoder struct {
+}
+
+func (d *sliceI32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*rt.GoSlice)(vp) = rt.GoSlice{}
+ return nil
+ }
+
+ return node.AsSliceI32(ctx, vp)
+}
+
+type sliceI64Decoder struct {
+}
+
+func (d *sliceI64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*rt.GoSlice)(vp) = rt.GoSlice{}
+ return nil
+ }
+
+ return node.AsSliceI64(ctx, vp)
+}
+
+type sliceU32Decoder struct {
+}
+
+func (d *sliceU32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*rt.GoSlice)(vp) = rt.GoSlice{}
+ return nil
+ }
+
+ return node.AsSliceU32(ctx, vp)
+}
+
+type sliceU64Decoder struct {
+}
+
+func (d *sliceU64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*rt.GoSlice)(vp) = rt.GoSlice{}
+ return nil
+ }
+
+ return node.AsSliceU64(ctx, vp)
+}
+
+type sliceStringDecoder struct {
+}
+
+func (d *sliceStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*rt.GoSlice)(vp) = rt.GoSlice{}
+ return nil
+ }
+
+ return node.AsSliceString(ctx, vp)
+}
+
+type sliceBytesDecoder struct {
+}
+
+func (d *sliceBytesDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*rt.GoSlice)(vp) = rt.GoSlice{}
+ return nil
+ }
+
+ s, err := node.AsSliceBytes(ctx)
+ if err != nil {
+ return err
+ }
+
+ *(*[]byte)(vp) = s
+ return nil
+}
+
+type sliceBytesUnmarshalerDecoder struct {
+ elemType *rt.GoType
+ elemDec decFunc
+ typ reflect.Type
+}
+
+func (d *sliceBytesUnmarshalerDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*rt.GoSlice)(vp) = rt.GoSlice{}
+ return nil
+ }
+
+ /* parse JSON string into `[]byte` */
+ if node.IsStr() {
+ slice, err := node.AsSliceBytes(ctx)
+ if err != nil {
+ return err
+ }
+ *(*[]byte)(vp) = slice
+ return nil
+ }
+
+ /* parse JSON array into `[]byte` */
+ arr, ok := node.AsArr()
+ if !ok {
+ return error_mismatch(node, ctx, d.typ)
+ }
+
+ slice := rt.MakeSlice(vp, d.elemType, arr.Len())
+ elems := slice.Ptr
+
+ var gerr error
+ next := arr.Children()
+ for i := 0; i < arr.Len(); i++ {
+ child := NewNode(next)
+ elem := unsafe.Pointer(uintptr(elems) + uintptr(i)*d.elemType.Size)
+ err := d.elemDec.FromDom(elem, child, ctx)
+ if gerr == nil && err != nil {
+ gerr = err
+ }
+ next = child.Next()
+ }
+
+ *(*rt.GoSlice)(vp) = *slice
+ return gerr
+}
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go
new file mode 100644
index 000000000..5af8c97e2
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go
@@ -0,0 +1,360 @@
+package optdec
+
+import (
+ "encoding/json"
+ "math"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/rt"
+)
+
+type ptrStrDecoder struct {
+ typ *rt.GoType
+ deref decFunc
+}
+
+// Pointer Value is allocated in the Caller
+func (d *ptrStrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ *(*unsafe.Pointer)(vp) = nil
+ return nil
+ }
+
+ s, ok := node.AsStrRef(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, stringType)
+ }
+
+ if s == "null" {
+ *(*unsafe.Pointer)(vp) = nil
+ return nil
+ }
+
+ if *(*unsafe.Pointer)(vp) == nil {
+ *(*unsafe.Pointer)(vp) = rt.Mallocgc(d.typ.Size, d.typ, true)
+ }
+
+ return d.deref.FromDom(*(*unsafe.Pointer)(vp), node, ctx)
+}
+
+type boolStringDecoder struct {
+}
+
+func (d *boolStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ s, ok := node.AsStrRef(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, stringType)
+ }
+
+ if s == "null" {
+ return nil
+ }
+
+ b, err := ParseBool(s)
+ if err != nil {
+ return error_mismatch(node, ctx, boolType)
+ }
+
+ *(*bool)(vp) = b
+ return nil
+}
+
+func parseI64(node Node, ctx *context) (int64, error, bool) {
+ if node.IsNull() {
+ return 0, nil, true
+ }
+
+ s, ok := node.AsStrRef(ctx)
+ if !ok {
+ return 0, error_mismatch(node, ctx, stringType), false
+ }
+
+ if s == "null" {
+ return 0, nil, true
+ }
+
+ ret, err := ParseI64(s)
+ return ret, err, false
+}
+
+type i8StringDecoder struct{}
+
+func (d *i8StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ ret, err, null := parseI64(node, ctx)
+ if null {
+ return nil
+ }
+
+ if err != nil {
+ return err
+ }
+
+ if ret > math.MaxInt8 || ret < math.MinInt8 {
+ return error_mismatch(node, ctx, int8Type)
+ }
+
+ *(*int8)(vp) = int8(ret)
+ return nil
+}
+
+type i16StringDecoder struct{}
+
+func (d *i16StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ ret, err, null := parseI64(node, ctx)
+ if null {
+ return nil
+ }
+
+ if err != nil {
+ return err
+ }
+
+ if ret > math.MaxInt16 || ret < math.MinInt16 {
+ return error_mismatch(node, ctx, int16Type)
+ }
+
+ *(*int16)(vp) = int16(ret)
+ return nil
+}
+
+type i32StringDecoder struct{}
+
+func (d *i32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ ret, err, null := parseI64(node, ctx)
+ if null {
+ return nil
+ }
+
+ if err != nil {
+ return err
+ }
+
+ if ret > math.MaxInt32 || ret < math.MinInt32 {
+ return error_mismatch(node, ctx, int32Type)
+ }
+
+ *(*int32)(vp) = int32(ret)
+ return nil
+}
+
+type i64StringDecoder struct{}
+
+func (d *i64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ ret, err, null := parseI64(node, ctx)
+ if null {
+ return nil
+ }
+
+ if err != nil {
+ return err
+ }
+
+ *(*int64)(vp) = int64(ret)
+ return nil
+}
+
+func parseU64(node Node, ctx *context) (uint64, error, bool) {
+ if node.IsNull() {
+ return 0, nil, true
+ }
+
+ s, ok := node.AsStrRef(ctx)
+ if !ok {
+ return 0, error_mismatch(node, ctx, stringType), false
+ }
+
+ if s == "null" {
+ return 0, nil, true
+ }
+
+ ret, err := ParseU64(s)
+ return ret, err, false
+}
+
+type u8StringDecoder struct{}
+
+func (d *u8StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ ret, err, null := parseU64(node, ctx)
+ if null {
+ return nil
+ }
+
+ if err != nil {
+ return err
+ }
+
+ if ret > math.MaxUint8 {
+ return error_mismatch(node, ctx, uint8Type)
+ }
+
+ *(*uint8)(vp) = uint8(ret)
+ return nil
+}
+
+type u16StringDecoder struct{}
+
+func (d *u16StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ ret, err, null := parseU64(node, ctx)
+ if null {
+ return nil
+ }
+
+ if err != nil {
+ return err
+ }
+
+ if ret > math.MaxUint16 {
+ return error_mismatch(node, ctx, uint16Type)
+ }
+
+ *(*uint16)(vp) = uint16(ret)
+ return nil
+}
+
+type u32StringDecoder struct{}
+
+func (d *u32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ ret, err, null := parseU64(node, ctx)
+ if null {
+ return nil
+ }
+
+ if err != nil {
+ return err
+ }
+
+ if ret > math.MaxUint32 {
+ return error_mismatch(node, ctx, uint32Type)
+ }
+
+ *(*uint32)(vp) = uint32(ret)
+ return nil
+}
+
+
+type u64StringDecoder struct{}
+
+func (d *u64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ ret, err, null := parseU64(node, ctx)
+ if null {
+ return nil
+ }
+
+ if err != nil {
+ return err
+ }
+
+ *(*uint64)(vp) = uint64(ret)
+ return nil
+}
+
+type f32StringDecoder struct{}
+
+func (d *f32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ s, ok := node.AsStrRef(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, stringType)
+ }
+
+ if s == "null" {
+ return nil
+ }
+
+ ret, err := ParseF64(s)
+ if err != nil || ret > math.MaxFloat32 || ret < -math.MaxFloat32 {
+ return error_mismatch(node, ctx, float32Type)
+ }
+
+ *(*float32)(vp) = float32(ret)
+ return nil
+}
+
+type f64StringDecoder struct{}
+
+func (d *f64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ s, ok := node.AsStrRef(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, stringType)
+ }
+
+ if s == "null" {
+ return nil
+ }
+
+ ret, err := ParseF64(s)
+ if err != nil {
+ return error_mismatch(node, ctx, float64Type)
+ }
+
+ *(*float64)(vp) = float64(ret)
+ return nil
+}
+
+/* parse string field with string options */
+type strStringDecoder struct{}
+
+func (d *strStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ s, ok := node.AsStrRef(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, stringType)
+ }
+
+ if s == "null" {
+ return nil
+ }
+
+ s, err := Unquote(s)
+ if err != nil {
+ return error_mismatch(node, ctx, stringType)
+ }
+
+ *(*string)(vp) = s
+ return nil
+}
+
+type numberStringDecoder struct{}
+
+func (d *numberStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ s, ok := node.AsStrRef(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, stringType)
+ }
+
+ if s == "null" {
+ return nil
+ }
+
+ num, ok := node.ParseNumber(ctx)
+ if !ok {
+ return error_mismatch(node, ctx, jsonNumberType)
+ }
+
+ end, ok := SkipNumberFast(s, 0)
+ // has error or trailing chars
+ if !ok || end != len(s) {
+ return error_mismatch(node, ctx, jsonNumberType)
+ }
+
+ *(*json.Number)(vp) = json.Number(num)
+ return nil
+}
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go
new file mode 100644
index 000000000..bce2758f1
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go
@@ -0,0 +1,61 @@
+package optdec
+
+import (
+ "reflect"
+ "unsafe"
+
+ caching "github.com/bytedance/sonic/internal/optcaching"
+ "github.com/bytedance/sonic/internal/resolver"
+)
+
+type fieldEntry struct {
+ resolver.FieldMeta
+ fieldDec decFunc
+}
+
+type structDecoder struct {
+ fieldMap caching.FieldLookup
+ fields []fieldEntry
+ structName string
+ typ reflect.Type
+}
+
+func (d *structDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error {
+ if node.IsNull() {
+ return nil
+ }
+
+ var gerr error
+ obj, ok := node.AsObj()
+ if !ok {
+ return error_mismatch(node, ctx, d.typ)
+ }
+
+ next := obj.Children()
+ for i := 0; i < obj.Len(); i++ {
+ key, _ := NewNode(next).AsStrRef(ctx)
+ val := NewNode(PtrOffset(next, 1))
+ next = val.Next()
+
+ // find field idx
+ idx := d.fieldMap.Get(key)
+ if idx == -1 {
+ if Options(ctx.Options())&OptionDisableUnknown != 0 {
+ return error_field(key)
+ }
+ continue
+ }
+
+ offset := d.fields[idx].Path[0].Size
+ elem := unsafe.Pointer(uintptr(vp) + offset)
+ err := d.fields[idx].fieldDec.FromDom(elem, val, ctx)
+
+ // deal with mismatch type errors
+ if gerr == nil && err != nil {
+ // TODO: better error info
+ gerr = err
+ }
+ }
+ return gerr
+}
+
diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go
new file mode 100644
index 000000000..fe1433eec
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2021 ByteDance Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package optdec
+
+import (
+ "encoding"
+ "encoding/base64"
+ "encoding/json"
+ "reflect"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/rt"
+)
+
+var (
+ boolType = reflect.TypeOf(bool(false))
+ byteType = reflect.TypeOf(byte(0))
+ intType = reflect.TypeOf(int(0))
+ int8Type = reflect.TypeOf(int8(0))
+ int16Type = reflect.TypeOf(int16(0))
+ int32Type = reflect.TypeOf(int32(0))
+ int64Type = reflect.TypeOf(int64(0))
+ uintType = reflect.TypeOf(uint(0))
+ uint8Type = reflect.TypeOf(uint8(0))
+ uint16Type = reflect.TypeOf(uint16(0))
+ uint32Type = reflect.TypeOf(uint32(0))
+ uint64Type = reflect.TypeOf(uint64(0))
+ float32Type = reflect.TypeOf(float32(0))
+ float64Type = reflect.TypeOf(float64(0))
+ stringType = reflect.TypeOf("")
+ bytesType = reflect.TypeOf([]byte(nil))
+ jsonNumberType = reflect.TypeOf(json.Number(""))
+ base64CorruptInputError = reflect.TypeOf(base64.CorruptInputError(0))
+ anyType = rt.UnpackType(reflect.TypeOf((*interface{})(nil)).Elem())
+)
+
+var (
+ errorType = reflect.TypeOf((*error)(nil)).Elem()
+ jsonUnmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
+ encodingTextUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
+)
+
+func rtype(t reflect.Type) (*rt.GoItab, *rt.GoType) {
+ p := (*rt.GoIface)(unsafe.Pointer(&t))
+ return p.Itab, (*rt.GoType)(p.Value)
+}