| 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})
|
| }
|
| }
|
|
|