func typeMarshaler(t reflect.Type, tags []string, nozero, oneof bool) (sizer, marshaler) {
	encoding := tags[0]
	pointer := false
	slice := false
	if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 {
		slice = true
		t = t.Elem()
	}
	if t.Kind() == reflect.Ptr {
		pointer = true
		t = t.Elem()
	}
	packed := false
	proto3 := false
	ctype := false
	isTime := false
	isDuration := false
	isWktPointer := false
	validateUTF8 := true
	for i := 2; i < len(tags); i++ {
		if tags[i] == "packed" {
			packed = true
		}
		if tags[i] == "proto3" {
			proto3 = true
		}
		if strings.HasPrefix(tags[i], "customtype=") {
			ctype = true
		}
		if tags[i] == "stdtime" {
			isTime = true
		}
		if tags[i] == "stdduration" {
			isDuration = true
		}
		if tags[i] == "wktptr" {
			isWktPointer = true
		}
	}
	validateUTF8 = validateUTF8 && proto3
	if !proto3 && !pointer && !slice {
		nozero = false
	}
	if ctype {
		if reflect.PtrTo(t).Implements(customType) {
			if slice {
				return makeMessageRefSliceMarshaler(getMarshalInfo(t))
			}
			if pointer {
				return makeCustomPtrMarshaler(getMarshalInfo(t))
			}
			return makeCustomMarshaler(getMarshalInfo(t))
		} else {
			panic(fmt.Sprintf("custom type: type: %v, does not implement the proto.custom interface", t))
		}
	}
	if isTime {
		if pointer {
			if slice {
				return makeTimePtrSliceMarshaler(getMarshalInfo(t))
			}
			return makeTimePtrMarshaler(getMarshalInfo(t))
		}
		if slice {
			return makeTimeSliceMarshaler(getMarshalInfo(t))
		}
		return makeTimeMarshaler(getMarshalInfo(t))
	}
	if isDuration {
		if pointer {
			if slice {
				return makeDurationPtrSliceMarshaler(getMarshalInfo(t))
			}
			return makeDurationPtrMarshaler(getMarshalInfo(t))
		}
		if slice {
			return makeDurationSliceMarshaler(getMarshalInfo(t))
		}
		return makeDurationMarshaler(getMarshalInfo(t))
	}
	if isWktPointer {
		switch t.Kind() {
		case reflect.Float64:
			if pointer {
				if slice {
					return makeStdDoubleValuePtrSliceMarshaler(getMarshalInfo(t))
				}
				return makeStdDoubleValuePtrMarshaler(getMarshalInfo(t))
			}
			if slice {
				return makeStdDoubleValueSliceMarshaler(getMarshalInfo(t))
			}
			return makeStdDoubleValueMarshaler(getMarshalInfo(t))
		case reflect.Float32:
			if pointer {
				if slice {
					return makeStdFloatValuePtrSliceMarshaler(getMarshalInfo(t))
				}
				return makeStdFloatValuePtrMarshaler(getMarshalInfo(t))
			}
			if slice {
				return makeStdFloatValueSliceMarshaler(getMarshalInfo(t))
			}
			return makeStdFloatValueMarshaler(getMarshalInfo(t))
		case reflect.Int64:
			if pointer {
				if slice {
					return makeStdInt64ValuePtrSliceMarshaler(getMarshalInfo(t))
				}
				return makeStdInt64ValuePtrMarshaler(getMarshalInfo(t))
			}
			if slice {
				return makeStdInt64ValueSliceMarshaler(getMarshalInfo(t))
			}
			return makeStdInt64ValueMarshaler(getMarshalInfo(t))
		case reflect.Uint64:
			if pointer {
				if slice {
					return makeStdUInt64ValuePtrSliceMarshaler(getMarshalInfo(t))
				}
				return makeStdUInt64ValuePtrMarshaler(getMarshalInfo(t))
			}
			if slice {
				return makeStdUInt64ValueSliceMarshaler(getMarshalInfo(t))
			}
			return makeStdUInt64ValueMarshaler(getMarshalInfo(t))
		case reflect.Int32:
			if pointer {
				if slice {
					return makeStdInt32ValuePtrSliceMarshaler(getMarshalInfo(t))
				}
				return makeStdInt32ValuePtrMarshaler(getMarshalInfo(t))
			}
			if slice {
				return makeStdInt32ValueSliceMarshaler(getMarshalInfo(t))
			}
			return makeStdInt32ValueMarshaler(getMarshalInfo(t))
		case reflect.Uint32:
			if pointer {
				if slice {
					return makeStdUInt32ValuePtrSliceMarshaler(getMarshalInfo(t))
				}
				return makeStdUInt32ValuePtrMarshaler(getMarshalInfo(t))
			}
			if slice {
				return makeStdUInt32ValueSliceMarshaler(getMarshalInfo(t))
			}
			return makeStdUInt32ValueMarshaler(getMarshalInfo(t))
		case reflect.Bool:
			if pointer {
				if slice {
					return makeStdBoolValuePtrSliceMarshaler(getMarshalInfo(t))
				}
				return makeStdBoolValuePtrMarshaler(getMarshalInfo(t))
			}
			if slice {
				return makeStdBoolValueSliceMarshaler(getMarshalInfo(t))
			}
			return makeStdBoolValueMarshaler(getMarshalInfo(t))
		case reflect.String:
			if pointer {
				if slice {
					return makeStdStringValuePtrSliceMarshaler(getMarshalInfo(t))
				}
				return makeStdStringValuePtrMarshaler(getMarshalInfo(t))
			}
			if slice {
				return makeStdStringValueSliceMarshaler(getMarshalInfo(t))
			}
			return makeStdStringValueMarshaler(getMarshalInfo(t))
		case uint8SliceType:
			if pointer {
				if slice {
					return makeStdBytesValuePtrSliceMarshaler(getMarshalInfo(t))
				}
				return makeStdBytesValuePtrMarshaler(getMarshalInfo(t))
			}
			if slice {
				return makeStdBytesValueSliceMarshaler(getMarshalInfo(t))
			}
			return makeStdBytesValueMarshaler(getMarshalInfo(t))
		default:
			panic(fmt.Sprintf("unknown wktpointer type %#v", t))
		}
	}
	switch t.Kind() {
	case reflect.Bool:
		if pointer {
			return sizeBoolPtr, appendBoolPtr
		}
		if slice {
			if packed {
				return sizeBoolPackedSlice, appendBoolPackedSlice
			}
			return sizeBoolSlice, appendBoolSlice
		}
		if nozero {
			return sizeBoolValueNoZero, appendBoolValueNoZero
		}
		return sizeBoolValue, appendBoolValue
	case reflect.Uint32:
		switch encoding {
		case "fixed32":
			if pointer {
				return sizeFixed32Ptr, appendFixed32Ptr
			}
			if slice {
				if packed {
					return sizeFixed32PackedSlice, appendFixed32PackedSlice
				}
				return sizeFixed32Slice, appendFixed32Slice
			}
			if nozero {
				return sizeFixed32ValueNoZero, appendFixed32ValueNoZero
			}
			return sizeFixed32Value, appendFixed32Value
		case "varint":
			if pointer {
				return sizeVarint32Ptr, appendVarint32Ptr
			}
			if slice {
				if packed {
					return sizeVarint32PackedSlice, appendVarint32PackedSlice
				}
				return sizeVarint32Slice, appendVarint32Slice
			}
			if nozero {
				return sizeVarint32ValueNoZero, appendVarint32ValueNoZero
			}
			return sizeVarint32Value, appendVarint32Value
		}
	case reflect.Int32:
		switch encoding {
		case "fixed32":
			if pointer {
				return sizeFixedS32Ptr, appendFixedS32Ptr
			}
			if slice {
				if packed {
					return sizeFixedS32PackedSlice, appendFixedS32PackedSlice
				}
				return sizeFixedS32Slice, appendFixedS32Slice
			}
			if nozero {
				return sizeFixedS32ValueNoZero, appendFixedS32ValueNoZero
			}
			return sizeFixedS32Value, appendFixedS32Value
		case "varint":
			if pointer {
				return sizeVarintS32Ptr, appendVarintS32Ptr
			}
			if slice {
				if packed {
					return sizeVarintS32PackedSlice, appendVarintS32PackedSlice
				}
				return sizeVarintS32Slice, appendVarintS32Slice
			}
			if nozero {
				return sizeVarintS32ValueNoZero, appendVarintS32ValueNoZero
			}
			return sizeVarintS32Value, appendVarintS32Value
		case "zigzag32":
			if pointer {
				return sizeZigzag32Ptr, appendZigzag32Ptr
			}
			if slice {
				if packed {
					return sizeZigzag32PackedSlice, appendZigzag32PackedSlice
				}
				return sizeZigzag32Slice, appendZigzag32Slice
			}
			if nozero {
				return sizeZigzag32ValueNoZero, appendZigzag32ValueNoZero
			}
			return sizeZigzag32Value, appendZigzag32Value
		}
	case reflect.Uint64:
		switch encoding {
		case "fixed64":
			if pointer {
				return sizeFixed64Ptr, appendFixed64Ptr
			}
			if slice {
				if packed {
					return sizeFixed64PackedSlice, appendFixed64PackedSlice
				}
				return sizeFixed64Slice, appendFixed64Slice
			}
			if nozero {
				return sizeFixed64ValueNoZero, appendFixed64ValueNoZero
			}
			return sizeFixed64Value, appendFixed64Value
		case "varint":
			if pointer {
				return sizeVarint64Ptr, appendVarint64Ptr
			}
			if slice {
				if packed {
					return sizeVarint64PackedSlice, appendVarint64PackedSlice
				}
				return sizeVarint64Slice, appendVarint64Slice
			}
			if nozero {
				return sizeVarint64ValueNoZero, appendVarint64ValueNoZero
			}
			return sizeVarint64Value, appendVarint64Value
		}
	case reflect.Int64:
		switch encoding {
		case "fixed64":
			if pointer {
				return sizeFixedS64Ptr, appendFixedS64Ptr
			}
			if slice {
				if packed {
					return sizeFixedS64PackedSlice, appendFixedS64PackedSlice
				}
				return sizeFixedS64Slice, appendFixedS64Slice
			}
			if nozero {
				return sizeFixedS64ValueNoZero, appendFixedS64ValueNoZero
			}
			return sizeFixedS64Value, appendFixedS64Value
		case "varint":
			if pointer {
				return sizeVarintS64Ptr, appendVarintS64Ptr
			}
			if slice {
				if packed {
					return sizeVarintS64PackedSlice, appendVarintS64PackedSlice
				}
				return sizeVarintS64Slice, appendVarintS64Slice
			}
			if nozero {
				return sizeVarintS64ValueNoZero, appendVarintS64ValueNoZero
			}
			return sizeVarintS64Value, appendVarintS64Value
		case "zigzag64":
			if pointer {
				return sizeZigzag64Ptr, appendZigzag64Ptr
			}
			if slice {
				if packed {
					return sizeZigzag64PackedSlice, appendZigzag64PackedSlice
				}
				return sizeZigzag64Slice, appendZigzag64Slice
			}
			if nozero {
				return sizeZigzag64ValueNoZero, appendZigzag64ValueNoZero
			}
			return sizeZigzag64Value, appendZigzag64Value
		}
	case reflect.Float32:
		if pointer {
			return sizeFloat32Ptr, appendFloat32Ptr
		}
		if slice {
			if packed {
				return sizeFloat32PackedSlice, appendFloat32PackedSlice
			}
			return sizeFloat32Slice, appendFloat32Slice
		}
		if nozero {
			return sizeFloat32ValueNoZero, appendFloat32ValueNoZero
		}
		return sizeFloat32Value, appendFloat32Value
	case reflect.Float64:
		if pointer {
			return sizeFloat64Ptr, appendFloat64Ptr
		}
		if slice {
			if packed {
				return sizeFloat64PackedSlice, appendFloat64PackedSlice
			}
			return sizeFloat64Slice, appendFloat64Slice
		}
		if nozero {
			return sizeFloat64ValueNoZero, appendFloat64ValueNoZero
		}
		return sizeFloat64Value, appendFloat64Value
	case reflect.String:
		if validateUTF8 {
			if pointer {
				return sizeStringPtr, appendUTF8StringPtr
			}
			if slice {
				return sizeStringSlice, appendUTF8StringSlice
			}
			if nozero {
				return sizeStringValueNoZero, appendUTF8StringValueNoZero
			}
			return sizeStringValue, appendUTF8StringValue
		}
		if pointer {
			return sizeStringPtr, appendStringPtr
		}
		if slice {
			return sizeStringSlice, appendStringSlice
		}
		if nozero {
			return sizeStringValueNoZero, appendStringValueNoZero
		}
		return sizeStringValue, appendStringValue
	case reflect.Slice:
		if slice {
			return sizeBytesSlice, appendBytesSlice
		}
		if oneof {
			return sizeBytesOneof, appendBytesOneof
		}
		if proto3 {
			return sizeBytes3, appendBytes3
		}
		return sizeBytes, appendBytes
	case reflect.Struct:
		switch encoding {
		case "group":
			if slice {
				return makeGroupSliceMarshaler(getMarshalInfo(t))
			}
			return makeGroupMarshaler(getMarshalInfo(t))
		case "bytes":
			if pointer {
				if slice {
					return makeMessageSliceMarshaler(getMarshalInfo(t))
				}
				return makeMessageMarshaler(getMarshalInfo(t))
			} else {
				if slice {
					return makeMessageRefSliceMarshaler(getMarshalInfo(t))
				}
				return makeMessageRefMarshaler(getMarshalInfo(t))
			}
		}
	}
	panic(fmt.Sprintf("unknown or mismatched type: type: %v, wire type: %v", t, encoding))
}
typeMarshaler returns the sizer and marshaler of a given field.
t is the type of the field.
tags is the generated "protobuf" tag of the field.
If nozero is true, zero value is not marshaled to the wire.
If oneof is true, it is a oneof field.
package proto
import (
	"errors"
	"fmt"
	"math"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"unicode/utf8"
)
type sizer func(pointer, int) int
type marshaler func(b []byte, ptr pointer, wiretag uint64, deterministic bool) ([]byte, error)
type marshalInfo struct {
	typ          reflect.Type
	fields       []*marshalFieldInfo
	unrecognized field                       
	extensions   field                       
	v1extensions field                       
	sizecache    field                       
	initialized  int32                       
	messageset   bool                        
	hasmarshaler bool                        
	sync.RWMutex                             
	extElems     map[int32]*marshalElemInfo  
	hassizer      bool  
	hasprotosizer bool  
	bytesExtensions field  
}
type marshalFieldInfo struct {
	field      field
	wiretag    uint64  
	tagsize    int     
	sizer      sizer
	marshaler  marshaler
	isPointer  bool
	required   bool                               
	name       string                             
	oneofElems map[reflect.Type]*marshalElemInfo  
}
type marshalElemInfo struct {
	wiretag   uint64  
	tagsize   int     
	sizer     sizer
	marshaler marshaler
	isptr     bool  
}
var (
	marshalInfoMap  = map[reflect.Type]*marshalInfo{}
	marshalInfoLock sync.Mutex
	uint8SliceType = reflect.TypeOf(([]uint8)(nil)).Kind()
)
func getMarshalInfo(t reflect.Type) *marshalInfo {
	marshalInfoLock.Lock()
	u, ok := marshalInfoMap[t]
	if !ok {
		u = &marshalInfo{typ: t}
		marshalInfoMap[t] = u
	}
	marshalInfoLock.Unlock()
	return u
}
func (a *InternalMessageInfo) Size(msg Message) int {
	u := getMessageMarshalInfo(msg, a)
	ptr := toPointer(&msg)
	if ptr.isNil() {
		return 0
	}
	return u.size(ptr)
}
func (a *InternalMessageInfo) Marshal(b []byte, msg Message, deterministic bool) ([]byte, error) {
	u := getMessageMarshalInfo(msg, a)
	ptr := toPointer(&msg)
	if ptr.isNil() {
		return b, ErrNil
	}
	return u.marshal(b, ptr, deterministic)
}
func getMessageMarshalInfo(msg interface{}, a *InternalMessageInfo) *marshalInfo {
	u := atomicLoadMarshalInfo(&a.marshal)
	if u == nil {
		t := reflect.ValueOf(msg).Type()
		if t.Kind() != reflect.Ptr {
			panic(fmt.Sprintf("cannot handle non-pointer message type %v", t))
		}
		u = getMarshalInfo(t.Elem())
		atomicStoreMarshalInfo(&a.marshal, u)
	}
	return u
}
func (u *marshalInfo) size(ptr pointer) int {
	if atomic.LoadInt32(&u.initialized) == 0 {
		u.computeMarshalInfo()
	}
	if u.hasmarshaler {
		if u.hassizer {
			s := ptr.asPointerTo(u.typ).Interface().(Sizer)
			return s.Size()
		}
		if u.hasprotosizer {
			s := ptr.asPointerTo(u.typ).Interface().(ProtoSizer)
			return s.ProtoSize()
		}
		m := ptr.asPointerTo(u.typ).Interface().(Marshaler)
		b, _ := m.Marshal()
		return len(b)
	}
	n := 0
	for _, f := range u.fields {
		if f.isPointer && ptr.offset(f.field).getPointer().isNil() {
			continue
		}
		n += f.sizer(ptr.offset(f.field), f.tagsize)
	}
	if u.extensions.IsValid() {
		e := ptr.offset(u.extensions).toExtensions()
		if u.messageset {
			n += u.sizeMessageSet(e)
		} else {
			n += u.sizeExtensions(e)
		}
	}
	if u.v1extensions.IsValid() {
		m := *ptr.offset(u.v1extensions).toOldExtensions()
		n += u.sizeV1Extensions(m)
	}
	if u.bytesExtensions.IsValid() {
		s := *ptr.offset(u.bytesExtensions).toBytes()
		n += len(s)
	}
	if u.unrecognized.IsValid() {
		s := *ptr.offset(u.unrecognized).toBytes()
		n += len(s)
	}
	if u.sizecache.IsValid() {
		atomic.StoreInt32(ptr.offset(u.sizecache).toInt32(), int32(n))
	}
	return n
}
func (u *marshalInfo) cachedsize(ptr pointer) int {
	if u.sizecache.IsValid() {
		return int(atomic.LoadInt32(ptr.offset(u.sizecache).toInt32()))
	}
	return u.size(ptr)
}
func (u *marshalInfo) marshal(b []byte, ptr pointer, deterministic bool) ([]byte, error) {
	if atomic.LoadInt32(&u.initialized) == 0 {
		u.computeMarshalInfo()
	}
	if u.hasmarshaler {
		m := ptr.asPointerTo(u.typ).Interface().(Marshaler)
		b1, err := m.Marshal()
		b = append(b, b1...)
		return b, err
	}
	var err, errLater error
	if u.extensions.IsValid() {
		e := ptr.offset(u.extensions).toExtensions()
		if u.messageset {
			b, err = u.appendMessageSet(b, e, deterministic)
		} else {
			b, err = u.appendExtensions(b, e, deterministic)
		}
		if err != nil {
			return b, err
		}
	}
	if u.v1extensions.IsValid() {
		m := *ptr.offset(u.v1extensions).toOldExtensions()
		b, err = u.appendV1Extensions(b, m, deterministic)
		if err != nil {
			return b, err
		}
	}
	if u.bytesExtensions.IsValid() {
		s := *ptr.offset(u.bytesExtensions).toBytes()
		b = append(b, s...)
	}
	for _, f := range u.fields {
		if f.required {
			if f.isPointer && ptr.offset(f.field).getPointer().isNil() {
				if errLater == nil {
					errLater = &RequiredNotSetError{f.name}
				}
				continue
			}
		}
		if f.isPointer && ptr.offset(f.field).getPointer().isNil() {
			continue
		}
		b, err = f.marshaler(b, ptr.offset(f.field), f.wiretag, deterministic)
		if err != nil {
			if err1, ok := err.(*RequiredNotSetError); ok {
				if errLater == nil {
					errLater = &RequiredNotSetError{f.name + "." + err1.field}
				}
				continue
			}
			if err == errRepeatedHasNil {
				err = errors.New("proto: repeated field " + f.name + " has nil element")
			}
			if err == errInvalidUTF8 {
				if errLater == nil {
					fullName := revProtoTypes[reflect.PtrTo(u.typ)] + "." + f.name
					errLater = &invalidUTF8Error{fullName}
				}
				continue
			}
			return b, err
		}
	}
	if u.unrecognized.IsValid() {
		s := *ptr.offset(u.unrecognized).toBytes()
		b = append(b, s...)
	}
	return b, errLater
}
func (u *marshalInfo) computeMarshalInfo() {
	u.Lock()
	defer u.Unlock()
	if u.initialized != 0 {  
		return
	}
	t := u.typ
	u.unrecognized = invalidField
	u.extensions = invalidField
	u.v1extensions = invalidField
	u.bytesExtensions = invalidField
	u.sizecache = invalidField
	isOneofMessage := false
	if reflect.PtrTo(t).Implements(sizerType) {
		u.hassizer = true
	}
	if reflect.PtrTo(t).Implements(protosizerType) {
		u.hasprotosizer = true
	}
	if reflect.PtrTo(t).Implements(marshalerType) {
		u.hasmarshaler = true
		atomic.StoreInt32(&u.initialized, 1)
		return
	}
	n := t.NumField()
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		if f.Tag.Get("protobuf_oneof") != "" {
			isOneofMessage = true
		}
		if !strings.HasPrefix(f.Name, "XXX_") {
			continue
		}
		switch f.Name {
		case "XXX_sizecache":
			u.sizecache = toField(&f)
		case "XXX_unrecognized":
			u.unrecognized = toField(&f)
		case "XXX_InternalExtensions":
			u.extensions = toField(&f)
			u.messageset = f.Tag.Get("protobuf_messageset") == "1"
		case "XXX_extensions":
			if f.Type.Kind() == reflect.Map {
				u.v1extensions = toField(&f)
			} else {
				u.bytesExtensions = toField(&f)
			}
		case "XXX_NoUnkeyedLiteral":
		default:
			panic("unknown XXX field: " + f.Name)
		}
		n--
	}
	var oneofImplementers []interface{}
	if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok && isOneofMessage {
		_, _, _, oneofImplementers = m.XXX_OneofFuncs()
	}
	fields := make([]marshalFieldInfo, n)  
	u.fields = make([]*marshalFieldInfo, 0, n)
	for i, j := 0, 0; i < t.NumField(); i++ {
		f := t.Field(i)
		if strings.HasPrefix(f.Name, "XXX_") {
			continue
		}
		field := &fields[j]
		j++
		field.name = f.Name
		u.fields = append(u.fields, field)
		if f.Tag.Get("protobuf_oneof") != "" {
			field.computeOneofFieldInfo(&f, oneofImplementers)
			continue
		}
		if f.Tag.Get("protobuf") == "" {
			u.fields = u.fields[:len(u.fields)-1]
			j--
			continue
		}
		field.computeMarshalFieldInfo(&f)
	}
	sort.Sort(byTag(u.fields))
	atomic.StoreInt32(&u.initialized, 1)
}
type byTag []*marshalFieldInfo
func (a byTag) Len() int           { return len(a) }
func (a byTag) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a byTag) Less(i, j int) bool { return a[i].wiretag < a[j].wiretag }
func (u *marshalInfo) getExtElemInfo(desc *ExtensionDesc) *marshalElemInfo {
	u.RLock()
	e, ok := u.extElems[desc.Field]
	u.RUnlock()
	if ok {
		return e
	}
	t := reflect.TypeOf(desc.ExtensionType)  
	tags := strings.Split(desc.Tag, ",")
	tag, err := strconv.Atoi(tags[1])
	if err != nil {
		panic("tag is not an integer")
	}
	wt := wiretype(tags[0])
	sizr, marshalr := typeMarshaler(t, tags, false, false)
	e = &marshalElemInfo{
		wiretag:   uint64(tag)<<3 | wt,
		tagsize:   SizeVarint(uint64(tag) << 3),
		sizer:     sizr,
		marshaler: marshalr,
		isptr:     t.Kind() == reflect.Ptr,
	}
	u.Lock()
	if u.extElems == nil {
		u.extElems = make(map[int32]*marshalElemInfo)
	}
	u.extElems[desc.Field] = e
	u.Unlock()
	return e
}
func (fi *marshalFieldInfo) computeMarshalFieldInfo(f *reflect.StructField) {
	tags := strings.Split(f.Tag.Get("protobuf"), ",")
	if tags[0] == "" {
		return
	}
	tag, err := strconv.Atoi(tags[1])
	if err != nil {
		panic("tag is not an integer")
	}
	wt := wiretype(tags[0])
	if tags[2] == "req" {
		fi.required = true
	}
	fi.setTag(f, tag, wt)
	fi.setMarshaler(f, tags)
}
func (fi *marshalFieldInfo) computeOneofFieldInfo(f *reflect.StructField, oneofImplementers []interface{}) {
	fi.field = toField(f)
	fi.wiretag = math.MaxInt32  
	fi.isPointer = true
	fi.sizer, fi.marshaler = makeOneOfMarshaler(fi, f)
	fi.oneofElems = make(map[reflect.Type]*marshalElemInfo)
	ityp := f.Type  
	for _, o := range oneofImplementers {
		t := reflect.TypeOf(o)
		if !t.Implements(ityp) {
			continue
		}
		sf := t.Elem().Field(0)  
		tags := strings.Split(sf.Tag.Get("protobuf"), ",")
		tag, err := strconv.Atoi(tags[1])
		if err != nil {
			panic("tag is not an integer")
		}
		wt := wiretype(tags[0])
		sizr, marshalr := typeMarshaler(sf.Type, tags, false, true)  
		fi.oneofElems[t.Elem()] = &marshalElemInfo{
			wiretag:   uint64(tag)<<3 | wt,
			tagsize:   SizeVarint(uint64(tag) << 3),
			sizer:     sizr,
			marshaler: marshalr,
		}
	}
}
type oneofMessage interface {
	XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
}
func wiretype(encoding string) uint64 {
	switch encoding {
	case "fixed32":
		return WireFixed32
	case "fixed64":
		return WireFixed64
	case "varint", "zigzag32", "zigzag64":
		return WireVarint
	case "bytes":
		return WireBytes
	case "group":
		return WireStartGroup
	}
	panic("unknown wire type " + encoding)
}
func (fi *marshalFieldInfo) setTag(f *reflect.StructField, tag int, wt uint64) {
	fi.field = toField(f)
	fi.wiretag = uint64(tag)<<3 | wt
	fi.tagsize = SizeVarint(uint64(tag) << 3)
}
func (fi *marshalFieldInfo) setMarshaler(f *reflect.StructField, tags []string) {
	switch f.Type.Kind() {
	case reflect.Map:
		fi.isPointer = true
		fi.sizer, fi.marshaler = makeMapMarshaler(f)
		return
	case reflect.Ptr, reflect.Slice:
		fi.isPointer = true
	}
	fi.sizer, fi.marshaler = typeMarshaler(f.Type, tags, true, false)
}