diff.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package structdiff
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "reflect"
  7. "sync"
  8. )
  9. var bufPool = sync.Pool{
  10. New: func() interface{} {
  11. return new(bytes.Buffer)
  12. },
  13. }
  14. type Entry struct {
  15. Name string
  16. Value interface{}
  17. }
  18. type Entries []Entry
  19. func (d Entries) String() string {
  20. buf := bufPool.Get().(*bytes.Buffer)
  21. last := len(d) - 1
  22. buf.Reset()
  23. for i, e := range d {
  24. buf.WriteString(e.Name)
  25. buf.WriteString(": ")
  26. if dd, ok := e.Value.(Entries); ok {
  27. buf.WriteByte('{')
  28. buf.WriteString(dd.String())
  29. buf.WriteByte('}')
  30. } else {
  31. fmt.Fprint(buf, e.Value)
  32. }
  33. if i != last {
  34. buf.WriteString("; ")
  35. }
  36. }
  37. return buf.String()
  38. }
  39. func (d Entries) MarshalJSON() ([]byte, error) {
  40. buf := bufPool.Get().(*bytes.Buffer)
  41. last := len(d) - 1
  42. buf.Reset()
  43. buf.WriteByte('{')
  44. for i, e := range d {
  45. j, err := json.Marshal(e.Value)
  46. if err != nil {
  47. return nil, err
  48. }
  49. fmt.Fprintf(buf, "%q:%s", e.Name, j)
  50. if i != last {
  51. buf.WriteByte(',')
  52. }
  53. }
  54. buf.WriteByte('}')
  55. return buf.Bytes(), nil
  56. }
  57. func Diff(a, b interface{}) Entries {
  58. valA := reflect.Indirect(reflect.ValueOf(a))
  59. valB := reflect.Indirect(reflect.ValueOf(b))
  60. d := make(Entries, 0, valA.NumField())
  61. if valA.Type() != valB.Type() {
  62. return d
  63. }
  64. for i := 0; i < valA.NumField(); i++ {
  65. fieldA := valA.Field(i)
  66. fieldB := valB.Field(i)
  67. intA := fieldA.Interface()
  68. intB := fieldB.Interface()
  69. if !reflect.DeepEqual(intA, intB) {
  70. name := valB.Type().Field(i).Name
  71. value := intB
  72. if fieldB.Kind() == reflect.Struct {
  73. value = Diff(intA, intB)
  74. }
  75. d = append(d, Entry{name, value})
  76. }
  77. }
  78. return d
  79. }