1package toml 2 3import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "reflect" 9 "sort" 10 "strconv" 11 "strings" 12 "time" 13) 14 15const ( 16 tagFieldName = "toml" 17 tagFieldComment = "comment" 18 tagCommented = "commented" 19 tagMultiline = "multiline" 20 tagDefault = "default" 21) 22 23type tomlOpts struct { 24 name string 25 comment string 26 commented bool 27 multiline bool 28 include bool 29 omitempty bool 30 defaultValue string 31} 32 33type encOpts struct { 34 quoteMapKeys bool 35 arraysOneElementPerLine bool 36} 37 38var encOptsDefaults = encOpts{ 39 quoteMapKeys: false, 40} 41 42type annotation struct { 43 tag string 44 comment string 45 commented string 46 multiline string 47 defaultValue string 48} 49 50var annotationDefault = annotation{ 51 tag: tagFieldName, 52 comment: tagFieldComment, 53 commented: tagCommented, 54 multiline: tagMultiline, 55 defaultValue: tagDefault, 56} 57 58type marshalOrder int 59 60// Orders the Encoder can write the fields to the output stream. 61const ( 62 // Sort fields alphabetically. 63 OrderAlphabetical marshalOrder = iota + 1 64 // Preserve the order the fields are encountered. For example, the order of fields in 65 // a struct. 66 OrderPreserve 67) 68 69var timeType = reflect.TypeOf(time.Time{}) 70var marshalerType = reflect.TypeOf(new(Marshaler)).Elem() 71var localDateType = reflect.TypeOf(LocalDate{}) 72var localTimeType = reflect.TypeOf(LocalTime{}) 73var localDateTimeType = reflect.TypeOf(LocalDateTime{}) 74 75// Check if the given marshal type maps to a Tree primitive 76func isPrimitive(mtype reflect.Type) bool { 77 switch mtype.Kind() { 78 case reflect.Ptr: 79 return isPrimitive(mtype.Elem()) 80 case reflect.Bool: 81 return true 82 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 83 return true 84 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 85 return true 86 case reflect.Float32, reflect.Float64: 87 return true 88 case reflect.String: 89 return true 90 case reflect.Struct: 91 return mtype == timeType || mtype == localDateType || mtype == localDateTimeType || mtype == localTimeType || isCustomMarshaler(mtype) 92 default: 93 return false 94 } 95} 96 97// Check if the given marshal type maps to a Tree slice or array 98func isTreeSequence(mtype reflect.Type) bool { 99 switch mtype.Kind() { 100 case reflect.Ptr: 101 return isTreeSequence(mtype.Elem()) 102 case reflect.Slice, reflect.Array: 103 return isTree(mtype.Elem()) 104 default: 105 return false 106 } 107} 108 109// Check if the given marshal type maps to a non-Tree slice or array 110func isOtherSequence(mtype reflect.Type) bool { 111 switch mtype.Kind() { 112 case reflect.Ptr: 113 return isOtherSequence(mtype.Elem()) 114 case reflect.Slice, reflect.Array: 115 return !isTreeSequence(mtype) 116 default: 117 return false 118 } 119} 120 121// Check if the given marshal type maps to a Tree 122func isTree(mtype reflect.Type) bool { 123 switch mtype.Kind() { 124 case reflect.Ptr: 125 return isTree(mtype.Elem()) 126 case reflect.Map: 127 return true 128 case reflect.Struct: 129 return !isPrimitive(mtype) 130 default: 131 return false 132 } 133} 134 135func isCustomMarshaler(mtype reflect.Type) bool { 136 return mtype.Implements(marshalerType) 137} 138 139func callCustomMarshaler(mval reflect.Value) ([]byte, error) { 140 return mval.Interface().(Marshaler).MarshalTOML() 141} 142 143// Marshaler is the interface implemented by types that 144// can marshal themselves into valid TOML. 145type Marshaler interface { 146 MarshalTOML() ([]byte, error) 147} 148 149/* 150Marshal returns the TOML encoding of v. Behavior is similar to the Go json 151encoder, except that there is no concept of a Marshaler interface or MarshalTOML 152function for sub-structs, and currently only definite types can be marshaled 153(i.e. no `interface{}`). 154 155The following struct annotations are supported: 156 157 toml:"Field" Overrides the field's name to output. 158 omitempty When set, empty values and groups are not emitted. 159 comment:"comment" Emits a # comment on the same line. This supports new lines. 160 commented:"true" Emits the value as commented. 161 162Note that pointers are automatically assigned the "omitempty" option, as TOML 163explicitly does not handle null values (saying instead the label should be 164dropped). 165 166Tree structural types and corresponding marshal types: 167 168 *Tree (*)struct, (*)map[string]interface{} 169 []*Tree (*)[](*)struct, (*)[](*)map[string]interface{} 170 []interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{}) 171 interface{} (*)primitive 172 173Tree primitive types and corresponding marshal types: 174 175 uint64 uint, uint8-uint64, pointers to same 176 int64 int, int8-uint64, pointers to same 177 float64 float32, float64, pointers to same 178 string string, pointers to same 179 bool bool, pointers to same 180 time.LocalTime time.LocalTime{}, pointers to same 181 182For additional flexibility, use the Encoder API. 183*/ 184func Marshal(v interface{}) ([]byte, error) { 185 return NewEncoder(nil).marshal(v) 186} 187 188// Encoder writes TOML values to an output stream. 189type Encoder struct { 190 w io.Writer 191 encOpts 192 annotation 193 line int 194 col int 195 order marshalOrder 196} 197 198// NewEncoder returns a new encoder that writes to w. 199func NewEncoder(w io.Writer) *Encoder { 200 return &Encoder{ 201 w: w, 202 encOpts: encOptsDefaults, 203 annotation: annotationDefault, 204 line: 0, 205 col: 1, 206 order: OrderAlphabetical, 207 } 208} 209 210// Encode writes the TOML encoding of v to the stream. 211// 212// See the documentation for Marshal for details. 213func (e *Encoder) Encode(v interface{}) error { 214 b, err := e.marshal(v) 215 if err != nil { 216 return err 217 } 218 if _, err := e.w.Write(b); err != nil { 219 return err 220 } 221 return nil 222} 223 224// QuoteMapKeys sets up the encoder to encode 225// maps with string type keys with quoted TOML keys. 226// 227// This relieves the character limitations on map keys. 228func (e *Encoder) QuoteMapKeys(v bool) *Encoder { 229 e.quoteMapKeys = v 230 return e 231} 232 233// ArraysWithOneElementPerLine sets up the encoder to encode arrays 234// with more than one element on multiple lines instead of one. 235// 236// For example: 237// 238// A = [1,2,3] 239// 240// Becomes 241// 242// A = [ 243// 1, 244// 2, 245// 3, 246// ] 247func (e *Encoder) ArraysWithOneElementPerLine(v bool) *Encoder { 248 e.arraysOneElementPerLine = v 249 return e 250} 251 252// Order allows to change in which order fields will be written to the output stream. 253func (e *Encoder) Order(ord marshalOrder) *Encoder { 254 e.order = ord 255 return e 256} 257 258// SetTagName allows changing default tag "toml" 259func (e *Encoder) SetTagName(v string) *Encoder { 260 e.tag = v 261 return e 262} 263 264// SetTagComment allows changing default tag "comment" 265func (e *Encoder) SetTagComment(v string) *Encoder { 266 e.comment = v 267 return e 268} 269 270// SetTagCommented allows changing default tag "commented" 271func (e *Encoder) SetTagCommented(v string) *Encoder { 272 e.commented = v 273 return e 274} 275 276// SetTagMultiline allows changing default tag "multiline" 277func (e *Encoder) SetTagMultiline(v string) *Encoder { 278 e.multiline = v 279 return e 280} 281 282func (e *Encoder) marshal(v interface{}) ([]byte, error) { 283 mtype := reflect.TypeOf(v) 284 285 switch mtype.Kind() { 286 case reflect.Struct, reflect.Map: 287 case reflect.Ptr: 288 if mtype.Elem().Kind() != reflect.Struct { 289 return []byte{}, errors.New("Only pointer to struct can be marshaled to TOML") 290 } 291 default: 292 return []byte{}, errors.New("Only a struct or map can be marshaled to TOML") 293 } 294 295 sval := reflect.ValueOf(v) 296 if isCustomMarshaler(mtype) { 297 return callCustomMarshaler(sval) 298 } 299 t, err := e.valueToTree(mtype, sval) 300 if err != nil { 301 return []byte{}, err 302 } 303 304 var buf bytes.Buffer 305 _, err = t.writeToOrdered(&buf, "", "", 0, e.arraysOneElementPerLine, e.order, false) 306 307 return buf.Bytes(), err 308} 309 310// Create next tree with a position based on Encoder.line 311func (e *Encoder) nextTree() *Tree { 312 return newTreeWithPosition(Position{Line: e.line, Col: 1}) 313} 314 315// Convert given marshal struct or map value to toml tree 316func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) { 317 if mtype.Kind() == reflect.Ptr { 318 return e.valueToTree(mtype.Elem(), mval.Elem()) 319 } 320 tval := e.nextTree() 321 switch mtype.Kind() { 322 case reflect.Struct: 323 switch mval.Interface().(type) { 324 case Tree: 325 reflect.ValueOf(tval).Elem().Set(mval) 326 default: 327 for i := 0; i < mtype.NumField(); i++ { 328 mtypef, mvalf := mtype.Field(i), mval.Field(i) 329 opts := tomlOptions(mtypef, e.annotation) 330 if opts.include && ((mtypef.Type.Kind() != reflect.Interface && !opts.omitempty) || !isZero(mvalf)) { 331 val, err := e.valueToToml(mtypef.Type, mvalf) 332 if err != nil { 333 return nil, err 334 } 335 336 tval.SetWithOptions(opts.name, SetOptions{ 337 Comment: opts.comment, 338 Commented: opts.commented, 339 Multiline: opts.multiline, 340 }, val) 341 } 342 } 343 } 344 case reflect.Map: 345 keys := mval.MapKeys() 346 if e.order == OrderPreserve && len(keys) > 0 { 347 // Sorting []reflect.Value is not straight forward. 348 // 349 // OrderPreserve will support deterministic results when string is used 350 // as the key to maps. 351 typ := keys[0].Type() 352 kind := keys[0].Kind() 353 if kind == reflect.String { 354 ikeys := make([]string, len(keys)) 355 for i := range keys { 356 ikeys[i] = keys[i].Interface().(string) 357 } 358 sort.Strings(ikeys) 359 for i := range ikeys { 360 keys[i] = reflect.ValueOf(ikeys[i]).Convert(typ) 361 } 362 } 363 } 364 for _, key := range keys { 365 mvalf := mval.MapIndex(key) 366 if (mtype.Elem().Kind() == reflect.Ptr || mtype.Elem().Kind() == reflect.Interface) && mvalf.IsNil() { 367 continue 368 } 369 val, err := e.valueToToml(mtype.Elem(), mvalf) 370 if err != nil { 371 return nil, err 372 } 373 if e.quoteMapKeys { 374 keyStr, err := tomlValueStringRepresentation(key.String(), "", "", e.arraysOneElementPerLine) 375 if err != nil { 376 return nil, err 377 } 378 tval.SetPath([]string{keyStr}, val) 379 } else { 380 tval.Set(key.String(), val) 381 } 382 } 383 } 384 return tval, nil 385} 386 387// Convert given marshal slice to slice of Toml trees 388func (e *Encoder) valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) { 389 tval := make([]*Tree, mval.Len(), mval.Len()) 390 for i := 0; i < mval.Len(); i++ { 391 val, err := e.valueToTree(mtype.Elem(), mval.Index(i)) 392 if err != nil { 393 return nil, err 394 } 395 tval[i] = val 396 } 397 return tval, nil 398} 399 400// Convert given marshal slice to slice of toml values 401func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) { 402 if mtype.Elem().Kind() == reflect.Interface { 403 return nil, fmt.Errorf("marshal can't handle []interface{}") 404 } 405 tval := make([]interface{}, mval.Len(), mval.Len()) 406 for i := 0; i < mval.Len(); i++ { 407 val, err := e.valueToToml(mtype.Elem(), mval.Index(i)) 408 if err != nil { 409 return nil, err 410 } 411 tval[i] = val 412 } 413 return tval, nil 414} 415 416// Convert given marshal value to toml value 417func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) { 418 e.line++ 419 if mtype.Kind() == reflect.Ptr { 420 return e.valueToToml(mtype.Elem(), mval.Elem()) 421 } 422 if mtype.Kind() == reflect.Interface { 423 return e.valueToToml(mval.Elem().Type(), mval.Elem()) 424 } 425 switch { 426 case isCustomMarshaler(mtype): 427 return callCustomMarshaler(mval) 428 case isTree(mtype): 429 return e.valueToTree(mtype, mval) 430 case isTreeSequence(mtype): 431 return e.valueToTreeSlice(mtype, mval) 432 case isOtherSequence(mtype): 433 return e.valueToOtherSlice(mtype, mval) 434 default: 435 switch mtype.Kind() { 436 case reflect.Bool: 437 return mval.Bool(), nil 438 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 439 if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) { 440 return fmt.Sprint(mval), nil 441 } 442 return mval.Int(), nil 443 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 444 return mval.Uint(), nil 445 case reflect.Float32, reflect.Float64: 446 return mval.Float(), nil 447 case reflect.String: 448 return mval.String(), nil 449 case reflect.Struct: 450 return mval.Interface(), nil 451 default: 452 return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind()) 453 } 454 } 455} 456 457// Unmarshal attempts to unmarshal the Tree into a Go struct pointed by v. 458// Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for 459// sub-structs, and only definite types can be unmarshaled. 460func (t *Tree) Unmarshal(v interface{}) error { 461 d := Decoder{tval: t, tagName: tagFieldName} 462 return d.unmarshal(v) 463} 464 465// Marshal returns the TOML encoding of Tree. 466// See Marshal() documentation for types mapping table. 467func (t *Tree) Marshal() ([]byte, error) { 468 var buf bytes.Buffer 469 _, err := t.WriteTo(&buf) 470 if err != nil { 471 return nil, err 472 } 473 return buf.Bytes(), nil 474} 475 476// Unmarshal parses the TOML-encoded data and stores the result in the value 477// pointed to by v. Behavior is similar to the Go json encoder, except that there 478// is no concept of an Unmarshaler interface or UnmarshalTOML function for 479// sub-structs, and currently only definite types can be unmarshaled to (i.e. no 480// `interface{}`). 481// 482// The following struct annotations are supported: 483// 484// toml:"Field" Overrides the field's name to map to. 485// default:"foo" Provides a default value. 486// 487// For default values, only fields of the following types are supported: 488// * string 489// * bool 490// * int 491// * int64 492// * float64 493// 494// See Marshal() documentation for types mapping table. 495func Unmarshal(data []byte, v interface{}) error { 496 t, err := LoadReader(bytes.NewReader(data)) 497 if err != nil { 498 return err 499 } 500 return t.Unmarshal(v) 501} 502 503// Decoder reads and decodes TOML values from an input stream. 504type Decoder struct { 505 r io.Reader 506 tval *Tree 507 encOpts 508 tagName string 509} 510 511// NewDecoder returns a new decoder that reads from r. 512func NewDecoder(r io.Reader) *Decoder { 513 return &Decoder{ 514 r: r, 515 encOpts: encOptsDefaults, 516 tagName: tagFieldName, 517 } 518} 519 520// Decode reads a TOML-encoded value from it's input 521// and unmarshals it in the value pointed at by v. 522// 523// See the documentation for Marshal for details. 524func (d *Decoder) Decode(v interface{}) error { 525 var err error 526 d.tval, err = LoadReader(d.r) 527 if err != nil { 528 return err 529 } 530 return d.unmarshal(v) 531} 532 533// SetTagName allows changing default tag "toml" 534func (d *Decoder) SetTagName(v string) *Decoder { 535 d.tagName = v 536 return d 537} 538 539func (d *Decoder) unmarshal(v interface{}) error { 540 mtype := reflect.TypeOf(v) 541 if mtype.Kind() != reflect.Ptr { 542 return errors.New("only a pointer to struct or map can be unmarshaled from TOML") 543 } 544 545 elem := mtype.Elem() 546 547 switch elem.Kind() { 548 case reflect.Struct, reflect.Map: 549 default: 550 return errors.New("only a pointer to struct or map can be unmarshaled from TOML") 551 } 552 553 vv := reflect.ValueOf(v).Elem() 554 555 sval, err := d.valueFromTree(elem, d.tval, &vv) 556 if err != nil { 557 return err 558 } 559 reflect.ValueOf(v).Elem().Set(sval) 560 return nil 561} 562 563// Convert toml tree to marshal struct or map, using marshal type. When mval1 564// is non-nil, merge fields into the given value instead of allocating a new one. 565func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.Value) (reflect.Value, error) { 566 if mtype.Kind() == reflect.Ptr { 567 return d.unwrapPointer(mtype, tval, mval1) 568 } 569 var mval reflect.Value 570 switch mtype.Kind() { 571 case reflect.Struct: 572 if mval1 != nil { 573 mval = *mval1 574 } else { 575 mval = reflect.New(mtype).Elem() 576 } 577 578 switch mval.Interface().(type) { 579 case Tree: 580 mval.Set(reflect.ValueOf(tval).Elem()) 581 default: 582 for i := 0; i < mtype.NumField(); i++ { 583 mtypef := mtype.Field(i) 584 an := annotation{tag: d.tagName} 585 opts := tomlOptions(mtypef, an) 586 if !opts.include { 587 continue 588 } 589 baseKey := opts.name 590 keysToTry := []string{ 591 baseKey, 592 strings.ToLower(baseKey), 593 strings.ToTitle(baseKey), 594 strings.ToLower(string(baseKey[0])) + baseKey[1:], 595 } 596 597 found := false 598 if tval != nil { 599 for _, key := range keysToTry { 600 exists := tval.Has(key) 601 if !exists { 602 continue 603 } 604 val := tval.Get(key) 605 fval := mval.Field(i) 606 mvalf, err := d.valueFromToml(mtypef.Type, val, &fval) 607 if err != nil { 608 return mval, formatError(err, tval.GetPosition(key)) 609 } 610 mval.Field(i).Set(mvalf) 611 found = true 612 break 613 } 614 } 615 616 if !found && opts.defaultValue != "" { 617 mvalf := mval.Field(i) 618 var val interface{} 619 var err error 620 switch mvalf.Kind() { 621 case reflect.Bool: 622 val, err = strconv.ParseBool(opts.defaultValue) 623 if err != nil { 624 return mval.Field(i), err 625 } 626 case reflect.Int: 627 val, err = strconv.Atoi(opts.defaultValue) 628 if err != nil { 629 return mval.Field(i), err 630 } 631 case reflect.String: 632 val = opts.defaultValue 633 case reflect.Int64: 634 val, err = strconv.ParseInt(opts.defaultValue, 10, 64) 635 if err != nil { 636 return mval.Field(i), err 637 } 638 case reflect.Float64: 639 val, err = strconv.ParseFloat(opts.defaultValue, 64) 640 if err != nil { 641 return mval.Field(i), err 642 } 643 default: 644 return mval.Field(i), fmt.Errorf("unsuported field type for default option") 645 } 646 mval.Field(i).Set(reflect.ValueOf(val)) 647 } 648 649 // save the old behavior above and try to check structs 650 if !found && opts.defaultValue == "" && mtypef.Type.Kind() == reflect.Struct { 651 tmpTval := tval 652 if !mtypef.Anonymous { 653 tmpTval = nil 654 } 655 v, err := d.valueFromTree(mtypef.Type, tmpTval, nil) 656 if err != nil { 657 return v, err 658 } 659 mval.Field(i).Set(v) 660 } 661 } 662 } 663 case reflect.Map: 664 mval = reflect.MakeMap(mtype) 665 for _, key := range tval.Keys() { 666 // TODO: path splits key 667 val := tval.GetPath([]string{key}) 668 mvalf, err := d.valueFromToml(mtype.Elem(), val, nil) 669 if err != nil { 670 return mval, formatError(err, tval.GetPosition(key)) 671 } 672 mval.SetMapIndex(reflect.ValueOf(key).Convert(mtype.Key()), mvalf) 673 } 674 } 675 return mval, nil 676} 677 678// Convert toml value to marshal struct/map slice, using marshal type 679func (d *Decoder) valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) { 680 mval := reflect.MakeSlice(mtype, len(tval), len(tval)) 681 for i := 0; i < len(tval); i++ { 682 val, err := d.valueFromTree(mtype.Elem(), tval[i], nil) 683 if err != nil { 684 return mval, err 685 } 686 mval.Index(i).Set(val) 687 } 688 return mval, nil 689} 690 691// Convert toml value to marshal primitive slice, using marshal type 692func (d *Decoder) valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) { 693 mval := reflect.MakeSlice(mtype, len(tval), len(tval)) 694 for i := 0; i < len(tval); i++ { 695 val, err := d.valueFromToml(mtype.Elem(), tval[i], nil) 696 if err != nil { 697 return mval, err 698 } 699 mval.Index(i).Set(val) 700 } 701 return mval, nil 702} 703 704// Convert toml value to marshal value, using marshal type. When mval1 is non-nil 705// and the given type is a struct value, merge fields into it. 706func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *reflect.Value) (reflect.Value, error) { 707 if mtype.Kind() == reflect.Ptr { 708 return d.unwrapPointer(mtype, tval, mval1) 709 } 710 711 switch t := tval.(type) { 712 case *Tree: 713 var mval11 *reflect.Value 714 if mtype.Kind() == reflect.Struct { 715 mval11 = mval1 716 } 717 718 if isTree(mtype) { 719 return d.valueFromTree(mtype, t, mval11) 720 } 721 722 if mtype.Kind() == reflect.Interface { 723 if mval1 == nil || mval1.IsNil() { 724 return d.valueFromTree(reflect.TypeOf(map[string]interface{}{}), t, nil) 725 } else { 726 return d.valueFromToml(mval1.Elem().Type(), t, nil) 727 } 728 } 729 730 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval) 731 case []*Tree: 732 if isTreeSequence(mtype) { 733 return d.valueFromTreeSlice(mtype, t) 734 } 735 if mtype.Kind() == reflect.Interface { 736 if mval1 == nil || mval1.IsNil() { 737 return d.valueFromTreeSlice(reflect.TypeOf([]map[string]interface{}{}), t) 738 } else { 739 ival := mval1.Elem() 740 return d.valueFromToml(mval1.Elem().Type(), t, &ival) 741 } 742 } 743 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval) 744 case []interface{}: 745 if isOtherSequence(mtype) { 746 return d.valueFromOtherSlice(mtype, t) 747 } 748 if mtype.Kind() == reflect.Interface { 749 if mval1 == nil || mval1.IsNil() { 750 return d.valueFromOtherSlice(reflect.TypeOf([]interface{}{}), t) 751 } else { 752 ival := mval1.Elem() 753 return d.valueFromToml(mval1.Elem().Type(), t, &ival) 754 } 755 } 756 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval) 757 default: 758 switch mtype.Kind() { 759 case reflect.Bool, reflect.Struct: 760 val := reflect.ValueOf(tval) 761 762 switch val.Type() { 763 case localDateType: 764 localDate := val.Interface().(LocalDate) 765 switch mtype { 766 case timeType: 767 return reflect.ValueOf(time.Date(localDate.Year, localDate.Month, localDate.Day, 0, 0, 0, 0, time.Local)), nil 768 } 769 case localDateTimeType: 770 localDateTime := val.Interface().(LocalDateTime) 771 switch mtype { 772 case timeType: 773 return reflect.ValueOf(time.Date( 774 localDateTime.Date.Year, 775 localDateTime.Date.Month, 776 localDateTime.Date.Day, 777 localDateTime.Time.Hour, 778 localDateTime.Time.Minute, 779 localDateTime.Time.Second, 780 localDateTime.Time.Nanosecond, 781 time.Local)), nil 782 } 783 } 784 785 // if this passes for when mtype is reflect.Struct, tval is a time.LocalTime 786 if !val.Type().ConvertibleTo(mtype) { 787 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) 788 } 789 790 return val.Convert(mtype), nil 791 case reflect.String: 792 val := reflect.ValueOf(tval) 793 // stupidly, int64 is convertible to string. So special case this. 794 if !val.Type().ConvertibleTo(mtype) || val.Kind() == reflect.Int64 { 795 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) 796 } 797 798 return val.Convert(mtype), nil 799 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 800 val := reflect.ValueOf(tval) 801 if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) && val.Kind() == reflect.String { 802 d, err := time.ParseDuration(val.String()) 803 if err != nil { 804 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v. %s", tval, tval, mtype.String(), err) 805 } 806 return reflect.ValueOf(d), nil 807 } 808 if !val.Type().ConvertibleTo(mtype) { 809 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) 810 } 811 if reflect.Indirect(reflect.New(mtype)).OverflowInt(val.Convert(mtype).Int()) { 812 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) 813 } 814 815 return val.Convert(mtype), nil 816 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 817 val := reflect.ValueOf(tval) 818 if !val.Type().ConvertibleTo(mtype) { 819 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) 820 } 821 822 if val.Convert(reflect.TypeOf(int(1))).Int() < 0 { 823 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String()) 824 } 825 if reflect.Indirect(reflect.New(mtype)).OverflowUint(uint64(val.Convert(mtype).Uint())) { 826 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) 827 } 828 829 return val.Convert(mtype), nil 830 case reflect.Float32, reflect.Float64: 831 val := reflect.ValueOf(tval) 832 if !val.Type().ConvertibleTo(mtype) { 833 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) 834 } 835 if reflect.Indirect(reflect.New(mtype)).OverflowFloat(val.Convert(mtype).Float()) { 836 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) 837 } 838 839 return val.Convert(mtype), nil 840 case reflect.Interface: 841 if mval1 == nil || mval1.IsNil() { 842 return reflect.ValueOf(tval), nil 843 } else { 844 ival := mval1.Elem() 845 return d.valueFromToml(mval1.Elem().Type(), t, &ival) 846 } 847 default: 848 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind()) 849 } 850 } 851} 852 853func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}, mval1 *reflect.Value) (reflect.Value, error) { 854 var melem *reflect.Value 855 856 if mval1 != nil && !mval1.IsNil() && (mtype.Elem().Kind() == reflect.Struct || mtype.Elem().Kind() == reflect.Interface) { 857 elem := mval1.Elem() 858 melem = &elem 859 } 860 861 val, err := d.valueFromToml(mtype.Elem(), tval, melem) 862 if err != nil { 863 return reflect.ValueOf(nil), err 864 } 865 mval := reflect.New(mtype.Elem()) 866 mval.Elem().Set(val) 867 return mval, nil 868} 869 870func tomlOptions(vf reflect.StructField, an annotation) tomlOpts { 871 tag := vf.Tag.Get(an.tag) 872 parse := strings.Split(tag, ",") 873 var comment string 874 if c := vf.Tag.Get(an.comment); c != "" { 875 comment = c 876 } 877 commented, _ := strconv.ParseBool(vf.Tag.Get(an.commented)) 878 multiline, _ := strconv.ParseBool(vf.Tag.Get(an.multiline)) 879 defaultValue := vf.Tag.Get(tagDefault) 880 result := tomlOpts{ 881 name: vf.Name, 882 comment: comment, 883 commented: commented, 884 multiline: multiline, 885 include: true, 886 omitempty: false, 887 defaultValue: defaultValue, 888 } 889 if parse[0] != "" { 890 if parse[0] == "-" && len(parse) == 1 { 891 result.include = false 892 } else { 893 result.name = strings.Trim(parse[0], " ") 894 } 895 } 896 if vf.PkgPath != "" { 897 result.include = false 898 } 899 if len(parse) > 1 && strings.Trim(parse[1], " ") == "omitempty" { 900 result.omitempty = true 901 } 902 if vf.Type.Kind() == reflect.Ptr { 903 result.omitempty = true 904 } 905 return result 906} 907 908func isZero(val reflect.Value) bool { 909 switch val.Type().Kind() { 910 case reflect.Map: 911 fallthrough 912 case reflect.Array: 913 fallthrough 914 case reflect.Slice: 915 return val.Len() == 0 916 default: 917 return reflect.DeepEqual(val.Interface(), reflect.Zero(val.Type()).Interface()) 918 } 919} 920 921func formatError(err error, pos Position) error { 922 if err.Error()[0] == '(' { // Error already contains position information 923 return err 924 } 925 return fmt.Errorf("%s: %s", pos, err) 926} 927