diff unexported struct fields

Fixes #21.
Closes #33 (superseded).
diff --git a/diff.go b/diff.go
index 8fe8e24..fb9580b 100644
--- a/diff.go
+++ b/diff.go
@@ -40,11 +40,11 @@
 
 func (w diffWriter) diff(av, bv reflect.Value) {
 	if !av.IsValid() && bv.IsValid() {
-		w.printf("nil != %#v", bv.Interface())
+		w.printf("nil != %# v", formatter{v: bv, quote: true})
 		return
 	}
 	if av.IsValid() && !bv.IsValid() {
-		w.printf("%#v != nil", av.Interface())
+		w.printf("%# v != nil", formatter{v: av, quote: true})
 		return
 	}
 	if !av.IsValid() && !bv.IsValid() {
@@ -58,34 +58,61 @@
 		return
 	}
 
-	// numeric types, including bool
-	if at.Kind() < reflect.Array {
-		a, b := av.Interface(), bv.Interface()
-		if a != b {
-			w.printf("%#v != %#v", a, b)
+	switch kind := at.Kind(); kind {
+	case reflect.Bool:
+		if a, b := av.Bool(), bv.Bool(); a != b {
+			w.printf("%v != %v", a, b)
 		}
-		return
-	}
-
-	switch at.Kind() {
-	case reflect.String:
-		a, b := av.Interface(), bv.Interface()
-		if a != b {
-			w.printf("%q != %q", a, b)
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		if a, b := av.Int(), bv.Int(); a != b {
+			w.printf("%d != %d", a, b)
+		}
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		if a, b := av.Uint(), bv.Uint(); a != b {
+			w.printf("%d != %d", a, b)
+		}
+	case reflect.Float32, reflect.Float64:
+		if a, b := av.Float(), bv.Float(); a != b {
+			w.printf("%v != %v", a, b)
+		}
+	case reflect.Complex64, reflect.Complex128:
+		if a, b := av.Complex(), bv.Complex(); a != b {
+			w.printf("%v != %v", a, b)
+		}
+	case reflect.Array:
+		n := av.Len()
+		for i := 0; i < n; i++ {
+			w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
+		}
+	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
+		if a, b := av.Pointer(), bv.Pointer(); a != b {
+			w.printf("%#x != %#x", a, b)
+		}
+	case reflect.Interface:
+		w.diff(av.Elem(), bv.Elem())
+	case reflect.Map:
+		ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys())
+		for _, k := range ak {
+			w := w.relabel(fmt.Sprintf("[%#v]", k))
+			w.printf("%q != (missing)", av.MapIndex(k))
+		}
+		for _, k := range both {
+			w := w.relabel(fmt.Sprintf("[%#v]", k))
+			w.diff(av.MapIndex(k), bv.MapIndex(k))
+		}
+		for _, k := range bk {
+			w := w.relabel(fmt.Sprintf("[%#v]", k))
+			w.printf("(missing) != %q", bv.MapIndex(k))
 		}
 	case reflect.Ptr:
 		switch {
 		case av.IsNil() && !bv.IsNil():
-			w.printf("nil != %v", bv.Interface())
+			w.printf("nil != %# v", formatter{v: bv, quote: true})
 		case !av.IsNil() && bv.IsNil():
-			w.printf("%v != nil", av.Interface())
+			w.printf("%# v != nil", formatter{v: av, quote: true})
 		case !av.IsNil() && !bv.IsNil():
 			w.diff(av.Elem(), bv.Elem())
 		}
-	case reflect.Struct:
-		for i := 0; i < av.NumField(); i++ {
-			w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i))
-		}
 	case reflect.Slice:
 		lenA := av.Len()
 		lenB := bv.Len()
@@ -96,26 +123,16 @@
 		for i := 0; i < lenA; i++ {
 			w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
 		}
-	case reflect.Map:
-		ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys())
-		for _, k := range ak {
-			w := w.relabel(fmt.Sprintf("[%#v]", k.Interface()))
-			w.printf("%q != (missing)", av.MapIndex(k))
+	case reflect.String:
+		if a, b := av.String(), bv.String(); a != b {
+			w.printf("%q != %q", a, b)
 		}
-		for _, k := range both {
-			w := w.relabel(fmt.Sprintf("[%#v]", k.Interface()))
-			w.diff(av.MapIndex(k), bv.MapIndex(k))
+	case reflect.Struct:
+		for i := 0; i < av.NumField(); i++ {
+			w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i))
 		}
-		for _, k := range bk {
-			w := w.relabel(fmt.Sprintf("[%#v]", k.Interface()))
-			w.printf("(missing) != %q", bv.MapIndex(k))
-		}
-	case reflect.Interface:
-		w.diff(reflect.ValueOf(av.Interface()), reflect.ValueOf(bv.Interface()))
 	default:
-		if !reflect.DeepEqual(av.Interface(), bv.Interface()) {
-			w.printf("%# v != %# v", Formatter(av.Interface()), Formatter(bv.Interface()))
-		}
+		panic("unknown reflect Kind: " + kind.String())
 	}
 }
 
