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