1package decoder
2
3import (
4	"bytes"
5	"unsafe"
6
7	"github.com/goccy/go-json/internal/errors"
8	"github.com/goccy/go-json/internal/runtime"
9)
10
11type funcDecoder struct {
12	typ        *runtime.Type
13	structName string
14	fieldName  string
15}
16
17func newFuncDecoder(typ *runtime.Type, structName, fieldName string) *funcDecoder {
18	fnDecoder := &funcDecoder{typ, structName, fieldName}
19	return fnDecoder
20}
21
22func (d *funcDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
23	s.skipWhiteSpace()
24	start := s.cursor
25	if err := s.skipValue(depth); err != nil {
26		return err
27	}
28	src := s.buf[start:s.cursor]
29	if len(src) > 0 {
30		switch src[0] {
31		case '"':
32			return &errors.UnmarshalTypeError{
33				Value:  "string",
34				Type:   runtime.RType2Type(d.typ),
35				Offset: s.totalOffset(),
36			}
37		case '[':
38			return &errors.UnmarshalTypeError{
39				Value:  "array",
40				Type:   runtime.RType2Type(d.typ),
41				Offset: s.totalOffset(),
42			}
43		case '{':
44			return &errors.UnmarshalTypeError{
45				Value:  "object",
46				Type:   runtime.RType2Type(d.typ),
47				Offset: s.totalOffset(),
48			}
49		case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
50			return &errors.UnmarshalTypeError{
51				Value:  "number",
52				Type:   runtime.RType2Type(d.typ),
53				Offset: s.totalOffset(),
54			}
55		case 'n':
56			if err := nullBytes(s); err != nil {
57				return err
58			}
59			*(*unsafe.Pointer)(p) = nil
60			return nil
61		case 't':
62			if err := trueBytes(s); err == nil {
63				return &errors.UnmarshalTypeError{
64					Value:  "boolean",
65					Type:   runtime.RType2Type(d.typ),
66					Offset: s.totalOffset(),
67				}
68			}
69		case 'f':
70			if err := falseBytes(s); err == nil {
71				return &errors.UnmarshalTypeError{
72					Value:  "boolean",
73					Type:   runtime.RType2Type(d.typ),
74					Offset: s.totalOffset(),
75				}
76			}
77		}
78	}
79	return errors.ErrInvalidBeginningOfValue(s.buf[s.cursor], s.totalOffset())
80}
81
82func (d *funcDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
83	buf := ctx.Buf
84	cursor = skipWhiteSpace(buf, cursor)
85	start := cursor
86	end, err := skipValue(buf, cursor, depth)
87	if err != nil {
88		return 0, err
89	}
90	src := buf[start:end]
91	if len(src) > 0 {
92		switch src[0] {
93		case '"':
94			return 0, &errors.UnmarshalTypeError{
95				Value:  "string",
96				Type:   runtime.RType2Type(d.typ),
97				Offset: start,
98			}
99		case '[':
100			return 0, &errors.UnmarshalTypeError{
101				Value:  "array",
102				Type:   runtime.RType2Type(d.typ),
103				Offset: start,
104			}
105		case '{':
106			return 0, &errors.UnmarshalTypeError{
107				Value:  "object",
108				Type:   runtime.RType2Type(d.typ),
109				Offset: start,
110			}
111		case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
112			return 0, &errors.UnmarshalTypeError{
113				Value:  "number",
114				Type:   runtime.RType2Type(d.typ),
115				Offset: start,
116			}
117		case 'n':
118			if bytes.Equal(src, nullbytes) {
119				*(*unsafe.Pointer)(p) = nil
120				return end, nil
121			}
122		case 't':
123			if err := validateTrue(buf, start); err == nil {
124				return 0, &errors.UnmarshalTypeError{
125					Value:  "boolean",
126					Type:   runtime.RType2Type(d.typ),
127					Offset: start,
128				}
129			}
130		case 'f':
131			if err := validateFalse(buf, start); err == nil {
132				return 0, &errors.UnmarshalTypeError{
133					Value:  "boolean",
134					Type:   runtime.RType2Type(d.typ),
135					Offset: start,
136				}
137			}
138		}
139	}
140	return cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor)
141}
142