podman

Форк
0
355 строк · 7.8 Кб
1
package pretty
2

3
import (
4
	"fmt"
5
	"io"
6
	"reflect"
7
	"strconv"
8
	"text/tabwriter"
9

10
	"github.com/kr/text"
11
	"github.com/rogpeppe/go-internal/fmtsort"
12
)
13

14
type formatter struct {
15
	v     reflect.Value
16
	force bool
17
	quote bool
18
}
19

20
// Formatter makes a wrapper, f, that will format x as go source with line
21
// breaks and tabs. Object f responds to the "%v" formatting verb when both the
22
// "#" and " " (space) flags are set, for example:
23
//
24
//     fmt.Sprintf("%# v", Formatter(x))
25
//
26
// If one of these two flags is not set, or any other verb is used, f will
27
// format x according to the usual rules of package fmt.
28
// In particular, if x satisfies fmt.Formatter, then x.Format will be called.
29
func Formatter(x interface{}) (f fmt.Formatter) {
30
	return formatter{v: reflect.ValueOf(x), quote: true}
31
}
32

33
func (fo formatter) String() string {
34
	return fmt.Sprint(fo.v.Interface()) // unwrap it
35
}
36

37
func (fo formatter) passThrough(f fmt.State, c rune) {
38
	s := "%"
39
	for i := 0; i < 128; i++ {
40
		if f.Flag(i) {
41
			s += string(rune(i))
42
		}
43
	}
44
	if w, ok := f.Width(); ok {
45
		s += fmt.Sprintf("%d", w)
46
	}
47
	if p, ok := f.Precision(); ok {
48
		s += fmt.Sprintf(".%d", p)
49
	}
50
	s += string(c)
51
	fmt.Fprintf(f, s, fo.v.Interface())
52
}
53

54
func (fo formatter) Format(f fmt.State, c rune) {
55
	if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') {
56
		w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0)
57
		p := &printer{tw: w, Writer: w, visited: make(map[visit]int)}
58
		p.printValue(fo.v, true, fo.quote)
59
		w.Flush()
60
		return
61
	}
62
	fo.passThrough(f, c)
63
}
64

65
type printer struct {
66
	io.Writer
67
	tw      *tabwriter.Writer
68
	visited map[visit]int
69
	depth   int
70
}
71

72
func (p *printer) indent() *printer {
73
	q := *p
74
	q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0)
75
	q.Writer = text.NewIndentWriter(q.tw, []byte{'\t'})
76
	return &q
77
}
78

79
func (p *printer) printInline(v reflect.Value, x interface{}, showType bool) {
80
	if showType {
81
		io.WriteString(p, v.Type().String())
82
		fmt.Fprintf(p, "(%#v)", x)
83
	} else {
84
		fmt.Fprintf(p, "%#v", x)
85
	}
86
}
87

88
// printValue must keep track of already-printed pointer values to avoid
89
// infinite recursion.
90
type visit struct {
91
	v   uintptr
92
	typ reflect.Type
93
}
94

95
func (p *printer) catchPanic(v reflect.Value, method string) {
96
	if r := recover(); r != nil {
97
		if v.Kind() == reflect.Ptr && v.IsNil() {
98
			writeByte(p, '(')
99
			io.WriteString(p, v.Type().String())
100
			io.WriteString(p, ")(nil)")
101
			return
102
		}
103
		writeByte(p, '(')
104
		io.WriteString(p, v.Type().String())
105
		io.WriteString(p, ")(PANIC=calling method ")
106
		io.WriteString(p, strconv.Quote(method))
107
		io.WriteString(p, ": ")
108
		fmt.Fprint(p, r)
109
		writeByte(p, ')')
110
	}
111
}
112

