Browse Source

Refactor `structdiff` package

DarthSim 1 tháng trước cách đây
mục cha
commit
0bf347b1fe
2 tập tin đã thay đổi với 47 bổ sung38 xóa
  1. 1 5
      metrics/metrics.go
  2. 46 33
      structdiff/diff.go

+ 1 - 5
metrics/metrics.go

@@ -71,11 +71,7 @@ func setMetadata(ctx context.Context, key string, value any) {
 }
 
 func SetMetadata(ctx context.Context, key string, value any) {
-	type diffable interface {
-		Diff() structdiff.Entries
-	}
-
-	if diff, ok := value.(diffable); ok {
+	if diff, ok := value.(structdiff.Diffable); ok {
 		m := diff.Diff().Flatten()
 		for k, v := range m {
 			setMetadata(ctx, fmt.Sprintf("%s.%s", key, k), v)

+ 46 - 33
structdiff/diff.go

@@ -6,19 +6,10 @@ import (
 	"fmt"
 	"reflect"
 	"strings"
-	"sync"
 )
 
-var bufPool = sync.Pool{
-	New: func() interface{} {
-		return new(bytes.Buffer)
-	},
-}
-
-var builderPool = sync.Pool{
-	New: func() interface{} {
-		return new(strings.Builder)
-	},
+type Diffable interface {
+	Diff() Entries
 }
 
 type Entry struct {
@@ -29,11 +20,9 @@ type Entry struct {
 type Entries []Entry
 
 func (d Entries) String() string {
-	buf := builderPool.Get().(*strings.Builder)
+	buf := new(strings.Builder)
 	last := len(d) - 1
 
-	buf.Reset()
-
 	for i, e := range d {
 		buf.WriteString(e.Name)
 		buf.WriteString(": ")
@@ -43,7 +32,7 @@ func (d Entries) String() string {
 			buf.WriteString(dd.String())
 			buf.WriteByte('}')
 		} else {
-			fmt.Fprint(buf, e.Value)
+			fmt.Fprintf(buf, "%+v", e.Value)
 		}
 
 		if i != last {
@@ -55,11 +44,9 @@ func (d Entries) String() string {
 }
 
 func (d Entries) MarshalJSON() ([]byte, error) {
-	buf := bufPool.Get().(*bytes.Buffer)
+	buf := new(bytes.Buffer)
 	last := len(d) - 1
 
-	buf.Reset()
-
 	buf.WriteByte('{')
 
 	for i, e := range d {
@@ -101,6 +88,45 @@ func (d Entries) Flatten() map[string]interface{} {
 	return m
 }
 
+func valDiff(a, b reflect.Value) (any, bool) {
+	if !a.CanInterface() || !b.CanInterface() {
+		return nil, false
+	}
+
+	typeB := b.Type()
+
+	if a.Type() != typeB {
+		return b.Interface(), true
+	}
+
+	intA := a.Interface()
+	intB := b.Interface()
+
+	if reflect.DeepEqual(intA, intB) {
+		return nil, false
+	}
+
+	if typeB.Kind() == reflect.Struct {
+		return Diff(intA, intB), true
+	}
+
+	if typeB.Kind() == reflect.Ptr && typeB.Elem().Kind() == reflect.Struct {
+		if !a.IsNil() && !b.IsNil() {
+			return Diff(intA, intB), true
+		}
+
+		if !b.IsNil() {
+			if diffable, ok := intB.(Diffable); ok {
+				return diffable.Diff(), true
+			}
+		}
+
+		return nil, true
+	}
+
+	return intB, true
+}
+
 func Diff(a, b interface{}) Entries {
 	valA := reflect.Indirect(reflect.ValueOf(a))
 	valB := reflect.Indirect(reflect.ValueOf(b))
@@ -115,22 +141,9 @@ func Diff(a, b interface{}) Entries {
 		fieldA := valA.Field(i)
 		fieldB := valB.Field(i)
 
-		if !fieldA.CanInterface() || !fieldB.CanInterface() {
-			continue
-		}
-
-		intA := fieldA.Interface()
-		intB := fieldB.Interface()
-
-		if !reflect.DeepEqual(intA, intB) {
+		if v, ok := valDiff(fieldA, fieldB); ok {
 			name := valB.Type().Field(i).Name
-			value := intB
-
-			if fieldB.Kind() == reflect.Struct {
-				value = Diff(intA, intB)
-			}
-
-			d = append(d, Entry{name, value})
+			d = append(d, Entry{name, v})
 		}
 	}