Mercurial > yakumo_izuru > aya
comparison vendor/gopkg.in/yaml.v2/decode.go @ 66:787b5ee0289d draft
Use vendored modules
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>
author | yakumo.izuru |
---|---|
date | Sun, 23 Jul 2023 13:18:53 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
65:6d985efa0f7a | 66:787b5ee0289d |
---|---|
1 package yaml | |
2 | |
3 import ( | |
4 "encoding" | |
5 "encoding/base64" | |
6 "fmt" | |
7 "io" | |
8 "math" | |
9 "reflect" | |
10 "strconv" | |
11 "time" | |
12 ) | |
13 | |
14 const ( | |
15 documentNode = 1 << iota | |
16 mappingNode | |
17 sequenceNode | |
18 scalarNode | |
19 aliasNode | |
20 ) | |
21 | |
22 type node struct { | |
23 kind int | |
24 line, column int | |
25 tag string | |
26 // For an alias node, alias holds the resolved alias. | |
27 alias *node | |
28 value string | |
29 implicit bool | |
30 children []*node | |
31 anchors map[string]*node | |
32 } | |
33 | |
34 // ---------------------------------------------------------------------------- | |
35 // Parser, produces a node tree out of a libyaml event stream. | |
36 | |
37 type parser struct { | |
38 parser yaml_parser_t | |
39 event yaml_event_t | |
40 doc *node | |
41 doneInit bool | |
42 } | |
43 | |
44 func newParser(b []byte) *parser { | |
45 p := parser{} | |
46 if !yaml_parser_initialize(&p.parser) { | |
47 panic("failed to initialize YAML emitter") | |
48 } | |
49 if len(b) == 0 { | |
50 b = []byte{'\n'} | |
51 } | |
52 yaml_parser_set_input_string(&p.parser, b) | |
53 return &p | |
54 } | |
55 | |
56 func newParserFromReader(r io.Reader) *parser { | |
57 p := parser{} | |
58 if !yaml_parser_initialize(&p.parser) { | |
59 panic("failed to initialize YAML emitter") | |
60 } | |
61 yaml_parser_set_input_reader(&p.parser, r) | |
62 return &p | |
63 } | |
64 | |
65 func (p *parser) init() { | |
66 if p.doneInit { | |
67 return | |
68 } | |
69 p.expect(yaml_STREAM_START_EVENT) | |
70 p.doneInit = true | |
71 } | |
72 | |
73 func (p *parser) destroy() { | |
74 if p.event.typ != yaml_NO_EVENT { | |
75 yaml_event_delete(&p.event) | |
76 } | |
77 yaml_parser_delete(&p.parser) | |
78 } | |
79 | |
80 // expect consumes an event from the event stream and | |
81 // checks that it's of the expected type. | |
82 func (p *parser) expect(e yaml_event_type_t) { | |
83 if p.event.typ == yaml_NO_EVENT { | |
84 if !yaml_parser_parse(&p.parser, &p.event) { | |
85 p.fail() | |
86 } | |
87 } | |
88 if p.event.typ == yaml_STREAM_END_EVENT { | |
89 failf("attempted to go past the end of stream; corrupted value?") | |
90 } | |
91 if p.event.typ != e { | |
92 p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ) | |
93 p.fail() | |
94 } | |
95 yaml_event_delete(&p.event) | |
96 p.event.typ = yaml_NO_EVENT | |
97 } | |
98 | |
99 // peek peeks at the next event in the event stream, | |
100 // puts the results into p.event and returns the event type. | |
101 func (p *parser) peek() yaml_event_type_t { | |
102 if p.event.typ != yaml_NO_EVENT { | |
103 return p.event.typ | |
104 } | |
105 if !yaml_parser_parse(&p.parser, &p.event) { | |
106 p.fail() | |
107 } | |
108 return p.event.typ | |
109 } | |
110 | |
111 func (p *parser) fail() { | |
112 var where string | |
113 var line int | |
114 if p.parser.problem_mark.line != 0 { | |
115 line = p.parser.problem_mark.line | |
116 // Scanner errors don't iterate line before returning error | |
117 if p.parser.error == yaml_SCANNER_ERROR { | |
118 line++ | |
119 } | |
120 } else if p.parser.context_mark.line != 0 { | |
121 line = p.parser.context_mark.line | |
122 } | |
123 if line != 0 { | |
124 where = "line " + strconv.Itoa(line) + ": " | |
125 } | |
126 var msg string | |
127 if len(p.parser.problem) > 0 { | |
128 msg = p.parser.problem | |
129 } else { | |
130 msg = "unknown problem parsing YAML content" | |
131 } | |
132 failf("%s%s", where, msg) | |
133 } | |
134 | |
135 func (p *parser) anchor(n *node, anchor []byte) { | |
136 if anchor != nil { | |
137 p.doc.anchors[string(anchor)] = n | |
138 } | |
139 } | |
140 | |
141 func (p *parser) parse() *node { | |
142 p.init() | |
143 switch p.peek() { | |
144 case yaml_SCALAR_EVENT: | |
145 return p.scalar() | |
146 case yaml_ALIAS_EVENT: | |
147 return p.alias() | |
148 case yaml_MAPPING_START_EVENT: | |
149 return p.mapping() | |
150 case yaml_SEQUENCE_START_EVENT: | |
151 return p.sequence() | |
152 case yaml_DOCUMENT_START_EVENT: | |
153 return p.document() | |
154 case yaml_STREAM_END_EVENT: | |
155 // Happens when attempting to decode an empty buffer. | |
156 return nil | |
157 default: | |
158 panic("attempted to parse unknown event: " + p.event.typ.String()) | |
159 } | |
160 } | |
161 | |
162 func (p *parser) node(kind int) *node { | |
163 return &node{ | |
164 kind: kind, | |
165 line: p.event.start_mark.line, | |
166 column: p.event.start_mark.column, | |
167 } | |
168 } | |
169 | |
170 func (p *parser) document() *node { | |
171 n := p.node(documentNode) | |
172 n.anchors = make(map[string]*node) | |
173 p.doc = n | |
174 p.expect(yaml_DOCUMENT_START_EVENT) | |
175 n.children = append(n.children, p.parse()) | |
176 p.expect(yaml_DOCUMENT_END_EVENT) | |
177 return n | |
178 } | |
179 | |
180 func (p *parser) alias() *node { | |
181 n := p.node(aliasNode) | |
182 n.value = string(p.event.anchor) | |
183 n.alias = p.doc.anchors[n.value] | |
184 if n.alias == nil { | |
185 failf("unknown anchor '%s' referenced", n.value) | |
186 } | |
187 p.expect(yaml_ALIAS_EVENT) | |
188 return n | |
189 } | |
190 | |
191 func (p *parser) scalar() *node { | |
192 n := p.node(scalarNode) | |
193 n.value = string(p.event.value) | |
194 n.tag = string(p.event.tag) | |
195 n.implicit = p.event.implicit | |
196 p.anchor(n, p.event.anchor) | |
197 p.expect(yaml_SCALAR_EVENT) | |
198 return n | |
199 } | |
200 | |
201 func (p *parser) sequence() *node { | |
202 n := p.node(sequenceNode) | |
203 p.anchor(n, p.event.anchor) | |
204 p.expect(yaml_SEQUENCE_START_EVENT) | |
205 for p.peek() != yaml_SEQUENCE_END_EVENT { | |
206 n.children = append(n.children, p.parse()) | |
207 } | |
208 p.expect(yaml_SEQUENCE_END_EVENT) | |
209 return n | |
210 } | |
211 | |
212 func (p *parser) mapping() *node { | |
213 n := p.node(mappingNode) | |
214 p.anchor(n, p.event.anchor) | |
215 p.expect(yaml_MAPPING_START_EVENT) | |
216 for p.peek() != yaml_MAPPING_END_EVENT { | |
217 n.children = append(n.children, p.parse(), p.parse()) | |
218 } | |
219 p.expect(yaml_MAPPING_END_EVENT) | |
220 return n | |
221 } | |
222 | |
223 // ---------------------------------------------------------------------------- | |
224 // Decoder, unmarshals a node into a provided value. | |
225 | |
226 type decoder struct { | |
227 doc *node | |
228 aliases map[*node]bool | |
229 mapType reflect.Type | |
230 terrors []string | |
231 strict bool | |
232 | |
233 decodeCount int | |
234 aliasCount int | |
235 aliasDepth int | |
236 } | |
237 | |
238 var ( | |
239 mapItemType = reflect.TypeOf(MapItem{}) | |
240 durationType = reflect.TypeOf(time.Duration(0)) | |
241 defaultMapType = reflect.TypeOf(map[interface{}]interface{}{}) | |
242 ifaceType = defaultMapType.Elem() | |
243 timeType = reflect.TypeOf(time.Time{}) | |
244 ptrTimeType = reflect.TypeOf(&time.Time{}) | |
245 ) | |
246 | |
247 func newDecoder(strict bool) *decoder { | |
248 d := &decoder{mapType: defaultMapType, strict: strict} | |
249 d.aliases = make(map[*node]bool) | |
250 return d | |
251 } | |
252 | |
253 func (d *decoder) terror(n *node, tag string, out reflect.Value) { | |
254 if n.tag != "" { | |
255 tag = n.tag | |
256 } | |
257 value := n.value | |
258 if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG { | |
259 if len(value) > 10 { | |
260 value = " `" + value[:7] + "...`" | |
261 } else { | |
262 value = " `" + value + "`" | |
263 } | |
264 } | |
265 d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type())) | |
266 } | |
267 | |
268 func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) { | |
269 terrlen := len(d.terrors) | |
270 err := u.UnmarshalYAML(func(v interface{}) (err error) { | |
271 defer handleErr(&err) | |
272 d.unmarshal(n, reflect.ValueOf(v)) | |
273 if len(d.terrors) > terrlen { | |
274 issues := d.terrors[terrlen:] | |
275 d.terrors = d.terrors[:terrlen] | |
276 return &TypeError{issues} | |
277 } | |
278 return nil | |
279 }) | |
280 if e, ok := err.(*TypeError); ok { | |
281 d.terrors = append(d.terrors, e.Errors...) | |
282 return false | |
283 } | |
284 if err != nil { | |
285 fail(err) | |
286 } | |
287 return true | |
288 } | |
289 | |
290 // d.prepare initializes and dereferences pointers and calls UnmarshalYAML | |
291 // if a value is found to implement it. | |
292 // It returns the initialized and dereferenced out value, whether | |
293 // unmarshalling was already done by UnmarshalYAML, and if so whether | |
294 // its types unmarshalled appropriately. | |
295 // | |
296 // If n holds a null value, prepare returns before doing anything. | |
297 func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) { | |
298 if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) { | |
299 return out, false, false | |
300 } | |
301 again := true | |
302 for again { | |
303 again = false | |
304 if out.Kind() == reflect.Ptr { | |
305 if out.IsNil() { | |
306 out.Set(reflect.New(out.Type().Elem())) | |
307 } | |
308 out = out.Elem() | |
309 again = true | |
310 } | |
311 if out.CanAddr() { | |
312 if u, ok := out.Addr().Interface().(Unmarshaler); ok { | |
313 good = d.callUnmarshaler(n, u) | |
314 return out, true, good | |
315 } | |
316 } | |
317 } | |
318 return out, false, false | |
319 } | |
320 | |
321 const ( | |
322 // 400,000 decode operations is ~500kb of dense object declarations, or | |
323 // ~5kb of dense object declarations with 10000% alias expansion | |
324 alias_ratio_range_low = 400000 | |
325 | |
326 // 4,000,000 decode operations is ~5MB of dense object declarations, or | |
327 // ~4.5MB of dense object declarations with 10% alias expansion | |
328 alias_ratio_range_high = 4000000 | |
329 | |
330 // alias_ratio_range is the range over which we scale allowed alias ratios | |
331 alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low) | |
332 ) | |
333 | |
334 func allowedAliasRatio(decodeCount int) float64 { | |
335 switch { | |
336 case decodeCount <= alias_ratio_range_low: | |
337 // allow 99% to come from alias expansion for small-to-medium documents | |
338 return 0.99 | |
339 case decodeCount >= alias_ratio_range_high: | |
340 // allow 10% to come from alias expansion for very large documents | |
341 return 0.10 | |
342 default: | |
343 // scale smoothly from 99% down to 10% over the range. | |
344 // this maps to 396,000 - 400,000 allowed alias-driven decodes over the range. | |
345 // 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps). | |
346 return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range) | |
347 } | |
348 } | |
349 | |
350 func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) { | |
351 d.decodeCount++ | |
352 if d.aliasDepth > 0 { | |
353 d.aliasCount++ | |
354 } | |
355 if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) { | |
356 failf("document contains excessive aliasing") | |
357 } | |
358 switch n.kind { | |
359 case documentNode: | |
360 return d.document(n, out) | |
361 case aliasNode: | |
362 return d.alias(n, out) | |
363 } | |
364 out, unmarshaled, good := d.prepare(n, out) | |
365 if unmarshaled { | |
366 return good | |
367 } | |
368 switch n.kind { | |
369 case scalarNode: | |
370 good = d.scalar(n, out) | |
371 case mappingNode: | |
372 good = d.mapping(n, out) | |
373 case sequenceNode: | |
374 good = d.sequence(n, out) | |
375 default: | |
376 panic("internal error: unknown node kind: " + strconv.Itoa(n.kind)) | |
377 } | |
378 return good | |
379 } | |
380 | |
381 func (d *decoder) document(n *node, out reflect.Value) (good bool) { | |
382 if len(n.children) == 1 { | |
383 d.doc = n | |
384 d.unmarshal(n.children[0], out) | |
385 return true | |
386 } | |
387 return false | |
388 } | |
389 | |
390 func (d *decoder) alias(n *node, out reflect.Value) (good bool) { | |
391 if d.aliases[n] { | |
392 // TODO this could actually be allowed in some circumstances. | |
393 failf("anchor '%s' value contains itself", n.value) | |
394 } | |
395 d.aliases[n] = true | |
396 d.aliasDepth++ | |
397 good = d.unmarshal(n.alias, out) | |
398 d.aliasDepth-- | |
399 delete(d.aliases, n) | |
400 return good | |
401 } | |
402 | |
403 var zeroValue reflect.Value | |
404 | |
405 func resetMap(out reflect.Value) { | |
406 for _, k := range out.MapKeys() { | |
407 out.SetMapIndex(k, zeroValue) | |
408 } | |
409 } | |
410 | |
411 func (d *decoder) scalar(n *node, out reflect.Value) bool { | |
412 var tag string | |
413 var resolved interface{} | |
414 if n.tag == "" && !n.implicit { | |
415 tag = yaml_STR_TAG | |
416 resolved = n.value | |
417 } else { | |
418 tag, resolved = resolve(n.tag, n.value) | |
419 if tag == yaml_BINARY_TAG { | |
420 data, err := base64.StdEncoding.DecodeString(resolved.(string)) | |
421 if err != nil { | |
422 failf("!!binary value contains invalid base64 data") | |
423 } | |
424 resolved = string(data) | |
425 } | |
426 } | |
427 if resolved == nil { | |
428 if out.Kind() == reflect.Map && !out.CanAddr() { | |
429 resetMap(out) | |
430 } else { | |
431 out.Set(reflect.Zero(out.Type())) | |
432 } | |
433 return true | |
434 } | |
435 if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { | |
436 // We've resolved to exactly the type we want, so use that. | |
437 out.Set(resolvedv) | |
438 return true | |
439 } | |
440 // Perhaps we can use the value as a TextUnmarshaler to | |
441 // set its value. | |
442 if out.CanAddr() { | |
443 u, ok := out.Addr().Interface().(encoding.TextUnmarshaler) | |
444 if ok { | |
445 var text []byte | |
446 if tag == yaml_BINARY_TAG { | |
447 text = []byte(resolved.(string)) | |
448 } else { | |
449 // We let any value be unmarshaled into TextUnmarshaler. | |
450 // That might be more lax than we'd like, but the | |
451 // TextUnmarshaler itself should bowl out any dubious values. | |
452 text = []byte(n.value) | |
453 } | |
454 err := u.UnmarshalText(text) | |
455 if err != nil { | |
456 fail(err) | |
457 } | |
458 return true | |
459 } | |
460 } | |
461 switch out.Kind() { | |
462 case reflect.String: | |
463 if tag == yaml_BINARY_TAG { | |
464 out.SetString(resolved.(string)) | |
465 return true | |
466 } | |
467 if resolved != nil { | |
468 out.SetString(n.value) | |
469 return true | |
470 } | |
471 case reflect.Interface: | |
472 if resolved == nil { | |
473 out.Set(reflect.Zero(out.Type())) | |
474 } else if tag == yaml_TIMESTAMP_TAG { | |
475 // It looks like a timestamp but for backward compatibility | |
476 // reasons we set it as a string, so that code that unmarshals | |
477 // timestamp-like values into interface{} will continue to | |
478 // see a string and not a time.Time. | |
479 // TODO(v3) Drop this. | |
480 out.Set(reflect.ValueOf(n.value)) | |
481 } else { | |
482 out.Set(reflect.ValueOf(resolved)) | |
483 } | |
484 return true | |
485 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |
486 switch resolved := resolved.(type) { | |
487 case int: | |
488 if !out.OverflowInt(int64(resolved)) { | |
489 out.SetInt(int64(resolved)) | |
490 return true | |
491 } | |
492 case int64: | |
493 if !out.OverflowInt(resolved) { | |
494 out.SetInt(resolved) | |
495 return true | |
496 } | |
497 case uint64: | |
498 if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { | |
499 out.SetInt(int64(resolved)) | |
500 return true | |
501 } | |
502 case float64: | |
503 if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { | |
504 out.SetInt(int64(resolved)) | |
505 return true | |
506 } | |
507 case string: | |
508 if out.Type() == durationType { | |
509 d, err := time.ParseDuration(resolved) | |
510 if err == nil { | |
511 out.SetInt(int64(d)) | |
512 return true | |
513 } | |
514 } | |
515 } | |
516 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | |
517 switch resolved := resolved.(type) { | |
518 case int: | |
519 if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { | |
520 out.SetUint(uint64(resolved)) | |
521 return true | |
522 } | |
523 case int64: | |
524 if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { | |
525 out.SetUint(uint64(resolved)) | |
526 return true | |
527 } | |
528 case uint64: | |
529 if !out.OverflowUint(uint64(resolved)) { | |
530 out.SetUint(uint64(resolved)) | |
531 return true | |
532 } | |
533 case float64: | |
534 if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) { | |
535 out.SetUint(uint64(resolved)) | |
536 return true | |
537 } | |
538 } | |
539 case reflect.Bool: | |
540 switch resolved := resolved.(type) { | |
541 case bool: | |
542 out.SetBool(resolved) | |
543 return true | |
544 } | |
545 case reflect.Float32, reflect.Float64: | |
546 switch resolved := resolved.(type) { | |
547 case int: | |
548 out.SetFloat(float64(resolved)) | |
549 return true | |
550 case int64: | |
551 out.SetFloat(float64(resolved)) | |
552 return true | |
553 case uint64: | |
554 out.SetFloat(float64(resolved)) | |
555 return true | |
556 case float64: | |
557 out.SetFloat(resolved) | |
558 return true | |
559 } | |
560 case reflect.Struct: | |
561 if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { | |
562 out.Set(resolvedv) | |
563 return true | |
564 } | |
565 case reflect.Ptr: | |
566 if out.Type().Elem() == reflect.TypeOf(resolved) { | |
567 // TODO DOes this make sense? When is out a Ptr except when decoding a nil value? | |
568 elem := reflect.New(out.Type().Elem()) | |
569 elem.Elem().Set(reflect.ValueOf(resolved)) | |
570 out.Set(elem) | |
571 return true | |
572 } | |
573 } | |
574 d.terror(n, tag, out) | |
575 return false | |
576 } | |
577 | |
578 func settableValueOf(i interface{}) reflect.Value { | |
579 v := reflect.ValueOf(i) | |
580 sv := reflect.New(v.Type()).Elem() | |
581 sv.Set(v) | |
582 return sv | |
583 } | |
584 | |
585 func (d *decoder) sequence(n *node, out reflect.Value) (good bool) { | |
586 l := len(n.children) | |
587 | |
588 var iface reflect.Value | |
589 switch out.Kind() { | |
590 case reflect.Slice: | |
591 out.Set(reflect.MakeSlice(out.Type(), l, l)) | |
592 case reflect.Array: | |
593 if l != out.Len() { | |
594 failf("invalid array: want %d elements but got %d", out.Len(), l) | |
595 } | |
596 case reflect.Interface: | |
597 // No type hints. Will have to use a generic sequence. | |
598 iface = out | |
599 out = settableValueOf(make([]interface{}, l)) | |
600 default: | |
601 d.terror(n, yaml_SEQ_TAG, out) | |
602 return false | |
603 } | |
604 et := out.Type().Elem() | |
605 | |
606 j := 0 | |
607 for i := 0; i < l; i++ { | |
608 e := reflect.New(et).Elem() | |
609 if ok := d.unmarshal(n.children[i], e); ok { | |
610 out.Index(j).Set(e) | |
611 j++ | |
612 } | |
613 } | |
614 if out.Kind() != reflect.Array { | |
615 out.Set(out.Slice(0, j)) | |
616 } | |
617 if iface.IsValid() { | |
618 iface.Set(out) | |
619 } | |
620 return true | |
621 } | |
622 | |
623 func (d *decoder) mapping(n *node, out reflect.Value) (good bool) { | |
624 switch out.Kind() { | |
625 case reflect.Struct: | |
626 return d.mappingStruct(n, out) | |
627 case reflect.Slice: | |
628 return d.mappingSlice(n, out) | |
629 case reflect.Map: | |
630 // okay | |
631 case reflect.Interface: | |
632 if d.mapType.Kind() == reflect.Map { | |
633 iface := out | |
634 out = reflect.MakeMap(d.mapType) | |
635 iface.Set(out) | |
636 } else { | |
637 slicev := reflect.New(d.mapType).Elem() | |
638 if !d.mappingSlice(n, slicev) { | |
639 return false | |
640 } | |
641 out.Set(slicev) | |
642 return true | |
643 } | |
644 default: | |
645 d.terror(n, yaml_MAP_TAG, out) | |
646 return false | |
647 } | |
648 outt := out.Type() | |
649 kt := outt.Key() | |
650 et := outt.Elem() | |
651 | |
652 mapType := d.mapType | |
653 if outt.Key() == ifaceType && outt.Elem() == ifaceType { | |
654 d.mapType = outt | |
655 } | |
656 | |
657 if out.IsNil() { | |
658 out.Set(reflect.MakeMap(outt)) | |
659 } | |
660 l := len(n.children) | |
661 for i := 0; i < l; i += 2 { | |
662 if isMerge(n.children[i]) { | |
663 d.merge(n.children[i+1], out) | |
664 continue | |
665 } | |
666 k := reflect.New(kt).Elem() | |
667 if d.unmarshal(n.children[i], k) { | |
668 kkind := k.Kind() | |
669 if kkind == reflect.Interface { | |
670 kkind = k.Elem().Kind() | |
671 } | |
672 if kkind == reflect.Map || kkind == reflect.Slice { | |
673 failf("invalid map key: %#v", k.Interface()) | |
674 } | |
675 e := reflect.New(et).Elem() | |
676 if d.unmarshal(n.children[i+1], e) { | |
677 d.setMapIndex(n.children[i+1], out, k, e) | |
678 } | |
679 } | |
680 } | |
681 d.mapType = mapType | |
682 return true | |
683 } | |
684 | |
685 func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) { | |
686 if d.strict && out.MapIndex(k) != zeroValue { | |
687 d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface())) | |
688 return | |
689 } | |
690 out.SetMapIndex(k, v) | |
691 } | |
692 | |
693 func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) { | |
694 outt := out.Type() | |
695 if outt.Elem() != mapItemType { | |
696 d.terror(n, yaml_MAP_TAG, out) | |
697 return false | |
698 } | |
699 | |
700 mapType := d.mapType | |
701 d.mapType = outt | |
702 | |
703 var slice []MapItem | |
704 var l = len(n.children) | |
705 for i := 0; i < l; i += 2 { | |
706 if isMerge(n.children[i]) { | |
707 d.merge(n.children[i+1], out) | |
708 continue | |
709 } | |
710 item := MapItem{} | |
711 k := reflect.ValueOf(&item.Key).Elem() | |
712 if d.unmarshal(n.children[i], k) { | |
713 v := reflect.ValueOf(&item.Value).Elem() | |
714 if d.unmarshal(n.children[i+1], v) { | |
715 slice = append(slice, item) | |
716 } | |
717 } | |
718 } | |
719 out.Set(reflect.ValueOf(slice)) | |
720 d.mapType = mapType | |
721 return true | |
722 } | |
723 | |
724 func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) { | |
725 sinfo, err := getStructInfo(out.Type()) | |
726 if err != nil { | |
727 panic(err) | |
728 } | |
729 name := settableValueOf("") | |
730 l := len(n.children) | |
731 | |
732 var inlineMap reflect.Value | |
733 var elemType reflect.Type | |
734 if sinfo.InlineMap != -1 { | |
735 inlineMap = out.Field(sinfo.InlineMap) | |
736 inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) | |
737 elemType = inlineMap.Type().Elem() | |
738 } | |
739 | |
740 var doneFields []bool | |
741 if d.strict { | |
742 doneFields = make([]bool, len(sinfo.FieldsList)) | |
743 } | |
744 for i := 0; i < l; i += 2 { | |
745 ni := n.children[i] | |
746 if isMerge(ni) { | |
747 d.merge(n.children[i+1], out) | |
748 continue | |
749 } | |
750 if !d.unmarshal(ni, name) { | |
751 continue | |
752 } | |
753 if info, ok := sinfo.FieldsMap[name.String()]; ok { | |
754 if d.strict { | |
755 if doneFields[info.Id] { | |
756 d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type())) | |
757 continue | |
758 } | |
759 doneFields[info.Id] = true | |
760 } | |
761 var field reflect.Value | |
762 if info.Inline == nil { | |
763 field = out.Field(info.Num) | |
764 } else { | |
765 field = out.FieldByIndex(info.Inline) | |
766 } | |
767 d.unmarshal(n.children[i+1], field) | |
768 } else if sinfo.InlineMap != -1 { | |
769 if inlineMap.IsNil() { | |
770 inlineMap.Set(reflect.MakeMap(inlineMap.Type())) | |
771 } | |
772 value := reflect.New(elemType).Elem() | |
773 d.unmarshal(n.children[i+1], value) | |
774 d.setMapIndex(n.children[i+1], inlineMap, name, value) | |
775 } else if d.strict { | |
776 d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type())) | |
777 } | |
778 } | |
779 return true | |
780 } | |
781 | |
782 func failWantMap() { | |
783 failf("map merge requires map or sequence of maps as the value") | |
784 } | |
785 | |
786 func (d *decoder) merge(n *node, out reflect.Value) { | |
787 switch n.kind { | |
788 case mappingNode: | |
789 d.unmarshal(n, out) | |
790 case aliasNode: | |
791 if n.alias != nil && n.alias.kind != mappingNode { | |
792 failWantMap() | |
793 } | |
794 d.unmarshal(n, out) | |
795 case sequenceNode: | |
796 // Step backwards as earlier nodes take precedence. | |
797 for i := len(n.children) - 1; i >= 0; i-- { | |
798 ni := n.children[i] | |
799 if ni.kind == aliasNode { | |
800 if ni.alias != nil && ni.alias.kind != mappingNode { | |
801 failWantMap() | |
802 } | |
803 } else if ni.kind != mappingNode { | |
804 failWantMap() | |
805 } | |
806 d.unmarshal(ni, out) | |
807 } | |
808 default: | |
809 failWantMap() | |
810 } | |
811 } | |
812 | |
813 func isMerge(n *node) bool { | |
814 return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG) | |
815 } |