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)
}
setMarshaler fills up the sizer and marshaler in the info of a 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  
}
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
)
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 {
		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.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
		}
	}
	for _, f := range u.fields {
		if f.required {
			if 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.sizecache = invalidField
	if reflect.PtrTo(t).Implements(marshalerType) {
		u.hasmarshaler = true
		atomic.StoreInt32(&u.initialized, 1)
		return
	}
	var oneofImplementers []interface{}
	if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
		_, _, _, oneofImplementers = m.XXX_OneofFuncs()
	}
	n := t.NumField()
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		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":
			u.v1extensions = toField(&f)
		case "XXX_NoUnkeyedLiteral":
		default:
			panic("unknown XXX field: " + f.Name)
		}
		n--
	}
	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])
	sizer, marshaler := typeMarshaler(t, tags, false, false)
	e = &marshalElemInfo{
		wiretag:   uint64(tag)<<3 | wt,
		tagsize:   SizeVarint(uint64(tag) << 3),
		sizer:     sizer,
		marshaler: marshaler,
		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 = 1<<31 - 1  
	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])
		sizer, marshaler := typeMarshaler(sf.Type, tags, false, true)  
		fi.oneofElems[t.Elem()] = &marshalElemInfo{
			wiretag:   uint64(tag)<<3 | wt,
			tagsize:   SizeVarint(uint64(tag) << 3),
			sizer:     sizer,
			marshaler: marshaler,
		}
	}
}
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)
}