Assisted-by: DeepSeek V4.1 Flash
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
package interpres
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
@@ -63,6 +64,19 @@ func (d *decoder) assign(data any, dst reflect.Value) error {
|
||||
}
|
||||
}
|
||||
|
||||
// A TOML string fills a destination that implements
|
||||
// encoding.TextUnmarshaler, the rule encoding/json follows. Every other
|
||||
// value kind keeps its own rule, so an integer still reaches a numeric
|
||||
// destination.
|
||||
if s, isString := data.(string); isString {
|
||||
if tu, ok := textUnmarshalerOf(dst); ok {
|
||||
if err := tu.UnmarshalText([]byte(s)); err != nil {
|
||||
return fmt.Errorf("unmarshal text: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
switch v := data.(type) {
|
||||
case map[string]any:
|
||||
return d.assignTable(v, dst)
|
||||
@@ -71,6 +85,9 @@ func (d *decoder) assign(data any, dst reflect.Value) error {
|
||||
case []any:
|
||||
return d.assignSlice(v, dst)
|
||||
case string:
|
||||
if dst.Type() == durationType {
|
||||
return setDuration(dst, v)
|
||||
}
|
||||
return setBasic(dst, reflect.ValueOf(v), "string")
|
||||
case bool:
|
||||
return setBasic(dst, reflect.ValueOf(v), "bool")
|
||||
@@ -94,6 +111,26 @@ func (d *decoder) assign(data any, dst reflect.Value) error {
|
||||
}
|
||||
}
|
||||
|
||||
// textUnmarshalerOf finds the encoding.TextUnmarshaler for dst: on the value
|
||||
// itself, or on its address, so a pointer-receiver UnmarshalText is invoked on
|
||||
// an addressable struct field. The TOML date-time types are excluded, because
|
||||
// they carry time.Time's UnmarshalText through an embedded field while their
|
||||
// only accepted form is a bare timestamp.
|
||||
func textUnmarshalerOf(dst reflect.Value) (encoding.TextUnmarshaler, bool) {
|
||||
if !dst.CanInterface() || isDateTimeType(dst.Type()) {
|
||||
return nil, false
|
||||
}
|
||||
if u, ok := dst.Interface().(encoding.TextUnmarshaler); ok {
|
||||
return u, true
|
||||
}
|
||||
if dst.CanAddr() {
|
||||
if u, ok := dst.Addr().Interface().(encoding.TextUnmarshaler); ok {
|
||||
return u, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (d *decoder) assignTable(tbl map[string]any, dst reflect.Value) error {
|
||||
switch dst.Kind() {
|
||||
case reflect.Struct:
|
||||
@@ -209,6 +246,19 @@ func setBasic(dst, val reflect.Value, kind string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// setDuration reads a duration literal into a time.Duration destination. TOML
|
||||
// has no duration type, so the encoder writes the canonical Go form and the
|
||||
// decoder reads that back; a bare integer stays the nanosecond count it has
|
||||
// always been, and reaches the destination through setInt.
|
||||
func setDuration(dst reflect.Value, s string) error {
|
||||
d, err := time.ParseDuration(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("interpres: invalid duration %q", s)
|
||||
}
|
||||
dst.SetInt(int64(d))
|
||||
return nil
|
||||
}
|
||||
|
||||
func setInt(dst reflect.Value, v int64) error {
|
||||
switch dst.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
|
||||
Reference in New Issue
Block a user