48 case reflect.Float32, reflect.Float64: |
86 case reflect.Float32, reflect.Float64: |
49 return true |
87 return true |
50 case reflect.String: |
88 case reflect.String: |
51 return true |
89 return true |
52 case reflect.Struct: |
90 case reflect.Struct: |
53 return mtype == timeType || isCustomMarshaler(mtype) |
91 return mtype == timeType || mtype == localDateType || mtype == localDateTimeType || mtype == localTimeType || isCustomMarshaler(mtype) |
54 default: |
92 default: |
55 return false |
93 return false |
56 } |
94 } |
57 } |
95 } |
58 |
96 |
59 // Check if the given marshall type maps to a Tree slice |
97 // Check if the given marshal type maps to a Tree slice or array |
60 func isTreeSlice(mtype reflect.Type) bool { |
98 func isTreeSequence(mtype reflect.Type) bool { |
61 switch mtype.Kind() { |
99 switch mtype.Kind() { |
62 case reflect.Slice: |
100 case reflect.Ptr: |
63 return !isOtherSlice(mtype) |
101 return isTreeSequence(mtype.Elem()) |
|
102 case reflect.Slice, reflect.Array: |
|
103 return isTree(mtype.Elem()) |
64 default: |
104 default: |
65 return false |
105 return false |
66 } |
106 } |
67 } |
107 } |
68 |
108 |
69 // Check if the given marshall type maps to a non-Tree slice |
109 // Check if the given marshal type maps to a non-Tree slice or array |
70 func isOtherSlice(mtype reflect.Type) bool { |
110 func isOtherSequence(mtype reflect.Type) bool { |
71 switch mtype.Kind() { |
111 switch mtype.Kind() { |
72 case reflect.Ptr: |
112 case reflect.Ptr: |
73 return isOtherSlice(mtype.Elem()) |
113 return isOtherSequence(mtype.Elem()) |
74 case reflect.Slice: |
114 case reflect.Slice, reflect.Array: |
75 return isPrimitive(mtype.Elem()) || isOtherSlice(mtype.Elem()) |
115 return !isTreeSequence(mtype) |
76 default: |
116 default: |
77 return false |
117 return false |
78 } |
118 } |
79 } |
119 } |
80 |
120 |
81 // Check if the given marshall type maps to a Tree |
121 // Check if the given marshal type maps to a Tree |
82 func isTree(mtype reflect.Type) bool { |
122 func isTree(mtype reflect.Type) bool { |
83 switch mtype.Kind() { |
123 switch mtype.Kind() { |
|
124 case reflect.Ptr: |
|
125 return isTree(mtype.Elem()) |
84 case reflect.Map: |
126 case reflect.Map: |
85 return true |
127 return true |
86 case reflect.Struct: |
128 case reflect.Struct: |
87 return !isPrimitive(mtype) |
129 return !isPrimitive(mtype) |
88 default: |
130 default: |
133 uint64 uint, uint8-uint64, pointers to same |
175 uint64 uint, uint8-uint64, pointers to same |
134 int64 int, int8-uint64, pointers to same |
176 int64 int, int8-uint64, pointers to same |
135 float64 float32, float64, pointers to same |
177 float64 float32, float64, pointers to same |
136 string string, pointers to same |
178 string string, pointers to same |
137 bool bool, pointers to same |
179 bool bool, pointers to same |
138 time.Time time.Time{}, pointers to same |
180 time.LocalTime time.LocalTime{}, pointers to same |
|
181 |
|
182 For additional flexibility, use the Encoder API. |
139 */ |
183 */ |
140 func Marshal(v interface{}) ([]byte, error) { |
184 func Marshal(v interface{}) ([]byte, error) { |
141 return NewEncoder(nil).marshal(v) |
185 return NewEncoder(nil).marshal(v) |
142 } |
186 } |
143 |
187 |
144 // Encoder writes TOML values to an output stream. |
188 // Encoder writes TOML values to an output stream. |
145 type Encoder struct { |
189 type Encoder struct { |
146 w io.Writer |
190 w io.Writer |
147 encOpts |
191 encOpts |
|
192 annotation |
|
193 line int |
|
194 col int |
|
195 order marshalOrder |
148 } |
196 } |
149 |
197 |
150 // NewEncoder returns a new encoder that writes to w. |
198 // NewEncoder returns a new encoder that writes to w. |
151 func NewEncoder(w io.Writer) *Encoder { |
199 func NewEncoder(w io.Writer) *Encoder { |
152 return &Encoder{ |
200 return &Encoder{ |
153 w: w, |
201 w: w, |
154 encOpts: encOptsDefaults, |
202 encOpts: encOptsDefaults, |
|
203 annotation: annotationDefault, |
|
204 line: 0, |
|
205 col: 1, |
|
206 order: OrderAlphabetical, |
155 } |
207 } |
156 } |
208 } |
157 |
209 |
158 // Encode writes the TOML encoding of v to the stream. |
210 // Encode writes the TOML encoding of v to the stream. |
159 // |
211 // |
195 func (e *Encoder) ArraysWithOneElementPerLine(v bool) *Encoder { |
247 func (e *Encoder) ArraysWithOneElementPerLine(v bool) *Encoder { |
196 e.arraysOneElementPerLine = v |
248 e.arraysOneElementPerLine = v |
197 return e |
249 return e |
198 } |
250 } |
199 |
251 |
|
252 // Order allows to change in which order fields will be written to the output stream. |
|
253 func (e *Encoder) Order(ord marshalOrder) *Encoder { |
|
254 e.order = ord |
|
255 return e |
|
256 } |
|
257 |
|
258 // SetTagName allows changing default tag "toml" |
|
259 func (e *Encoder) SetTagName(v string) *Encoder { |
|
260 e.tag = v |
|
261 return e |
|
262 } |
|
263 |
|
264 // SetTagComment allows changing default tag "comment" |
|
265 func (e *Encoder) SetTagComment(v string) *Encoder { |
|
266 e.comment = v |
|
267 return e |
|
268 } |
|
269 |
|
270 // SetTagCommented allows changing default tag "commented" |
|
271 func (e *Encoder) SetTagCommented(v string) *Encoder { |
|
272 e.commented = v |
|
273 return e |
|
274 } |
|
275 |
|
276 // SetTagMultiline allows changing default tag "multiline" |
|
277 func (e *Encoder) SetTagMultiline(v string) *Encoder { |
|
278 e.multiline = v |
|
279 return e |
|
280 } |
|
281 |
200 func (e *Encoder) marshal(v interface{}) ([]byte, error) { |
282 func (e *Encoder) marshal(v interface{}) ([]byte, error) { |
201 mtype := reflect.TypeOf(v) |
283 mtype := reflect.TypeOf(v) |
202 if mtype.Kind() != reflect.Struct { |
284 |
203 return []byte{}, errors.New("Only a struct can be marshaled to TOML") |
285 switch mtype.Kind() { |
204 } |
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 |
205 sval := reflect.ValueOf(v) |
295 sval := reflect.ValueOf(v) |
206 if isCustomMarshaler(mtype) { |
296 if isCustomMarshaler(mtype) { |
207 return callCustomMarshaler(sval) |
297 return callCustomMarshaler(sval) |
208 } |
298 } |
209 t, err := e.valueToTree(mtype, sval) |
299 t, err := e.valueToTree(mtype, sval) |
210 if err != nil { |
300 if err != nil { |
211 return []byte{}, err |
301 return []byte{}, err |
212 } |
302 } |
213 |
303 |
214 var buf bytes.Buffer |
304 var buf bytes.Buffer |
215 _, err = t.writeTo(&buf, "", "", 0, e.arraysOneElementPerLine) |
305 _, err = t.writeToOrdered(&buf, "", "", 0, e.arraysOneElementPerLine, e.order) |
216 |
306 |
217 return buf.Bytes(), err |
307 return buf.Bytes(), err |
|
308 } |
|
309 |
|
310 // Create next tree with a position based on Encoder.line |
|
311 func (e *Encoder) nextTree() *Tree { |
|
312 return newTreeWithPosition(Position{Line: e.line, Col: 1}) |
218 } |
313 } |
219 |
314 |
220 // Convert given marshal struct or map value to toml tree |
315 // Convert given marshal struct or map value to toml tree |
221 func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) { |
316 func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) { |
222 if mtype.Kind() == reflect.Ptr { |
317 if mtype.Kind() == reflect.Ptr { |
223 return e.valueToTree(mtype.Elem(), mval.Elem()) |
318 return e.valueToTree(mtype.Elem(), mval.Elem()) |
224 } |
319 } |
225 tval := newTree() |
320 tval := e.nextTree() |
226 switch mtype.Kind() { |
321 switch mtype.Kind() { |
227 case reflect.Struct: |
322 case reflect.Struct: |
228 for i := 0; i < mtype.NumField(); i++ { |
323 for i := 0; i < mtype.NumField(); i++ { |
229 mtypef, mvalf := mtype.Field(i), mval.Field(i) |
324 mtypef, mvalf := mtype.Field(i), mval.Field(i) |
230 opts := tomlOptions(mtypef) |
325 opts := tomlOptions(mtypef, e.annotation) |
231 if opts.include && (!opts.omitempty || !isZero(mvalf)) { |
326 if opts.include && (!opts.omitempty || !isZero(mvalf)) { |
232 val, err := e.valueToToml(mtypef.Type, mvalf) |
327 val, err := e.valueToToml(mtypef.Type, mvalf) |
233 if err != nil { |
328 if err != nil { |
234 return nil, err |
329 return nil, err |
235 } |
330 } |
288 return tval, nil |
402 return tval, nil |
289 } |
403 } |
290 |
404 |
291 // Convert given marshal value to toml value |
405 // Convert given marshal value to toml value |
292 func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) { |
406 func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) { |
|
407 e.line++ |
293 if mtype.Kind() == reflect.Ptr { |
408 if mtype.Kind() == reflect.Ptr { |
294 return e.valueToToml(mtype.Elem(), mval.Elem()) |
409 return e.valueToToml(mtype.Elem(), mval.Elem()) |
295 } |
410 } |
296 switch { |
411 switch { |
297 case isCustomMarshaler(mtype): |
412 case isCustomMarshaler(mtype): |
298 return callCustomMarshaler(mval) |
413 return callCustomMarshaler(mval) |
299 case isTree(mtype): |
414 case isTree(mtype): |
300 return e.valueToTree(mtype, mval) |
415 return e.valueToTree(mtype, mval) |
301 case isTreeSlice(mtype): |
416 case isTreeSequence(mtype): |
302 return e.valueToTreeSlice(mtype, mval) |
417 return e.valueToTreeSlice(mtype, mval) |
303 case isOtherSlice(mtype): |
418 case isOtherSequence(mtype): |
304 return e.valueToOtherSlice(mtype, mval) |
419 return e.valueToOtherSlice(mtype, mval) |
305 default: |
420 default: |
306 switch mtype.Kind() { |
421 switch mtype.Kind() { |
307 case reflect.Bool: |
422 case reflect.Bool: |
308 return mval.Bool(), nil |
423 return mval.Bool(), nil |
309 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
424 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
|
425 if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) { |
|
426 return fmt.Sprint(mval), nil |
|
427 } |
310 return mval.Int(), nil |
428 return mval.Int(), nil |
311 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
429 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
312 return mval.Uint(), nil |
430 return mval.Uint(), nil |
313 case reflect.Float32, reflect.Float64: |
431 case reflect.Float32, reflect.Float64: |
314 return mval.Float(), nil |
432 return mval.Float(), nil |
315 case reflect.String: |
433 case reflect.String: |
316 return mval.String(), nil |
434 return mval.String(), nil |
317 case reflect.Struct: |
435 case reflect.Struct: |
318 return mval.Interface().(time.Time), nil |
436 return mval.Interface(), nil |
319 default: |
437 default: |
320 return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind()) |
438 return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind()) |
321 } |
439 } |
322 } |
440 } |
323 } |
441 } |
324 |
442 |
325 // Unmarshal attempts to unmarshal the Tree into a Go struct pointed by v. |
443 // Unmarshal attempts to unmarshal the Tree into a Go struct pointed by v. |
326 // Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for |
444 // Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for |
327 // sub-structs, and only definite types can be unmarshaled. |
445 // sub-structs, and only definite types can be unmarshaled. |
328 func (t *Tree) Unmarshal(v interface{}) error { |
446 func (t *Tree) Unmarshal(v interface{}) error { |
329 d := Decoder{tval: t} |
447 d := Decoder{tval: t, tagName: tagFieldName} |
330 return d.unmarshal(v) |
448 return d.unmarshal(v) |
331 } |
449 } |
332 |
450 |
333 // Marshal returns the TOML encoding of Tree. |
451 // Marshal returns the TOML encoding of Tree. |
334 // See Marshal() documentation for types mapping table. |
452 // See Marshal() documentation for types mapping table. |
335 func (t *Tree) Marshal() ([]byte, error) { |
453 func (t *Tree) Marshal() ([]byte, error) { |
336 var buf bytes.Buffer |
454 var buf bytes.Buffer |
337 err := NewEncoder(&buf).Encode(t) |
455 _, err := t.WriteTo(&buf) |
338 return buf.Bytes(), err |
456 if err != nil { |
|
457 return nil, err |
|
458 } |
|
459 return buf.Bytes(), nil |
339 } |
460 } |
340 |
461 |
341 // Unmarshal parses the TOML-encoded data and stores the result in the value |
462 // Unmarshal parses the TOML-encoded data and stores the result in the value |
342 // pointed to by v. Behavior is similar to the Go json encoder, except that there |
463 // pointed to by v. Behavior is similar to the Go json encoder, except that there |
343 // is no concept of an Unmarshaler interface or UnmarshalTOML function for |
464 // is no concept of an Unmarshaler interface or UnmarshalTOML function for |
383 return err |
514 return err |
384 } |
515 } |
385 return d.unmarshal(v) |
516 return d.unmarshal(v) |
386 } |
517 } |
387 |
518 |
|
519 // SetTagName allows changing default tag "toml" |
|
520 func (d *Decoder) SetTagName(v string) *Decoder { |
|
521 d.tagName = v |
|
522 return d |
|
523 } |
|
524 |
388 func (d *Decoder) unmarshal(v interface{}) error { |
525 func (d *Decoder) unmarshal(v interface{}) error { |
389 mtype := reflect.TypeOf(v) |
526 mtype := reflect.TypeOf(v) |
390 if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct { |
527 if mtype.Kind() != reflect.Ptr { |
391 return errors.New("Only a pointer to struct can be unmarshaled from TOML") |
528 return errors.New("only a pointer to struct or map can be unmarshaled from TOML") |
392 } |
529 } |
393 |
530 |
394 sval, err := d.valueFromTree(mtype.Elem(), d.tval) |
531 elem := mtype.Elem() |
|
532 |
|
533 switch elem.Kind() { |
|
534 case reflect.Struct, reflect.Map: |
|
535 default: |
|
536 return errors.New("only a pointer to struct or map can be unmarshaled from TOML") |
|
537 } |
|
538 |
|
539 vv := reflect.ValueOf(v).Elem() |
|
540 |
|
541 sval, err := d.valueFromTree(elem, d.tval, &vv) |
395 if err != nil { |
542 if err != nil { |
396 return err |
543 return err |
397 } |
544 } |
398 reflect.ValueOf(v).Elem().Set(sval) |
545 reflect.ValueOf(v).Elem().Set(sval) |
399 return nil |
546 return nil |
400 } |
547 } |
401 |
548 |
402 // Convert toml tree to marshal struct or map, using marshal type |
549 // Convert toml tree to marshal struct or map, using marshal type. When mval1 |
403 func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) { |
550 // is non-nil, merge fields into the given value instead of allocating a new one. |
|
551 func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.Value) (reflect.Value, error) { |
404 if mtype.Kind() == reflect.Ptr { |
552 if mtype.Kind() == reflect.Ptr { |
405 return d.unwrapPointer(mtype, tval) |
553 return d.unwrapPointer(mtype, tval, mval1) |
406 } |
554 } |
407 var mval reflect.Value |
555 var mval reflect.Value |
408 switch mtype.Kind() { |
556 switch mtype.Kind() { |
409 case reflect.Struct: |
557 case reflect.Struct: |
410 mval = reflect.New(mtype).Elem() |
558 if mval1 != nil { |
|
559 mval = *mval1 |
|
560 } else { |
|
561 mval = reflect.New(mtype).Elem() |
|
562 } |
|
563 |
411 for i := 0; i < mtype.NumField(); i++ { |
564 for i := 0; i < mtype.NumField(); i++ { |
412 mtypef := mtype.Field(i) |
565 mtypef := mtype.Field(i) |
413 opts := tomlOptions(mtypef) |
566 an := annotation{tag: d.tagName} |
|
567 opts := tomlOptions(mtypef, an) |
414 if opts.include { |
568 if opts.include { |
415 baseKey := opts.name |
569 baseKey := opts.name |
416 keysToTry := []string{baseKey, strings.ToLower(baseKey), strings.ToTitle(baseKey)} |
570 keysToTry := []string{ |
|
571 baseKey, |
|
572 strings.ToLower(baseKey), |
|
573 strings.ToTitle(baseKey), |
|
574 strings.ToLower(string(baseKey[0])) + baseKey[1:], |
|
575 } |
|
576 |
|
577 found := false |
417 for _, key := range keysToTry { |
578 for _, key := range keysToTry { |
418 exists := tval.Has(key) |
579 exists := tval.Has(key) |
419 if !exists { |
580 if !exists { |
420 continue |
581 continue |
421 } |
582 } |
422 val := tval.Get(key) |
583 val := tval.Get(key) |
423 mvalf, err := d.valueFromToml(mtypef.Type, val) |
584 fval := mval.Field(i) |
|
585 mvalf, err := d.valueFromToml(mtypef.Type, val, &fval) |
424 if err != nil { |
586 if err != nil { |
425 return mval, formatError(err, tval.GetPosition(key)) |
587 return mval, formatError(err, tval.GetPosition(key)) |
426 } |
588 } |
427 mval.Field(i).Set(mvalf) |
589 mval.Field(i).Set(mvalf) |
|
590 found = true |
428 break |
591 break |
|
592 } |
|
593 |
|
594 if !found && opts.defaultValue != "" { |
|
595 mvalf := mval.Field(i) |
|
596 var val interface{} |
|
597 var err error |
|
598 switch mvalf.Kind() { |
|
599 case reflect.Bool: |
|
600 val, err = strconv.ParseBool(opts.defaultValue) |
|
601 if err != nil { |
|
602 return mval.Field(i), err |
|
603 } |
|
604 case reflect.Int: |
|
605 val, err = strconv.Atoi(opts.defaultValue) |
|
606 if err != nil { |
|
607 return mval.Field(i), err |
|
608 } |
|
609 case reflect.String: |
|
610 val = opts.defaultValue |
|
611 case reflect.Int64: |
|
612 val, err = strconv.ParseInt(opts.defaultValue, 10, 64) |
|
613 if err != nil { |
|
614 return mval.Field(i), err |
|
615 } |
|
616 case reflect.Float64: |
|
617 val, err = strconv.ParseFloat(opts.defaultValue, 64) |
|
618 if err != nil { |
|
619 return mval.Field(i), err |
|
620 } |
|
621 default: |
|
622 return mval.Field(i), fmt.Errorf("unsuported field type for default option") |
|
623 } |
|
624 mval.Field(i).Set(reflect.ValueOf(val)) |
|
625 } |
|
626 |
|
627 // save the old behavior above and try to check anonymous structs |
|
628 if !found && opts.defaultValue == "" && mtypef.Anonymous && mtypef.Type.Kind() == reflect.Struct { |
|
629 v, err := d.valueFromTree(mtypef.Type, tval, nil) |
|
630 if err != nil { |
|
631 return v, err |
|
632 } |
|
633 mval.Field(i).Set(v) |
429 } |
634 } |
430 } |
635 } |
431 } |
636 } |
432 case reflect.Map: |
637 case reflect.Map: |
433 mval = reflect.MakeMap(mtype) |
638 mval = reflect.MakeMap(mtype) |
434 for _, key := range tval.Keys() { |
639 for _, key := range tval.Keys() { |
435 // TODO: path splits key |
640 // TODO: path splits key |
436 val := tval.GetPath([]string{key}) |
641 val := tval.GetPath([]string{key}) |
437 mvalf, err := d.valueFromToml(mtype.Elem(), val) |
642 mvalf, err := d.valueFromToml(mtype.Elem(), val, nil) |
438 if err != nil { |
643 if err != nil { |
439 return mval, formatError(err, tval.GetPosition(key)) |
644 return mval, formatError(err, tval.GetPosition(key)) |
440 } |
645 } |
441 mval.SetMapIndex(reflect.ValueOf(key), mvalf) |
646 mval.SetMapIndex(reflect.ValueOf(key).Convert(mtype.Key()), mvalf) |
442 } |
647 } |
443 } |
648 } |
444 return mval, nil |
649 return mval, nil |
445 } |
650 } |
446 |
651 |
447 // Convert toml value to marshal struct/map slice, using marshal type |
652 // Convert toml value to marshal struct/map slice, using marshal type |
448 func (d *Decoder) valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) { |
653 func (d *Decoder) valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) { |
449 mval := reflect.MakeSlice(mtype, len(tval), len(tval)) |
654 mval := reflect.MakeSlice(mtype, len(tval), len(tval)) |
450 for i := 0; i < len(tval); i++ { |
655 for i := 0; i < len(tval); i++ { |
451 val, err := d.valueFromTree(mtype.Elem(), tval[i]) |
656 val, err := d.valueFromTree(mtype.Elem(), tval[i], nil) |
452 if err != nil { |
657 if err != nil { |
453 return mval, err |
658 return mval, err |
454 } |
659 } |
455 mval.Index(i).Set(val) |
660 mval.Index(i).Set(val) |
456 } |
661 } |
459 |
664 |
460 // Convert toml value to marshal primitive slice, using marshal type |
665 // Convert toml value to marshal primitive slice, using marshal type |
461 func (d *Decoder) valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) { |
666 func (d *Decoder) valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) { |
462 mval := reflect.MakeSlice(mtype, len(tval), len(tval)) |
667 mval := reflect.MakeSlice(mtype, len(tval), len(tval)) |
463 for i := 0; i < len(tval); i++ { |
668 for i := 0; i < len(tval); i++ { |
464 val, err := d.valueFromToml(mtype.Elem(), tval[i]) |
669 val, err := d.valueFromToml(mtype.Elem(), tval[i], nil) |
465 if err != nil { |
670 if err != nil { |
466 return mval, err |
671 return mval, err |
467 } |
672 } |
468 mval.Index(i).Set(val) |
673 mval.Index(i).Set(val) |
469 } |
674 } |
470 return mval, nil |
675 return mval, nil |
471 } |
676 } |
472 |
677 |
473 // Convert toml value to marshal value, using marshal type |
678 // Convert toml value to marshal value, using marshal type. When mval1 is non-nil |
474 func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) { |
679 // and the given type is a struct value, merge fields into it. |
|
680 func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *reflect.Value) (reflect.Value, error) { |
475 if mtype.Kind() == reflect.Ptr { |
681 if mtype.Kind() == reflect.Ptr { |
476 return d.unwrapPointer(mtype, tval) |
682 return d.unwrapPointer(mtype, tval, mval1) |
477 } |
683 } |
478 |
684 |
479 switch tval.(type) { |
685 switch t := tval.(type) { |
480 case *Tree: |
686 case *Tree: |
|
687 var mval11 *reflect.Value |
|
688 if mtype.Kind() == reflect.Struct { |
|
689 mval11 = mval1 |
|
690 } |
|
691 |
481 if isTree(mtype) { |
692 if isTree(mtype) { |
482 return d.valueFromTree(mtype, tval.(*Tree)) |
693 return d.valueFromTree(mtype, t, mval11) |
483 } |
694 } |
484 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval) |
695 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval) |
485 case []*Tree: |
696 case []*Tree: |
486 if isTreeSlice(mtype) { |
697 if isTreeSequence(mtype) { |
487 return d.valueFromTreeSlice(mtype, tval.([]*Tree)) |
698 return d.valueFromTreeSlice(mtype, t) |
488 } |
699 } |
489 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval) |
700 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval) |
490 case []interface{}: |
701 case []interface{}: |
491 if isOtherSlice(mtype) { |
702 if isOtherSequence(mtype) { |
492 return d.valueFromOtherSlice(mtype, tval.([]interface{})) |
703 return d.valueFromOtherSlice(mtype, t) |
493 } |
704 } |
494 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval) |
705 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval) |
495 default: |
706 default: |
496 switch mtype.Kind() { |
707 switch mtype.Kind() { |
497 case reflect.Bool, reflect.Struct: |
708 case reflect.Bool, reflect.Struct: |
498 val := reflect.ValueOf(tval) |
709 val := reflect.ValueOf(tval) |
499 // if this passes for when mtype is reflect.Struct, tval is a time.Time |
710 |
|
711 switch val.Type() { |
|
712 case localDateType: |
|
713 localDate := val.Interface().(LocalDate) |
|
714 switch mtype { |
|
715 case timeType: |
|
716 return reflect.ValueOf(time.Date(localDate.Year, localDate.Month, localDate.Day, 0, 0, 0, 0, time.Local)), nil |
|
717 } |
|
718 case localDateTimeType: |
|
719 localDateTime := val.Interface().(LocalDateTime) |
|
720 switch mtype { |
|
721 case timeType: |
|
722 return reflect.ValueOf(time.Date( |
|
723 localDateTime.Date.Year, |
|
724 localDateTime.Date.Month, |
|
725 localDateTime.Date.Day, |
|
726 localDateTime.Time.Hour, |
|
727 localDateTime.Time.Minute, |
|
728 localDateTime.Time.Second, |
|
729 localDateTime.Time.Nanosecond, |
|
730 time.Local)), nil |
|
731 } |
|
732 } |
|
733 |
|
734 // if this passes for when mtype is reflect.Struct, tval is a time.LocalTime |
500 if !val.Type().ConvertibleTo(mtype) { |
735 if !val.Type().ConvertibleTo(mtype) { |
501 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) |
736 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) |
502 } |
737 } |
503 |
738 |
504 return val.Convert(mtype), nil |
739 return val.Convert(mtype), nil |
510 } |
745 } |
511 |
746 |
512 return val.Convert(mtype), nil |
747 return val.Convert(mtype), nil |
513 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
748 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
514 val := reflect.ValueOf(tval) |
749 val := reflect.ValueOf(tval) |
|
750 if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) && val.Kind() == reflect.String { |
|
751 d, err := time.ParseDuration(val.String()) |
|
752 if err != nil { |
|
753 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v. %s", tval, tval, mtype.String(), err) |
|
754 } |
|
755 return reflect.ValueOf(d), nil |
|
756 } |
515 if !val.Type().ConvertibleTo(mtype) { |
757 if !val.Type().ConvertibleTo(mtype) { |
516 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) |
758 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) |
517 } |
759 } |
518 if reflect.Indirect(reflect.New(mtype)).OverflowInt(val.Int()) { |
760 if reflect.Indirect(reflect.New(mtype)).OverflowInt(val.Convert(mtype).Int()) { |
519 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) |
761 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) |
520 } |
762 } |
521 |
763 |
522 return val.Convert(mtype), nil |
764 return val.Convert(mtype), nil |
523 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: |
765 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: |
524 val := reflect.ValueOf(tval) |
766 val := reflect.ValueOf(tval) |
525 if !val.Type().ConvertibleTo(mtype) { |
767 if !val.Type().ConvertibleTo(mtype) { |
526 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) |
768 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) |
527 } |
769 } |
528 if val.Int() < 0 { |
770 |
|
771 if val.Convert(reflect.TypeOf(int(1))).Int() < 0 { |
529 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String()) |
772 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String()) |
530 } |
773 } |
531 if reflect.Indirect(reflect.New(mtype)).OverflowUint(uint64(val.Int())) { |
774 if reflect.Indirect(reflect.New(mtype)).OverflowUint(uint64(val.Convert(mtype).Uint())) { |
532 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) |
775 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) |
533 } |
776 } |
534 |
777 |
535 return val.Convert(mtype), nil |
778 return val.Convert(mtype), nil |
536 case reflect.Float32, reflect.Float64: |
779 case reflect.Float32, reflect.Float64: |
537 val := reflect.ValueOf(tval) |
780 val := reflect.ValueOf(tval) |
538 if !val.Type().ConvertibleTo(mtype) { |
781 if !val.Type().ConvertibleTo(mtype) { |
539 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) |
782 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) |
540 } |
783 } |
541 if reflect.Indirect(reflect.New(mtype)).OverflowFloat(val.Float()) { |
784 if reflect.Indirect(reflect.New(mtype)).OverflowFloat(val.Convert(mtype).Float()) { |
542 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) |
785 return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) |
543 } |
786 } |
544 |
787 |
545 return val.Convert(mtype), nil |
788 return val.Convert(mtype), nil |
546 default: |
789 default: |
547 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind()) |
790 return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind()) |
548 } |
791 } |
549 } |
792 } |
550 } |
793 } |
551 |
794 |
552 func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) { |
795 func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}, mval1 *reflect.Value) (reflect.Value, error) { |
553 val, err := d.valueFromToml(mtype.Elem(), tval) |
796 var melem *reflect.Value |
|
797 |
|
798 if mval1 != nil && !mval1.IsNil() && mtype.Elem().Kind() == reflect.Struct { |
|
799 elem := mval1.Elem() |
|
800 melem = &elem |
|
801 } |
|
802 |
|
803 val, err := d.valueFromToml(mtype.Elem(), tval, melem) |
554 if err != nil { |
804 if err != nil { |
555 return reflect.ValueOf(nil), err |
805 return reflect.ValueOf(nil), err |
556 } |
806 } |
557 mval := reflect.New(mtype.Elem()) |
807 mval := reflect.New(mtype.Elem()) |
558 mval.Elem().Set(val) |
808 mval.Elem().Set(val) |
559 return mval, nil |
809 return mval, nil |
560 } |
810 } |
561 |
811 |
562 func tomlOptions(vf reflect.StructField) tomlOpts { |
812 func tomlOptions(vf reflect.StructField, an annotation) tomlOpts { |
563 tag := vf.Tag.Get("toml") |
813 tag := vf.Tag.Get(an.tag) |
564 parse := strings.Split(tag, ",") |
814 parse := strings.Split(tag, ",") |
565 var comment string |
815 var comment string |
566 if c := vf.Tag.Get("comment"); c != "" { |
816 if c := vf.Tag.Get(an.comment); c != "" { |
567 comment = c |
817 comment = c |
568 } |
818 } |
569 commented, _ := strconv.ParseBool(vf.Tag.Get("commented")) |
819 commented, _ := strconv.ParseBool(vf.Tag.Get(an.commented)) |
570 multiline, _ := strconv.ParseBool(vf.Tag.Get(tagKeyMultiline)) |
820 multiline, _ := strconv.ParseBool(vf.Tag.Get(an.multiline)) |
571 result := tomlOpts{name: vf.Name, comment: comment, commented: commented, multiline: multiline, include: true, omitempty: false} |
821 defaultValue := vf.Tag.Get(tagDefault) |
|
822 result := tomlOpts{ |
|
823 name: vf.Name, |
|
824 comment: comment, |
|
825 commented: commented, |
|
826 multiline: multiline, |
|
827 include: true, |
|
828 omitempty: false, |
|
829 defaultValue: defaultValue, |
|
830 } |
572 if parse[0] != "" { |
831 if parse[0] != "" { |
573 if parse[0] == "-" && len(parse) == 1 { |
832 if parse[0] == "-" && len(parse) == 1 { |
574 result.include = false |
833 result.include = false |
575 } else { |
834 } else { |
576 result.name = strings.Trim(parse[0], " ") |
835 result.name = strings.Trim(parse[0], " ") |