[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>
This commit is contained in:
dependabot[bot]
2025-01-14 13:10:39 +00:00
committed by GitHub
parent 8cfae010a9
commit 4d423102c1
519 changed files with 156968 additions and 132058 deletions

View File

@ -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,
}
}

View File

@ -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)))
}

View File

@ -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
)

View File

@ -0,0 +1,3 @@
package optdec
type context = Context

View File

@ -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)
}

View File

@ -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,
}
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

File diff suppressed because it is too large Load Diff

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}