Add Transform.Option helper method (#59)

Currently there is no easy way to create non-reentrant transformers
where they do not recursively apply on their own output.
You could check for the Transformer name, but the API does not
require the names to be unique.

The only way to write a helper to do this is to generate some obscure
name that is guaranteed to probabilistic never have a conflict.

A better approach is to simply return the original Option
as returned by the Transformer constructor.
Thus, users can rely on == to check if a Transform step exactly
matches a Transformer that they created.

It would be useful to a non-reentrant transformer to cmpopts,
but that can be a future addition. It will also need a better name.
diff --git a/cmp/compare_test.go b/cmp/compare_test.go
index 00b4ccf..7bbb977 100644
--- a/cmp/compare_test.go
+++ b/cmp/compare_test.go
@@ -457,10 +457,25 @@
 }
 
 func transformerTests() []test {
-	type JSON string
+	type StringBytes struct {
+		String string
+		Bytes  []byte
+	}
 
 	const label = "Transformer"
 
+	transformOnce := func(name string, f interface{}) cmp.Option {
+		xform := cmp.Transformer(name, f)
+		return cmp.FilterPath(func(p cmp.Path) bool {
+			for _, ps := range p {
+				if tr, ok := ps.(cmp.Transform); ok && tr.Option() == xform {
+					return false
+				}
+			}
+			return true
+		}, xform)
+	}
+
 	return []test{{
 		label: label,
 		x:     uint8(0),
@@ -522,7 +537,7 @@
 	+: 1`,
 	}, {
 		label: label,
-		x: JSON(`{
+		x: `{
 		  "firstName": "John",
 		  "lastName": "Smith",
 		  "age": 25,
@@ -544,14 +559,14 @@
 		    "type": "mobile"
 		  }],
 		  "children": []
-		}`),
-		y: JSON(`{"firstName":"John","lastName":"Smith","isAlive":true,"age":25,
+		}`,
+		y: `{"firstName":"John","lastName":"Smith","isAlive":true,"age":25,
 			"address":{"streetAddress":"21 2nd Street","city":"New York",
 			"state":"NY","postalCode":"10021-3100"},"phoneNumbers":[{"type":"home",
 			"number":"212 555-1234"},{"type":"office","number":"646 555-4567"},{
-			"type":"mobile","number":"123 456-7890"}],"children":[],"spouse":null}`),
+			"type":"mobile","number":"123 456-7890"}],"children":[],"spouse":null}`,
 		opts: []cmp.Option{
-			cmp.Transformer("ParseJSON", func(s JSON) (m map[string]interface{}) {
+			transformOnce("ParseJSON", func(s string) (m map[string]interface{}) {
 				if err := json.Unmarshal([]byte(s), &m); err != nil {
 					panic(err)
 				}
@@ -559,18 +574,33 @@
 			}),
 		},
 		wantDiff: `
-ParseJSON({cmp_test.JSON})["address"]["city"]:
+ParseJSON({string})["address"]["city"]:
 	-: "Los Angeles"
 	+: "New York"
-ParseJSON({cmp_test.JSON})["address"]["state"]:
+ParseJSON({string})["address"]["state"]:
 	-: "CA"
 	+: "NY"
-ParseJSON({cmp_test.JSON})["phoneNumbers"][0]["number"]:
+ParseJSON({string})["phoneNumbers"][0]["number"]:
 	-: "212 555-4321"
 	+: "212 555-1234"
-ParseJSON({cmp_test.JSON})["spouse"]:
+ParseJSON({string})["spouse"]:
 	-: <non-existent>
 	+: interface {}(nil)`,
+	}, {
+		label: label,
+		x:     StringBytes{String: "some\nmulti\nLine\nstring", Bytes: []byte("some\nmulti\nline\nbytes")},
+		y:     StringBytes{String: "some\nmulti\nline\nstring", Bytes: []byte("some\nmulti\nline\nBytes")},
+		opts: []cmp.Option{
+			transformOnce("SplitString", func(s string) []string { return strings.Split(s, "\n") }),
+			transformOnce("SplitBytes", func(b []byte) [][]byte { return bytes.Split(b, []byte("\n")) }),
+		},
+		wantDiff: `
+SplitString({cmp_test.StringBytes}.String)[2]:
+	-: "Line"
+	+: "line"
+SplitBytes({cmp_test.StringBytes}.Bytes)[3][0]:
+	-: 0x62
+	+: 0x42`,
 	}}
 }
 
diff --git a/cmp/path.go b/cmp/path.go
index 13d9c2e..c08a3cf 100644
--- a/cmp/path.go
+++ b/cmp/path.go
@@ -79,6 +79,11 @@
 		PathStep
 		Name() string
 		Func() reflect.Value
+
+		// Option returns the originally constructed Transformer option.
+		// The == operator can be used to detect the exact option used.
+		Option() Option
+
 		isTransform()
 	}
 )
@@ -260,6 +265,7 @@
 func (sf structField) Index() int           { return sf.idx }
 func (tf transform) Name() string           { return tf.trans.name }
 func (tf transform) Func() reflect.Value    { return tf.trans.fnc }
+func (tf transform) Option() Option         { return tf.trans }
 
 func (pathStep) isPathStep()           {}
 func (sliceIndex) isSliceIndex()       {}