func (p *Properties) Parse(s string) {
	fields := strings.Split(s, ",")  
	if len(fields) < 2 {
		log.Printf("proto: tag has too few fields: %q", s)
		return
	}
	p.Wire = fields[0]
	switch p.Wire {
	case "varint":
		p.WireType = WireVarint
	case "fixed32":
		p.WireType = WireFixed32
	case "fixed64":
		p.WireType = WireFixed64
	case "zigzag32":
		p.WireType = WireVarint
	case "zigzag64":
		p.WireType = WireVarint
	case "bytes", "group":
		p.WireType = WireBytes
	default:
		log.Printf("proto: tag has unknown wire type: %q", s)
		return
	}
	var err error
	p.Tag, err = strconv.Atoi(fields[1])
	if err != nil {
		return
	}
outer:
	for i := 2; i < len(fields); i++ {
		f := fields[i]
		switch {
		case f == "req":
			p.Required = true
		case f == "opt":
			p.Optional = true
		case f == "rep":
			p.Repeated = true
		case f == "packed":
			p.Packed = true
		case strings.HasPrefix(f, "name="):
			p.OrigName = f[5:]
		case strings.HasPrefix(f, "json="):
			p.JSONName = f[5:]
		case strings.HasPrefix(f, "enum="):
			p.Enum = f[5:]
		case f == "proto3":
			p.proto3 = true
		case f == "oneof":
			p.oneof = true
		case strings.HasPrefix(f, "def="):
			p.HasDefault = true
			p.Default = f[4:]  
			if i+1 < len(fields) {
				p.Default += "," + strings.Join(fields[i+1:], ",")
				break outer
			}
		case strings.HasPrefix(f, "embedded="):
			p.OrigName = strings.Split(f, "=")[1]
		case strings.HasPrefix(f, "customtype="):
			p.CustomType = strings.Split(f, "=")[1]
		case strings.HasPrefix(f, "casttype="):
			p.CastType = strings.Split(f, "=")[1]
		case f == "stdtime":
			p.StdTime = true
		case f == "stdduration":
			p.StdDuration = true
		case f == "wktptr":
			p.WktPointer = true
		}
	}
}
Parse populates p by parsing a string in the protobuf struct field tag style.
package proto
import (
	"fmt"
	"log"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"sync"
)
const debug bool = false
const (
	WireVarint     = 0
	WireFixed64    = 1
	WireBytes      = 2
	WireStartGroup = 3
	WireEndGroup   = 4
	WireFixed32    = 5
)
type tagMap struct {
	fastTags []int
	slowTags map[int]int
}
const tagMapFastLimit = 1024
func (p *tagMap) get(t int) (int, bool) {
	if t > 0 && t < tagMapFastLimit {
		if t >= len(p.fastTags) {
			return 0, false
		}
		fi := p.fastTags[t]
		return fi, fi >= 0
	}
	fi, ok := p.slowTags[t]
	return fi, ok
}
func (p *tagMap) put(t int, fi int) {
	if t > 0 && t < tagMapFastLimit {
		for len(p.fastTags) < t+1 {
			p.fastTags = append(p.fastTags, -1)
		}
		p.fastTags[t] = fi
		return
	}
	if p.slowTags == nil {
		p.slowTags = make(map[int]int)
	}
	p.slowTags[t] = fi
}
type StructProperties struct {
	Prop             []*Properties   
	reqCount         int             
	decoderTags      tagMap          
	decoderOrigNames map[string]int  
	order            []int           
	OneofTypes map[string]*OneofProperties
}
type OneofProperties struct {
	Type  reflect.Type  
	Field int           
	Prop  *Properties
}
func (sp *StructProperties) Len() int { return len(sp.order) }
func (sp *StructProperties) Less(i, j int) bool {
	return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
}
func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
type Properties struct {
	Name     string  
	OrigName string  
	JSONName string  
	Wire     string
	WireType int
	Tag      int
	Required bool
	Optional bool
	Repeated bool
	Packed   bool    
	Enum     string  
	proto3   bool    
	oneof    bool    
	Default     string  
	HasDefault  bool    
	CustomType  string
	CastType    string
	StdTime     bool
	StdDuration bool
	WktPointer  bool
	stype reflect.Type       
	ctype reflect.Type       
	sprop *StructProperties  
	mtype      reflect.Type  
	MapKeyProp *Properties   
	MapValProp *Properties   
}
func (p *Properties) String() string {
	s := p.Wire
	s += ","
	s += strconv.Itoa(p.Tag)
	if p.Required {
		s += ",req"
	}
	if p.Optional {
		s += ",opt"
	}
	if p.Repeated {
		s += ",rep"
	}
	if p.Packed {
		s += ",packed"
	}
	s += ",name=" + p.OrigName
	if p.JSONName != p.OrigName {
		s += ",json=" + p.JSONName
	}
	if p.proto3 {
		s += ",proto3"
	}
	if p.oneof {
		s += ",oneof"
	}
	if len(p.Enum) > 0 {
		s += ",enum=" + p.Enum
	}
	if p.HasDefault {
		s += ",def=" + p.Default
	}
	return s
}