Browse Source

增加旧版protobuf功能,临时使用

张富强 4 months ago
parent
commit
78a64323fc
5 changed files with 1515 additions and 0 deletions
  1. 514 0
      proto.old/decode.go
  2. 576 0
      proto.old/encode.go
  3. 111 0
      proto.old/field.go
  4. 260 0
      proto.old/generate.go
  5. 54 0
      proto.old/interface.go

+ 514 - 0
proto.old/decode.go

@@ -0,0 +1,514 @@
+package yu_proto_old
+
+import (
+	"encoding"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"math"
+	"reflect"
+	"time"
+)
+
+// Constructors represents a map defining how to instantiate any interface
+// types that Decode() might encounter while reading and decoding structured
+// data. The keys are reflect.Type values denoting interface types. The
+// corresponding values are functions expected to instantiate, and initialize
+// as necessary, an appropriate concrete object type supporting that
+// interface. A caller could use this capability to support
+// dynamic instantiation of objects of the concrete type
+// appropriate for a given abstract type.
+type Constructors map[reflect.Type]func() interface{}
+
+// String returns an easy way to visualize what you have in your constructors.
+func (c *Constructors) String() string {
+	var s string
+	for k := range *c {
+		s += k.String() + "=>" + "(func() interface {})" + "\t"
+	}
+	return s
+}
+
+// Decoder is the main struct used to decode a protobuf blob.
+type decoder struct {
+	nm Constructors
+}
+
+// Decode a protocol buffer into a Go struct.
+// The caller must pass a pointer to the struct to decode into.
+//
+// Decode() currently does not explicitly check that all 'required' fields
+// are actually present in the input buffer being decoded.
+// If required fields are missing, then the corresponding fields
+// will be left unmodified, meaning they will take on
+// their default Go zero values if Decode() is passed a fresh struct.
+func Decode(buf []byte, structPtr interface{}) error {
+	return DecodeWithConstructors(buf, structPtr, nil)
+}
+
+// DecodeWithConstructors is like Decode, but you can pass a map of
+// constructors with which to instantiate interface types.
+func DecodeWithConstructors(buf []byte, structPtr interface{}, cons Constructors) (err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			switch e := r.(type) {
+			case string:
+				err = errors.New(e)
+			case error:
+				err = e
+			default:
+				err = errors.New("Failed to decode the field")
+			}
+		}
+	}()
+	if structPtr == nil {
+		return nil
+	}
+
+	if bu, ok := structPtr.(encoding.BinaryUnmarshaler); ok {
+		return bu.UnmarshalBinary(buf)
+	}
+
+	de := decoder{cons}
+	val := reflect.ValueOf(structPtr)
+	// if its NOT a pointer, it is bad return an error
+	if val.Kind() != reflect.Ptr {
+		return errors.New("Decode has been given a non pointer type")
+	}
+	return de.message(buf, val.Elem())
+}
+
+// Decode a Protocol Buffers message into a Go struct.
+// The Kind of the passed value v must be Struct.
+func (de *decoder) message(buf []byte, sval reflect.Value) error {
+	if sval.Kind() != reflect.Struct {
+		return errors.New("not a struct")
+	}
+
+	for i := 0; i < sval.NumField(); i++ {
+		switch field := sval.Field(i); field.Kind() {
+		case reflect.Interface:
+			// Interface are not reset because the decoder won't
+			// be able to instantiate it again in some scenarios.
+		default:
+			if field.CanSet() {
+				field.Set(reflect.Zero(field.Type()))
+			}
+		}
+	}
+
+	// Decode all the fields
+	fields := ProtoFields(sval.Type())
+	fieldi := 0
+	for len(buf) > 0 {
+		// Parse the key
+		key, n := binary.Uvarint(buf)
+		if n <= 0 {
+			return errors.New("bad protobuf field key")
+		}
+		buf = buf[n:]
+		wiretype := int(key & 7)
+		fieldnum := key >> 3
+
+		// Lookup the corresponding struct field.
+		// Leave field with a zero Value if fieldnum is out-of-range.
+		// In this case, as well as for blank fields,
+		// value() will just skip over and discard the field content.
+		var field reflect.Value
+		for fieldi < len(fields) && fields[fieldi].ID < int64(fieldnum) {
+			fieldi++
+		}
+
+		if fieldi < len(fields) && fields[fieldi].ID == int64(fieldnum) {
+			// For fields within embedded structs, ensure the embedded values aren't nil.
+			index := fields[fieldi].Index
+			path := make([]int, 0, len(index))
+			for _, id := range index {
+				path = append(path, id)
+				field = sval.FieldByIndex(path)
+				if field.Kind() == reflect.Ptr && field.IsNil() {
+					field.Set(reflect.New(field.Type().Elem()))
+				}
+			}
+		}
+
+		// For more debugging output, uncomment the following three lines.
+		// if fieldi < len(fields){
+		//   fmt.Printf("Decoding FieldName %+v\n", fields[fieldi].Field)
+		// }
+		// Decode the field's value
+		rem, err := de.value(wiretype, buf, field)
+		if err != nil {
+			if fieldi < len(fields) && fields[fieldi] != nil {
+				return fmt.Errorf("Error while decoding field %+v: %v", fields[fieldi].Field, err)
+			}
+
+			return err
+		}
+		buf = rem
+	}
+	return nil
+}
+
+// Pull a value from the buffer and put it into a reflective Value.
+func (de *decoder) value(wiretype int, buf []byte,
+	val reflect.Value) ([]byte, error) {
+
+	// Break out the value from the buffer based on the wire type
+	var v uint64
+	var n int
+	var vb []byte
+	switch wiretype {
+	case 0: // varint
+		v, n = binary.Uvarint(buf)
+		if n <= 0 {
+			return nil, errors.New("bad protobuf varint value")
+		}
+		buf = buf[n:]
+
+	case 5: // 32-bit
+		if len(buf) < 4 {
+			return nil, errors.New("bad protobuf 32-bit value")
+		}
+		v = uint64(buf[0]) |
+			uint64(buf[1])<<8 |
+			uint64(buf[2])<<16 |
+			uint64(buf[3])<<24
+		buf = buf[4:]
+
+	case 1: // 64-bit
+		if len(buf) < 8 {
+			return nil, errors.New("bad protobuf 64-bit value")
+		}
+		v = uint64(buf[0]) |
+			uint64(buf[1])<<8 |
+			uint64(buf[2])<<16 |
+			uint64(buf[3])<<24 |
+			uint64(buf[4])<<32 |
+			uint64(buf[5])<<40 |
+			uint64(buf[6])<<48 |
+			uint64(buf[7])<<56
+		buf = buf[8:]
+
+	case 2: // length-delimited
+		v, n = binary.Uvarint(buf)
+		if n <= 0 || v > uint64(len(buf)-n) {
+			return nil, errors.New(
+				"bad protobuf length-delimited value")
+		}
+		vb = buf[n : n+int(v) : n+int(v)]
+		buf = buf[n+int(v):]
+
+	default:
+		return nil, errors.New("unknown protobuf wire-type")
+	}
+
+	// We've gotten the value out of the buffer,
+	// now put it into the appropriate reflective Value.
+	if err := de.putvalue(wiretype, val, v, vb); err != nil {
+		return nil, err
+	}
+	return buf, nil
+}
+
+func (de *decoder) decodeSignedInt(wiretype int, v uint64) (int64, error) {
+	if wiretype == 0 { // encoded as varint
+		sv := int64(v) >> 1
+		if v&1 != 0 {
+			sv = ^sv
+		}
+		return sv, nil
+	} else if wiretype == 5 { // sfixed32
+		return int64(int32(v)), nil
+	} else if wiretype == 1 { // sfixed64
+		return int64(v), nil
+	} else {
+		return -1, errors.New("bad wiretype for sint")
+	}
+}
+
+func (de *decoder) putvalue(wiretype int, val reflect.Value,
+	v uint64, vb []byte) error {
+	// If val is not settable, it either represents an out-of-range field
+	// or an in-range but blank (padding) field in the struct.
+	// In this case, simply ignore and discard the field's content.
+	if !val.CanSet() {
+		return nil
+	}
+	switch val.Kind() {
+	case reflect.Bool:
+		if wiretype != 0 {
+			return errors.New("bad wiretype for bool")
+		}
+		if v > 1 {
+			return errors.New("invalid bool value")
+		}
+		val.SetBool(v != 0)
+
+	case reflect.Int, reflect.Int32, reflect.Int64:
+		// Signed integers may be encoded either zigzag-varint or fixed
+		// Note that protobufs don't support 8- or 16-bit ints.
+		if val.Kind() == reflect.Int && val.Type().Size() < 8 {
+			return errors.New("detected a 32bit machine, please use either int64 or int32")
+		}
+		sv, err := de.decodeSignedInt(wiretype, v)
+		if err != nil {
+			fmt.Println("Error Reflect.Int for v=", v, "wiretype=", wiretype, "for Value=", val.Type().Name())
+			return err
+		}
+		val.SetInt(sv)
+
+	case reflect.Uint, reflect.Uint32, reflect.Uint64:
+		// Varint-encoded 32-bit and 64-bit unsigned integers.
+		if val.Kind() == reflect.Uint && val.Type().Size() < 8 {
+			return errors.New("detected a 32bit machine, please use either uint64 or uint32")
+		}
+		if wiretype == 0 {
+			val.SetUint(v)
+		} else if wiretype == 5 { // ufixed32
+			val.SetUint(uint64(uint32(v)))
+		} else if wiretype == 1 { // ufixed64
+			val.SetUint(uint64(v))
+		} else {
+			return errors.New("bad wiretype for uint")
+		}
+
+	case reflect.Float32:
+		// Fixed-length 32-bit floats.
+		if wiretype != 5 {
+			return errors.New("bad wiretype for float32")
+		}
+		val.SetFloat(float64(math.Float32frombits(uint32(v))))
+
+	case reflect.Float64:
+		// Fixed-length 64-bit floats.
+		if wiretype != 1 {
+			return errors.New("bad wiretype for float64")
+		}
+		val.SetFloat(math.Float64frombits(v))
+
+	case reflect.String:
+		// Length-delimited string.
+		if wiretype != 2 {
+			return errors.New("bad wiretype for string")
+		}
+		val.SetString(string(vb))
+
+	case reflect.Struct:
+		// Embedded message
+		if val.Type() == timeType {
+			sv, err := de.decodeSignedInt(wiretype, v)
+			if err != nil {
+				return err
+			}
+			t := time.Unix(sv/int64(time.Second), sv%int64(time.Second))
+			val.Set(reflect.ValueOf(t))
+			return nil
+		} else if enc, ok := val.Addr().Interface().(encoding.BinaryUnmarshaler); ok {
+			return enc.UnmarshalBinary(vb[:])
+		}
+		if wiretype != 2 {
+			return errors.New("bad wiretype for embedded message")
+		}
+		return de.message(vb, val)
+
+	case reflect.Ptr:
+		// Optional field
+		// Instantiate pointer's element type.
+		if val.IsNil() {
+			val.Set(de.instantiate(val.Type().Elem()))
+		}
+		return de.putvalue(wiretype, val.Elem(), v, vb)
+
+	case reflect.Slice, reflect.Array:
+		// Repeated field or byte-slice
+		if wiretype != 2 {
+			return errors.New("bad wiretype for repeated field")
+		}
+		return de.slice(val, vb)
+	case reflect.Map:
+		if wiretype != 2 {
+			return errors.New("bad wiretype for repeated field")
+		}
+		if val.IsNil() {
+			// make(map[k]v):
+			val.Set(reflect.MakeMap(val.Type()))
+		}
+		return de.mapEntry(val, vb)
+	case reflect.Interface:
+		data := vb[:]
+
+		// Abstract field: instantiate via dynamic constructor.
+		if val.IsNil() {
+			id := GeneratorID{}
+			var g InterfaceGeneratorFunc
+			if len(id) < len(vb) {
+				copy(id[:], vb[:len(id)])
+				g = generators.get(id)
+			}
+
+			if g == nil {
+				// Backwards compatible usage of the default constructors
+				val.Set(de.instantiate(val.Type()))
+			} else {
+				// As pointers to interface are discouraged in Go, we use
+				// the generator only for interface types
+				data = vb[len(id):]
+				val.Set(reflect.ValueOf(g()))
+			}
+		}
+
+		// If the object support self-decoding, use that.
+		if enc, ok := val.Interface().(encoding.BinaryUnmarshaler); ok {
+			if wiretype != 2 {
+				return errors.New("bad wiretype for bytes")
+			}
+
+			return enc.UnmarshalBinary(data)
+		}
+
+		// Decode into the object the interface points to.
+		// XXX perhaps better ONLY to support self-decoding
+		// for interface fields?
+		return Decode(vb, val.Interface())
+
+	default:
+		panic("unsupported value kind " + val.Kind().String())
+	}
+	return nil
+}
+
+// Instantiate an arbitrary type, handling dynamic interface types.
+// Returns a Ptr value.
+func (de *decoder) instantiate(t reflect.Type) reflect.Value {
+
+	// If it's an interface type, lookup a dynamic constructor for it.
+	if t.Kind() == reflect.Interface {
+		newfunc, ok := de.nm[t]
+		if !ok {
+			panic("no constructor for interface " + t.String())
+		}
+		return reflect.ValueOf(newfunc())
+	}
+
+	// Otherwise, for all concrete types, just instantiate directly.
+	return reflect.New(t)
+}
+
+var sfixed32type = reflect.TypeOf(Sfixed32(0))
+var sfixed64type = reflect.TypeOf(Sfixed64(0))
+var ufixed32type = reflect.TypeOf(Ufixed32(0))
+var ufixed64type = reflect.TypeOf(Ufixed64(0))
+
+// Handle decoding of slices
+func (de *decoder) slice(slval reflect.Value, vb []byte) error {
+	// Find the element type, and create a temporary instance of it.
+	eltype := slval.Type().Elem()
+	val := reflect.New(eltype).Elem()
+
+	// Decide on the wiretype to use for decoding.
+	var wiretype int
+	switch eltype.Kind() {
+	case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Int,
+		reflect.Uint32, reflect.Uint64, reflect.Uint:
+		if (eltype.Kind() == reflect.Int || eltype.Kind() == reflect.Uint) && eltype.Size() < 8 {
+			return errors.New("detected a 32bit machine, please either use (u)int64 or (u)int32")
+		}
+		switch eltype {
+
+		case sfixed32type:
+			wiretype = 5 // Packed 32-bit representation
+		case sfixed64type:
+			wiretype = 1 // Packed 64-bit representation
+		case ufixed32type:
+			wiretype = 5 // Packed 32-bit representation
+		case ufixed64type:
+			wiretype = 1 // Packed 64-bit representation
+		default:
+			wiretype = 0 // Packed varint representation
+		}
+
+	case reflect.Float32:
+		wiretype = 5 // Packed 32-bit representation
+
+	case reflect.Float64:
+		wiretype = 1 // Packed 64-bit representation
+
+	case reflect.Uint8: // Unpacked byte-slice
+		if slval.Kind() == reflect.Array {
+			if slval.Len() != len(vb) {
+				return errors.New("array length and buffer length differ")
+			}
+			for i := 0; i < slval.Len(); i++ {
+				// no SetByte method in reflect so has to pass down by uint64
+				slval.Index(i).SetUint(uint64(vb[i]))
+			}
+		} else {
+			slval.SetBytes(vb)
+		}
+		return nil
+
+	default: // Other unpacked repeated types
+		// Just unpack and append one value from vb.
+		if err := de.putvalue(2, val, 0, vb); err != nil {
+			return err
+		}
+		if slval.Kind() != reflect.Slice {
+			return errors.New("append to non-slice")
+		}
+		slval.Set(reflect.Append(slval, val))
+		return nil
+	}
+
+	// Decode packed values from the buffer and append them to the slice.
+	for len(vb) > 0 {
+		rem, err := de.value(wiretype, vb, val)
+		if err != nil {
+			return err
+		}
+		slval.Set(reflect.Append(slval, val))
+		vb = rem
+	}
+	return nil
+}
+
+// Handles the entry k,v of a map[K]V
+func (de *decoder) mapEntry(slval reflect.Value, vb []byte) error {
+	mKey := reflect.New(slval.Type().Key())
+	mVal := reflect.New(slval.Type().Elem())
+	k := mKey.Elem()
+	v := mVal.Elem()
+	key, n := binary.Uvarint(vb)
+	if n <= 0 {
+		return errors.New("bad protobuf field key")
+	}
+	buf := vb[n:]
+	wiretype := int(key & 7)
+
+	var err error
+	buf, err = de.value(wiretype, buf, k)
+	if err != nil {
+		return err
+	}
+	for len(buf) > 0 { // for repeated values (slices etc)
+		key, n = binary.Uvarint(buf)
+		if n <= 0 {
+			return errors.New("bad protobuf field key")
+		}
+		buf = buf[n:]
+		wiretype = int(key & 7)
+		buf, err = de.value(wiretype, buf, v)
+		if err != nil {
+			return err
+		}
+	}
+
+	if !k.IsValid() || !v.IsValid() {
+		// We did not decode the key or the value in the map entry.
+		// Either way, it's an invalid map entry.
+		return errors.New("proto: bad map data: missing key/val")
+	}
+	slval.SetMapIndex(k, v)
+
+	return nil
+}

