| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |