From 0ed53acbb6ce55a3917f0c126c2b23c24ae4a843 Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Wed, 24 Nov 2021 14:38:20 -0500 Subject: [PATCH] Encoder: try to use pointer type TextMarshaler If a type does not implement the encoding.TextMarshaler interface but its pointer type does, use it if possible. Fixes #678 --- marshaler.go | 9 +++++-- marshaler_test.go | 66 +++++++++++++++++++++++++++++---------------- unmarshaler_test.go | 30 +++++++++++++++++++++ 3 files changed, 80 insertions(+), 25 deletions(-) diff --git a/marshaler.go b/marshaler.go index 648a6657..9425ebe1 100644 --- a/marshaler.go +++ b/marshaler.go @@ -209,7 +209,12 @@ func (enc *Encoder) encode(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, e } } - if v.Type().Implements(textMarshalerType) { + hasTextMarshaler := v.Type().Implements(textMarshalerType) + if hasTextMarshaler || (v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) { + if !hasTextMarshaler { + v = v.Addr() + } + if ctx.isRoot() { return nil, fmt.Errorf("toml: type %s implementing the TextMarshaler interface cannot be a root element", v.Type()) } @@ -657,7 +662,7 @@ func willConvertToTable(ctx encoderCtx, v reflect.Value) bool { if !v.IsValid() { return false } - if v.Type() == timeType || v.Type().Implements(textMarshalerType) { + if v.Type() == timeType || v.Type().Implements(textMarshalerType) || (v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) { return false } diff --git a/marshaler_test.go b/marshaler_test.go index 4e6c22a5..f9c21cdc 100644 --- a/marshaler_test.go +++ b/marshaler_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "math/big" "strings" "testing" @@ -798,6 +799,48 @@ func TestIssue590(t *testing.T) { require.NoError(t, err) } +func TestIssue571(t *testing.T) { + type Foo struct { + Float32 float32 + Float64 float64 + } + + const closeEnough = 1e-9 + + foo := Foo{ + Float32: 42, + Float64: 43, + } + b, err := toml.Marshal(foo) + require.NoError(t, err) + + var foo2 Foo + err = toml.Unmarshal(b, &foo2) + require.NoError(t, err) + + assert.InDelta(t, 42, foo2.Float32, closeEnough) + assert.InDelta(t, 43, foo2.Float64, closeEnough) +} + +func TestIssue678(t *testing.T) { + type Config struct { + BigInt big.Int + } + + cfg := &Config{ + BigInt: *big.NewInt(123), + } + + out, err := toml.Marshal(cfg) + require.NoError(t, err) + equalStringsIgnoreNewlines(t, "BigInt = '123'", string(out)) + + cfg2 := &Config{} + err = toml.Unmarshal(out, cfg2) + require.NoError(t, err) + require.Equal(t, cfg, cfg2) +} + func ExampleMarshal() { type MyConfig struct { Version int @@ -822,26 +865,3 @@ func ExampleMarshal() { // Name = 'go-toml' // Tags = ['go', 'toml'] } - -func TestIssue571(t *testing.T) { - type Foo struct { - Float32 float32 - Float64 float64 - } - - const closeEnough = 1e-9 - - foo := Foo{ - Float32: 42, - Float64: 43, - } - b, err := toml.Marshal(foo) - require.NoError(t, err) - - var foo2 Foo - err = toml.Unmarshal(b, &foo2) - require.NoError(t, err) - - assert.InDelta(t, 42, foo2.Float32, closeEnough) - assert.InDelta(t, 43, foo2.Float64, closeEnough) -} diff --git a/unmarshaler_test.go b/unmarshaler_test.go index d296675e..7215ee99 100644 --- a/unmarshaler_test.go +++ b/unmarshaler_test.go @@ -664,6 +664,36 @@ func TestUnmarshal(t *testing.T) { } }, }, + { + desc: "long string array into []string", + input: `A = ["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17"]`, + gen: func() test { + type doc struct { + A []string + } + + return test{ + target: &doc{}, + expected: &doc{A: []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17"}}, + } + }, + }, + { + desc: "long string array into []interface{}", + input: `A = ["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14", +"15","16","17"]`, + gen: func() test { + type doc struct { + A []interface{} + } + + return test{ + target: &doc{}, + expected: &doc{A: []interface{}{"0", "1", "2", "3", "4", "5", "6", + "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17"}}, + } + }, + }, { desc: "standard table", input: `[A]