1// 2// Copyright 2021, Sander van Harmelen 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17package gitlab 18 19import ( 20 "bytes" 21 "fmt" 22 23 "reflect" 24) 25 26// Stringify attempts to create a reasonable string representation of types in 27// the Gitlab library. It does things like resolve pointers to their values 28// and omits struct fields with nil values. 29func Stringify(message interface{}) string { 30 var buf bytes.Buffer 31 v := reflect.ValueOf(message) 32 stringifyValue(&buf, v) 33 return buf.String() 34} 35 36// stringifyValue was heavily inspired by the goprotobuf library. 37func stringifyValue(buf *bytes.Buffer, val reflect.Value) { 38 if val.Kind() == reflect.Ptr && val.IsNil() { 39 buf.WriteString("<nil>") 40 return 41 } 42 43 v := reflect.Indirect(val) 44 45 switch v.Kind() { 46 case reflect.String: 47 fmt.Fprintf(buf, `"%s"`, v) 48 case reflect.Slice: 49 buf.WriteByte('[') 50 for i := 0; i < v.Len(); i++ { 51 if i > 0 { 52 buf.WriteByte(' ') 53 } 54 55 stringifyValue(buf, v.Index(i)) 56 } 57 58 buf.WriteByte(']') 59 return 60 case reflect.Struct: 61 if v.Type().Name() != "" { 62 buf.WriteString(v.Type().String()) 63 } 64 65 buf.WriteByte('{') 66 67 var sep bool 68 for i := 0; i < v.NumField(); i++ { 69 fv := v.Field(i) 70 if fv.Kind() == reflect.Ptr && fv.IsNil() { 71 continue 72 } 73 if fv.Kind() == reflect.Slice && fv.IsNil() { 74 continue 75 } 76 77 if sep { 78 buf.WriteString(", ") 79 } else { 80 sep = true 81 } 82 83 buf.WriteString(v.Type().Field(i).Name) 84 buf.WriteByte(':') 85 stringifyValue(buf, fv) 86 } 87 88 buf.WriteByte('}') 89 default: 90 if v.CanInterface() { 91 fmt.Fprint(buf, v.Interface()) 92 } 93 } 94} 95