github.com/jmigpin/editor@v1.6.0/core/godebug/debug/stringify.go (about) 1 package debug 2 3 import ( 4 "reflect" 5 "strconv" 6 "strings" 7 ) 8 9 func stringify(v interface{}) string { 10 return stringifyV3(v) 11 } 12 func stringifyV3(v interface{}) string { 13 p := newPrint3(150, 7, stringifyBytesRunes) 14 p.do(v) 15 return p.ToString() 16 } 17 18 //---------- 19 //---------- 20 //---------- 21 22 // note: avoid using fmt.printf to skip triggering *.String()/*.Error(). Allows debugging string/error funcs. 23 24 type print3 struct { 25 buf strings.Builder // need to use strings.builder to construct immutable value to be sent later on 26 avail int 27 maxDepth int 28 stk []reflect.Value 29 30 stringifyBytesAndRunes bool 31 } 32 33 func newPrint3(max, maxDepth int, sbr bool) *print3 { 34 return &print3{avail: max, maxDepth: maxDepth, stringifyBytesAndRunes: sbr} 35 } 36 37 func (p *print3) do(v interface{}) { 38 rv := reflect.ValueOf(v) 39 p.doValue(rv, 0) 40 } 41 func (p *print3) doValue(v reflect.Value, depth int) { 42 defer func() { 43 if r := recover(); r != nil { 44 // found errors: 45 // reflect.Value.Interface: cannot return value obtained from unexported field or method 46 // reflect.Value.UnsafeAddr of unaddressable value 47 // interface conversion: interface {} is debug.t3, not []uint8}} 48 //p.print("PANIC" + fmt.Sprint(r)) // use fmt.sprintf just for debug 49 50 //if err, ok := r.(error); ok { 51 // p.print("<" + err.Error() + ">") 52 //} 53 54 p.print("PANIC") 55 } 56 }() 57 p.doValue2(v, depth) 58 } 59 func (p *print3) doValue2(v reflect.Value, depth int) { 60 //fmt.Printf("dovalue2: %v, %v\n", v.Kind(), v.String()) 61 62 p.stk = append(p.stk, v) 63 defer func() { p.stk = p.stk[:len(p.stk)-1] }() 64 65 switch v.Kind() { 66 case reflect.Struct: 67 p.doStruct(v, depth) 68 case reflect.Slice, reflect.Array: 69 p.doSliceOrArray(v, depth) 70 case reflect.Map: 71 p.doMap(v, depth) 72 case reflect.Pointer: 73 p.doPointer(v, depth) 74 case reflect.Interface: 75 p.doInterface(v, depth) 76 case reflect.Chan, reflect.Func, reflect.UnsafePointer: 77 v2 := reflect.ValueOf(v.Pointer()) 78 p.doValue(v2, depth+1) 79 80 case reflect.Bool: 81 p.print(strconv.FormatBool(v.Bool())) 82 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 83 p.print(strconv.FormatInt(v.Int(), 10)) 84 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 85 // note: byte=uint8 86 p.print(strconv.FormatUint(v.Uint(), 10)) 87 case reflect.Uintptr: 88 //p.print(fmt.Sprintf("%#x", v.Uint())) // #=0x prefix 89 p.print("0x" + strconv.FormatUint(v.Uint(), 16)) 90 case reflect.Float32: 91 p.print(strconv.FormatFloat(v.Float(), 'f', -1, 32)) 92 case reflect.Float64: 93 p.print(strconv.FormatFloat(v.Float(), 'f', -1, 64)) 94 case reflect.Complex64: 95 p.print(strconv.FormatComplex(v.Complex(), 'f', -1, 64)) 96 case reflect.Complex128: 97 p.print(strconv.FormatComplex(v.Complex(), 'f', -1, 128)) 98 case reflect.String: 99 p.print("\"") 100 defer p.print("\"") 101 p.printCut(v.String()) 102 case reflect.Invalid: 103 p.print("nil") 104 default: 105 p.print("(TODO:") 106 defer p.print(")") 107 p.print(v.String()) 108 } 109 } 110 111 //---------- 112 113 func (p *print3) doPointer(v reflect.Value, depth int) { 114 if v.IsNil() { 115 p.print("nil") 116 return 117 } 118 p.print("&") 119 p.doValue(v.Elem(), depth+1) 120 } 121 func (p *print3) doInterface(v reflect.Value, depth int) { 122 p.doValue(v.Elem(), depth) // keeping depth to allow more prints 123 } 124 func (p *print3) doStruct(v reflect.Value, depth int) { 125 p.printStructTypeName(v) 126 127 p.print("{") 128 defer p.print("}") 129 vt := v.Type() 130 for i := 0; i < vt.NumField(); i++ { 131 if !p.printLoopSep(i, depth+1) { 132 break 133 } 134 f := v.Field(i) 135 p.doValue(f, depth+1) 136 } 137 } 138 func (p *print3) doSliceOrArray(v reflect.Value, depth int) { 139 if p.stringifyBytesAndRunes { 140 if p.printSliceOrArrayAsString(v) { 141 return 142 } 143 } 144 145 p.print("[") 146 defer p.print("]") 147 for i := 0; i < v.Len(); i++ { 148 if !p.printLoopSep(i, depth+1) { 149 break 150 } 151 u := v.Index(i) 152 p.doValue(u, depth+1) 153 } 154 } 155 func (p *print3) doMap(v reflect.Value, depth int) { 156 p.print("map[") 157 defer p.print("]") 158 iter := v.MapRange() 159 for i := 0; iter.Next(); i++ { 160 if !p.printLoopSep(i, depth+1) { 161 break 162 } 163 p.doValue(iter.Key(), depth+1) 164 p.print(":") 165 p.doValue(iter.Value(), depth+1) 166 } 167 } 168 169 //---------- 170 171 func (p *print3) printStructTypeName(v reflect.Value) { 172 //fmt.Printf("printstk\n") 173 printType := false 174 k := len(p.stk) - 1 - 1 // extra -1 to bypass the struct itself 175 for ; k >= 0; k-- { 176 v := p.stk[k] 177 //fmt.Printf("\tkind %v\n", v.Kind()) 178 if v.Kind() == reflect.Pointer { 179 continue 180 } 181 if v.Kind() == reflect.Interface { 182 printType = true 183 } 184 break 185 } 186 if k < 0 { // cover case of interface{} as an arg 187 printType = true 188 } 189 if printType { 190 p.print(v.Type().Name()) 191 } 192 } 193 194 //---------- 195 196 func (p *print3) printSliceOrArrayAsString(v reflect.Value) bool { 197 switch v.Type().Elem().Kind() { 198 case reflect.Uint8: // byte 199 p.print("\"") 200 defer p.print("\"") 201 202 //b := v.Interface().([]byte) // can fail if field unexported 203 //b := ReflectValueUnexported(v).Interface().([]byte) 204 //p.printBytesCut(b) 205 206 for i := 0; i < v.Len(); i++ { 207 if p.avail <= 0 { 208 p.print("...") 209 break 210 } 211 u := uint8(v.Index(i).Uint()) 212 p.printBytes([]byte{u}) 213 } 214 215 return true 216 case reflect.Int32: // rune 217 p.print("\"") 218 defer p.print("\"") 219 220 //b := v.Interface().([]int32) // can fail if field unexported 221 //b := ReflectValueUnexported(v).Interface().([]int32) 222 //p.printBytesCut([]byte(string(b))) 223 224 for i := 0; i < v.Len(); i++ { 225 if p.avail <= 0 { 226 p.print("...") 227 break 228 } 229 u := int32(v.Index(i).Int()) 230 p.print(string([]rune{u})) 231 } 232 233 return true 234 } 235 return false 236 } 237 238 //---------- 239 240 func (p *print3) printLoopSep(i int, depth int) bool { 241 if depth >= p.maxDepth { 242 p.print("...") 243 return false 244 } 245 if i > 0 { 246 p.print(" ") 247 } 248 if p.avail <= 0 { 249 p.print("...") 250 return false 251 } 252 return true 253 } 254 255 //---------- 256 257 func (p *print3) printCut(s string) { 258 if len(s) > p.avail { 259 p.print(s[:p.avail]) 260 p.print("...") 261 return 262 } 263 p.print(s) 264 } 265 func (p *print3) printBytesCut(b []byte) { 266 if len(b) > p.avail { 267 p.printBytes(b[:p.avail]) 268 p.print("...") 269 return 270 } 271 p.printBytes(b) 272 } 273 274 //---------- 275 276 func (p *print3) print(s string) { 277 n, err := p.buf.WriteString(s) 278 if err != nil { 279 return 280 } 281 p.avail -= n 282 } 283 func (p *print3) printBytes(b []byte) { 284 n, err := p.buf.Write(b) 285 if err != nil { 286 return 287 } 288 p.avail -= n 289 } 290 func (p *print3) canPrint() bool { 291 return p.avail >= 0 292 } 293 func (p *print3) ToString() string { 294 return p.buf.String() 295 } 296 297 //---------- 298 //---------- 299 //---------- 300 301 //func protect(fn func()) { 302 // defer func() { 303 // if x := recover(); x != nil { 304 // // calling any function here could itself cause a panic in case of "invalid pointer found on stack" (ex: fmt.println) 305 // } 306 // }() 307 // fn() 308 //} 309 310 //func ReflectValueUnexported(v reflect.Value) reflect.Value { 311 // if !v.CanAddr() { 312 // return v 313 // } 314 // ptr := unsafe.Pointer(v.UnsafeAddr()) 315 // return reflect.NewAt(v.Type(), ptr).Elem() 316 //} 317 318 func SprintCutCheckQuote(max int, s string) string { 319 if len(s) > max { 320 u := s[:max] + "..." 321 // close quote if present 322 const q = '"' 323 if rune(u[0]) == q { 324 u += string(q) 325 } 326 return u 327 } 328 return s 329 }