Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: render/render.go

Issue 1716743002: Better rendering for implicit types. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/go-render.git@master
Patch Set: Normalize copyright Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | render/render_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package render 5 package render
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "fmt" 9 "fmt"
10 "reflect" 10 "reflect"
11 "sort" 11 "sort"
12 "strconv" 12 "strconv"
13 ) 13 )
14 14
15 var implicitTypeMap = map[reflect.Kind]string{ 15 var builtinTypeMap = map[reflect.Kind]string{
16 reflect.Bool: "bool", 16 reflect.Bool: "bool",
17 » reflect.String: "string", 17 » reflect.Complex128: "complex128",
18 » reflect.Int: "int", 18 » reflect.Complex64: "complex64",
19 » reflect.Int8: "int8", 19 » reflect.Float32: "float32",
20 » reflect.Float64: "float64",
20 reflect.Int16: "int16", 21 reflect.Int16: "int16",
21 reflect.Int32: "int32", 22 reflect.Int32: "int32",
22 reflect.Int64: "int64", 23 reflect.Int64: "int64",
23 » reflect.Uint: "uint", 24 » reflect.Int8: "int8",
24 » reflect.Uint8: "uint8", 25 » reflect.Int: "int",
26 » reflect.String: "string",
25 reflect.Uint16: "uint16", 27 reflect.Uint16: "uint16",
26 reflect.Uint32: "uint32", 28 reflect.Uint32: "uint32",
27 reflect.Uint64: "uint64", 29 reflect.Uint64: "uint64",
28 » reflect.Float32: "float32", 30 » reflect.Uint8: "uint8",
29 » reflect.Float64: "float64", 31 » reflect.Uint: "uint",
30 » reflect.Complex64: "complex64", 32 » reflect.Uintptr: "uintptr",
31 » reflect.Complex128: "complex128",
32 } 33 }
33 34
35 var builtinTypeSet = map[string]struct{}{}
36
37 func init() {
38 for _, v := range builtinTypeMap {
39 builtinTypeSet[v] = struct{}{}
40 }
41 }
42
43 var typeOfString = reflect.TypeOf("")
44 var typeOfInt = reflect.TypeOf(int(1))
45 var typeOfUint = reflect.TypeOf(uint(1))
46 var typeOfFloat = reflect.TypeOf(10.1)
47
34 // Render converts a structure to a string representation. Unline the "%#v" 48 // Render converts a structure to a string representation. Unline the "%#v"
35 // format string, this resolves pointer types' contents in structs, maps, and 49 // format string, this resolves pointer types' contents in structs, maps, and
36 // slices/arrays and prints their field values. 50 // slices/arrays and prints their field values.
37 func Render(v interface{}) string { 51 func Render(v interface{}) string {
38 buf := bytes.Buffer{} 52 buf := bytes.Buffer{}
39 s := (*traverseState)(nil) 53 s := (*traverseState)(nil)
40 » s.render(&buf, 0, reflect.ValueOf(v)) 54 » s.render(&buf, 0, reflect.ValueOf(v), false)
41 return buf.String() 55 return buf.String()
42 } 56 }
43 57
44 // renderPointer is called to render a pointer value. 58 // renderPointer is called to render a pointer value.
45 // 59 //
46 // This is overridable so that the test suite can have deterministic pointer 60 // This is overridable so that the test suite can have deterministic pointer
47 // values in its expectations. 61 // values in its expectations.
48 var renderPointer = func(buf *bytes.Buffer, p uintptr) { 62 var renderPointer = func(buf *bytes.Buffer, p uintptr) {
49 fmt.Fprintf(buf, "0x%016x", p) 63 fmt.Fprintf(buf, "0x%016x", p)
50 } 64 }
(...skipping 14 matching lines...) Expand all
65 } 79 }
66 } 80 }
67 81
68 fs := &traverseState{ 82 fs := &traverseState{
69 parent: s, 83 parent: s,
70 ptr: ptr, 84 ptr: ptr,
71 } 85 }
72 return fs 86 return fs
73 } 87 }
74 88
75 func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) { 89 func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value, imp licit bool) {
76 if v.Kind() == reflect.Invalid { 90 if v.Kind() == reflect.Invalid {
77 buf.WriteString("nil") 91 buf.WriteString("nil")
78 return 92 return
79 } 93 }
80 vt := v.Type() 94 vt := v.Type()
81 95
82 // If the type being rendered is a potentially recursive type (a type th at 96 // If the type being rendered is a potentially recursive type (a type th at
83 // can contain itself as a member), we need to avoid recursion. 97 // can contain itself as a member), we need to avoid recursion.
84 // 98 //
85 // If we've already seen this type before, mark that this is the case an d 99 // If we've already seen this type before, mark that this is the case an d
(...skipping 14 matching lines...) Expand all
100 pe = v.Pointer() 114 pe = v.Pointer()
101 } 115 }
102 116
103 case reflect.Slice, reflect.Map: 117 case reflect.Slice, reflect.Map:
104 pe = v.Pointer() 118 pe = v.Pointer()
105 } 119 }
106 if pe != 0 { 120 if pe != 0 {
107 s = s.forkFor(pe) 121 s = s.forkFor(pe)
108 if s == nil { 122 if s == nil {
109 buf.WriteString("<REC(") 123 buf.WriteString("<REC(")
110 » » » writeType(buf, ptrs, vt) 124 » » » if !implicit {
125 » » » » writeType(buf, ptrs, vt)
126 » » » }
111 buf.WriteString(")>") 127 buf.WriteString(")>")
112 return 128 return
113 } 129 }
114 } 130 }
115 131
132 isAnon := func(t reflect.Type) bool {
133 if t.Name() != "" {
134 if _, ok := builtinTypeSet[t.Name()]; !ok {
135 return false
136 }
137 }
138 return t.Kind() != reflect.Interface
139 }
140
116 switch vk { 141 switch vk {
117 case reflect.Struct: 142 case reflect.Struct:
118 » » writeType(buf, ptrs, vt) 143 » » if !implicit {
144 » » » writeType(buf, ptrs, vt)
145 » » }
146 » » structAnon := vt.Name() == ""
119 buf.WriteRune('{') 147 buf.WriteRune('{')
120 for i := 0; i < vt.NumField(); i++ { 148 for i := 0; i < vt.NumField(); i++ {
121 if i > 0 { 149 if i > 0 {
122 buf.WriteString(", ") 150 buf.WriteString(", ")
123 } 151 }
124 » » » buf.WriteString(vt.Field(i).Name) 152 » » » anon := structAnon && isAnon(vt.Field(i).Type)
125 » » » buf.WriteRune(':')
126 153
127 » » » s.render(buf, 0, v.Field(i)) 154 » » » if !anon {
155 » » » » buf.WriteString(vt.Field(i).Name)
156 » » » » buf.WriteRune(':')
157 » » » }
158
159 » » » s.render(buf, 0, v.Field(i), anon)
128 } 160 }
129 buf.WriteRune('}') 161 buf.WriteRune('}')
130 162
131 case reflect.Slice: 163 case reflect.Slice:
132 if v.IsNil() { 164 if v.IsNil() {
133 » » » writeType(buf, ptrs, vt) 165 » » » if !implicit {
134 » » » buf.WriteString("(nil)") 166 » » » » writeType(buf, ptrs, vt)
167 » » » » buf.WriteString("(nil)")
168 » » » } else {
169 » » » » buf.WriteString("nil")
170 » » » }
135 return 171 return
136 } 172 }
137 fallthrough 173 fallthrough
138 174
139 case reflect.Array: 175 case reflect.Array:
140 » » writeType(buf, ptrs, vt) 176 » » if !implicit {
177 » » » writeType(buf, ptrs, vt)
178 » » }
179 » » anon := vt.Name() == "" && isAnon(vt.Elem())
141 buf.WriteString("{") 180 buf.WriteString("{")
142 for i := 0; i < v.Len(); i++ { 181 for i := 0; i < v.Len(); i++ {
143 if i > 0 { 182 if i > 0 {
144 buf.WriteString(", ") 183 buf.WriteString(", ")
145 } 184 }
146 185
147 » » » s.render(buf, 0, v.Index(i)) 186 » » » s.render(buf, 0, v.Index(i), anon)
148 } 187 }
149 buf.WriteRune('}') 188 buf.WriteRune('}')
150 189
151 case reflect.Map: 190 case reflect.Map:
152 » » writeType(buf, ptrs, vt) 191 » » if !implicit {
192 » » » writeType(buf, ptrs, vt)
193 » » }
153 if v.IsNil() { 194 if v.IsNil() {
154 buf.WriteString("(nil)") 195 buf.WriteString("(nil)")
155 } else { 196 } else {
156 buf.WriteString("{") 197 buf.WriteString("{")
157 198
158 mkeys := v.MapKeys() 199 mkeys := v.MapKeys()
159 tryAndSortMapKeys(vt, mkeys) 200 tryAndSortMapKeys(vt, mkeys)
160 201
202 kt := vt.Key()
203 keyAnon := typeOfString.ConvertibleTo(kt) || typeOfInt.C onvertibleTo(kt) || typeOfUint.ConvertibleTo(kt) || typeOfFloat.ConvertibleTo(kt )
204 valAnon := vt.Name() == "" && isAnon(vt.Elem())
161 for i, mk := range mkeys { 205 for i, mk := range mkeys {
162 if i > 0 { 206 if i > 0 {
163 buf.WriteString(", ") 207 buf.WriteString(", ")
164 } 208 }
165 209
166 » » » » s.render(buf, 0, mk) 210 » » » » s.render(buf, 0, mk, keyAnon)
167 buf.WriteString(":") 211 buf.WriteString(":")
168 » » » » s.render(buf, 0, v.MapIndex(mk)) 212 » » » » s.render(buf, 0, v.MapIndex(mk), valAnon)
169 } 213 }
170 buf.WriteRune('}') 214 buf.WriteRune('}')
171 } 215 }
172 216
173 case reflect.Ptr: 217 case reflect.Ptr:
174 ptrs++ 218 ptrs++
175 fallthrough 219 fallthrough
176 case reflect.Interface: 220 case reflect.Interface:
177 if v.IsNil() { 221 if v.IsNil() {
178 writeType(buf, ptrs, v.Type()) 222 writeType(buf, ptrs, v.Type())
179 » » » buf.WriteRune('(') 223 » » » buf.WriteString("(nil)")
180 » » » fmt.Fprint(buf, "nil")
181 » » » buf.WriteRune(')')
182 } else { 224 } else {
183 » » » s.render(buf, ptrs, v.Elem()) 225 » » » s.render(buf, ptrs, v.Elem(), false)
184 } 226 }
185 227
186 case reflect.Chan, reflect.Func, reflect.UnsafePointer: 228 case reflect.Chan, reflect.Func, reflect.UnsafePointer:
187 writeType(buf, ptrs, vt) 229 writeType(buf, ptrs, vt)
188 buf.WriteRune('(') 230 buf.WriteRune('(')
189 renderPointer(buf, v.Pointer()) 231 renderPointer(buf, v.Pointer())
190 buf.WriteRune(')') 232 buf.WriteRune(')')
191 233
192 default: 234 default:
193 tstr := vt.String() 235 tstr := vt.String()
194 » » implicit := ptrs == 0 && implicitTypeMap[vk] == tstr 236 » » implicit = implicit || (ptrs == 0 && builtinTypeMap[vk] == tstr)
195 if !implicit { 237 if !implicit {
196 writeType(buf, ptrs, vt) 238 writeType(buf, ptrs, vt)
197 buf.WriteRune('(') 239 buf.WriteRune('(')
198 } 240 }
199 241
200 switch vk { 242 switch vk {
201 case reflect.String: 243 case reflect.String:
202 fmt.Fprintf(buf, "%q", v.String()) 244 fmt.Fprintf(buf, "%q", v.String())
203 case reflect.Bool: 245 case reflect.Bool:
204 fmt.Fprintf(buf, "%v", v.Bool()) 246 fmt.Fprintf(buf, "%v", v.Bool())
205 247
206 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, re flect.Int64: 248 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, re flect.Int64:
207 fmt.Fprintf(buf, "%d", v.Int()) 249 fmt.Fprintf(buf, "%d", v.Int())
208 250
209 » » case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32 , reflect.Uint64: 251 » » case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32 , reflect.Uint64, reflect.Uintptr:
210 fmt.Fprintf(buf, "%d", v.Uint()) 252 fmt.Fprintf(buf, "%d", v.Uint())
211 253
212 case reflect.Float32, reflect.Float64: 254 case reflect.Float32, reflect.Float64:
213 fmt.Fprintf(buf, "%g", v.Float()) 255 fmt.Fprintf(buf, "%g", v.Float())
214 256
215 case reflect.Complex64, reflect.Complex128: 257 case reflect.Complex64, reflect.Complex128:
216 fmt.Fprintf(buf, "%g", v.Complex()) 258 fmt.Fprintf(buf, "%g", v.Complex())
217 } 259 }
218 260
219 if !implicit { 261 if !implicit {
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 // Try our stock sortable values. 360 // Try our stock sortable values.
319 switch mt.Key().Kind() { 361 switch mt.Key().Kind() {
320 case reflect.String, reflect.Int: 362 case reflect.String, reflect.Int:
321 vs := &sortableValueSlice{ 363 vs := &sortableValueSlice{
322 kind: mt.Key().Kind(), 364 kind: mt.Key().Kind(),
323 elements: k, 365 elements: k,
324 } 366 }
325 sort.Sort(vs) 367 sort.Sort(vs)
326 } 368 }
327 } 369 }
OLDNEW
« no previous file with comments | « no previous file | render/render_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698