diff --git a/encode.go b/encode.go index 6b41533b..d9aa4a3f 100644 --- a/encode.go +++ b/encode.go @@ -654,10 +654,9 @@ func (enc *Encoder) isEmpty(rv reflect.Value) bool { case reflect.Array, reflect.Slice, reflect.Map, reflect.String: return rv.Len() == 0 case reflect.Struct: - if !rv.Type().Comparable() { - encPanic(fmt.Errorf("type %q cannot be used with omitempty as it's uncomparable", rv.Type())) + if rv.Type().Comparable() { + return reflect.Zero(rv.Type()).Interface() == rv.Interface() } - return reflect.Zero(rv.Type()).Interface() == rv.Interface() case reflect.Bool: return !rv.Bool() } diff --git a/encode_test.go b/encode_test.go index 4c7d6afa..9f456c97 100644 --- a/encode_test.go +++ b/encode_test.go @@ -182,23 +182,33 @@ func TestEncodeOmitEmptyStruct(t *testing.T) { } func TestEncodeWithOmitEmpty(t *testing.T) { + type uncomparable struct { + Field []string `toml:"Field,omitempty"` + } type simple struct { - Bool bool `toml:"bool,omitempty"` - String string `toml:"string,omitempty"` - Array [0]byte `toml:"array,omitempty"` - Slice []int `toml:"slice,omitempty"` - Map map[string]string `toml:"map,omitempty"` - Time time.Time `toml:"time,omitempty"` + Bool bool `toml:"bool,omitempty"` + String string `toml:"string,omitempty"` + Array [0]byte `toml:"array,omitempty"` + Slice []int `toml:"slice,omitempty"` + Map map[string]string `toml:"map,omitempty"` + Time time.Time `toml:"time,omitempty"` + Uncomparable1 uncomparable `toml:"uncomparable1,omitempty"` + Uncomparable2 uncomparable `toml:"uncomparable2,omitempty"` } var v simple - encodeExpected(t, "fields with omitempty are omitted when empty", v, "", nil) + encodeExpected(t, "fields with omitempty are omitted when empty", v, ` +[uncomparable1] + +[uncomparable2] +`, nil) v = simple{ - Bool: true, - String: " ", - Slice: []int{2, 3, 4}, - Map: map[string]string{"foo": "bar"}, - Time: time.Date(1985, 6, 18, 15, 16, 17, 0, time.UTC), + Bool: true, + String: " ", + Slice: []int{2, 3, 4}, + Map: map[string]string{"foo": "bar"}, + Time: time.Date(1985, 6, 18, 15, 16, 17, 0, time.UTC), + Uncomparable2: uncomparable{[]string{"XXX"}}, } expected := `bool = true string = " " @@ -207,43 +217,16 @@ time = 1985-06-18T15:16:17Z [map] foo = "bar" + +[uncomparable1] + +[uncomparable2] + Field = ["XXX"] ` encodeExpected(t, "fields with omitempty are not omitted when non-empty", v, expected, nil) } -func TestEncodeWithOmitEmptyError(t *testing.T) { - type nest struct { - Field []string `toml:"Field,omitempty"` - } - - tests := []struct { - in interface{} - wantErr string - }{ - { // Make sure it doesn't panic on uncomparable types; #360 - struct { - Values nest `toml:"values,omitempty"` - Empty nest `toml:"empty,omitempty"` - }{Values: nest{[]string{"XXX"}}}, - "cannot be used with omitempty as it's uncomparable", - }, - } - - for _, tt := range tests { - t.Run("", func(t *testing.T) { - buf := new(bytes.Buffer) - err := NewEncoder(buf).Encode(tt.in) - if !errorContains(err, tt.wantErr) { - t.Fatalf("wrong error: %v", err) - } - if buf.String() != "" { - t.Errorf("output not empty:\n%s", buf) - } - }) - } -} - func TestEncodeWithOmitZero(t *testing.T) { type simple struct { Number int `toml:"number,omitzero"` @@ -1164,8 +1147,8 @@ ArrayOfMixedSlices = [[1, 2], ["a", "b"]] func encodeExpected(t *testing.T, label string, val interface{}, want string, wantErr error) { t.Helper() - t.Run(label, func(t *testing.T) { + t.Helper() var buf bytes.Buffer err := NewEncoder(&buf).Encode(val) if err != wantErr {