diff --git a/encode.go b/encode.go index 64e8c47e..c7e227c7 100644 --- a/encode.go +++ b/encode.go @@ -343,6 +343,14 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value) { if keyName == "" { keyName = sft.Name } + + keyName, opts := getOptions(keyName) + if _, ok := opts["omitempty"]; ok && isEmpty(sf) { + continue + } else if _, ok := opts["omitzero"]; ok && isZero(sf) { + continue + } + enc.encode(key.add(keyName), sf) } } @@ -433,6 +441,53 @@ func tomlArrayType(rv reflect.Value) tomlType { return firstType } +func getOptions(keyName string) (string, map[string]struct{}) { + opts := make(map[string]struct{}) + ss := strings.Split(keyName, ",") + name := ss[0] + if len(ss) > 1 { + for _, opt := range ss { + opts[opt] = struct{}{} + } + } + + return name, opts +} + +func isZero(rv reflect.Value) bool { + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if rv.Int() == 0 { + return true + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + if rv.Uint() == 0 { + return true + } + case reflect.Float32, reflect.Float64: + if rv.Float() == 0.0 { + return true + } + } + + return false +} + +func isEmpty(rv reflect.Value) bool { + switch rv.Kind() { + case reflect.String: + if len(strings.TrimSpace(rv.String())) == 0 { + return true + } + case reflect.Array, reflect.Slice, reflect.Map: + if rv.Len() == 0 { + return true + } + } + + return false +} + func (enc *Encoder) newline() { if enc.hasWritten { enc.wf("\n") diff --git a/encode_test.go b/encode_test.go index 74a5ee5d..445ca8e2 100644 --- a/encode_test.go +++ b/encode_test.go @@ -455,6 +455,42 @@ func TestEncodeArrayHashWithNormalHashOrder(t *testing.T) { encodeExpected(t, "array hash with normal hash order", val, expected, nil) } +func TestEncodeWithOmitEmpty(t *testing.T) { + type simple struct { + User string `toml:"user"` + Pass string `toml:"password,omitempty"` + } + + value := simple{"Testing", ""} + expected := fmt.Sprintf("user = %q\n", value.User) + encodeExpected(t, "simple with omitempty, is empty", value, expected, nil) + value.Pass = "some password" + expected = fmt.Sprintf("user = %q\npassword = %q\n", value.User, value.Pass) + encodeExpected(t, "simple with omitempty, not empty", value, expected, nil) +} + +func TestEncodeWithOmitZero(t *testing.T) { + type simple struct { + Number int `toml:"number,omitzero"` + Real float64 `toml:"real,omitzero"` + Unsigned uint `toml:"unsigned,omitzero"` + } + + value := simple{0, 0.0, uint(0)} + expected := "" + + encodeExpected(t, "simple with omitzero, all zero", value, expected, nil) + + value.Number = 10 + value.Real = 20 + value.Unsigned = 5 + expected = `number = 10 +real = 20.0 +unsigned = 5 +` + encodeExpected(t, "simple with omitzero, non-zero", value, expected, nil) +} + func encodeExpected( t *testing.T, label string, val interface{}, wantStr string, wantErr error, ) {