github.com/google/go-github/v33@v33.0.0/github/strings.go (about) 1 // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 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 // Stringify attempts to create a reasonable string representation of types in 19 // the GitHub library. It does things like resolve pointers to their values 20 // and omits struct fields with nil values. 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 // stringifyValue was heavily inspired by the goprotobuf library. 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 // special handling of Timestamp values 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 76 if sep { 77 w.Write([]byte(", ")) 78 } else { 79 sep = true 80 } 81 82 w.Write([]byte(v.Type().Field(i).Name)) 83 w.Write([]byte{':'}) 84 stringifyValue(w, fv) 85 } 86 87 w.Write([]byte{'}'}) 88 default: 89 if v.CanInterface() { 90 fmt.Fprint(w, v.Interface()) 91 } 92 } 93 }