...
1
2
3
4
5
6 package github
7
8 import (
9 "bytes"
10 "fmt"
11 "io"
12
13 "reflect"
14 )
15
16 var timestampType = reflect.TypeOf(Timestamp{})
17
18
19
20
21 func Stringify(message interface{}) string {
22 var buf bytes.Buffer
23 v := reflect.ValueOf(message)
24 stringifyValue(&buf, v)
25 return buf.String()
26 }
27
28
29
30 func stringifyValue(w io.Writer, val reflect.Value) {
31 if val.Kind() == reflect.Ptr && val.IsNil() {
32 w.Write([]byte("<nil>"))
33 return
34 }
35
36 v := reflect.Indirect(val)
37
38 switch v.Kind() {
39 case reflect.String:
40 fmt.Fprintf(w, `"%s"`, v)
41 case reflect.Slice:
42 w.Write([]byte{'['})
43 for i := 0; i < v.Len(); i++ {
44 if i > 0 {
45 w.Write([]byte{' '})
46 }
47
48 stringifyValue(w, v.Index(i))
49 }
50
51 w.Write([]byte{']'})
52 return
53 case reflect.Struct:
54 if v.Type().Name() != "" {
55 w.Write([]byte(v.Type().String()))
56 }
57
58
59 if v.Type() == timestampType {
60 fmt.Fprintf(w, "{%s}", v.Interface())
61 return
62 }
63
64 w.Write([]byte{'{'})
65
66 var sep bool
67 for i := 0; i < v.NumField(); i++ {
68 fv := v.Field(i)
69 if fv.Kind() == reflect.Ptr && fv.IsNil() {
70 continue
71 }
72 if fv.Kind() == reflect.Slice && fv.IsNil() {
73 continue
74 }
75 if fv.Kind() == reflect.Map && fv.IsNil() {
76 continue
77 }
78
79 if sep {
80 w.Write([]byte(", "))
81 } else {
82 sep = true
83 }
84
85 w.Write([]byte(v.Type().Field(i).Name))
86 w.Write([]byte{':'})
87 stringifyValue(w, fv)
88 }
89
90 w.Write([]byte{'}'})
91 default:
92 if v.CanInterface() {
93 fmt.Fprint(w, v.Interface())
94 }
95 }
96 }
97
View as plain text