Index: render/render.go |
diff --git a/render/render.go b/render/render.go |
index bdb307ce9d49be5f2662606dbe61c7e6485edea8..23b7a586761fcb6e7e077be62ce767f3b3ef9483 100644 |
--- a/render/render.go |
+++ b/render/render.go |
@@ -330,40 +330,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.Int: |
- return s.elements[i].Int() < s.elements[j].Int() |
+ 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 |
+ } |
- default: |
- panic(fmt.Errorf("unsupported sort kind: %s", s.kind)) |
+ 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 |
+ } |
+ |
+ 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}) |
} |
} |