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