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