@@ -128,11 +145,26 @@
 	return d1
 }
 
+// keyEqual compares a and b for equality.
+// Both a and b must be valid map keys.
+func keyEqual(a, b reflect.Value) bool {
+	if a.Type() != b.Type() {
+		return false
+	}
+	switch kind := a.Kind(); kind {
+	case reflect.Int:
+		a, b := a.Int(), b.Int()
+		return a == b
+	default:
+		panic("invalid map reflect Kind: " + kind.String())
+	}
+}
+
 func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) {
 	for _, av := range a {
 		inBoth := false
 		for _, bv := range b {
-			if reflect.DeepEqual(av.Interface(), bv.Interface()) {
+			if keyEqual(av, bv) {
 				inBoth = true
 				both = append(both, av)
 				break
@@ -145,7 +177,7 @@
 	for _, bv := range b {
 		inBoth := false
 		for _, av := range a {
-			if reflect.DeepEqual(av.Interface(), bv.Interface()) {
+			if keyEqual(av, bv) {
 				inBoth = true
 				break
 			}
diff --git a/diff_test.go b/diff_test.go
index 3c388f1..782858c 100644
--- a/diff_test.go
+++ b/diff_test.go
@@ -1,7 +1,9 @@
 package pretty
 
 import (
+	"fmt"
 	"testing"
+	"unsafe"
 )
 
 type difftest struct {
@@ -17,6 +19,20 @@
 	C []int
 }
 
+type (
+	N struct{ N int }
+	E interface{}
+)
+
+var (
+	c0 = make(chan int)
+	c1 = make(chan int)
+	f0 = func() {}
+	f1 = func() {}
+	i0 = 0
+	i1 = 1
+)
+
 var diffs = []difftest{
 	{a: nil, b: nil},
 	{a: S{A: 1}, b: S{A: 1}},
@@ -28,12 +44,80 @@
 	{S{}, S{A: 1}, []string{`A: 0 != 1`}},
 	{new(S), &S{A: 1}, []string{`A: 0 != 1`}},
 	{S{S: new(S)}, S{S: &S{A: 1}}, []string{`S.A: 0 != 1`}},
-	{S{}, S{I: 0}, []string{`I: nil != 0`}},
+	{S{}, S{I: 0}, []string{`I: nil != int(0)`}},
 	{S{I: 1}, S{I: "x"}, []string{`I: int != string`}},
 	{S{}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}},
 	{S{C: []int{}}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}},
 	{S{C: []int{1, 2, 3}}, S{C: []int{1, 2, 4}}, []string{`C[2]: 3 != 4`}},
-	{S{}, S{A: 1, S: new(S)}, []string{`A: 0 != 1`, `S: nil != &{0 <nil> <nil> []}`}},
+	{S{}, S{A: 1, S: new(S)}, []string{`A: 0 != 1`, `S: nil != &pretty.S{}`}},
+
+	// unexported fields of every reflect.Kind (both equal and unequal)
+	{struct{ x bool }{false}, struct{ x bool }{false}, nil},
+	{struct{ x bool }{false}, struct{ x bool }{true}, []string{`x: false != true`}},
+	{struct{ x int }{0}, struct{ x int }{0}, nil},
+	{struct{ x int }{0}, struct{ x int }{1}, []string{`x: 0 != 1`}},
+	{struct{ x int8 }{0}, struct{ x int8 }{0}, nil},
+	{struct{ x int8 }{0}, struct{ x int8 }{1}, []string{`x: 0 != 1`}},
+	{struct{ x int16 }{0}, struct{ x int16 }{0}, nil},
+	{struct{ x int16 }{0}, struct{ x int16 }{1}, []string{`x: 0 != 1`}},
+	{struct{ x int32 }{0}, struct{ x int32 }{0}, nil},
+	{struct{ x int32 }{0}, struct{ x int32 }{1}, []string{`x: 0 != 1`}},
+	{struct{ x int64 }{0}, struct{ x int64 }{0}, nil},
+	{struct{ x int64 }{0}, struct{ x int64 }{1}, []string{`x: 0 != 1`}},
+	{struct{ x uint }{0}, struct{ x uint }{0}, nil},
+	{struct{ x uint }{0}, struct{ x uint }{1}, []string{`x: 0 != 1`}},
+	{struct{ x uint8 }{0}, struct{ x uint8 }{0}, nil},
+	{struct{ x uint8 }{0}, struct{ x uint8 }{1}, []string{`x: 0 != 1`}},
+	{struct{ x uint16 }{0}, struct{ x uint16 }{0}, nil},
+	{struct{ x uint16 }{0}, struct{ x uint16 }{1}, []string{`x: 0 != 1`}},
+	{struct{ x uint32 }{0}, struct{ x uint32 }{0}, nil},
+	{struct{ x uint32 }{0}, struct{ x uint32 }{1}, []string{`x: 0 != 1`}},
+	{struct{ x uint64 }{0}, struct{ x uint64 }{0}, nil},
+	{struct{ x uint64 }{0}, struct{ x uint64 }{1}, []string{`x: 0 != 1`}},
+	{struct{ x uintptr }{0}, struct{ x uintptr }{0}, nil},
+	{struct{ x uintptr }{0}, struct{ x uintptr }{1}, []string{`x: 0 != 1`}},
+	{struct{ x float32 }{0}, struct{ x float32 }{0}, nil},
+	{struct{ x float32 }{0}, struct{ x float32 }{1}, []string{`x: 0 != 1`}},
+	{struct{ x float64 }{0}, struct{ x float64 }{0}, nil},
+	{struct{ x float64 }{0}, struct{ x float64 }{1}, []string{`x: 0 != 1`}},
+	{struct{ x complex64 }{0}, struct{ x complex64 }{0}, nil},
+	{struct{ x complex64 }{0}, struct{ x complex64 }{1}, []string{`x: (0+0i) != (1+0i)`}},
+	{struct{ x complex128 }{0}, struct{ x complex128 }{0}, nil},
+	{struct{ x complex128 }{0}, struct{ x complex128 }{1}, []string{`x: (0+0i) != (1+0i)`}},
+	{struct{ x [1]int }{[1]int{0}}, struct{ x [1]int }{[1]int{0}}, nil},
+	{struct{ x [1]int }{[1]int{0}}, struct{ x [1]int }{[1]int{1}}, []string{`x[0]: 0 != 1`}},
+	{struct{ x chan int }{c0}, struct{ x chan int }{c0}, nil},
+	{struct{ x chan int }{c0}, struct{ x chan int }{c1}, []string{fmt.Sprintf("x: %p != %p", c0, c1)}},
+	{struct{ x func() }{f0}, struct{ x func() }{f0}, nil},
+	{struct{ x func() }{f0}, struct{ x func() }{f1}, []string{fmt.Sprintf("x: %p != %p", f0, f1)}},
+	{struct{ x interface{} }{0}, struct{ x interface{} }{0}, nil},
+	{struct{ x interface{} }{0}, struct{ x interface{} }{1}, []string{`x: 0 != 1`}},
+	{struct{ x interface{} }{0}, struct{ x interface{} }{""}, []string{`x: int != string`}},
+	{struct{ x interface{} }{0}, struct{ x interface{} }{nil}, []string{`x: int(0) != nil`}},
+	{struct{ x interface{} }{nil}, struct{ x interface{} }{0}, []string{`x: nil != int(0)`}},
+	{struct{ x map[int]int }{map[int]int{0: 0}}, struct{ x map[int]int }{map[int]int{0: 0}}, nil},
+	{struct{ x map[int]int }{map[int]int{0: 0}}, struct{ x map[int]int }{map[int]int{0: 1}}, []string{`x[0]: 0 != 1`}},
+	{struct{ x *int }{new(int)}, struct{ x *int }{new(int)}, nil},
+	{struct{ x *int }{&i0}, struct{ x *int }{&i1}, []string{`x: 0 != 1`}},
+	{struct{ x *int }{nil}, struct{ x *int }{&i0}, []string{`x: nil != &int(0)`}},
+	{struct{ x *int }{&i0}, struct{ x *int }{nil}, []string{`x: &int(0) != nil`}},
+	{struct{ x []int }{[]int{0}}, struct{ x []int }{[]int{0}}, nil},
+	{struct{ x []int }{[]int{0}}, struct{ x []int }{[]int{1}}, []string{`x[0]: 0 != 1`}},
+	{struct{ x string }{"a"}, struct{ x string }{"a"}, nil},
+	{struct{ x string }{"a"}, struct{ x string }{"b"}, []string{`x: "a" != "b"`}},
+	{struct{ x N }{N{0}}, struct{ x N }{N{0}}, nil},
+	{struct{ x N }{N{0}}, struct{ x N }{N{1}}, []string{`x.N: 0 != 1`}},
+
+	{
+		struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))},
+		struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))},
+		nil,
+	},
+	{
+		struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))},
+		struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(1))},
+		[]string{`x: 0x0 != 0x1`},
+	},
 }
 
 func TestDiff(t *testing.T) {
diff --git a/formatter.go b/formatter.go
index 8dacda2..dff7cb3 100644
--- a/formatter.go
+++ b/formatter.go
@@ -15,7 +15,7 @@
 )
 
 type formatter struct {
-	x     interface{}
+	v     reflect.Value
 	force bool
 	quote bool
 }