+ 576 - 0
proto.old/encode.go

@@ -0,0 +1,576 @@
+package yu_proto_old
+
+import (
+	"bytes"
+	"encoding"
+	"encoding/binary"
+	"fmt"
+	"math"
+	"reflect"
+	"time"
+)
+
+// Ufixed32 Message fields declared to have exactly this type
+// will be transmitted as fixed-size 32-bit unsigned integers.
+type Ufixed32 uint32
+
+// Ufixed64 Message fields declared to have exactly this type
+// will be transmitted as fixed-size 64-bit unsigned integers.
+type Ufixed64 uint64
+
+// Sfixed32 Message fields declared to have exactly this type
+// will be transmitted as fixed-size 32-bit signed integers.
+type Sfixed32 int32
+
+// Sfixed64 Message fields declared to have exactly this type
+// will be transmitted as fixed-size 64-bit signed integers.
+type Sfixed64 int64
+
+// Enum Protobufs enums are transmitted as unsigned varints;
+// using this type alias is optional but recommended
+// to ensure they get the correct type.
+type Enum uint32
+
+type encoder struct {
+	bytes.Buffer
+}
+
+// Encode a Go struct into protocol buffer format.
+// The caller must pass a pointer to the struct to encode.
+func Encode(structPtr interface{}) (bytes []byte) {
+	defer func() {
+		if e := recover(); e != nil {
+			bytes = nil
+		}
+	}()
+
+	if structPtr == nil {
+		return
+	}
+
+	if bu, ok := structPtr.(encoding.BinaryMarshaler); ok {
+		bytes, _ = bu.MarshalBinary()
+		return
+	}
+
+	en := encoder{}
+	val := reflect.ValueOf(structPtr)
+	if val.Kind() != reflect.Ptr {
+		return nil
+	}
+	en.message(val.Elem())
+	return en.Bytes()
+}
+
+/*
+func Encode(structPtr interface{}) (bytes []byte, err error) {
+	defer func() {
+		if e := recover(); e != nil {
+			err = fmt.Errorf("%v", e)
+			bytes = nil
+		}
+	}()
+	if structPtr == nil {
+		return nil, nil
+	}
+
+	if bu, ok := structPtr.(encoding.BinaryMarshaler); ok {
+		return bu.MarshalBinary()
+	}
+
+	en := encoder{}
+	val := reflect.ValueOf(structPtr)
+	if val.Kind() != reflect.Ptr {
+		return nil, errors.New("encode takes a pointer to struct")
+	}
+	en.message(val.Elem())
+	return en.Bytes(), nil
+}
+*/
+
+func (en *encoder) message(sval reflect.Value) {
+	var index *ProtoField
+	defer func() {
+		if r := recover(); r != nil {
+			if index != nil {
+				panic(fmt.Sprintf("%s (field %s)", r, index.Field.Name))
+			} else {
+				panic(r)
+			}
+		}
+	}()
+	// Encode all fields in-order
+	protoFields := ProtoFields(sval.Type())
+	if len(protoFields) == 0 {
+		return
+	}
+	noPublicFields := true
+	for _, index = range protoFields {
+		field := sval.FieldByIndex(index.Index)
+		key := uint64(index.ID) << 3
+		if field.CanSet() { // Skip blank/padding fields
+			en.value(key, field, index.Prefix)
+			noPublicFields = false
+		}
+	}
+	if noPublicFields {
+		panic("struct has no serializable fields")
+	}
+}
+
+var timeType = reflect.TypeOf(time.Time{})
+var durationType = reflect.TypeOf(time.Duration(0))
+
+func (en *encoder) value(key uint64, val reflect.Value, prefix TagPrefix) {
+
+	// Non-reflectively handle some of the fixed types
+	switch v := val.Interface().(type) {
+	case bool:
+		en.uvarint(key | 0)
+		vi := uint64(0)
+		if v {
+			vi = 1
+		}
+		en.uvarint(vi)
+		return
+
+	case int:
+		en.uvarint(key | 0)
+		en.svarint(int64(v))
+		return
+
+	case int32:
+		en.uvarint(key | 0)
+		en.svarint(int64(v))
+		return
+
+	case time.Time: // Encode time.Time as sfixed64
+		t := v.UnixNano()
+		en.uvarint(key | 1)
+		en.u64(uint64(t))
+		return
+
+	case int64:
+		en.uvarint(key | 0)
+		en.svarint(v)
+		return
+
+	case uint32:
+		en.uvarint(key | 0)
+		en.uvarint(uint64(v))
+		return
+
+	case uint64:
+		en.uvarint(key | 0)
+		en.uvarint(v)
+		return
+
+	case Sfixed32:
+		en.uvarint(key | 5)
+		en.u32(uint32(v))
+		return
+
+	case Sfixed64:
+		en.uvarint(key | 1)
+		en.u64(uint64(v))
+		return
+
+	case Ufixed32:
+		en.uvarint(key | 5)
+		en.u32(uint32(v))
+		return
+
+	case Ufixed64:
+		en.uvarint(key | 1)
+		en.u64(uint64(v))
+		return
+
+	case float32:
+		en.uvarint(key | 5)
+		en.u32(math.Float32bits(v))
+		return
+
+	case float64:
+		en.uvarint(key | 1)
+		en.u64(math.Float64bits(v))
+		return
+
+	case string:
+		en.uvarint(key | 2)
+		b := []byte(v)
+		en.uvarint(uint64(len(b)))
+		en.Write(b)
+		return
+	}
+
+	// Handle pointer or interface values (possibly within slices).
+	// Note that this switch has to handle all the cases,
+	// because custom type aliases will fail the above typeswitch.
+	switch val.Kind() {
+	case reflect.Bool:
+		en.uvarint(key | 0)
+		v := uint64(0)
+		if val.Bool() {
+			v = 1
+		}
+		en.uvarint(v)
+
+	case reflect.Int, reflect.Int32, reflect.Int64:
+		// Varint-encoded 32-bit and 64-bit signed integers.
+		// Note that protobufs don't support 8- or 16-bit ints.
+		en.uvarint(key | 0)
+		en.svarint(val.Int())
+
+	case reflect.Uint32, reflect.Uint64:
+		// Varint-encoded 32-bit and 64-bit unsigned integers.
+		en.uvarint(key | 0)
+		en.uvarint(val.Uint())
+
+	case reflect.Float32:
+		// Fixed-length 32-bit floats.
+		en.uvarint(key | 5)
+		en.u32(math.Float32bits(float32(val.Float())))
+
+	case reflect.Float64:
+		// Fixed-length 64-bit floats.
+		en.uvarint(key | 1)
+		en.u64(math.Float64bits(val.Float()))
+
+	case reflect.String:
+		// Length-delimited string.
+		en.uvarint(key | 2)
+		b := []byte(val.String())
+		en.uvarint(uint64(len(b)))
+		en.Write(b)
+
+	case reflect.Struct:
+		var b []byte
+		if enc, ok := val.Interface().(encoding.BinaryMarshaler); ok {
+			en.uvarint(key | 2)
+			var err error
+			b, err = enc.MarshalBinary()
+			if err != nil {
+				panic(err.Error())
+			}
+		} else {
+			// Embedded messages.
+			en.uvarint(key | 2)
+			emb := encoder{}
+			emb.message(val)
+			b = emb.Bytes()
+		}
+		en.uvarint(uint64(len(b)))
+		en.Write(b)
+	case reflect.Slice, reflect.Array:
+		// Length-delimited slices or byte-vectors.
+		en.slice(key, val)
+		return
+
+	case reflect.Ptr:
+		// Optional field: encode only if pointer is non-nil.
+		if val.IsNil() {
+			if prefix == TagRequired {
+				panic("required field is nil")
+			}
+			return
+		}
+		en.value(key, val.Elem(), prefix)
+
+	case reflect.Interface:
+		// Abstract interface field.
+		if val.IsNil() {
+			return
+		}
+
+		// If the object support self-encoding, use that.
+		if enc, ok := val.Interface().(encoding.BinaryMarshaler); ok {
+			en.uvarint(key | 2)
+			bytes, err := enc.MarshalBinary()
+			if err != nil {
+				panic(err.Error())
+			}
+
+			size := len(bytes)
+			var id GeneratorID
+			im, ok := val.Interface().(InterfaceMarshaler)
+			if ok {
+				id = im.MarshalID()
+
+				g := generators.get(id)
+				ok = g != nil
+				if ok {
+					// add the length of the type tag
+					size += len(id)
+				}
+			}
+
+			en.uvarint(uint64(size))
+			if ok {
+				// Only write the tag if a generator exists
+				en.Write(id[:])
+			}
+			en.Write(bytes)
+			return
+		}
+
+		// Encode from the object the interface points to.
+		en.value(key, val.Elem(), prefix)
+
+	case reflect.Map:
+		en.handleMap(key, val, prefix)
+		return
+
+	default:
+		panic(fmt.Sprintf("unsupported field Kind %d", val.Kind()))
+	}
+}
+
+func (en *encoder) slice(key uint64, slval reflect.Value) {
+
+	// First handle common cases with a direct typeswitch
+	sllen := slval.Len()
+	packed := encoder{}
+	switch slt := slval.Interface().(type) {
+	case []bool:
+		for i := 0; i < sllen; i++ {
+			v := uint64(0)
+			if slt[i] {
+				v = 1
+			}
+			packed.uvarint(v)
+		}
+
+	case []int32:
+		for i := 0; i < sllen; i++ {
+			packed.svarint(int64(slt[i]))
+		}
+
+	case []int64:
+		for i := 0; i < sllen; i++ {
+			packed.svarint(slt[i])
+		}
+
+	case []uint32:
+		for i := 0; i < sllen; i++ {
+			packed.uvarint(uint64(slt[i]))
+		}
+
+	case []uint64:
+		for i := 0; i < sllen; i++ {
+			packed.uvarint(slt[i])
+		}
+
+	case []Sfixed32:
+		for i := 0; i < sllen; i++ {
+			packed.u32(uint32(slt[i]))
+		}
+
+	case []Sfixed64:
+		for i := 0; i < sllen; i++ {
+			packed.u64(uint64(slt[i]))
+		}
+
+	case []Ufixed32:
+		for i := 0; i < sllen; i++ {
+			packed.u32(uint32(slt[i]))
+		}
+
+	case []Ufixed64:
+		for i := 0; i < sllen; i++ {
+			packed.u64(uint64(slt[i]))
+		}
+
+	case []float32:
+		for i := 0; i < sllen; i++ {
+			packed.u32(math.Float32bits(slt[i]))
+		}
+
+	case []float64:
+		for i := 0; i < sllen; i++ {
+			packed.u64(math.Float64bits(slt[i]))
+		}
+
+	case []byte: // Write the whole byte-slice as one key,value pair
+		en.uvarint(key | 2)
+		en.uvarint(uint64(sllen))
+		en.Write(slt)
+		return
+
+	case []string:
+		for i := 0; i < sllen; i++ {
+			subVal := slval.Index(i)
+			subStr := subVal.Interface().(string)
+			subSlice := []byte(subStr)
+			en.uvarint(key | 2)
+			en.uvarint(uint64(len(subSlice)))
+			en.Write(subSlice)
+		}
+		return
+	default: // We'll need to use the reflective path
+		en.sliceReflect(key, slval)
+		return
+	}
+
+	// Encode packed representation key/value pair
+	en.uvarint(key | 2)
+	b := packed.Bytes()
+	en.uvarint(uint64(len(b)))
+	en.Write(b)
+}
+
+// Handle the encoding of an arbritary map[K]V
+func (en *encoder) handleMap(key uint64, mpval reflect.Value, prefix TagPrefix) {
+	/*
+		A map defined as
+			map<key_type, value_type> map_field = N;
+		is encoded in the same way as
+			message MapFieldEntry {
+				key_type key = 1;
+				value_type value = 2;
+			}
+			repeated MapFieldEntry map_field = N;
+	*/
+
+	for _, mkey := range mpval.MapKeys() {
+		mval := mpval.MapIndex(mkey)
+
+		// illegal map entry values
+		// - nil message pointers.
+		switch kind := mval.Kind(); kind {
+		case reflect.Ptr:
+			if mval.IsNil() {
+				panic("proto: map has nil element")
+			}
+		case reflect.Slice, reflect.Array:
+			if mval.Type().Elem().Kind() != reflect.Uint8 {
+				panic("protobuf: map only support []byte or string as repeated value")
+			}
+		}
+
+		packed := encoder{}
+		packed.value(1<<3, mkey, prefix)
+		packed.value(2<<3, mval, prefix)
+
+		en.uvarint(key | 2)
+		b := packed.Bytes()
+		en.uvarint((uint64(len(b))))
+		en.Write(b)
+	}
+}
+
+var bytesType = reflect.TypeOf([]byte{})
+
+func (en *encoder) sliceReflect(key uint64, slval reflect.Value) {
+	kind := slval.Kind()
+	if kind != reflect.Slice && kind != reflect.Array {
+		panic("no slice passed")
+	}
+	sllen := slval.Len()
+	slelt := slval.Type().Elem()
+	packed := encoder{}
+	switch slelt.Kind() {
+	case reflect.Bool:
+		for i := 0; i < sllen; i++ {
+			v := uint64(0)
+			if slval.Index(i).Bool() {
+				v = 1
+			}
+			packed.uvarint(v)
+		}
+
+	case reflect.Int, reflect.Int32, reflect.Int64:
+		for i := 0; i < sllen; i++ {
+			packed.svarint(slval.Index(i).Int())
+		}
+
+	case reflect.Uint32, reflect.Uint64:
+		for i := 0; i < sllen; i++ {
+			packed.uvarint(slval.Index(i).Uint())
+		}
+
+	case reflect.Float32:
+		for i := 0; i < sllen; i++ {
+			packed.u32(math.Float32bits(
+				float32(slval.Index(i).Float())))
+		}
+
+	case reflect.Float64:
+		for i := 0; i < sllen; i++ {
+			packed.u64(math.Float64bits(slval.Index(i).Float()))
+		}
+
+	case reflect.Uint8: // Write the byte-slice as one key,value pair
+		en.uvarint(key | 2)
+		en.uvarint(uint64(sllen))
+		var b []byte
+		if slval.Kind() == reflect.Array {
+			if slval.CanAddr() {
+				sliceVal := slval.Slice(0, sllen)
+				b = sliceVal.Convert(bytesType).Interface().([]byte)
+			} else {
+				sliceVal := reflect.MakeSlice(bytesType, sllen, sllen)
+				reflect.Copy(sliceVal, slval)
+				b = sliceVal.Interface().([]byte)
+			}
+		} else {
+			b = slval.Convert(bytesType).Interface().([]byte)
+		}
+		en.Write(b)
+		return
+
+	default: // Write each element as a separate key,value pair
+		t := slval.Type().Elem()
+		if t.Kind() == reflect.Slice || t.Kind() == reflect.Array {
+			subSlice := t.Elem()
+			if subSlice.Kind() != reflect.Uint8 {
+				panic("protobuf: no support for 2-dimensional array except for [][]byte")
+			}
+		}
+		for i := 0; i < sllen; i++ {
+			en.value(key, slval.Index(i), TagNone)
+		}
+		return
+	}
+
+	// Encode packed representation key/value pair
+	en.uvarint(key | 2)
+	b := packed.Bytes()
+	en.uvarint(uint64(len(b)))
+	en.Write(b)
+}
+
+func (en *encoder) uvarint(v uint64) {
+	var b [binary.MaxVarintLen64]byte
+	n := binary.PutUvarint(b[:], v)
+	en.Write(b[:n])
+}
+
+func (en *encoder) svarint(v int64) {
+	if v >= 0 {
+		en.uvarint(uint64(v) << 1)
+	} else {
+		en.uvarint(^uint64(v << 1))
+	}
+}
+
+func (en *encoder) u32(v uint32) {
+	var b [4]byte
+	b[0] = byte(v)
+	b[1] = byte(v >> 8)
+	b[2] = byte(v >> 16)
+	b[3] = byte(v >> 24)
+	en.Write(b[:])
+}
+
+func (en *encoder) u64(v uint64) {
+	var b [8]byte
+	b[0] = byte(v)
+	b[1] = byte(v >> 8)
+	b[2] = byte(v >> 16)
+	b[3] = byte(v >> 24)
+	b[4] = byte(v >> 32)
+	b[5] = byte(v >> 40)
+	b[6] = byte(v >> 48)
+	b[7] = byte(v >> 56)
+	en.Write(b[:])
+}

