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 } |
