strings.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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. package github
  6. import (
  7. "bytes"
  8. "fmt"
  9. "io"
  10. "reflect"
  11. )
  12. var timestampType = reflect.TypeOf(Timestamp{})
  13. // Stringify attempts to create a reasonable string representation of types in
  14. // the GitHub library. It does things like resolve pointers to their values
  15. // and omits struct fields with nil values.
  16. func Stringify(message interface{}) string {
  17. var buf bytes.Buffer
  18. v := reflect.ValueOf(message)
  19. stringifyValue(&buf, v)
  20. return buf.String()
  21. }
  22. // stringifyValue was heavily inspired by the goprotobuf library.
  23. func stringifyValue(w io.Writer, val reflect.Value) {
  24. if val.Kind() == reflect.Ptr && val.IsNil() {
  25. w.Write([]byte("<nil>"))
  26. return
  27. }
  28. v := reflect.Indirect(val)
  29. switch v.Kind() {
  30. case reflect.String:
  31. fmt.Fprintf(w, `"%s"`, v)
  32. case reflect.Slice:
  33. w.Write([]byte{'['})
  34. for i := 0; i < v.Len(); i++ {
  35. if i > 0 {
  36. w.Write([]byte{' '})
  37. }
  38. stringifyValue(w, v.Index(i))
  39. }
  40. w.Write([]byte{']'})
  41. return
  42. case reflect.Struct:
  43. if v.Type().Name() != "" {
  44. w.Write([]byte(v.Type().String()))
  45. }
  46. // special handling of Timestamp values
  47. if v.Type() == timestampType {
  48. fmt.Fprintf(w, "{%s}", v.Interface())
  49. return
  50. }
  51. w.Write([]byte{'{'})
  52. var sep bool
  53. for i := 0; i < v.NumField(); i++ {
  54. fv := v.Field(i)
  55. if fv.Kind() == reflect.Ptr && fv.IsNil() {
  56. continue
  57. }
  58. if fv.Kind() == reflect.Slice && fv.IsNil() {
  59. continue
  60. }
  61. if sep {
  62. w.Write([]byte(", "))
  63. } else {
  64. sep = true
  65. }
  66. w.Write([]byte(v.Type().Field(i).Name))
  67. w.Write([]byte{':'})
  68. stringifyValue(w, fv)
  69. }
  70. w.Write([]byte{'}'})
  71. default:
  72. if v.CanInterface() {
  73. fmt.Fprint(w, v.Interface())
  74. }
  75. }
  76. }