| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 | // Copyright 2013 The go-github AUTHORS. All rights reserved.//// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package githubimport (	"bytes"	"fmt"	"io"	"reflect")var timestampType = reflect.TypeOf(Timestamp{})// Stringify attempts to create a reasonable string representation of types in// the GitHub library. It does things like resolve pointers to their values// and omits struct fields with nil values.func Stringify(message interface{}) string {	var buf bytes.Buffer	v := reflect.ValueOf(message)	stringifyValue(&buf, v)	return buf.String()}// stringifyValue was heavily inspired by the goprotobuf library.func stringifyValue(w io.Writer, val reflect.Value) {	if val.Kind() == reflect.Ptr && val.IsNil() {		w.Write([]byte("<nil>"))		return	}	v := reflect.Indirect(val)	switch v.Kind() {	case reflect.String:		fmt.Fprintf(w, `"%s"`, v)	case reflect.Slice:		w.Write([]byte{'['})		for i := 0; i < v.Len(); i++ {			if i > 0 {				w.Write([]byte{' '})			}			stringifyValue(w, v.Index(i))		}		w.Write([]byte{']'})		return	case reflect.Struct:		if v.Type().Name() != "" {			w.Write([]byte(v.Type().String()))		}		// special handling of Timestamp values		if v.Type() == timestampType {			fmt.Fprintf(w, "{%s}", v.Interface())			return		}		w.Write([]byte{'{'})		var sep bool		for i := 0; i < v.NumField(); i++ {			fv := v.Field(i)			if fv.Kind() == reflect.Ptr && fv.IsNil() {				continue			}			if fv.Kind() == reflect.Slice && fv.IsNil() {				continue			}			if sep {				w.Write([]byte(", "))			} else {				sep = true			}			w.Write([]byte(v.Type().Field(i).Name))			w.Write([]byte{':'})			stringifyValue(w, fv)		}		w.Write([]byte{'}'})	default:		if v.CanInterface() {			fmt.Fprint(w, v.Interface())		}	}}
 |