Expose the thorny part of the oneof metadata interpretation.

This makes it very easy for other code to understand what to do with
incoming data that references oneof fields.
diff --git a/jsonpb/jsonpb.go b/jsonpb/jsonpb.go
index 2663c92..389c5e0 100644
--- a/jsonpb/jsonpb.go
+++ b/jsonpb/jsonpb.go
@@ -332,41 +332,15 @@
 			}
 		}
 		// Check for any oneof fields.
-		// This might be slow; we can optimise it if it becomes a problem.
-		type oneofMessage interface {
-			XXX_OneofFuncs() (func(proto.Message, *proto.Buffer) error, func(proto.Message, int, int, *proto.Buffer) (bool, error), []interface{})
-		}
-		var oneofTypes []interface{}
-		if om, ok := reflect.Zero(reflect.PtrTo(targetType)).Interface().(oneofMessage); ok {
-			_, _, oneofTypes = om.XXX_OneofFuncs()
-		}
+		sprops := proto.GetProperties(targetType)
 		for fname, raw := range jsonFields {
-			for _, oot := range oneofTypes {
-				sp := reflect.ValueOf(oot).Type() // *T
-				var props proto.Properties
-				props.Parse(sp.Elem().Field(0).Tag.Get("protobuf"))
-				if props.OrigName != fname {
-					continue
-				}
-				nv := reflect.New(sp.Elem())
-				// There will be exactly one interface field that
-				// this new value is assignable to.
-				for i := 0; i < targetType.NumField(); i++ {
-					f := targetType.Field(i)
-					if f.Type.Kind() != reflect.Interface {
-						continue
-					}
-					if !nv.Type().AssignableTo(f.Type) {
-						continue
-					}
-					target.Field(i).Set(nv)
-					break
-				}
+			if oop, ok := sprops.OneofTypes[fname]; ok {
+				nv := reflect.New(oop.Type.Elem())
+				target.Field(oop.Field).Set(nv)
 				if err := unmarshalValue(nv.Elem().Field(0), raw); err != nil {
 					return err
 				}
 				delete(jsonFields, fname)
-				break
 			}
 		}
 		if len(jsonFields) > 0 {
diff --git a/proto/properties.go b/proto/properties.go
index 5685445..692fe43 100644
--- a/proto/properties.go
+++ b/proto/properties.go
@@ -142,7 +142,17 @@
 	oneofMarshaler   oneofMarshaler
 	oneofUnmarshaler oneofUnmarshaler
 	stype            reflect.Type
-	oneofTypes       []interface{}
+
+	// OneofTypes contains information about the oneof fields in this message.
+	// It is keyed by the original name of a field.
+	OneofTypes map[string]*OneofProperties
+}
+
+// OneofProperties represents information about a specific field in a oneof.
+type OneofProperties struct {
+	Type  reflect.Type // pointer to generated struct type for this oneof field
+	Field int          // struct field number of the containing oneof in the message
+	Prop  *Properties
 }
 
 // Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
@@ -698,8 +708,35 @@
 		XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), []interface{})
 	}
 	if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
-		prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofTypes = om.XXX_OneofFuncs()
+		var oots []interface{}
+		prop.oneofMarshaler, prop.oneofUnmarshaler, oots = om.XXX_OneofFuncs()
 		prop.stype = t
+
+		// Interpret oneof metadata.
+		prop.OneofTypes = make(map[string]*OneofProperties)
+		for _, oot := range oots {
+			oop := &OneofProperties{
+				Type: reflect.ValueOf(oot).Type(), // *T
+				Prop: new(Properties),
+			}
+			sft := oop.Type.Elem().Field(0)
+			oop.Prop.Name = sft.Name
+			oop.Prop.Parse(sft.Tag.Get("protobuf"))
+			// There will be exactly one interface field that
+			// this new value is assignable to.
+			for i := 0; i < t.NumField(); i++ {
+				f := t.Field(i)
+				if f.Type.Kind() != reflect.Interface {
+					continue
+				}
+				if !oop.Type.AssignableTo(f.Type) {
+					continue
+				}
+				oop.Field = i
+				break
+			}
+			prop.OneofTypes[oop.Prop.OrigName] = oop
+		}
 	}
 
 	// build required counts
diff --git a/proto/text_parser.go b/proto/text_parser.go
index 2e2a67f..8bce369 100644
--- a/proto/text_parser.go
+++ b/proto/text_parser.go
@@ -532,34 +532,12 @@
 		fi, props, ok := structFieldByName(sprops, name)
 		if ok {
 			dst = sv.Field(fi)
-		} else {
-			// Maybe it is a oneof.
-			// TODO: If this shows in profiles, cache the mapping.
-			for _, oot := range sprops.oneofTypes {
-				sp := reflect.ValueOf(oot).Type() // *T
-				var p Properties
-				p.Parse(sp.Elem().Field(0).Tag.Get("protobuf"))
-				if p.OrigName != name {
-					continue
-				}
-				nv := reflect.New(sp.Elem())
-				dst = nv.Elem().Field(0)
-				props = &p
-				// There will be exactly one interface field that
-				// this new value is assignable to.
-				for i := 0; i < st.NumField(); i++ {
-					f := st.Field(i)
-					if f.Type.Kind() != reflect.Interface {
-						continue
-					}
-					if !nv.Type().AssignableTo(f.Type) {
-						continue
-					}
-					sv.Field(i).Set(nv)
-					break
-				}
-				break
-			}
+		} else if oop, ok := sprops.OneofTypes[name]; ok {
+			// It is a oneof.
+			props = oop.Prop
+			nv := reflect.New(oop.Type.Elem())
+			dst = nv.Elem().Field(0)
+			sv.Field(oop.Field).Set(nv)
 		}
 		if !dst.IsValid() {
 			return p.errorf("unknown field name %q in %v", name, st)