Skip to content

Commit 299c0d4

Browse files
committed
8
Change-Id: Iade683ed5c91d148096e4b80f8c5807697afc134
1 parent 1d5dc72 commit 299c0d4

File tree

2 files changed

+41
-45
lines changed

2 files changed

+41
-45
lines changed

src/encoding/json/encode.go

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -329,49 +329,6 @@ func isEmptyValue(v reflect.Value) bool {
329329
return false
330330
}
331331

332-
type isZeroer interface {
333-
IsZero() bool
334-
}
335-
336-
var isZeroerType = reflect.TypeFor[isZeroer]()
337-
338-
func isZeroValue(v reflect.Value) bool {
339-
// Provide a function that uses a type's IsZero method.
340-
var isZero func() bool
341-
342-
switch {
343-
case v.Kind() == reflect.Interface && v.Type().Implements(isZeroerType):
344-
isZero = func() bool {
345-
// Avoid panics calling IsZero on a nil interface or
346-
// non-nil interface with nil pointer.
347-
return v.IsNil() ||
348-
(v.Elem().Kind() == reflect.Pointer && v.Elem().IsNil()) ||
349-
v.Interface().(isZeroer).IsZero()
350-
}
351-
case v.Kind() == reflect.Pointer && v.Type().Implements(isZeroerType):
352-
isZero = func() bool {
353-
// Avoid panics calling IsZero on nil pointer.
354-
return v.IsNil() || v.Interface().(isZeroer).IsZero()
355-
}
356-
case v.Type().Implements(isZeroerType):
357-
isZero = func() bool {
358-
return v.Interface().(isZeroer).IsZero()
359-
}
360-
case reflect.PointerTo(v.Type()).Implements(isZeroerType):
361-
isZero = func() bool {
362-
if !v.CanAddr() {
363-
// Temporarily box v so we can take the address.
364-
v2 := reflect.New(v.Type()).Elem()
365-
v2.Set(v)
366-
v = v2
367-
}
368-
return v.Addr().Interface().(isZeroer).IsZero()
369-
}
370-
}
371-
372-
return (isZero == nil && v.IsZero() || (isZero != nil && isZero()))
373-
}
374-
375332
func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) {
376333
valueEncoder(v)(e, v, opts)
377334
}
@@ -756,7 +713,7 @@ FieldLoop:
756713
}
757714

758715
if (f.omitEmpty && isEmptyValue(fv)) ||
759-
(f.omitZero && isZeroValue(fv)) {
716+
(f.omitZero && (f.isZero == nil && fv.IsZero() || (f.isZero != nil && f.isZero(fv)))) {
760717
continue
761718
}
762719
e.WriteByte(next)
@@ -1104,11 +1061,18 @@ type field struct {
11041061
typ reflect.Type
11051062
omitEmpty bool
11061063
omitZero bool
1064+
isZero func(reflect.Value) bool
11071065
quoted bool
11081066

11091067
encoder encoderFunc
11101068
}
11111069

1070+
type isZeroer interface {
1071+
IsZero() bool
1072+
}
1073+
1074+
var isZeroerType = reflect.TypeFor[isZeroer]()
1075+
11121076
// typeFields returns a list of fields that JSON should recognize for the given type.
11131077
// The algorithm is breadth-first search over the set of structs to include - the top struct
11141078
// and then any reachable anonymous structs.
@@ -1220,6 +1184,38 @@ func typeFields(t reflect.Type) structFields {
12201184
field.nameEscHTML = `"` + string(nameEscBuf) + `":`
12211185
field.nameNonEsc = `"` + field.name + `":`
12221186

1187+
if field.omitZero {
1188+
t := sf.Type
1189+
// Provide a function that uses a type's IsZero method.
1190+
switch {
1191+
case t.Kind() == reflect.Interface && t.Implements(isZeroerType):
1192+
field.isZero = func(v reflect.Value) bool {
1193+
// Avoid panics calling IsZero on a nil interface or
1194+
// non-nil interface with nil pointer.
1195+
return v.IsNil() || (v.Elem().Kind() == reflect.Pointer && v.Elem().IsNil()) || v.Interface().(isZeroer).IsZero()
1196+
}
1197+
case t.Kind() == reflect.Pointer && t.Implements(isZeroerType):
1198+
field.isZero = func(v reflect.Value) bool {
1199+
// Avoid panics calling IsZero on nil pointer.
1200+
return v.IsNil() || v.Interface().(isZeroer).IsZero()
1201+
}
1202+
case t.Implements(isZeroerType):
1203+
field.isZero = func(v reflect.Value) bool {
1204+
return v.Interface().(isZeroer).IsZero()
1205+
}
1206+
case reflect.PointerTo(t).Implements(isZeroerType):
1207+
field.isZero = func(v reflect.Value) bool {
1208+
if !v.CanAddr() {
1209+
// Temporarily box v so we can take the address.
1210+
v2 := reflect.New(v.Type()).Elem()
1211+
v2.Set(v)
1212+
v = v2
1213+
}
1214+
return v.Addr().Interface().(isZeroer).IsZero()
1215+
}
1216+
}
1217+
}
1218+
12231219
fields = append(fields, field)
12241220
if count[f.typ] > 1 {
12251221
// If there were multiple instances, add a second,

src/encoding/json/encode_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ func TestOmitZero(t *testing.T) {
147147
o.Mo = map[string]any{}
148148

149149
o.Foo = -0
150-
o.Foo2 = [2]float64{0, -0}
150+
o.Foo2 = [2]float64{+0, -0}
151151

152152
o.NonNilIsZeroer = time.Time{}
153153
o.NoPanicStruct1 = &NoPanicStruct{}

0 commit comments

Comments
 (0)