diff --git a/msgpack_test.go b/msgpack_test.go index 66ce312..c7e1682 100644 --- a/msgpack_test.go +++ b/msgpack_test.go @@ -380,3 +380,68 @@ func TestSetSortMapKeys(t *testing.T) { require.Equal(t, in, out) } } + +type NullInt struct { + Valid bool + Int int +} + +func (i *NullInt) Set(j int) { + i.Int = j + i.Valid = true +} + +func (i NullInt) IsZero() bool { + return !i.Valid +} + +func (i NullInt) MarshalMsgpack() ([]byte, error) { + return msgpack.Marshal(i.Int) +} + +func (i *NullInt) UnmarshalMsgpack(b []byte) error { + if err := msgpack.Unmarshal(b, &i.Int); err != nil { + return err + } + i.Valid = true + return nil +} + +type Secretive struct { + Visible bool + hidden bool +} + +type T struct { + I NullInt `msgpack:",omitempty"` + J NullInt + // Secretive is not a "simple" struct because it has an hidden field. + S Secretive `msgpack:",omitempty"` +} + +func ExampleMarshal_ignore_simple_zero_structs_when_tagged_with_omitempty() { + var t1 T + raw, err := msgpack.Marshal(t1) + if err != nil { + panic(err) + } + var t2 T + if err = msgpack.Unmarshal(raw, &t2); err != nil { + panic(err) + } + fmt.Printf("%#v\n", t2) + + t2.I.Set(42) + t2.S.hidden = true // won't be included because it is a hidden field + raw, err = msgpack.Marshal(t2) + if err != nil { + panic(err) + } + var t3 T + if err = msgpack.Unmarshal(raw, &t3); err != nil { + panic(err) + } + fmt.Printf("%#v\n", t3) + // Output: msgpack_test.T{I:msgpack_test.NullInt{Valid:false, Int:0}, J:msgpack_test.NullInt{Valid:true, Int:0}, S:msgpack_test.Secretive{Visible:false, hidden:false}} + // msgpack_test.T{I:msgpack_test.NullInt{Valid:true, Int:42}, J:msgpack_test.NullInt{Valid:true, Int:0}, S:msgpack_test.Secretive{Visible:false, hidden:false}} +} diff --git a/types.go b/types.go index fc8b08b..35c850f 100644 --- a/types.go +++ b/types.go @@ -313,7 +313,14 @@ func shouldInline(fs *fields, typ reflect.Type, f *field, tag string) bool { return true } +type isZeroer interface { + IsZero() bool +} + func isEmptyValue(v reflect.Value) bool { + if z, ok := v.Interface().(isZeroer); ok { + return z.IsZero() + } switch v.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: return v.Len() == 0