1 package decoder
2
3 import (
4 "reflect"
5 "unsafe"
6
7 "github.com/goccy/go-json/internal/errors"
8 "github.com/goccy/go-json/internal/runtime"
9 )
10
11 type mapDecoder struct {
12 mapType *runtime.Type
13 keyType *runtime.Type
14 valueType *runtime.Type
15 canUseAssignFaststrType bool
16 keyDecoder Decoder
17 valueDecoder Decoder
18 structName string
19 fieldName string
20 }
21
22 func newMapDecoder(mapType *runtime.Type, keyType *runtime.Type, keyDec Decoder, valueType *runtime.Type, valueDec Decoder, structName, fieldName string) *mapDecoder {
23 return &mapDecoder{
24 mapType: mapType,
25 keyDecoder: keyDec,
26 keyType: keyType,
27 canUseAssignFaststrType: canUseAssignFaststrType(keyType, valueType),
28 valueType: valueType,
29 valueDecoder: valueDec,
30 structName: structName,
31 fieldName: fieldName,
32 }
33 }
34
35 const (
36 mapMaxElemSize = 128
37 )
38
39
40 func canUseAssignFaststrType(key *runtime.Type, value *runtime.Type) bool {
41 indirectElem := value.Size() > mapMaxElemSize
42 if indirectElem {
43 return false
44 }
45 return key.Kind() == reflect.String
46 }
47
48
49 func makemap(*runtime.Type, int) unsafe.Pointer
50
51
52
53
54 func mapassign_faststr(t *runtime.Type, m unsafe.Pointer, s string) unsafe.Pointer
55
56
57
58 func mapassign(t *runtime.Type, m unsafe.Pointer, k, v unsafe.Pointer)
59
60 func (d *mapDecoder) mapassign(t *runtime.Type, m, k, v unsafe.Pointer) {
61 if d.canUseAssignFaststrType {
62 mapV := mapassign_faststr(t, m, *(*string)(k))
63 typedmemmove(d.valueType, mapV, v)
64 } else {
65 mapassign(t, m, k, v)
66 }
67 }
68
69 func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error {
70 depth++
71 if depth > maxDecodeNestingDepth {
72 return errors.ErrExceededMaxDepth(s.char(), s.cursor)
73 }
74
75 switch s.skipWhiteSpace() {
76 case 'n':
77 if err := nullBytes(s); err != nil {
78 return err
79 }
80 **(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
81 return nil
82 case '{':
83 default:
84 return errors.ErrExpected("{ character for map value", s.totalOffset())
85 }
86 mapValue := *(*unsafe.Pointer)(p)
87 if mapValue == nil {
88 mapValue = makemap(d.mapType, 0)
89 }
90 s.cursor++
91 if s.skipWhiteSpace() == '}' {
92 *(*unsafe.Pointer)(p) = mapValue
93 s.cursor++
94 return nil
95 }
96 for {
97 k := unsafe_New(d.keyType)
98 if err := d.keyDecoder.DecodeStream(s, depth, k); err != nil {
99 return err
100 }
101 s.skipWhiteSpace()
102 if !s.equalChar(':') {
103 return errors.ErrExpected("colon after object key", s.totalOffset())
104 }
105 s.cursor++
106 v := unsafe_New(d.valueType)
107 if err := d.valueDecoder.DecodeStream(s, depth, v); err != nil {
108 return err
109 }
110 d.mapassign(d.mapType, mapValue, k, v)
111 s.skipWhiteSpace()
112 if s.equalChar('}') {
113 **(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
114 s.cursor++
115 return nil
116 }
117 if !s.equalChar(',') {
118 return errors.ErrExpected("comma after object value", s.totalOffset())
119 }
120 s.cursor++
121 }
122 }
123
124 func (d *mapDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) {
125 buf := ctx.Buf
126 depth++
127 if depth > maxDecodeNestingDepth {
128 return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
129 }
130
131 cursor = skipWhiteSpace(buf, cursor)
132 buflen := int64(len(buf))
133 if buflen < 2 {
134 return 0, errors.ErrExpected("{} for map", cursor)
135 }
136 switch buf[cursor] {
137 case 'n':
138 if err := validateNull(buf, cursor); err != nil {
139 return 0, err
140 }
141 cursor += 4
142 **(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil
143 return cursor, nil
144 case '{':
145 default:
146 return 0, errors.ErrExpected("{ character for map value", cursor)
147 }
148 cursor++
149 cursor = skipWhiteSpace(buf, cursor)
150 mapValue := *(*unsafe.Pointer)(p)
151 if mapValue == nil {
152 mapValue = makemap(d.mapType, 0)
153 }
154 if buf[cursor] == '}' {
155 **(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
156 cursor++
157 return cursor, nil
158 }
159 for {
160 k := unsafe_New(d.keyType)
161 keyCursor, err := d.keyDecoder.Decode(ctx, cursor, depth, k)
162 if err != nil {
163 return 0, err
164 }
165 cursor = skipWhiteSpace(buf, keyCursor)
166 if buf[cursor] != ':' {
167 return 0, errors.ErrExpected("colon after object key", cursor)
168 }
169 cursor++
170 v := unsafe_New(d.valueType)
171 valueCursor, err := d.valueDecoder.Decode(ctx, cursor, depth, v)
172 if err != nil {
173 return 0, err
174 }
175 d.mapassign(d.mapType, mapValue, k, v)
176 cursor = skipWhiteSpace(buf, valueCursor)
177 if buf[cursor] == '}' {
178 **(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue
179 cursor++
180 return cursor, nil
181 }
182 if buf[cursor] != ',' {
183 return 0, errors.ErrExpected("comma after object value", cursor)
184 }
185 cursor++
186 }
187 }
188
189 func (d *mapDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) {
190 buf := ctx.Buf
191 depth++
192 if depth > maxDecodeNestingDepth {
193 return nil, 0, errors.ErrExceededMaxDepth(buf[cursor], cursor)
194 }
195
196 cursor = skipWhiteSpace(buf, cursor)
197 buflen := int64(len(buf))
198 if buflen < 2 {
199 return nil, 0, errors.ErrExpected("{} for map", cursor)
200 }
201 switch buf[cursor] {
202 case 'n':
203 if err := validateNull(buf, cursor); err != nil {
204 return nil, 0, err
205 }
206 cursor += 4
207 return [][]byte{nullbytes}, cursor, nil
208 case '{':
209 default:
210 return nil, 0, errors.ErrExpected("{ character for map value", cursor)
211 }
212 cursor++
213 cursor = skipWhiteSpace(buf, cursor)
214 if buf[cursor] == '}' {
215 cursor++
216 return nil, cursor, nil
217 }
218 keyDecoder, ok := d.keyDecoder.(*stringDecoder)
219 if !ok {
220 return nil, 0, &errors.UnmarshalTypeError{
221 Value: "string",
222 Type: reflect.TypeOf(""),
223 Offset: cursor,
224 Struct: d.structName,
225 Field: d.fieldName,
226 }
227 }
228 ret := [][]byte{}
229 for {
230 key, keyCursor, err := keyDecoder.decodeByte(buf, cursor)
231 if err != nil {
232 return nil, 0, err
233 }
234 cursor = skipWhiteSpace(buf, keyCursor)
235 if buf[cursor] != ':' {
236 return nil, 0, errors.ErrExpected("colon after object key", cursor)
237 }
238 cursor++
239 child, found, err := ctx.Option.Path.Field(string(key))
240 if err != nil {
241 return nil, 0, err
242 }
243 if found {
244 if child != nil {
245 oldPath := ctx.Option.Path.node
246 ctx.Option.Path.node = child
247 paths, c, err := d.valueDecoder.DecodePath(ctx, cursor, depth)
248 if err != nil {
249 return nil, 0, err
250 }
251 ctx.Option.Path.node = oldPath
252 ret = append(ret, paths...)
253 cursor = c
254 } else {
255 start := cursor
256 end, err := skipValue(buf, cursor, depth)
257 if err != nil {
258 return nil, 0, err
259 }
260 ret = append(ret, buf[start:end])
261 cursor = end
262 }
263 } else {
264 c, err := skipValue(buf, cursor, depth)
265 if err != nil {
266 return nil, 0, err
267 }
268 cursor = c
269 }
270 cursor = skipWhiteSpace(buf, cursor)
271 if buf[cursor] == '}' {
272 cursor++
273 return ret, cursor, nil
274 }
275 if buf[cursor] != ',' {
276 return nil, 0, errors.ErrExpected("comma after object value", cursor)
277 }
278 cursor++
279 }
280 }
281
View as plain text