@@ -30,11 +30,11 @@
 // format x according to the usual rules of package fmt.
 // In particular, if x satisfies fmt.Formatter, then x.Format will be called.
 func Formatter(x interface{}) (f fmt.Formatter) {
-	return formatter{x: x, quote: true}
+	return formatter{v: reflect.ValueOf(x), quote: true}
 }
 
 func (fo formatter) String() string {
-	return fmt.Sprint(fo.x) // unwrap it
+	return fmt.Sprint(fo.v) // unwrap it
 }
 
 func (fo formatter) passThrough(f fmt.State, c rune) {
@@ -51,14 +51,14 @@
 		s += fmt.Sprintf(".%d", p)
 	}
 	s += string(c)
-	fmt.Fprintf(f, s, fo.x)
+	fmt.Fprintf(f, s, fo.v)
 }
 
 func (fo formatter) Format(f fmt.State, c rune) {
 	if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') {
 		w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0)
 		p := &printer{tw: w, Writer: w, visited: make(map[visit]int)}
-		p.printValue(reflect.ValueOf(fo.x), true, fo.quote)
+		p.printValue(fo.v, true, fo.quote)
 		w.Flush()
 		return
 	}
diff --git a/pretty.go b/pretty.go
index b91020a..49423ec 100644
--- a/pretty.go
+++ b/pretty.go
@@ -11,6 +11,7 @@
 	"fmt"
 	"io"
 	"log"
+	"reflect"
 )
 
 // Errorf is a convenience wrapper for fmt.Errorf.
@@ -101,7 +102,7 @@
 func wrap(a []interface{}, force bool) []interface{} {
 	w := make([]interface{}, len(a))
 	for i, x := range a {
-		w[i] = formatter{x: x, force: force}
+		w[i] = formatter{v: reflect.ValueOf(x), force: force}
 	}
 	return w
 }