github.com/seeker-insurance/kit@v0.0.13/pretty/formatter.go (about)

     1  package pretty
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"reflect"
     7  	"strconv"
     8  	"text/tabwriter"
     9  
    10  	"github.com/seeker-insurance/kit/pretty/text"
    11  )
    12  
    13  type formatter struct {
    14  	v     reflect.Value
    15  	force bool
    16  	quote bool
    17  }
    18  
    19  // Formatter makes a wrapper, f, that will format x as go source with line
    20  // breaks and tabs. Object f responds to the "%v" formatting verb when both the
    21  // "#" and " " (space) flags are set, for example:
    22  //
    23  //     fmt.Sprintf("%# v", Formatter(x))
    24  //
    25  // If one of these two flags is not set, or any other verb is used, f will
    26  // format x according to the usual rules of package fmt.
    27  // In particular, if x satisfies fmt.Formatter, then x.Format will be called.
    28  func Formatter(x interface{}) (f fmt.Formatter) {
    29  	return formatter{v: reflect.ValueOf(x), quote: true}
    30  }
    31  
    32  func (fo formatter) String() string {
    33  	return fmt.Sprint(fo.v.Interface()) // unwrap it
    34  }
    35  
    36  func (fo formatter) passThrough(f fmt.State, c rune) {
    37  	s := "%"
    38  	for i := 0; i < 128; i++ {
    39  		if f.Flag(i) {
    40  			s += string(i)
    41  		}
    42  	}
    43  	if w, ok := f.Width(); ok {
    44  		s += fmt.Sprintf("%d", w)
    45  	}
    46  	if p, ok := f.Precision(); ok {
    47  		s += fmt.Sprintf(".%d", p)
    48  	}
    49  	s += string(c)
    50  	fmt.Fprintf(f, s, fo.v.Interface())
    51  }
    52  
    53  func (fo formatter) Format(f fmt.State, c rune) {
    54  	if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') {
    55  		w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0)
    56  		p := &printer{tw: w, Writer: w, visited: make(map[visit]int)}
    57  		p.printValue(fo.v, true, fo.quote)
    58  		w.Flush()
    59  		return
    60  	}
    61  	fo.passThrough(f, c)
    62  }
    63  
    64  type printer struct {
    65  	io.Writer
    66  	tw      *tabwriter.Writer
    67  	visited map[visit]int
    68  	depth   int
    69  }
    70  
    71  func (p *printer) indent() *printer {
    72  	q := *p
    73  	q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0)
    74  	q.Writer = text.NewIndentWriter(q.tw, []byte{'\t'})
    75  	return &q
    76  }
    77  
    78  func (p *printer) printInline(v reflect.Value, x interface{}, showType bool) {
    79  	if showType {
    80  		io.WriteString(p, v.Type().String())
    81  		fmt.Fprintf(p, "(%#v)", x)
    82  	} else {
    83  		fmt.Fprintf(p, "%#v", x)
    84  	}
    85  }
    86  
    87  // printValue must keep track of already-printed pointer values to avoid
    88  // infinite recursion.
    89  type visit struct {
    90  	v   uintptr
    91  	typ reflect.Type
    92  }
    93  
    94  func (p *printer) printValue(v reflect.Value, showType, quote bool) {
    95  	if p.depth > 10 {
    96  		io.WriteString(p, "!%v(DEPTH EXCEEDED)")
    97  		return
    98  	}
    99  
   100  	switch v.Kind() {
   101  	case reflect.Bool:
   102  		p.printInline(v, v.Bool(), showType)
   103  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   104  		p.printInline(v, v.Int(), showType)
   105  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   106  		p.printInline(v, v.Uint(), showType)
   107  	case reflect.Float32, reflect.Float64:
   108  		p.printInline(v, v.Float(), showType)
   109  	case reflect.Complex64, reflect.Complex128:
   110  		fmt.Fprintf(p, "%#v", v.Complex())
   111  	case reflect.String:
   112  		p.fmtString(v.String(), quote)
   113  	case reflect.Map:
   114  		t := v.Type()
   115  		if showType {
   116  			io.WriteString(p, t.String())
   117  		}
   118  		writeByte(p, '{')
   119  		if nonzero(v) {
   120  			expand := !canInline(v.Type())
   121  			pp := p
   122  			if expand {
   123  				writeByte(p, '\n')
   124  				pp = p.indent()
   125  			}
   126  			keys := v.MapKeys()
   127  			for i := 0; i < v.Len(); i++ {
   128  				showTypeInStruct := true
   129  				k := keys[i]
   130  				mv := v.MapIndex(k)
   131  				pp.printValue(k, false, true)
   132  				writeByte(pp, ':')
   133  				if expand {
   134  					writeByte(pp, '\t')
   135  				}
   136  				showTypeInStruct = t.Elem().Kind() == reflect.Interface
   137  				pp.printValue(mv, showTypeInStruct, true)
   138  				if expand {
   139  					io.WriteString(pp, ",\n")
   140  				} else if i < v.Len()-1 {
   141  					io.WriteString(pp, ", ")
   142  				}
   143  			}
   144  			if expand {
   145  				pp.tw.Flush()
   146  			}
   147  		}
   148  		writeByte(p, '}')
   149  	case reflect.Struct:
   150  		t := v.Type()
   151  		if v.CanAddr() {
   152  			addr := v.UnsafeAddr()
   153  			vis := visit{addr, t}
   154  			if vd, ok := p.visited[vis]; ok && vd < p.depth {
   155  				p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false)
   156  				break // don't print v again
   157  			}
   158  			p.visited[vis] = p.depth
   159  		}
   160  
   161  		if showType {
   162  			io.WriteString(p, t.String())
   163  		}
   164  		writeByte(p, '{')
   165  		if nonzero(v) {
   166  			expand := !canInline(v.Type())
   167  			pp := p
   168  			if expand {
   169  				writeByte(p, '\n')
   170  				pp = p.indent()
   171  			}
   172  			for i := 0; i < v.NumField(); i++ {
   173  				showTypeInStruct := true
   174  				if f := t.Field(i); f.Name != "" {
   175  					io.WriteString(pp, f.Name)
   176  					writeByte(pp, ':')
   177  					if expand {
   178  						writeByte(pp, '\t')
   179  					}
   180  					showTypeInStruct = labelType(f.Type)
   181  				}
   182  				pp.printValue(getField(v, i), showTypeInStruct, true)
   183  				if expand {
   184  					io.WriteString(pp, ",\n")
   185  				} else if i < v.NumField()-1 {
   186  					io.WriteString(pp, ", ")
   187  				}
   188  			}
   189  			if expand {
   190  				pp.tw.Flush()
   191  			}
   192  		}
   193  		writeByte(p, '}')
   194  	case reflect.Interface:
   195  		switch e := v.Elem(); {
   196  		case e.Kind() == reflect.Invalid:
   197  			io.WriteString(p, "nil")
   198  		case e.IsValid():
   199  			pp := *p
   200  			pp.depth++
   201  			pp.printValue(e, showType, true)
   202  		default:
   203  			io.WriteString(p, v.Type().String())
   204  			io.WriteString(p, "(nil)")
   205  		}
   206  	case reflect.Array, reflect.Slice:
   207  		t := v.Type()
   208  		if showType {
   209  			io.WriteString(p, t.String())
   210  		}
   211  		if v.Kind() == reflect.Slice && v.IsNil() && showType {
   212  			io.WriteString(p, "(nil)")
   213  			break
   214  		}
   215  		if v.Kind() == reflect.Slice && v.IsNil() {
   216  			io.WriteString(p, "nil")
   217  			break
   218  		}
   219  		writeByte(p, '{')
   220  		expand := !canInline(v.Type())
   221  		pp := p
   222  		if expand {
   223  			writeByte(p, '\n')
   224  			pp = p.indent()
   225  		}
   226  		for i := 0; i < v.Len(); i++ {
   227  			showTypeInSlice := t.Elem().Kind() == reflect.Interface
   228  			pp.printValue(v.Index(i), showTypeInSlice, true)
   229  			if expand {
   230  				io.WriteString(pp, ",\n")
   231  			} else if i < v.Len()-1 {
   232  				io.WriteString(pp, ", ")
   233  			}
   234  		}
   235  		if expand {
   236  			pp.tw.Flush()
   237  		}
   238  		writeByte(p, '}')
   239  	case reflect.Ptr:
   240  		e := v.Elem()
   241  		if !e.IsValid() {
   242  			writeByte(p, '(')
   243  			io.WriteString(p, v.Type().String())
   244  			io.WriteString(p, ")(nil)")
   245  		} else {
   246  			pp := *p
   247  			pp.depth++
   248  			writeByte(pp, '&')
   249  			pp.printValue(e, true, true)
   250  		}
   251  	case reflect.Chan:
   252  		x := v.Pointer()
   253  		if showType {
   254  			writeByte(p, '(')
   255  			io.WriteString(p, v.Type().String())
   256  			fmt.Fprintf(p, ")(%#v)", x)
   257  		} else {
   258  			fmt.Fprintf(p, "%#v", x)
   259  		}
   260  	case reflect.Func:
   261  		io.WriteString(p, v.Type().String())
   262  		io.WriteString(p, " {...}")
   263  	case reflect.UnsafePointer:
   264  		p.printInline(v, v.Pointer(), showType)
   265  	case reflect.Invalid:
   266  		io.WriteString(p, "nil")
   267  	}
   268  }
   269  
   270  func canInline(t reflect.Type) bool {
   271  	switch t.Kind() {
   272  	case reflect.Map:
   273  		return !canExpand(t.Elem())
   274  	case reflect.Struct:
   275  		for i := 0; i < t.NumField(); i++ {
   276  			if canExpand(t.Field(i).Type) {
   277  				return false
   278  			}
   279  		}
   280  		return true
   281  	case reflect.Interface:
   282  		return false
   283  	case reflect.Array, reflect.Slice:
   284  		return !canExpand(t.Elem())
   285  	case reflect.Ptr:
   286  		return false
   287  	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
   288  		return false
   289  	}
   290  	return true
   291  }
   292  
   293  func canExpand(t reflect.Type) bool {
   294  	switch t.Kind() {
   295  	case reflect.Map, reflect.Struct,
   296  		reflect.Interface, reflect.Array, reflect.Slice,
   297  		reflect.Ptr:
   298  		return true
   299  	}
   300  	return false
   301  }
   302  
   303  func labelType(t reflect.Type) bool {
   304  	switch t.Kind() {
   305  	case reflect.Interface, reflect.Struct:
   306  		return true
   307  	}
   308  	return false
   309  }
   310  
   311  func (p *printer) fmtString(s string, quote bool) {
   312  	if quote {
   313  		s = strconv.Quote(s)
   314  	}
   315  	io.WriteString(p, s)
   316  }
   317  
   318  func writeByte(w io.Writer, b byte) {
   319  	w.Write([]byte{b})
   320  }
   321  
   322  func getField(v reflect.Value, i int) reflect.Value {
   323  	val := v.Field(i)
   324  	if val.Kind() == reflect.Interface && !val.IsNil() {
   325  		val = val.Elem()
   326  	}
   327  	return val
   328  }