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