+ 111 - 0
proto.old/field.go

@@ -0,0 +1,111 @@
+package yu_proto_old
+
+import (
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+type TagPrefix int
+
+// Possible tag options.
+const (
+	TagNone TagPrefix = iota
+	TagOptional
+	TagRequired
+)
+
+func ParseTag(field reflect.StructField) (id int, opt TagPrefix, name string) {
+	tag := field.Tag.Get("protobuf")
+	if tag == "" {
+		return
+	}
+	parts := strings.Split(tag, ",")
+	for _, part := range parts {
+		if part == "opt" {
+			opt = TagOptional
+		} else if part == "req" {
+			opt = TagRequired
+		} else {
+			i, err := strconv.Atoi(part)
+			if err != nil {
+				name = part
+			} else {
+				id = int(i)
+			}
+		}
+	}
+	return
+}
+
+// ProtoField contains cached reflected metadata for struct fields.
+type ProtoField struct {
+	ID     int64
+	Prefix TagPrefix
+	Name   string // If non-empty, tag-defined field name.
+	Index  []int
+	Field  reflect.StructField
+}
+
+func (p *ProtoField) Required() bool {
+	return p.Prefix == TagRequired || p.Field.Type.Kind() != reflect.Ptr
+}
+
+var cache = map[reflect.Type][]*ProtoField{}
+var cacheLock sync.Mutex
+
+func ProtoFields(t reflect.Type) []*ProtoField {
+	cacheLock.Lock()
+	idx, ok := cache[t]
+	cacheLock.Unlock()
+	if ok {
+		return idx
+	}
+	id := 0
+	idx = innerFieldIndexes(&id, t)
+	seen := map[int64]struct{}{}
+	for _, i := range idx {
+		if _, ok := seen[i.ID]; ok {
+			panic(fmt.Sprintf("protobuf ID %d reused in %s.%s", i.ID, t.PkgPath(), t.Name()))
+		}
+		seen[i.ID] = struct{}{}
+	}
+	cacheLock.Lock()
+	defer cacheLock.Unlock()
+	cache[t] = idx
+	return idx
+}
+
+func innerFieldIndexes(id *int, v reflect.Type) []*ProtoField {
+	if v.Kind() == reflect.Ptr {
+		return innerFieldIndexes(id, v.Elem())
+	}
+	out := []*ProtoField{}
+	for i := 0; i < v.NumField(); i++ {
+		f := v.Field(i)
+		*id++
+		tid, prefix, name := ParseTag(f)
+		if tid != 0 {
+			*id = tid
+		}
+		if f.Anonymous {
+			*id--
+			for _, inner := range innerFieldIndexes(id, f.Type) {
+				inner.Index = append([]int{i}, inner.Index...)
+				out = append(out, inner)
+			}
+		} else {
+			out = append(out, &ProtoField{
+				ID:     int64(*id),
+				Prefix: prefix,
+				Name:   name,
+				Index:  []int{i},
+				Field:  f,
+			})
+		}
+	}
+	return out
+
+}

+ 260 - 0
proto.old/generate.go

@@ -0,0 +1,260 @@
+package yu_proto_old
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"reflect"
+	"regexp"
+	"sort"
+	"strings"
+	"text/template"
+)
+
+const protoTemplate = `[[range $name, $values := .Enums]]
+enum [[$name|$.Renamer.TypeName]] {[[range $values]]
+  [[.Name|$.Renamer.ConstName]] = [[.Value]];[[end]]
+}
+
+[[end]][[range .Types]]
+message [[.Name|$.Renamer.TypeName]] {[[range .|Fields]]
+  [[.|TypeName]] [[.|$.Renamer.FieldName]] = [[.ID]][[.|Options]];[[end]]
+}
+[[end]]
+`
+
+var splitName = regexp.MustCompile(`((?:ID)|(?:[A-Z][a-z_0-9]+)|([\w\d]+))`)
+
+func typeIndirect(t reflect.Type) reflect.Type {
+	for t.Kind() == reflect.Ptr {
+		t = t.Elem()
+	}
+	return t
+}
+
+func typeName(f ProtoField, enums enumTypeMap, renamer GeneratorNamer) (s string) {
+	defer func() {
+		if e := recover(); e != nil {
+			s = ""
+			panic(e.(string))
+		}
+	}()
+	t := f.Field.Type
+	if t.Kind() == reflect.Slice {
+		if t.Elem().Kind() == reflect.Uint8 {
+			return fieldPrefix(f, TagNone) + "bytes"
+		}
+		return "repeated " + innerTypeName(typeIndirect(t.Elem()), enums, renamer)
+	}
+	if t.Kind() == reflect.Ptr {
+		return fieldPrefix(f, TagOptional) + innerTypeName(t.Elem(), enums, renamer)
+	}
+	return fieldPrefix(f, TagNone) + innerTypeName(t, enums, renamer)
+}
+
+func fieldPrefix(f ProtoField, def TagPrefix) string {
+	opt := def
+	if def == TagNone {
+		opt = f.Prefix
+	}
+	switch opt {
+	case TagOptional:
+		return "optional "
+	case TagRequired:
+		return "required "
+	default:
+		if f.Field.Type.Kind() == reflect.Ptr {
+			return "optional "
+		}
+		return "required "
+	}
+}
+
+func innerTypeName(t reflect.Type, enums enumTypeMap, renamer GeneratorNamer) string {
+	if (t.Kind() == reflect.Slice || t.Kind() == reflect.Array) && t.Elem().Kind() == reflect.Uint8 {
+		return "bytes"
+	}
+	if t.PkgPath() == "time" {
+		if t.Name() == "Time" {
+			return "sfixed64"
+		}
+		if t.Name() == "Duration" {
+			return "sint64"
+		}
+	}
+	switch t.Name() {
+	case "Ufixed32":
+		return "fixed32"
+	case "Ufixed64":
+		return "ufixed64"
+	case "Sfixed32":
+		return "sfixed32"
+	case "Sfixed64":
+		return "sfixed64"
+	}
+
+	if _, ok := enums[t.Name()]; ok {
+		return renamer.TypeName(t.Name())
+	}
+
+	switch t.Kind() {
+	case reflect.Float64:
+		return "double"
+	case reflect.Float32:
+		return "float"
+	case reflect.Int32:
+		return "sint32"
+	case reflect.Int, reflect.Int64:
+		return "sint64"
+	case reflect.Bool:
+		return "bool"
+	case reflect.Uint32:
+		return "uint32"
+	case reflect.Uint, reflect.Uint64:
+		return "uint64"
+	case reflect.String:
+		return "string"
+	case reflect.Struct:
+		return t.Name()
+	case reflect.Map:
+		// we have to do this again (otherwise we'll end up with an empty name for the value):
+		var valTypeName string
+		valType := t.Elem()
+		if valType.Kind() == reflect.Slice {
+			if valType.Elem().Kind() == reflect.Uint8 {
+				valTypeName = "bytes"
+			} else {
+				valTypeName = innerTypeName(typeIndirect(valType.Elem()), enums, renamer)
+			}
+		} else if valType.Kind() == reflect.Ptr {
+			valTypeName = innerTypeName(valType.Elem(), enums, renamer)
+		} else {
+			// here we can just use the value's type:
+			valTypeName = innerTypeName(valType, enums, renamer)
+		}
+		return fmt.Sprintf("map<%s, %s>", innerTypeName(t.Key(), enums, renamer), valTypeName)
+	default:
+		panic("unsupported type " + t.Name())
+	}
+}
+
+func options(f ProtoField) string {
+	if f.Field.Type.Kind() == reflect.Slice {
+		switch f.Field.Type.Elem().Kind() {
+		case reflect.Bool,
+			reflect.Int32, reflect.Int64,
+			reflect.Uint32, reflect.Uint64,
+			reflect.Float32, reflect.Float64:
+			return " [packed=true]"
+		}
+	}
+	return ""
+}
+
+type GeneratorNamer interface {
+	FieldName(ProtoField) string
+	TypeName(name string) string
+	ConstName(name string) string
+}
+
+// DefaultGeneratorNamer renames symbols when mapping from Go to .proto files.
+//
+// The rules are:
+// - Field names are mapped from SomeFieldName to some_field_name.
+// - Type names are not modified.
+// - Constants are mapped form SomeConstantName to SOME_CONSTANT_NAME.
+type DefaultGeneratorNamer struct{}
+
+func (d *DefaultGeneratorNamer) FieldName(f ProtoField) string {
+	if f.Name != "" {
+		return f.Name
+	}
+	parts := splitName.FindAllString(f.Field.Name, -1)
+	for i := range parts {
+		parts[i] = strings.ToLower(parts[i])
+	}
+	return strings.Join(parts, "_")
+}
+
+func (d *DefaultGeneratorNamer) TypeName(name string) string {
+	return name
+}
+
+func (d *DefaultGeneratorNamer) ConstName(name string) string {
+	parts := splitName.FindAllString(name, -1)
+	for i := range parts {
+		parts[i] = strings.ToUpper(parts[i])
+	}
+	return strings.Join(parts, "_")
+}
+
+type reflectedTypes []reflect.Type
+
+func (r reflectedTypes) Len() int           { return len(r) }
+func (r reflectedTypes) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
+func (r reflectedTypes) Less(i, j int) bool { return r[i].Name() < r[j].Name() }
+
+type EnumMap map[string]interface{}
+
+type enumValue struct {
+	Name  string
+	Value Enum
+}
+
+type enumValues []enumValue
+
+func (e enumValues) Len() int           { return len(e) }
+func (e enumValues) Swap(i, j int)      { e[i], e[j] = e[j], e[i] }
+func (e enumValues) Less(i, j int) bool { return e[i].Value < e[j].Value }
+
+type enumTypeMap map[string]enumValues
+
+// GenerateProtobufDefinition generates a .proto file from a list of structs via reflection.
+// fieldNamer is a function that maps ProtoField types to generated protobuf field names.
+func GenerateProtobufDefinition(w io.Writer, types []interface{}, enumMap EnumMap, renamer GeneratorNamer) (err error) {
+	defer func() {
+		if e := recover(); e != nil {
+			err = errors.New(e.(string))
+		}
+	}()
+	enums := enumTypeMap{}
+	for name, value := range enumMap {
+		v := reflect.ValueOf(value)
+		t := v.Type()
+		if t.Kind() != reflect.Uint32 {
+			return fmt.Errorf("enum type aliases must be uint32")
+		}
+		if t.Name() == "uint32" {
+			return fmt.Errorf("enum value must be a type alias, but got uint32")
+		}
+		enums[t.Name()] = append(enums[t.Name()], enumValue{name, Enum(v.Uint())})
+	}
+	for _, values := range enums {
+		sort.Sort(values)
+	}
+	rt := reflectedTypes{}
+	for _, t := range types {
+		typ := reflect.Indirect(reflect.ValueOf(t)).Type()
+		if typ.Kind() != reflect.Struct {
+			continue
+		}
+		rt = append(rt, typ)
+	}
+	sort.Sort(rt)
+	if renamer == nil {
+		renamer = &DefaultGeneratorNamer{}
+	}
+	t := template.Must(template.New("protobuf").Funcs(template.FuncMap{
+		"Fields":   ProtoFields,
+		"TypeName": func(f ProtoField) string { return typeName(f, enums, renamer) },
+		"Options":  options,
+	}).Delims("[[", "]]").Parse(protoTemplate))
+	return t.Execute(w, map[string]interface{}{
+		"Renamer": renamer,
+		"Enums":   enums,
+		"Types":   rt,
+		"Ptr":     reflect.Ptr,
+		"Slice":   reflect.Slice,
+		"Map":     reflect.Map,
+	})
+}

