Add omitzero tag support (#998)
This commit is contained in:
@@ -161,6 +161,8 @@ func (enc *Encoder) SetMarshalJsonNumbers(indent bool) *Encoder {
|
|||||||
//
|
//
|
||||||
// The "omitempty" option prevents empty values or groups from being emitted.
|
// The "omitempty" option prevents empty values or groups from being emitted.
|
||||||
//
|
//
|
||||||
|
// The "omitzero" option prevents zero values or groups from being emitted.
|
||||||
|
//
|
||||||
// The "commented" option prefixes the value and all its children with a comment
|
// The "commented" option prefixes the value and all its children with a comment
|
||||||
// symbol.
|
// symbol.
|
||||||
//
|
//
|
||||||
@@ -196,6 +198,7 @@ func (enc *Encoder) Encode(v interface{}) error {
|
|||||||
type valueOptions struct {
|
type valueOptions struct {
|
||||||
multiline bool
|
multiline bool
|
||||||
omitempty bool
|
omitempty bool
|
||||||
|
omitzero bool
|
||||||
commented bool
|
commented bool
|
||||||
comment string
|
comment string
|
||||||
}
|
}
|
||||||
@@ -384,6 +387,10 @@ func shouldOmitEmpty(options valueOptions, v reflect.Value) bool {
|
|||||||
return options.omitempty && isEmptyValue(v)
|
return options.omitempty && isEmptyValue(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func shouldOmitZero(options valueOptions, v reflect.Value) bool {
|
||||||
|
return options.omitzero && v.IsZero()
|
||||||
|
}
|
||||||
|
|
||||||
func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v reflect.Value) ([]byte, error) {
|
func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v reflect.Value) ([]byte, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@@ -774,6 +781,7 @@ func walkStruct(ctx encoderCtx, t *table, v reflect.Value) {
|
|||||||
options := valueOptions{
|
options := valueOptions{
|
||||||
multiline: opts.multiline,
|
multiline: opts.multiline,
|
||||||
omitempty: opts.omitempty,
|
omitempty: opts.omitempty,
|
||||||
|
omitzero: opts.omitzero,
|
||||||
commented: opts.commented,
|
commented: opts.commented,
|
||||||
comment: fieldType.Tag.Get("comment"),
|
comment: fieldType.Tag.Get("comment"),
|
||||||
}
|
}
|
||||||
@@ -834,6 +842,7 @@ type tagOptions struct {
|
|||||||
multiline bool
|
multiline bool
|
||||||
inline bool
|
inline bool
|
||||||
omitempty bool
|
omitempty bool
|
||||||
|
omitzero bool
|
||||||
commented bool
|
commented bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -862,6 +871,8 @@ func parseTag(tag string) (string, tagOptions) {
|
|||||||
opts.inline = true
|
opts.inline = true
|
||||||
case "omitempty":
|
case "omitempty":
|
||||||
opts.omitempty = true
|
opts.omitempty = true
|
||||||
|
case "omitzero":
|
||||||
|
opts.omitzero = true
|
||||||
case "commented":
|
case "commented":
|
||||||
opts.commented = true
|
opts.commented = true
|
||||||
}
|
}
|
||||||
@@ -896,6 +907,9 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
|
|||||||
if shouldOmitEmpty(kv.Options, kv.Value) {
|
if shouldOmitEmpty(kv.Options, kv.Value) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if shouldOmitZero(kv.Options, kv.Value) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
hasNonEmptyKV = true
|
hasNonEmptyKV = true
|
||||||
|
|
||||||
ctx.setKey(kv.Key)
|
ctx.setKey(kv.Key)
|
||||||
@@ -915,6 +929,9 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
|
|||||||
if shouldOmitEmpty(table.Options, table.Value) {
|
if shouldOmitEmpty(table.Options, table.Value) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if shouldOmitZero(table.Options, table.Value) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if first {
|
if first {
|
||||||
first = false
|
first = false
|
||||||
if hasNonEmptyKV {
|
if hasNonEmptyKV {
|
||||||
@@ -949,6 +966,9 @@ func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte
|
|||||||
if shouldOmitEmpty(kv.Options, kv.Value) {
|
if shouldOmitEmpty(kv.Options, kv.Value) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if shouldOmitZero(kv.Options, kv.Value) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if first {
|
if first {
|
||||||
first = false
|
first = false
|
||||||
|
|||||||
+66
-1
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"net/netip"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -1117,6 +1118,9 @@ func TestEncoderOmitempty(t *testing.T) {
|
|||||||
Ptr *string `toml:",omitempty,multiline"`
|
Ptr *string `toml:",omitempty,multiline"`
|
||||||
Iface interface{} `toml:",omitempty,multiline"`
|
Iface interface{} `toml:",omitempty,multiline"`
|
||||||
Struct struct{} `toml:",omitempty,multiline"`
|
Struct struct{} `toml:",omitempty,multiline"`
|
||||||
|
Inline struct {
|
||||||
|
String string `toml:",omitempty,multiline"`
|
||||||
|
} `toml:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
d := doc{}
|
d := doc{}
|
||||||
@@ -1124,7 +1128,68 @@ func TestEncoderOmitempty(t *testing.T) {
|
|||||||
b, err := toml.Marshal(d)
|
b, err := toml.Marshal(d)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
expected := ``
|
expected := `Inline = {}
|
||||||
|
`
|
||||||
|
|
||||||
|
assert.Equal(t, expected, string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncoderOmitzero(t *testing.T) {
|
||||||
|
type doc struct {
|
||||||
|
String string `toml:",omitzero,multiline"`
|
||||||
|
Bool bool `toml:",omitzero,multiline"`
|
||||||
|
Int int `toml:",omitzero,multiline"`
|
||||||
|
Int8 int8 `toml:",omitzero,multiline"`
|
||||||
|
Int16 int16 `toml:",omitzero,multiline"`
|
||||||
|
Int32 int32 `toml:",omitzero,multiline"`
|
||||||
|
Int64 int64 `toml:",omitzero,multiline"`
|
||||||
|
Uint uint `toml:",omitzero,multiline"`
|
||||||
|
Uint8 uint8 `toml:",omitzero,multiline"`
|
||||||
|
Uint16 uint16 `toml:",omitzero,multiline"`
|
||||||
|
Uint32 uint32 `toml:",omitzero,multiline"`
|
||||||
|
Uint64 uint64 `toml:",omitzero,multiline"`
|
||||||
|
Float32 float32 `toml:",omitzero,multiline"`
|
||||||
|
Float64 float64 `toml:",omitzero,multiline"`
|
||||||
|
MapNil map[string]string `toml:",omitzero,multiline"`
|
||||||
|
Slice []string `toml:",omitzero,multiline"`
|
||||||
|
Ptr *string `toml:",omitzero,multiline"`
|
||||||
|
Iface interface{} `toml:",omitzero,multiline"`
|
||||||
|
Struct struct{} `toml:",omitzero,multiline"`
|
||||||
|
Time time.Time `toml:",omitzero,multiline"`
|
||||||
|
IP netip.Addr `toml:",omitzero,multiline"`
|
||||||
|
Inline struct {
|
||||||
|
String string `toml:",omitzero,multiline"`
|
||||||
|
} `toml:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
d := doc{}
|
||||||
|
|
||||||
|
b, err := toml.Marshal(d)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
expected := `Inline = {}
|
||||||
|
`
|
||||||
|
|
||||||
|
assert.Equal(t, expected, string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncoderOmitzeroOpaqueStruct(t *testing.T) {
|
||||||
|
type doc struct {
|
||||||
|
Time time.Time `toml:",omitzero"`
|
||||||
|
IP netip.Addr `toml:",omitzero"`
|
||||||
|
}
|
||||||
|
|
||||||
|
d := doc{
|
||||||
|
Time: time.Date(2001, 2, 3, 4, 5, 6, 7, time.UTC),
|
||||||
|
IP: netip.MustParseAddr("192.168.178.35"),
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := toml.Marshal(d)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
expected := `Time = 2001-02-03T04:05:06.000000007Z
|
||||||
|
IP = '192.168.178.35'
|
||||||
|
`
|
||||||
|
|
||||||
assert.Equal(t, expected, string(b))
|
assert.Equal(t, expected, string(b))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user