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