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  }