1package toml 2 3import ( 4 "bytes" 5 "encoding" 6 "errors" 7 "fmt" 8 "io" 9 "reflect" 10 "sort" 11 "strconv" 12 "strings" 13 "time" 14) 15 16const ( 17 tagFieldName = "toml" 18 tagFieldComment = "comment" 19 tagCommented = "commented" 20 tagMultiline = "multiline" 21 tagLiteral = "literal" 22 tagDefault = "default" 23) 24 25type tomlOpts struct { 26 name string 27 nameFromTag bool 28 comment string 29 commented bool 30 multiline bool 31 literal bool 32 include bool 33 omitempty bool 34 defaultValue string 35} 36 37type encOpts struct { 38 quoteMapKeys bool 39 arraysOneElementPerLine bool 40} 41 42var encOptsDefaults = encOpts{ 43 quoteMapKeys: false, 44} 45 46type annotation struct { 47 tag string 48 comment string 49 commented string 50 multiline string 51 literal string 52 defaultValue string 53} 54 55var annotationDefault = annotation{ 56 tag: tagFieldName, 57 comment: tagFieldComment, 58 commented: tagCommented, 59 multiline: tagMultiline, 60 literal: tagLiteral, 61 defaultValue: tagDefault, 62} 63 64type MarshalOrder int 65 66// Orders the Encoder can write the fields to the output stream. 67const ( 68 // Sort fields alphabetically. 69 OrderAlphabetical MarshalOrder = iota + 1 70 // Preserve the order the fields are encountered. For example, the order of fields in 71 // a struct. 72 OrderPreserve 73) 74 75var timeType = reflect.TypeOf(time.Time{}) 76var marshalerType = reflect.TypeOf(new(Marshaler)).Elem() 77var unmarshalerType = reflect.TypeOf(new(Unmarshaler)).Elem() 78var textMarshalerType = reflect.TypeOf(new(encoding.TextMarshaler)).Elem() 79var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem() 80var localDateType = reflect.TypeOf(LocalDate{}) 81var localTimeType = reflect.TypeOf(LocalTime{}) 82var localDateTimeType = reflect.TypeOf(LocalDateTime{}) 83var mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{}) 84 85// Check if the given marshal type maps to a Tree primitive 86func isPrimitive(mtype reflect.Type) bool { 87 switch mtype.Kind() { 88 case reflect.Ptr: 89 return isPrimitive(mtype.Elem()) 90 case reflect.Bool: 91 return true 92 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 93 return true 94 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 95 return true 96 case reflect.Float32, reflect.Float64: 97 return true 98 case reflect.String: 99 return true 100 case reflect.Struct: 101 return isTimeType(mtype) 102 default: 103 return false 104 } 105} 106 107func isTimeType(mtype reflect.Type) bool { 108 return mtype == timeType || mtype == localDateType || mtype == localDateTimeType || mtype == localTimeType 109} 110 111// Check if the given marshal type maps to a Tree slice or array 112func isTreeSequence(mtype reflect.Type) bool { 113 switch mtype.Kind() { 114 case reflect.Ptr: 115 return isTreeSequence(mtype.Elem()) 116 case reflect.Slice, reflect.Array: 117 return isTree(mtype.Elem()) 118 default: 119 return false 120 } 121} 122 123// Check if the given marshal type maps to a slice or array of a custom marshaler type 124func isCustomMarshalerSequence(mtype reflect.Type) bool { 125 switch mtype.Kind() { 126 case reflect.Ptr: 127 return isCustomMarshalerSequence(mtype.Elem()) 128 case reflect.Slice, reflect.Array: 129 return isCustomMarshaler(mtype.Elem()) || isCustomMarshaler(reflect.New(mtype.Elem()).Type()) 130 default: 131 return false 132 } 133} 134 135// Check if the given marshal type maps to a slice or array of a text marshaler type 136func isTextMarshalerSequence(mtype reflect.Type) bool { 137 switch mtype.Kind() { 138 case reflect.Ptr: 139 return isTextMarshalerSequence(mtype.Elem()) 140 case reflect.Slice, reflect.Array: 141 return isTextMarshaler(mtype.Elem()) || isTextMarshaler(reflect.New(mtype.Elem()).Type()) 142 default: 143 return false 144 } 145} 146 147// Check if the given marshal type maps to a non-Tree slice or array 148func isOtherSequence(mtype reflect.Type) bool { 149 switch mtype.Kind() { 150 case reflect.Ptr: 151 return isOtherSequence(mtype.Elem()) 152 case reflect.Slice, reflect.Array: 153 return !isTreeSequence(mtype) 154 default: 155 return false 156 } 157} 158 159// Check if the given marshal type maps to a Tree 160func isTree(mtype reflect.Type) bool { 161 switch mtype.Kind() { 162 case reflect.Ptr: 163 return isTree(mtype.Elem()) 164 case reflect.Map: 165 return true 166 case reflect.Struct: 167 return !isPrimitive(mtype) 168 default: 169 return false 170 } 171} 172 173func isCustomMarshaler(mtype reflect.Type) bool { 174 return mtype.Implements(marshalerType) 175} 176 177func callCustomMarshaler(mval reflect.Value) ([]byte, error) { 178 return mval.Interface().(Marshaler).MarshalTOML() 179} 180 181func isTextMarshaler(mtype reflect.Type) bool { 182 return mtype.Implements(textMarshalerType) && !isTimeType(mtype) 183} 184 185func callTextMarshaler(mval reflect.Value) ([]byte, error) { 186 return mval.Interface().(encoding.TextMarshaler).MarshalText() 187} 188 189func isCustomUnmarshaler(mtype reflect.Type) bool { 190 return mtype.Implements(unmarshalerType) 191} 192 193func callCustomUnmarshaler(mval reflect.Value, tval interface{}) error { 194 return mval.Interface().(Unmarshaler).UnmarshalTOML(tval) 195} 196 197func isTextUnmarshaler(mtype reflect.Type) bool { 198 return mtype.Implements(textUnmarshalerType) 199} 200 201func callTextUnmarshaler(mval reflect.Value, text []byte) error { 202 return mval.Interface().(encoding.TextUnmarshaler).UnmarshalText(text) 203} 204 205// Marshaler is the interface implemented by types that 206// can marshal themselves into valid TOML. 207type Marshaler interface { 208 MarshalTOML() ([]byte, error) 209} 210 211// Unmarshaler is the interface implemented by types that 212// can unmarshal a TOML description of themselves. 213type Unmarshaler interface { 214 UnmarshalTOML(interface{}) error 215} 216 217/* 218Marshal returns the TOML encoding of v. Behavior is similar to the Go json 219encoder, except that there is no concept of a Marshaler interface or MarshalTOML 220function for sub-structs, and currently only definite types can be marshaled 221(i.e. no `interface{}`). 222 223The following struct annotations are supported: 224 225 toml:"Field" Overrides the field's name to output. 226 omitempty When set, empty values and groups are not emitted. 227 comment:"comment" Emits a # comment on the same line. This supports new lines. 228 commented:"true" Emits the value as commented. 229 230Note that pointers are automatically assigned the "omitempty" option, as TOML 231explicitly does not handle null values (saying instead the label should be 232dropped). 233 234Tree structural types and corresponding marshal types: 235 236 *Tree (*)struct, (*)map[string]interface{} 237 []*Tree (*)[](*)struct, (*)[](*)map[string]interface{} 238 []interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{}) 239 interface{} (*)primitive 240 241Tree primitive types and corresponding marshal types: 242 243 uint64 uint, uint8-uint64, pointers to same 244 int64 int, int8-uint64, pointers to same 245 float64 float32, float64, pointers to same 246 string string, pointers to same 247 bool bool, pointers to same 248 time.LocalTime time.LocalTime{}, pointers to same 249 250For additional flexibility, use the Encoder API. 251*/ 252func Marshal(v interface{}) ([]byte, error) { 253 return NewEncoder(nil).marshal(v) 254} 255 256// Encoder writes TOML values to an output stream. 257type Encoder struct { 258 w io.Writer 259 encOpts 260 annotation 261 line int 262 col int 263 order MarshalOrder 264 promoteAnon bool 265 indentation string 266} 267 268// NewEncoder returns a new encoder that writes to w. 269func NewEncoder(w io.Writer) *Encoder { 270 return &Encoder{ 271 w: w, 272 encOpts: encOptsDefaults, 273 annotation: annotationDefault, 274 line: 0, 275 col: 1, 276 order: OrderAlphabetical, 277 indentation: " ", 278 } 279} 280 281// Encode writes the TOML encoding of v to the stream. 282// 283// See the documentation for Marshal for details. 284func (e *Encoder) Encode(v interface{}) error { 285 b, err := e.marshal(v) 286 if err != nil { 287 return err 288 } 289 if _, err := e.w.Write(b); err != nil { 290 return err 291 } 292 return nil 293} 294 295// QuoteMapKeys sets up the encoder to encode 296// maps with string type keys with quoted TOML keys. 297// 298// This relieves the character limitations on map keys. 299func (e *Encoder) QuoteMapKeys(v bool) *Encoder { 300 e.quoteMapKeys = v 301 return e 302} 303 304// ArraysWithOneElementPerLine sets up the encoder to encode arrays 305// with more than one element on multiple lines instead of one. 306// 307// For example: 308// 309// A = [1,2,3] 310// 311// Becomes 312// 313// A = [ 314// 1, 315// 2, 316// 3, 317// ] 318func (e *Encoder) ArraysWithOneElementPerLine(v bool) *Encoder { 319 e.arraysOneElementPerLine = v 320 return e 321} 322 323// Order allows to change in which order fields will be written to the output stream. 324func (e *Encoder) Order(ord MarshalOrder) *Encoder { 325 e.order = ord 326 return e 327} 328 329// Indentation allows to change indentation when marshalling. 330func (e *Encoder) Indentation(indent string) *Encoder { 331 e.indentation = indent 332 return e 333} 334 335// SetTagName allows changing default tag "toml" 336func (e *Encoder) SetTagName(v string) *Encoder { 337 e.tag = v 338 return e 339} 340 341// SetTagComment allows changing default tag "comment" 342func (e *Encoder) SetTagComment(v string) *Encoder { 343 e.comment = v 344 return e 345} 346 347// SetTagCommented allows changing default tag "commented" 348func (e *Encoder) SetTagCommented(v string) *Encoder { 349 e.commented = v 350 return e 351} 352 353// SetTagMultiline allows changing default tag "multiline" 354func (e *Encoder) SetTagMultiline(v string) *Encoder { 355 e.multiline = v 356 return e 357} 358 359// PromoteAnonymous allows to change how anonymous struct fields are marshaled. 360// Usually, they are marshaled as if the inner exported fields were fields in 361// the outer struct. However, if an anonymous struct field is given a name in 362// its TOML tag, it is treated like a regular struct field with that name. 363// rather than being anonymous. 364// 365// In case anonymous promotion is enabled, all anonymous structs are promoted 366// and treated like regular struct fields. 367func (e *Encoder) PromoteAnonymous(promote bool) *Encoder { 368 e.promoteAnon = promote 369 return e 370} 371 372func (e *Encoder) marshal(v interface{}) ([]byte, error) { 373 // Check if indentation is valid 374 for _, char := range e.indentation { 375 if !isSpace(char) { 376 return []byte{}, fmt.Errorf("invalid indentation: must only contains space or tab characters") 377 } 378 } 379 380 mtype := reflect.TypeOf(v) 381 if mtype == nil { 382 return []byte{}, errors.New("nil cannot be marshaled to TOML") 383 } 384 385 switch mtype.Kind() { 386 case reflect.Struct, reflect.Map: 387 case reflect.Ptr: 388 if mtype.Elem().Kind() != reflect.Struct { 389 return []byte{}, errors.New("Only pointer to struct can be marshaled to TOML") 390 } 391 if reflect.ValueOf(v).IsNil() { 392 return []byte{}, errors.New("nil pointer cannot be marshaled to TOML") 393 } 394 default: 395 return []byte{}, errors.New("Only a struct or map can be marshaled to TOML") 396 } 397 398 sval := reflect.ValueOf(v) 399 if isCustomMarshaler(mtype) { 400 return callCustomMarshaler(sval) 401 } 402 if isTextMarshaler(mtype) { 403 return callTextMarshaler(sval) 404 } 405 t, err := e.valueToTree(mtype, sval) 406 if err != nil { 407 return []byte{}, err 408 } 409 410 var buf bytes.Buffer 411 _, err = t.writeToOrdered(&buf, "", "", 0, e.arraysOneElementPerLine, e.order, e.indentation, false) 412 413 return buf.Bytes(), err 414} 415 416// Create next tree with a position based on Encoder.line 417func (e *Encoder) nextTree() *Tree { 418 return newTreeWithPosition(Position{Line: e.line, Col: 1}) 419} 420 421// Convert given marshal struct or map value to toml tree 422func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) { 423 if mtype.Kind() == reflect.Ptr { 424 return e.valueToTree(mtype.Elem(), mval.Elem()) 425 } 426 tval := e.nextTree() 427 switch mtype.Kind() { 428 case reflect.Struct: 429 switch mval.Interface().(type) { 430 case Tree: 431 reflect.ValueOf(tval).Elem().Set(mval) 432 default: 433 for i := 0; i < mtype.NumField(); i++ { 434 mtypef, mvalf := mtype.Field(i), mval.Field(i) 435 opts := tomlOptions(mtypef, e.annotation) 436 if opts.include && ((mtypef.Type.Kind() != reflect.Interface && !opts.omitempty) || !isZero(mvalf)) { 437 val, err := e.valueToToml(mtypef.Type, mvalf) 438 if err != nil { 439 return nil, err 440 } 441 if tree, ok := val.(*Tree); ok && mtypef.Anonymous && !opts.nameFromTag && !e.promoteAnon { 442 e.appendTree(tval, tree) 443 } else { 444 val = e.wrapTomlValue(val, tval) 445 tval.SetPathWithOptions([]string{opts.name}, SetOptions{ 446 Comment: opts.comment, 447 Commented: opts.commented, 448 Multiline: opts.multiline, 449 Literal: opts.literal, 450 }, val) 451 } 452 } 453 } 454 } 455 case reflect.Map: 456 keys := mval.MapKeys() 457 if e.order == OrderPreserve && len(keys) > 0 { 458 // Sorting []reflect.Value is not straight forward. 459 // 460 // OrderPreserve will support deterministic results when string is used 461 // as the key to maps. 462 typ := keys[0].Type() 463 kind := keys[0].Kind() 464 if kind == reflect.String { 465 ikeys := make([]string, len(keys)) 466 for i := range keys { 467 ikeys[i] = keys[i].Interface().(string) 468 } 469 sort.Strings(ikeys) 470 for i := range ikeys { 471 keys[i] = reflect.ValueOf(ikeys[i]).Convert(typ) 472 } 473 } 474 } 475 for _, key := range keys { 476 mvalf := mval.MapIndex(key) 477 if (mtype.Elem().Kind() == reflect.Ptr || mtype.Elem().Kind() == reflect.Interface) && mvalf.IsNil() { 478 continue 479 } 480 val, err := e.valueToToml(mtype.Elem(), mvalf) 481 if err != nil { 482 return nil, err 483 } 484 val = e.wrapTomlValue(val, tval) 485 if e.quoteMapKeys { 486 keyStr, err := tomlValueStringRepresentation(key.String(), "", "", e.order, e.arraysOneElementPerLine) 487 if err != nil { 488 return nil, err 489 } 490 tval.SetPath([]string{keyStr}, val) 491 } else { 492 tval.SetPath([]string{key.String()}, val) 493 } 494 } 495 } 496 return tval, nil 497} 498 499// Convert given marshal slice to slice of Toml trees 500func (e *Encoder) valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) { 501 tval := make([]*Tree, mval.Len(), mval.Len()) 502 for i := 0; i < mval.Len(); i++ { 503 val, err := e.valueToTree(mtype.Elem(), mval.Index(i)) 504 if err != nil { 505 return nil, err 506 } 507 tval[i] = val 508 } 509 return tval, nil 510} 511 512// Convert given marshal slice to slice of toml values 513func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) { 514 tval := make([]interface{}, mval.Len(), mval.Len()) 515 for i := 0; i < mval.Len(); i++ { 516 val, err := e.valueToToml(mtype.Elem(), mval.Index(i)) 517 if err != nil { 518 return nil, err 519 } 520 tval[i] = val 521 } 522 return tval, nil 523} 524 525// Convert given marshal value to toml value 526func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) { 527 if mtype.Kind() == reflect.Ptr { 528 switch { 529 case isCustomMarshaler(mtype): 530 return callCustomMarshaler(mval) 531 case isTextMarshaler(mtype): 532 b, err := callTextMarshaler(mval) 533 return string(b), err 534 default: 535 return e.valueToToml(mtype.Elem(), mval.Elem()) 536 } 537 } 538 if mtype.Kind() == reflect.Interface { 539 return e.valueToToml(mval.Elem().Type(), mval.Elem()) 540 } 541 switch { 542 case isCustomMarshaler(mtype): 543 return callCustomMarshaler(mval) 544 case isTextMarshaler(mtype): 545 b, err := callTextMarshaler(mval) 546 return string(b), err 547 case isTree(mtype): 548 return e.valueToTree(mtype, mval) 549 case isOtherSequence(mtype), isCustomMarshalerSequence(mtype), isTextMarshalerSequence(mtype): 550 return e.valueToOtherSlice(mtype, mval) 551 case isTreeSequence(mtype): 552 return e.valueToTreeSlice(mtype, mval) 553 default: 554 switch mtype.Kind() { 555 case reflect.Bool: 556 return mval.Bool(), nil 557 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 558 if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) { 559 return fmt.Sprint(mval), nil 560 } 561 return mval.Int(), nil 562 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 563 return mval.Uint(), nil 564 case reflect.Float32, reflect.Float64: 565 return mval.Float(), nil 566 case reflect.String: 567 return mval.String(), nil 568 case reflect.Struct: 569 return mval.Interface(), nil 570 default: 571 return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind()) 572 } 573 } 574} 575 576func (e *Encoder) appendTree(t, o *Tree) error { 577 for key, value := range o.values { 578 if _, ok := t.values[key]; ok { 579 continue 580 } 581 if tomlValue, ok := value.(*tomlValue); ok { 582 tomlValue.position.Col = t.position.Col 583 } 584 t.values[key] = value 585 } 586 return nil 587} 588 589// Create a toml value with the current line number as the position line 590func (e *Encoder) wrapTomlValue(val interface{}, parent *Tree) interface{} { 591 _, isTree := val.(*Tree) 592 _, isTreeS := val.([]*Tree) 593 if isTree || isTreeS { 594 return val 595 } 596 597 ret := &tomlValue{ 598 value: val, 599 position: Position{ 600 e.line, 601 parent.position.Col, 602 }, 603 } 604 e.line++ 605 return ret 606} 607 608// Unmarshal attempts to unmarshal the Tree into a Go struct pointed by v. 609// Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for 610// sub-structs, and only definite types can be unmarshaled. 611func (t *Tree) Unmarshal(v interface{}) error { 612 d := Decoder{tval: t, tagName: tagFieldName} 613 return d.unmarshal(v) 614} 615 616// Marshal returns the TOML encoding of Tree. 617// See Marshal() documentation for types mapping table. 618func (t *Tree) Marshal() ([]byte, error) { 619 var buf bytes.Buffer 620 _, err := t.WriteTo(&buf) 621 if err != nil { 622 return nil, err 623 } 624 return buf.Bytes(), nil 625} 626 627// Unmarshal parses the TOML-encoded data and stores the result in the value 628// pointed to by v. Behavior is similar to the Go json encoder, except that there 629// is no concept of an Unmarshaler interface or UnmarshalTOML function for 630// sub-structs, and currently only definite types can be unmarshaled to (i.e. no 631// `interface{}`). 632// 633// The following struct annotations are supported: 634// 635// toml:"Field" Overrides the field's name to map to. 636// default:"foo" Provides a default value. 637// 638// For default values, only fields of the following types are supported: 639// * string 640// * bool 641// * int 642// * int64 643// * float64 644// 645// See Marshal() documentation for types mapping table. 646func Unmarshal(data []byte, v interface{}) error { 647 t, err := LoadReader(bytes.NewReader(data)) 648 if err != nil { 649 return err 650 } 651 return t.Unmarshal(v) 652} 653 654// Decoder reads and decodes TOML values from an input stream. 655type Decoder struct { 656 r io.Reader 657 tval *Tree 658 encOpts 659 tagName string 660 strict bool 661 visitor visitorState 662} 663 664// NewDecoder returns a new decoder that reads from r. 665func NewDecoder(r io.Reader) *Decoder { 666 return &Decoder{ 667 r: r, 668 encOpts: encOptsDefaults, 669 tagName: tagFieldName, 670 } 671} 672 673// Decode reads a TOML-encoded value from it's input 674// and unmarshals it in the value pointed at by v. 675// 676// See the documentation for Marshal for details. 677func (d *Decoder) Decode(v interface{}) error { 678 var err error 679 d.tval, err = LoadReader(d.r) 680 if err != nil { 681 return err 682 } 683 return d.unmarshal(v) 684} 685 686// SetTagName allows changing default tag "toml" 687func (d *Decoder) SetTagName(v string) *Decoder { 688 d.tagName = v 689 return d 690} 691 692// Strict allows changing to strict decoding. Any fields that are found in the 693// input data and do not have a corresponding struct member cause an error. 694func (d *Decoder) Strict(strict bool) *Decoder { 695 d.strict = strict 696 return d 697} 698 699func (d *Decoder) unmarshal(v interface{}) error { 700 mtype := reflect.TypeOf(v) 701 if mtype == nil { 702 return errors.New("nil cannot be unmarshaled from TOML") 703 } 704 if mtype.Kind() != reflect.Ptr { 705 return errors.New("only a pointer to struct or map can be unmarshaled from TOML") 706 } 707 708 elem := mtype.Elem() 709 710 switch elem.Kind() { 711 case reflect.Struct, reflect.Map: 712 case reflect.Interface: 713 elem = mapStringInterfaceType 714 default: 715 return errors.New("only a pointer to struct or map can be unmarshaled from TOML") 716 } 717 718 if reflect.ValueOf(v).IsNil() { 719 return errors.New("nil pointer cannot be unmarshaled from TOML") 720 } 721 722 vv := reflect.ValueOf(v).Elem() 723 724 if d.strict { 725 d.visitor = newVisitorState(d.tval) 726 } 727 728 sval, err := d.valueFromTree(elem, d.tval, &vv) 729 if err != nil { 730 return err 731 } 732 if err := d.visitor.validate(); err != nil { 733 return err 734 } 735 reflect.ValueOf(v).Elem().Set(sval) 736 return nil 737} 738 739// Convert toml tree to marshal struct or map, using marshal type. When mval1 740// is non-nil, merge fields into the given value instead of allocating a new one. 741func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.Value) (reflect.Value, error) { 742 if mtype.Kind() == reflect.Ptr { 743 return d.unwrapPointer(mtype, tval, mval1) 744 } 745 746 // Check if pointer to value implements the Unmarshaler interface. 747 if mvalPtr := reflect.New(mtype); isCustomUnmarshaler(mvalPtr.Type()) { 748 d.visitor.visitAll() 749 750 if tval == nil { 751 return mvalPtr.Elem(), nil 752 } 753 754 if err := callCustomUnmarshaler(mvalPtr, tval.ToMap()); err != nil { 755 return reflect.ValueOf(nil), fmt.Errorf("unmarshal toml: %v", err) 756 } 757 return mvalPtr.Elem(), nil 758 } 759 760 var mval reflect.Value 761 switch mtype.Kind() { 762 case reflect.Struct: 763 if mval1 != nil { 764 mval = *mval1 765 } else { 766 mval = reflect.New(mtype).Elem() 767 } 768 769 switch mval.Interface().(type) { 770 case Tree: 771 mval.Set(reflect.ValueOf(tval).Elem()) 772 default: 773 for i := 0; i < mtype.NumField(); i++ { 774 mtypef := mtype.Field(i) 775 an := annotation{tag: d.tagName} 776 opts := tomlOptions(mtypef, an) 777 if !opts.include { 778 continue 779 } 780 baseKey := opts.name 781 keysToTry := []string{ 782 baseKey, 783 strings.ToLower(baseKey), 784 strings.ToTitle(baseKey), 785 strings.ToLower(string(baseKey[0])) + baseKey[1:], 786 } 787 788 found := false 789 if tval != nil { 790 for _, key := range keysToTry { 791 exists := tval.HasPath([]string{key}) 792 if !exists { 793 continue 794 } 795 796 d.visitor.push(key) 797 val := tval.GetPath([]string{key}) 798 fval := mval.Field(i) 799 mvalf, err := d.valueFromToml(mtypef.Type, val, &fval) 800 if err != nil { 801 return mval, formatError(err, tval.GetPositionPath([]string{key})) 802 } 803 mval.Field(i).Set(mvalf) 804 found = true 805 d.visitor.pop() 806 break 807 } 808 } 809 810 if !found && opts.defaultValue != "" { 811 mvalf := mval.Field(i) 812 var val interface{} 813 var err error 814 switch mvalf.Kind() { 815 case reflect.String: 816 val = opts.defaultValue 817 case reflect.Bool: 818 val, err = strconv.ParseBool(opts.defaultValue) 819 case reflect.Uint: 820 val, err = strconv.ParseUint(opts.defaultValue, 10, 0) 821 case reflect.Uint8: 822 val, err = strconv.ParseUint(opts.defaultValue, 10, 8) 823 case reflect.Uint16: 824 val, err = strconv.ParseUint(opts.defaultValue, 10, 16) 825 case reflect.Uint32: 826 val, err = strconv.ParseUint(opts.defaultValue, 10, 32) 827 case reflect.Uint64: 828 val, err = strconv.ParseUint(opts.defaultValue, 10, 64) 829 case reflect.Int: 830 val, err = strconv.ParseInt(opts.defaultValue, 10, 0) 831 case reflect.Int8: 832 val, err = strconv.ParseInt(opts.defaultValue, 10, 8) 833 case reflect.Int16: 834 val, err = strconv.ParseInt(opts.defaultValue, 10, 16) 835 case reflect.Int32: 836 val, err = strconv.ParseInt(opts.defaultValue, 10, 32) 837 case reflect.Int64: 838 // Check if the provided number has a non-numeric extension. 839 var hasExtension bool 840 if len(opts.defaultValue) > 0 { 841 lastChar := opts.defaultValue[len(opts.defaultValue)-1] 842 if lastChar < '0' || lastChar > '9' { 843 hasExtension = true 844 } 845 } 846 // If the value is a time.Duration with extension, parse as duration. 847 // If the value is an int64 or a time.Duration without extension, parse as number. 848 if hasExtension && mvalf.Type().String() == "time.Duration" { 849 val, err = time.ParseDuration(opts.defaultValue) 850 } else { 851 val, err = strconv.ParseInt(opts.defaultValue, 10, 64) 852 } 853 case reflect.Float32: 854 val, err = strconv.ParseFloat(opts.defaultValue, 32) 855 case reflect.Float64: 856 val, err = strconv.ParseFloat(opts.defaultValue, 64) 857 default: 858 return mvalf, fmt.Errorf("unsupported field type for default option") 859 } 860 861 if err != nil { 862 return mvalf, err 863 } 864 mvalf.Set(reflect.ValueOf(val).Convert(mvalf.Type())) 865 } 866 867 // save the old behavior above and try to check structs 868 if !found && opts.defaultValue == "" && mtypef.Type.Kind() == reflect.Struct { 869 tmpTval := tval 870 if !mtypef.Anonymous { 871 tmpTval = nil 872 } 873 fval := mval.Field(i) 874 v, err := d.valueFromTree(mtypef.Type, tmpTval, &fval) 875 if err != nil { 876 return v, err 877 } 878 mval.Field(i).Set(v) 879 } 880 } 881 } 882 case reflect.Map: 883 mval = reflect.MakeMap(mtype) 884 for _, key := range tval.Keys() { 885 d.visitor.push(key) 886 // TODO: path splits key 887 val := tval.GetPath([]string{key}) 888 mvalf, err := d.valueFromToml(mtype.Elem(), val, nil) 889 if err != nil { 890 return mval, formatError(err, tval.GetPositionPath([]string{key})) 891 } 892 mval.SetMapIndex(reflect.ValueOf(key).Convert(mtype.Key()), mvalf) 893 d.visitor.pop() 894 } 895 } 896 return mval, nil 897} 898 899// Convert toml value to marshal struct/map slice, using marshal type 900func (d *Decoder) valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) { 901 mval, err := makeSliceOrArray(mtype, len(tval)) 902 if err != nil { 903 return mval, err 904 } 905 906 for i := 0; i < len(tval); i++ { 907 d.visitor.push(strconv.Itoa(i)) 908 val, err := d.valueFromTree(mtype.Elem(), tval[i], nil) 909 if err != nil { 910 return mval, err 911 } 912 mval.Index(i).Set(val) 913 d.visitor.pop() 914 } 915 return mval, nil 916} 917 918// Convert toml value to marshal primitive slice, using marshal type 919func (d *Decoder) valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) { 920 mval, err := makeSliceOrArray(mtype, len(tval)) 921 if err != nil { 922 return mval, err 923 } 924 925 for i := 0; i < len(tval); i++ { 926 val, err := d.valueFromToml(mtype.Elem(), tval[i], nil) 927 if err != nil { 928 return mval, err 929 } 930 mval.Index(i).Set(val) 931 } 932 return mval, nil 933} 934 935// Convert toml value to marshal primitive slice, using marshal type 936func (d *Decoder) valueFromOtherSliceI(mtype reflect.Type, tval interface{}) (reflect.Value, error) { 937 val := reflect.ValueOf(tval) 938 length := val.Len() 939 940 mval, err := makeSliceOrArray(mtype, length) 941 if err != nil { 942 return mval, err 943 } 944 945 for i := 0; i < length; i++ { 946 val, err := d.valueFromToml(mtype.Elem(), val.Index(i).Interface(), nil) 947 if err != nil { 948 return mval, err 949 } 950 mval.Index(i).Set(val) 951 } 952 return mval, nil 953} 954 955// Create a new slice or a new array with specified length 956func makeSliceOrArray(mtype reflect.Type, tLength int) (reflect.Value, error) { 957 var mval reflect.Value 958 switch mtype.Kind() { 959 case reflect.Slice: 960 mval = reflect.MakeSlice(mtype, tLength, tLength) 961 case reflect.Array: 962 mval = reflect.New(reflect.ArrayOf(mtype.Len(), mtype.Elem())).Elem() 963 if tLength > mtype.Len() { 964 return mval, fmt.Errorf("unmarshal: TOML array length (%v) exceeds destination array length (%v)", tLength, mtype.Len()) 965 } 966 } 967 return mval, nil 968} 969 970// Convert toml value to marshal value, using marshal type. When mval1 is non-nil 971// and the given type is a struct value, merge fields into it. 972func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *reflect.Value) (reflect.Value, error) { 973 if mtype.Kind() == reflect.Ptr { 974 return d.unwrapPointer(mtype, tval, mval1) 975 } 976 977 switch t := tval.(type) { 978 case *Tree: 979 var mval11 *reflect.Value 980 if mtype.Kind() == reflect.Struct { 981 mval11 = mval1 982 } 983 984 if isTree(mtype) { 985 return d.valueFromTree(mtype, t, mval11) 986 } 987 988 if mtype.Kind() == reflect.Interface { 989 if mval1 == nil || mval1.IsNil() { 990 return d.valueFromTree(reflect.TypeOf(map[string]interface{}{}), t, nil) 991 } else { 992 return d.valueFromToml(mval1.Elem().Type(), t, nil) 993 } 994 } 995 996 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval) 997 case []*Tree: 998 if isTreeSequence(mtype) { 999 return d.valueFromTreeSlice(mtype, t) 1000 } 1001 if mtype.Kind() == reflect.Interface { 1002 if mval1 == nil || mval1.IsNil() { 1003 return d.valueFromTreeSlice(reflect.TypeOf([]map[string]interface{}{}), t) 1004 } else { 1005 ival := mval1.Elem() 1006 return d.valueFromToml(mval1.Elem().Type(), t, &ival) 1007 } 1008 } 1009 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval) 1010 case []interface{}: 1011 d.visitor.visit() 1012 if isOtherSequence(mtype) { 1013 return d.valueFromOtherSlice(mtype, t) 1014 } 1015 if mtype.Kind() == reflect.Interface { 1016 if mval1 == nil || mval1.IsNil() { 1017 return d.valueFromOtherSlice(reflect.TypeOf([]interface{}{}), t) 1018 } else { 1019 ival := mval1.Elem() 1020 return d.valueFromToml(mval1.Elem().Type(), t, &ival) 1021 } 1022 } 1023 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval) 1024 default: 1025 d.visitor.visit() 1026 mvalPtr := reflect.New(mtype) 1027 1028 // Check if pointer to value implements the Unmarshaler interface. 1029 if isCustomUnmarshaler(mvalPtr.Type()) { 1030 if err := callCustomUnmarshaler(mvalPtr, tval); err != nil { 1031 return reflect.ValueOf(nil), fmt.Errorf("unmarshal toml: %v", err) 1032 } 1033 return mvalPtr.Elem(), nil 1034 } 1035 1036 // Check if pointer to value implements the encoding.TextUnmarshaler. 1037 if isTextUnmarshaler(mvalPtr.Type()) && !isTimeType(mtype) { 1038 if err := d.unmarshalText(tval, mvalPtr); err != nil { 1039 return reflect.ValueOf(nil), fmt.Errorf("unmarshal text: %v", err) 1040 } 1041 return mvalPtr.Elem(), nil 1042 } 1043 1044 switch mtype.Kind() { 1045 case reflect.Bool, reflect.Struct: 1046 val := reflect.ValueOf(tval) 1047 1048 switch val.Type() { 1049 case localDateType: 1050 localDate := val.Interface().(LocalDate) 1051 switch mtype { 1052 case timeType: 1053 return reflect.ValueOf(time.Date(localDate.Year, localDate.Month, localDate.Day, 0, 0, 0, 0, time.Local)), nil 1054 } 1055 case localDateTimeType: 1056 localDateTime := val.Interface().(LocalDateTime) 1057 switch mtype { 1058 case timeType: 1059 return reflect.ValueOf(time.Date( 1060 localDateTime.Date.Year, 1061 localDateTime.Date.Month, 1062 localDateTime.Date.Day, 1063 localDateTime.Time.Hour, 1064 localDateTime.Time.Minute, 1065 localDateTime.Time.Second, 1066 localDateTime.Time.Nanosecond, 1067 time.Local)), nil 1068 } 1069 } 1070 1071 // if this passes for when mtype is reflect.Struct, tval is a time.LocalTime 1072 if !val.Type().ConvertibleTo(mtype) { 1073 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) 1074 } 1075 1076 return val.Convert(mtype), nil 1077 case reflect.String: 1078 val := reflect.ValueOf(tval) 1079 // stupidly, int64 is convertible to string. So special case this. 1080 if !val.Type().ConvertibleTo(mtype) || val.Kind() == reflect.Int64 { 1081 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) 1082 } 1083 1084 return val.Convert(mtype), nil 1085 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1086 val := reflect.ValueOf(tval) 1087 if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) && val.Kind() == reflect.String { 1088 d, err := time.ParseDuration(val.String()) 1089 if err != nil { 1090 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v. %s", tval, tval, mtype.String(), err) 1091 } 1092 return reflect.ValueOf(d), nil 1093 } 1094 if !val.Type().ConvertibleTo(mtype) || val.Kind() == reflect.Float64 { 1095 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) 1096 } 1097 if reflect.Indirect(reflect.New(mtype)).OverflowInt(val.Convert(reflect.TypeOf(int64(0))).Int()) { 1098 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) 1099 } 1100 1101 return val.Convert(mtype), nil 1102 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 1103 val := reflect.ValueOf(tval) 1104 if !val.Type().ConvertibleTo(mtype) || val.Kind() == reflect.Float64 { 1105 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) 1106 } 1107 1108 if val.Convert(reflect.TypeOf(int(1))).Int() < 0 { 1109 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String()) 1110 } 1111 if reflect.Indirect(reflect.New(mtype)).OverflowUint(val.Convert(reflect.TypeOf(uint64(0))).Uint()) { 1112 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) 1113 } 1114 1115 return val.Convert(mtype), nil 1116 case reflect.Float32, reflect.Float64: 1117 val := reflect.ValueOf(tval) 1118 if !val.Type().ConvertibleTo(mtype) || val.Kind() == reflect.Int64 { 1119 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) 1120 } 1121 if reflect.Indirect(reflect.New(mtype)).OverflowFloat(val.Convert(reflect.TypeOf(float64(0))).Float()) { 1122 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) 1123 } 1124 1125 return val.Convert(mtype), nil 1126 case reflect.Interface: 1127 if mval1 == nil || mval1.IsNil() { 1128 return reflect.ValueOf(tval), nil 1129 } else { 1130 ival := mval1.Elem() 1131 return d.valueFromToml(mval1.Elem().Type(), t, &ival) 1132 } 1133 case reflect.Slice, reflect.Array: 1134 if isOtherSequence(mtype) && isOtherSequence(reflect.TypeOf(t)) { 1135 return d.valueFromOtherSliceI(mtype, t) 1136 } 1137 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind()) 1138 default: 1139 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind()) 1140 } 1141 } 1142} 1143 1144func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}, mval1 *reflect.Value) (reflect.Value, error) { 1145 var melem *reflect.Value 1146 1147 if mval1 != nil && !mval1.IsNil() && (mtype.Elem().Kind() == reflect.Struct || mtype.Elem().Kind() == reflect.Interface) { 1148 elem := mval1.Elem() 1149 melem = &elem 1150 } 1151 1152 val, err := d.valueFromToml(mtype.Elem(), tval, melem) 1153 if err != nil { 1154 return reflect.ValueOf(nil), err 1155 } 1156 mval := reflect.New(mtype.Elem()) 1157 mval.Elem().Set(val) 1158 return mval, nil 1159} 1160 1161func (d *Decoder) unmarshalText(tval interface{}, mval reflect.Value) error { 1162 var buf bytes.Buffer 1163 fmt.Fprint(&buf, tval) 1164 return callTextUnmarshaler(mval, buf.Bytes()) 1165} 1166 1167func tomlOptions(vf reflect.StructField, an annotation) tomlOpts { 1168 tag := vf.Tag.Get(an.tag) 1169 parse := strings.Split(tag, ",") 1170 var comment string 1171 if c := vf.Tag.Get(an.comment); c != "" { 1172 comment = c 1173 } 1174 commented, _ := strconv.ParseBool(vf.Tag.Get(an.commented)) 1175 multiline, _ := strconv.ParseBool(vf.Tag.Get(an.multiline)) 1176 literal, _ := strconv.ParseBool(vf.Tag.Get(an.literal)) 1177 defaultValue := vf.Tag.Get(tagDefault) 1178 result := tomlOpts{ 1179 name: vf.Name, 1180 nameFromTag: false, 1181 comment: comment, 1182 commented: commented, 1183 multiline: multiline, 1184 literal: literal, 1185 include: true, 1186 omitempty: false, 1187 defaultValue: defaultValue, 1188 } 1189 if parse[0] != "" { 1190 if parse[0] == "-" && len(parse) == 1 { 1191 result.include = false 1192 } else { 1193 result.name = strings.Trim(parse[0], " ") 1194 result.nameFromTag = true 1195 } 1196 } 1197 if vf.PkgPath != "" { 1198 result.include = false 1199 } 1200 if len(parse) > 1 && strings.Trim(parse[1], " ") == "omitempty" { 1201 result.omitempty = true 1202 } 1203 if vf.Type.Kind() == reflect.Ptr { 1204 result.omitempty = true 1205 } 1206 return result 1207} 1208 1209func isZero(val reflect.Value) bool { 1210 switch val.Type().Kind() { 1211 case reflect.Slice, reflect.Array, reflect.Map: 1212 return val.Len() == 0 1213 default: 1214 return reflect.DeepEqual(val.Interface(), reflect.Zero(val.Type()).Interface()) 1215 } 1216} 1217 1218func formatError(err error, pos Position) error { 1219 if err.Error()[0] == '(' { // Error already contains position information 1220 return err 1221 } 1222 return fmt.Errorf("%s: %s", pos, err) 1223} 1224 1225// visitorState keeps track of which keys were unmarshaled. 1226type visitorState struct { 1227 tree *Tree 1228 path []string 1229 keys map[string]struct{} 1230 active bool 1231} 1232 1233func newVisitorState(tree *Tree) visitorState { 1234 path, result := []string{}, map[string]struct{}{} 1235 insertKeys(path, result, tree) 1236 return visitorState{ 1237 tree: tree, 1238 path: path[:0], 1239 keys: result, 1240 active: true, 1241 } 1242} 1243 1244func (s *visitorState) push(key string) { 1245 if s.active { 1246 s.path = append(s.path, key) 1247 } 1248} 1249 1250func (s *visitorState) pop() { 1251 if s.active { 1252 s.path = s.path[:len(s.path)-1] 1253 } 1254} 1255 1256func (s *visitorState) visit() { 1257 if s.active { 1258 delete(s.keys, strings.Join(s.path, ".")) 1259 } 1260} 1261 1262func (s *visitorState) visitAll() { 1263 if s.active { 1264 for k := range s.keys { 1265 if strings.HasPrefix(k, strings.Join(s.path, ".")) { 1266 delete(s.keys, k) 1267 } 1268 } 1269 } 1270} 1271 1272func (s *visitorState) validate() error { 1273 if !s.active { 1274 return nil 1275 } 1276 undecoded := make([]string, 0, len(s.keys)) 1277 for key := range s.keys { 1278 undecoded = append(undecoded, key) 1279 } 1280 sort.Strings(undecoded) 1281 if len(undecoded) > 0 { 1282 return fmt.Errorf("undecoded keys: %q", undecoded) 1283 } 1284 return nil 1285} 1286 1287func insertKeys(path []string, m map[string]struct{}, tree *Tree) { 1288 for k, v := range tree.values { 1289 switch node := v.(type) { 1290 case []*Tree: 1291 for i, item := range node { 1292 insertKeys(append(path, k, strconv.Itoa(i)), m, item) 1293 } 1294 case *Tree: 1295 insertKeys(append(path, k), m, node) 1296 case *tomlValue: 1297 m[strings.Join(append(path, k), ".")] = struct{}{} 1298 } 1299 } 1300} 1301