+ 54 - 0
proto.old/interface.go

@@ -0,0 +1,54 @@
+package yu_proto_old
+
+import (
+	"encoding"
+)
+
+var generators = newInterfaceRegistry()
+
+// InterfaceMarshaler is used to differentiate implementations of an
+// interface when encoding/decoding
+type InterfaceMarshaler interface {
+	encoding.BinaryMarshaler
+	MarshalID() [8]byte
+}
+
+// InterfaceGeneratorFunc generates an instance of the implementation
+// of an interface
+type InterfaceGeneratorFunc func() interface{}
+
+// GeneratorID is the key used to map the generator functions
+type GeneratorID [8]byte
+
+type generatorRegistry struct {
+	generators map[GeneratorID]InterfaceGeneratorFunc
+}
+
+func newInterfaceRegistry() *generatorRegistry {
+	return &generatorRegistry{
+		generators: make(map[GeneratorID]InterfaceGeneratorFunc),
+	}
+}
+
+// register gets the type tag and map it to the generator function
+func (ir *generatorRegistry) register(g InterfaceGeneratorFunc) {
+	val, ok := g().(InterfaceMarshaler)
+	if !ok {
+		panic("Implementation of the interface must fulfilled InterfaceMarshaler")
+	}
+	key := val.MarshalID()
+
+	ir.generators[key] = g
+}
+
+// get returns the generator associated with the tag
+func (ir *generatorRegistry) get(key GeneratorID) InterfaceGeneratorFunc {
+	g, _ := ir.generators[key]
+	return g
+}
+
+// RegisterInterface registers the generator to be used to decode
+// the type generated by the function
+func RegisterInterface(f InterfaceGeneratorFunc) {
+	generators.register(f)
+}