github.com/goccy/go-json@v0.10.3-0.20240509105655-5e2ae3f23c1d/internal/decoder/unmarshal_json.go (about)

     1  package decoder
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"unsafe"
     8  
     9  	"github.com/goccy/go-json/internal/errors"
    10  	"github.com/goccy/go-json/internal/runtime"
    11  )
    12  
    13  type unmarshalJSONDecoder struct {
    14  	typ        *runtime.Type
    15  	structName string
    16  	fieldName  string
    17  }
    18  
    19  func newUnmarshalJSONDecoder(typ *runtime.Type, structName, fieldName string) *unmarshalJSONDecoder {
    20  	return &unmarshalJSONDecoder{
    21  		typ:        typ,
    22  		structName: structName,
    23  		fieldName:  fieldName,
    24  	}
    25  }
    26  
    27  func (d *unmarshalJSONDecoder) annotateError(cursor int64, err error) {
    28  	switch e := err.(type) {
    29  	case *errors.UnmarshalTypeError:
    30  		e.Struct = d.structName
    31  		e.Field = d.fieldName
    32  	case *errors.SyntaxError:
    33  		e.Offset = cursor
    34  	}
    35  }
    36  
    37  func (d *unmarshalJSONDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
    38  	s.skipWhiteSpace()
    39  	start := s.cursor
    40  	if err := s.skipValue(depth); err != nil {
    41  		return err
    42  	}
    43  	src := s.buf[start:s.cursor]
    44  	dst := make([]byte, len(src))
    45  	copy(dst, src)
    46  
    47  	v := *(*interface{})(unsafe.Pointer(&emptyInterface{
    48  		typ: d.typ,
    49  		ptr: p,
    50  	}))
    51  	switch v := v.(type) {
    52  	case unmarshalerContext:
    53  		var ctx context.Context
    54  		if (s.Option.Flags & ContextOption) != 0 {
    55  			ctx = s.Option.Context
    56  		} else {
    57  			ctx = context.Background()
    58  		}
    59  		if err := v.UnmarshalJSON(ctx, dst); err != nil {
    60  			d.annotateError(s.cursor, err)
    61  			return err
    62  		}
    63  	case json.Unmarshaler:
    64  		if err := v.UnmarshalJSON(dst); err != nil {
    65  			d.annotateError(s.cursor, err)
    66  			return err
    67  		}
    68  	}
    69  	return nil
    70  }
    71  
    72  func (d *unmarshalJSONDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
    73  	buf := ctx.Buf
    74  	cursor = skipWhiteSpace(buf, cursor)
    75  	start := cursor
    76  	end, err := skipValue(buf, cursor, depth)
    77  	if err != nil {
    78  		return 0, err
    79  	}
    80  	src := buf[start:end]
    81  	dst := make([]byte, len(src))
    82  	copy(dst, src)
    83  
    84  	v := *(*interface{})(unsafe.Pointer(&emptyInterface{
    85  		typ: d.typ,
    86  		ptr: p,
    87  	}))
    88  	if (ctx.Option.Flags & ContextOption) != 0 {
    89  		if err := v.(unmarshalerContext).UnmarshalJSON(ctx.Option.Context, dst); err != nil {
    90  			d.annotateError(cursor, err)
    91  			return 0, err
    92  		}
    93  	} else {
    94  		if err := v.(json.Unmarshaler).UnmarshalJSON(dst); err != nil {
    95  			d.annotateError(cursor, err)
    96  			return 0, err
    97  		}
    98  	}
    99  	return end, nil
   100  }
   101  
   102  func (d *unmarshalJSONDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) {
   103  	return nil, 0, fmt.Errorf("json: unmarshal json decoder does not support decode path")
   104  }