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