113
func (p *printer) printValue(v reflect.Value, showType, quote bool) {
114
	if p.depth > 10 {
115
		io.WriteString(p, "!%v(DEPTH EXCEEDED)")
116
		return
117
	}
118

119
	if v.IsValid() && v.CanInterface() {
120
		i := v.Interface()
121
		if goStringer, ok := i.(fmt.GoStringer); ok {
122
			defer p.catchPanic(v, "GoString")
123
			io.WriteString(p, goStringer.GoString())
124
			return
125
		}
126
	}
127

128
	switch v.Kind() {
129
	case reflect.Bool:
130
		p.printInline(v, v.Bool(), showType)
131
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
132
		p.printInline(v, v.Int(), showType)
133
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
134
		p.printInline(v, v.Uint(), showType)
135
	case reflect.Float32, reflect.Float64:
136
		p.printInline(v, v.Float(), showType)
137
	case reflect.Complex64, reflect.Complex128:
138
		fmt.Fprintf(p, "%#v", v.Complex())
139
	case reflect.String:
140
		p.fmtString(v.String(), quote)
141
	case reflect.Map:
142
		t := v.Type()
143
		if showType {
144
			io.WriteString(p, t.String())
145
		}
146
		writeByte(p, '{')
147
		if nonzero(v) {
148
			expand := !canInline(v.Type())
149
			pp := p
150
			if expand {
151
				writeByte(p, '\n')
152
				pp = p.indent()
153
			}
154
			sm := fmtsort.Sort(v)
155
			for i := 0; i < v.Len(); i++ {
156
				k := sm.Key[i]
157
				mv := sm.Value[i]
158
				pp.printValue(k, false, true)
159
				writeByte(pp, ':')
160
				if expand {
161
					writeByte(pp, '\t')
162
				}
163
				showTypeInStruct := t.Elem().Kind() == reflect.Interface
164
				pp.printValue(mv, showTypeInStruct, true)
165
				if expand {
166
					io.WriteString(pp, ",\n")
167
				} else if i < v.Len()-1 {
168
					io.WriteString(pp, ", ")
169
				}
170
			}
171
			if expand {
172
				pp.tw.Flush()
173
			}
174
		}
175
		writeByte(p, '}')
176
	case reflect.Struct:
177
		t := v.Type()
178
		if v.CanAddr() {
179
			addr := v.UnsafeAddr()
180
			vis := visit{addr, t}
181
			if vd, ok := p.visited[vis]; ok && vd < p.depth {
182
				p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false)
183
				break // don't print v again
184
			}
185
			p.visited[vis] = p.depth
186
		}
187

188
		if showType {
189
			io.WriteString(p, t.String())
190
		}
191
		writeByte(p, '{')
192
		if nonzero(v) {
193
			expand := !canInline(v.Type())
194
			pp := p
195
			if expand {
196
				writeByte(p, '\n')
197
				pp = p.indent()
198
			}
199
			for i := 0; i < v.NumField(); i++ {
200
				showTypeInStruct := true
201
				if f := t.Field(i); f.Name != "" {
202
					io.WriteString(pp, f.Name)
203
					writeByte(pp, ':')
204
					if expand {
205
						writeByte(pp, '\t')
206
					}
207
					showTypeInStruct = labelType(f.Type)
208
				}
209
				pp.printValue(getField(v, i), showTypeInStruct, true)
210
				if expand {
211
					io.WriteString(pp, ",\n")
212
				} else if i < v.NumField()-1 {
213
					io.WriteString(pp, ", ")
214
				}
215
			}
216
			if expand {
217
				pp.tw.Flush()
218
			}
219
		}
220
		writeByte(p, '}')
221
	case reflect.Interface:
222
		switch e := v.Elem(); {
223
		case e.Kind() == reflect.Invalid:
224
			io.WriteString(p, "nil")
225
		case e.IsValid():
226
			pp := *p
227
			pp.depth++
228
			pp.printValue(e, showType, true)
229
		default:
230
			io.WriteString(p, v.Type().String())
231
			io.WriteString(p, "(nil)")
232
		}
233
	case reflect.Array, reflect.Slice:
234
		t := v.Type()
235
		if showType {
236
			io.WriteString(p, t.String())
237
		}
238
		if v.Kind() == reflect.Slice && v.IsNil() && showType {
239
			io.WriteString(p, "(nil)")
240
			break
241
		}
242
		if v.Kind() == reflect.Slice && v.IsNil() {
243
			io.WriteString(p, "nil")
244
			break
245
		}
246
		writeByte(p, '{')
247
		expand := !canInline(v.Type())
248
		pp := p
249
		if expand {
250
			writeByte(p, '\n')
251
			pp = p.indent()
252
		}
253
		for i := 0; i < v.Len(); i++ {
254
			showTypeInSlice := t.Elem().Kind() == reflect.Interface
255
			pp.printValue(v.Index(i), showTypeInSlice, true)
256
			if expand {
257
				io.WriteString(pp, ",\n")
258
			} else if i < v.Len()-1 {
259
				io.WriteString(pp, ", ")
260
			}
261
		}
262
		if expand {
263
			pp.tw.Flush()
264
		}
265
		writeByte(p, '}')
266
	case reflect.Ptr:
267
		e := v.Elem()
268
		if !e.IsValid() {
269
			writeByte(p, '(')
270
			io.WriteString(p, v.Type().String())
271
			io.WriteString(p, ")(nil)")
272
		} else {
273
			pp := *p
274
			pp.depth++
275
			writeByte(pp, '&')
276
			pp.printValue(e, true, true)
277
		}
278
	case reflect.Chan:
279
		x := v.Pointer()
280
		if showType {
281
			writeByte(p, '(')
282
			io.WriteString(p, v.Type().String())
283
			fmt.Fprintf(p, ")(%#v)", x)
284
		} else {
285
			fmt.Fprintf(p, "%#v", x)
286
		}
287
	case reflect.Func:
288
		io.WriteString(p, v.Type().String())
289
		io.WriteString(p, " {...}")
290
	case reflect.UnsafePointer:
291
		p.printInline(v, v.Pointer(), showType)
292
	case reflect.Invalid:
293
		io.WriteString(p, "nil")
294
	}
295
}
296

297
func canInline(t reflect.Type) bool {
298
	switch t.Kind() {
299
	case reflect.Map:
300
		return !canExpand(t.Elem())
301
	case reflect.Struct:
302
		for i := 0; i < t.NumField(); i++ {
303
			if canExpand(t.Field(i).Type) {
304
				return false
305
			}
306
		}
307
		return true
308
	case reflect.Interface:
309
		return false
310
	case reflect.Array, reflect.Slice:
311
		return !canExpand(t.Elem())
312
	case reflect.Ptr:
313
		return false
314
	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
315
		return false
316
	}
317
	return true
318
}
319

320
func canExpand(t reflect.Type) bool {
321
	switch t.Kind() {
322
	case reflect.Map, reflect.Struct,
323
		reflect.Interface, reflect.Array, reflect.Slice,
324
		reflect.Ptr:
325
		return true
326
	}
327
	return false
328
}
329

330
func labelType(t reflect.Type) bool {
331
	switch t.Kind() {
332
	case reflect.Interface, reflect.Struct:
333
		return true
334
	}
335
	return false
336
}
337

338
func (p *printer) fmtString(s string, quote bool) {
339
	if quote {
340
		s = strconv.Quote(s)
341
	}
342
	io.WriteString(p, s)
343
}
344

345
func writeByte(w io.Writer, b byte) {
346
	w.Write([]byte{b})
347
}
348

349
func getField(v reflect.Value, i int) reflect.Value {
350
	val := v.Field(i)
351
	if val.Kind() == reflect.Interface && !val.IsNil() {
352
		val = val.Elem()
353
	}
354
	return val
355
}
356

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.