@@ -329,13 +329,37 @@ 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+
332338func isZeroValue (v reflect.Value ) bool {
333- if z , ok := v .Interface ().(interface {
334- IsZero () bool
335- }); ok {
336- return z .IsZero ()
339+ // Provide a function that uses a type's IsZero method.
340+ var isZero func (reflect.Value ) bool
341+
342+ switch {
343+ case v .Kind () == reflect .Interface && v .Type ().Implements (isZeroerType ):
344+ isZero = func (va reflect.Value ) bool {
345+ // Avoid panics calling IsZero on a nil interface or
346+ // non-nil interface with nil pointer.
347+ return va .IsNil () ||
348+ (va .Elem ().Kind () == reflect .Pointer && va .Elem ().IsNil ()) ||
349+ va .Interface ().(isZeroer ).IsZero ()
350+ }
351+ case v .Kind () == reflect .Pointer && v .Type ().Implements (isZeroerType ):
352+ isZero = func (va reflect.Value ) bool {
353+ // Avoid panics calling IsZero on nil pointer.
354+ return va .IsNil () || va .Interface ().(isZeroer ).IsZero ()
355+ }
356+ case v .Type ().Implements (isZeroerType ):
357+ isZero = func (va reflect.Value ) bool { return va .Interface ().(isZeroer ).IsZero () }
358+ case reflect .PointerTo (v .Type ()).Implements (isZeroerType ):
359+ isZero = func (va reflect.Value ) bool { return va .Addr ().Interface ().(isZeroer ).IsZero () }
337360 }
338- return v .IsZero ()
361+
362+ return (isZero == nil && v .IsZero () || (isZero != nil && isZero (v )))
339363}
340364
341365func (e * encodeState ) reflectValue (v reflect.Value , opts encOpts ) {
0 commit comments