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