Source file src/cmd/vendor/golang.org/x/xerrors/adaptor.go

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package xerrors
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"reflect"
    12  	"strconv"
    13  )
    14  
    15  // FormatError calls the FormatError method of f with an errors.Printer
    16  // configured according to s and verb, and writes the result to s.
    17  func FormatError(f Formatter, s fmt.State, verb rune) {
    18  	// Assuming this function is only called from the Format method, and given
    19  	// that FormatError takes precedence over Format, it cannot be called from
    20  	// any package that supports errors.Formatter. It is therefore safe to
    21  	// disregard that State may be a specific printer implementation and use one
    22  	// of our choice instead.
    23  
    24  	// limitations: does not support printing error as Go struct.
    25  
    26  	var (
    27  		sep    = " " // separator before next error
    28  		p      = &state{State: s}
    29  		direct = true
    30  	)
    31  
    32  	var err error = f
    33  
    34  	switch verb {
    35  	// Note that this switch must match the preference order
    36  	// for ordinary string printing (%#v before %+v, and so on).
    37  
    38  	case 'v':
    39  		if s.Flag('#') {
    40  			if stringer, ok := err.(fmt.GoStringer); ok {
    41  				io.WriteString(&p.buf, stringer.GoString())
    42  				goto exit
    43  			}
    44  			// proceed as if it were %v
    45  		} else if s.Flag('+') {
    46  			p.printDetail = true
    47  			sep = "\n  - "
    48  		}
    49  	case 's':
    50  	case 'q', 'x', 'X':
    51  		// Use an intermediate buffer in the rare cases that precision,
    52  		// truncation, or one of the alternative verbs (q, x, and X) are
    53  		// specified.
    54  		direct = false
    55  
    56  	default:
    57  		p.buf.WriteString("%!")
    58  		p.buf.WriteRune(verb)
    59  		p.buf.WriteByte('(')
    60  		switch {
    61  		case err != nil:
    62  			p.buf.WriteString(reflect.TypeOf(f).String())
    63  		default:
    64  			p.buf.WriteString("<nil>")
    65  		}
    66  		p.buf.WriteByte(')')
    67  		io.Copy(s, &p.buf)
    68  		return
    69  	}
    70  
    71  loop:
    72  	for {
    73  		switch v := err.(type) {
    74  		case Formatter:
    75  			err = v.FormatError((*printer)(p))
    76  		case fmt.Formatter:
    77  			v.Format(p, 'v')
    78  			break loop
    79  		default:
    80  			io.WriteString(&p.buf, v.Error())
    81  			break loop
    82  		}
    83  		if err == nil {
    84  			break
    85  		}
    86  		if p.needColon || !p.printDetail {
    87  			p.buf.WriteByte(':')
    88  			p.needColon = false
    89  		}
    90  		p.buf.WriteString(sep)
    91  		p.inDetail = false
    92  		p.needNewline = false
    93  	}
    94  
    95  exit:
    96  	width, okW := s.Width()
    97  	prec, okP := s.Precision()
    98  
    99  	if !direct || (okW && width > 0) || okP {
   100  		// Construct format string from State s.
   101  		format := []byte{'%'}
   102  		if s.Flag('-') {
   103  			format = append(format, '-')
   104  		}
   105  		if s.Flag('+') {
   106  			format = append(format, '+')
   107  		}
   108  		if s.Flag(' ') {
   109  			format = append(format, ' ')
   110  		}
   111  		if okW {
   112  			format = strconv.AppendInt(format, int64(width), 10)
   113  		}
   114  		if okP {
   115  			format = append(format, '.')
   116  			format = strconv.AppendInt(format, int64(prec), 10)
   117  		}
   118  		format = append(format, string(verb)...)
   119  		fmt.Fprintf(s, string(format), p.buf.String())
   120  	} else {
   121  		io.Copy(s, &p.buf)
   122  	}
   123  }
   124  
   125  var detailSep = []byte("\n    ")
   126  
   127  // state tracks error printing state. It implements fmt.State.
   128  type state struct {
   129  	fmt.State
   130  	buf bytes.Buffer
   131  
   132  	printDetail bool
   133  	inDetail    bool
   134  	needColon   bool
   135  	needNewline bool
   136  }
   137  
   138  func (s *state) Write(b []byte) (n int, err error) {
   139  	if s.printDetail {
   140  		if len(b) == 0 {
   141  			return 0, nil
   142  		}
   143  		if s.inDetail && s.needColon {
   144  			s.needNewline = true
   145  			if b[0] == '\n' {
   146  				b = b[1:]
   147  			}
   148  		}
   149  		k := 0
   150  		for i, c := range b {
   151  			if s.needNewline {
   152  				if s.inDetail && s.needColon {
   153  					s.buf.WriteByte(':')
   154  					s.needColon = false
   155  				}
   156  				s.buf.Write(detailSep)
   157  				s.needNewline = false
   158  			}
   159  			if c == '\n' {
   160  				s.buf.Write(b[k:i])
   161  				k = i + 1
   162  				s.needNewline = true
   163  			}
   164  		}
   165  		s.buf.Write(b[k:])
   166  		if !s.inDetail {
   167  			s.needColon = true
   168  		}
   169  	} else if !s.inDetail {
   170  		s.buf.Write(b)
   171  	}
   172  	return len(b), nil
   173  }
   174  
   175  // printer wraps a state to implement an xerrors.Printer.
   176  type printer state
   177  
   178  func (s *printer) Print(args ...interface{}) {
   179  	if !s.inDetail || s.printDetail {
   180  		fmt.Fprint((*state)(s), args...)
   181  	}
   182  }
   183  
   184  func (s *printer) Printf(format string, args ...interface{}) {
   185  	if !s.inDetail || s.printDetail {
   186  		fmt.Fprintf((*state)(s), format, args...)
   187  	}
   188  }
   189  
   190  func (s *printer) Detail() bool {
   191  	s.inDetail = true
   192  	return s.printDetail
   193  }
   194  

View as plain text