Sort numerically-keyed maps by numeric value.

This matches the C++ output and the specification
(https://developers.google.com/protocol-buffers/docs/proto#maps).

Technically we don't have to do this for the wire format,
but it's faster and less code to make them the same.
diff --git a/proto/lib.go b/proto/lib.go
index 0b28b08..95f7975 100644
--- a/proto/lib.go
+++ b/proto/lib.go
@@ -211,6 +211,7 @@
 	"fmt"
 	"log"
 	"reflect"
+	"sort"
 	"strconv"
 	"sync"
 )
@@ -787,12 +788,39 @@
 // If this turns out to be inefficient we can always consider other options,
 // such as doing a Schwartzian transform.
 
-type mapKeys []reflect.Value
+func mapKeys(vs []reflect.Value) sort.Interface {
+	s := mapKeySorter{
+		vs: vs,
+		// default Less function: textual comparison
+		less: func(a, b reflect.Value) bool {
+			return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface())
+		},
+	}
 
-func (s mapKeys) Len() int      { return len(s) }
-func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-func (s mapKeys) Less(i, j int) bool {
-	return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
+	// Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps;
+	// numeric keys are sorted numerically.
+	if len(vs) == 0 {
+		return s
+	}
+	switch vs[0].Kind() {
+	case reflect.Int32, reflect.Int64:
+		s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() }
+	case reflect.Uint32, reflect.Uint64:
+		s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() }
+	}
+
+	return s
+}
+
+type mapKeySorter struct {
+	vs   []reflect.Value
+	less func(a, b reflect.Value) bool
+}
+
+func (s mapKeySorter) Len() int      { return len(s.vs) }
+func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] }
+func (s mapKeySorter) Less(i, j int) bool {
+	return s.less(s.vs[i], s.vs[j])
 }
 
 // isProto3Zero reports whether v is a zero proto3 value.