diff options
Diffstat (limited to 'vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go')
-rw-r--r-- | vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go | 262 |
1 files changed, 208 insertions, 54 deletions
diff --git a/vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go b/vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go index e070a6b3..313611ef 100644 --- a/vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go +++ b/vendor/github.com/smartystreets/assertions/internal/go-render/render/render.go @@ -12,32 +12,46 @@ import ( "strconv" ) -var implicitTypeMap = map[reflect.Kind]string{ +var builtinTypeMap = map[reflect.Kind]string{ reflect.Bool: "bool", - reflect.String: "string", - reflect.Int: "int", - reflect.Int8: "int8", + reflect.Complex128: "complex128", + reflect.Complex64: "complex64", + reflect.Float32: "float32", + reflect.Float64: "float64", reflect.Int16: "int16", reflect.Int32: "int32", reflect.Int64: "int64", - reflect.Uint: "uint", - reflect.Uint8: "uint8", + reflect.Int8: "int8", + reflect.Int: "int", + reflect.String: "string", reflect.Uint16: "uint16", reflect.Uint32: "uint32", reflect.Uint64: "uint64", - reflect.Float32: "float32", - reflect.Float64: "float64", - reflect.Complex64: "complex64", - reflect.Complex128: "complex128", + reflect.Uint8: "uint8", + reflect.Uint: "uint", + reflect.Uintptr: "uintptr", +} + +var builtinTypeSet = map[string]struct{}{} + +func init() { + for _, v := range builtinTypeMap { + builtinTypeSet[v] = struct{}{} + } } +var typeOfString = reflect.TypeOf("") +var typeOfInt = reflect.TypeOf(int(1)) +var typeOfUint = reflect.TypeOf(uint(1)) +var typeOfFloat = reflect.TypeOf(10.1) + // Render converts a structure to a string representation. Unline the "%#v" // format string, this resolves pointer types' contents in structs, maps, and // slices/arrays and prints their field values. func Render(v interface{}) string { buf := bytes.Buffer{} s := (*traverseState)(nil) - s.render(&buf, 0, reflect.ValueOf(v)) + s.render(&buf, 0, reflect.ValueOf(v), false) return buf.String() } @@ -72,7 +86,7 @@ func (s *traverseState) forkFor(ptr uintptr) *traverseState { return fs } -func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) { +func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value, implicit bool) { if v.Kind() == reflect.Invalid { buf.WriteString("nil") return @@ -107,49 +121,80 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) { s = s.forkFor(pe) if s == nil { buf.WriteString("<REC(") - writeType(buf, ptrs, vt) + if !implicit { + writeType(buf, ptrs, vt) + } buf.WriteString(")>") return } } + isAnon := func(t reflect.Type) bool { + if t.Name() != "" { + if _, ok := builtinTypeSet[t.Name()]; !ok { + return false + } + } + return t.Kind() != reflect.Interface + } + switch vk { case reflect.Struct: - writeType(buf, ptrs, vt) + if !implicit { + writeType(buf, ptrs, vt) + } buf.WriteRune('{') - for i := 0; i < vt.NumField(); i++ { - if i > 0 { - buf.WriteString(", ") - } - buf.WriteString(vt.Field(i).Name) - buf.WriteRune(':') + if rendered, ok := renderTime(v); ok { + buf.WriteString(rendered) + } else { + structAnon := vt.Name() == "" + for i := 0; i < vt.NumField(); i++ { + if i > 0 { + buf.WriteString(", ") + } + anon := structAnon && isAnon(vt.Field(i).Type) - s.render(buf, 0, v.Field(i)) + if !anon { + buf.WriteString(vt.Field(i).Name) + buf.WriteRune(':') + } + + s.render(buf, 0, v.Field(i), anon) + } } buf.WriteRune('}') case reflect.Slice: if v.IsNil() { - writeType(buf, ptrs, vt) - buf.WriteString("(nil)") + if !implicit { + writeType(buf, ptrs, vt) + buf.WriteString("(nil)") + } else { + buf.WriteString("nil") + } return } fallthrough case reflect.Array: - writeType(buf, ptrs, vt) + if !implicit { + writeType(buf, ptrs, vt) + } + anon := vt.Name() == "" && isAnon(vt.Elem()) buf.WriteString("{") for i := 0; i < v.Len(); i++ { if i > 0 { buf.WriteString(", ") } - s.render(buf, 0, v.Index(i)) + s.render(buf, 0, v.Index(i), anon) } buf.WriteRune('}') case reflect.Map: - writeType(buf, ptrs, vt) + if !implicit { + writeType(buf, ptrs, vt) + } if v.IsNil() { buf.WriteString("(nil)") } else { @@ -158,14 +203,17 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) { mkeys := v.MapKeys() tryAndSortMapKeys(vt, mkeys) + kt := vt.Key() + keyAnon := typeOfString.ConvertibleTo(kt) || typeOfInt.ConvertibleTo(kt) || typeOfUint.ConvertibleTo(kt) || typeOfFloat.ConvertibleTo(kt) + valAnon := vt.Name() == "" && isAnon(vt.Elem()) for i, mk := range mkeys { if i > 0 { buf.WriteString(", ") } - s.render(buf, 0, mk) + s.render(buf, 0, mk, keyAnon) buf.WriteString(":") - s.render(buf, 0, v.MapIndex(mk)) + s.render(buf, 0, v.MapIndex(mk), valAnon) } buf.WriteRune('}') } @@ -176,11 +224,9 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) { case reflect.Interface: if v.IsNil() { writeType(buf, ptrs, v.Type()) - buf.WriteRune('(') - fmt.Fprint(buf, "nil") - buf.WriteRune(')') + buf.WriteString("(nil)") } else { - s.render(buf, ptrs, v.Elem()) + s.render(buf, ptrs, v.Elem(), false) } case reflect.Chan, reflect.Func, reflect.UnsafePointer: @@ -191,7 +237,7 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) { default: tstr := vt.String() - implicit := ptrs == 0 && implicitTypeMap[vk] == tstr + implicit = implicit || (ptrs == 0 && builtinTypeMap[vk] == tstr) if !implicit { writeType(buf, ptrs, vt) buf.WriteRune('(') @@ -206,7 +252,7 @@ func (s *traverseState) render(buf *bytes.Buffer, ptrs int, v reflect.Value) { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: fmt.Fprintf(buf, "%d", v.Int()) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: fmt.Fprintf(buf, "%d", v.Uint()) case reflect.Float32, reflect.Float64: @@ -288,40 +334,148 @@ func writeType(buf *bytes.Buffer, ptrs int, t reflect.Type) { } } +type cmpFn func(a, b reflect.Value) int + type sortableValueSlice struct { - kind reflect.Kind + cmp cmpFn elements []reflect.Value } -func (s *sortableValueSlice) Len() int { +func (s sortableValueSlice) Len() int { return len(s.elements) } -func (s *sortableValueSlice) Less(i, j int) bool { - switch s.kind { +func (s sortableValueSlice) Less(i, j int) bool { + return s.cmp(s.elements[i], s.elements[j]) < 0 +} + +func (s sortableValueSlice) Swap(i, j int) { + s.elements[i], s.elements[j] = s.elements[j], s.elements[i] +} + +// cmpForType returns a cmpFn which sorts the data for some type t in the same +// order that a go-native map key is compared for equality. +func cmpForType(t reflect.Type) cmpFn { + switch t.Kind() { case reflect.String: - return s.elements[i].String() < s.elements[j].String() + return func(av, bv reflect.Value) int { + a, b := av.String(), bv.String() + if a < b { + return -1 + } else if a > b { + return 1 + } + return 0 + } + + case reflect.Bool: + return func(av, bv reflect.Value) int { + a, b := av.Bool(), bv.Bool() + if !a && b { + return -1 + } else if a && !b { + return 1 + } + return 0 + } - case reflect.Int: - return s.elements[i].Int() < s.elements[j].Int() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return func(av, bv reflect.Value) int { + a, b := av.Int(), bv.Int() + if a < b { + return -1 + } else if a > b { + return 1 + } + return 0 + } - default: - panic(fmt.Errorf("unsupported sort kind: %s", s.kind)) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, + reflect.Uint64, reflect.Uintptr, reflect.UnsafePointer: + return func(av, bv reflect.Value) int { + a, b := av.Uint(), bv.Uint() + if a < b { + return -1 + } else if a > b { + return 1 + } + return 0 + } + + case reflect.Float32, reflect.Float64: + return func(av, bv reflect.Value) int { + a, b := av.Float(), bv.Float() + if a < b { + return -1 + } else if a > b { + return 1 + } + return 0 + } + + case reflect.Interface: + return func(av, bv reflect.Value) int { + a, b := av.InterfaceData(), bv.InterfaceData() + if a[0] < b[0] { + return -1 + } else if a[0] > b[0] { + return 1 + } + if a[1] < b[1] { + return -1 + } else if a[1] > b[1] { + return 1 + } + return 0 + } + + case reflect.Complex64, reflect.Complex128: + return func(av, bv reflect.Value) int { + a, b := av.Complex(), bv.Complex() + if real(a) < real(b) { + return -1 + } else if real(a) > real(b) { + return 1 + } + if imag(a) < imag(b) { + return -1 + } else if imag(a) > imag(b) { + return 1 + } + return 0 + } + + case reflect.Ptr, reflect.Chan: + return func(av, bv reflect.Value) int { + a, b := av.Pointer(), bv.Pointer() + if a < b { + return -1 + } else if a > b { + return 1 + } + return 0 + } + + case reflect.Struct: + cmpLst := make([]cmpFn, t.NumField()) + for i := range cmpLst { + cmpLst[i] = cmpForType(t.Field(i).Type) + } + return func(a, b reflect.Value) int { + for i, cmp := range cmpLst { + if rslt := cmp(a.Field(i), b.Field(i)); rslt != 0 { + return rslt + } + } + return 0 + } } -} -func (s *sortableValueSlice) Swap(i, j int) { - s.elements[i], s.elements[j] = s.elements[j], s.elements[i] + return nil } func tryAndSortMapKeys(mt reflect.Type, k []reflect.Value) { - // Try our stock sortable values. - switch mt.Key().Kind() { - case reflect.String, reflect.Int: - vs := &sortableValueSlice{ - kind: mt.Key().Kind(), - elements: k, - } - sort.Sort(vs) + if cmp := cmpForType(mt.Key()); cmp != nil { + sort.Sort(sortableValueSlice{cmp, k}) } } |