Browse Source

internal/impl: support packed extensions

Change-Id: I5a9e22f1c98f5db9caae1681775017da5aa67394
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/185541
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Damien Neil 6 years ago
parent
commit
7492a09da9

+ 47 - 1
internal/cmd/generate-types/impl.go

@@ -365,13 +365,59 @@ func consume{{.Name}}SliceIface(b []byte, ival interface{}, _ wire.Number, wtyp
 	return ival, n, nil
 }
 
-
 var coder{{.Name}}SliceIface = ifaceCoderFuncs{
 	size:      size{{.Name}}SliceIface,
 	marshal:   append{{.Name}}SliceIface,
 	unmarshal: consume{{.Name}}SliceIface,
 }
 
+{{if or (eq .WireType "Varint") (eq .WireType "Fixed32") (eq .WireType "Fixed64")}}
+// size{{.Name}}PackedSliceIface returns the size of wire encoding a []{{.GoType}} value as a packed repeated {{.Name}}.
+func size{{.Name}}PackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]{{.GoType}})
+	if len(s) == 0 {
+		return 0
+	}
+	{{if .WireType.ConstSize -}}
+	n := len(s) * {{template "Size" .}}
+	{{- else -}}
+	n := 0
+	for _, v := range s {
+		n += {{template "Size" .}}
+	}
+	{{- end}}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// append{{.Name}}PackedSliceIface encodes a []{{.GoType}} value as a packed repeated {{.Name}}.
+func append{{.Name}}PackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]{{.GoType}})
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	{{if .WireType.ConstSize -}}
+	n := len(s) * {{template "Size" .}}
+	{{- else -}}
+	n := 0
+	for _, v := range s {
+		n += {{template "Size" .}}
+	}
+	{{- end}}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		{{template "Append" .}}
+	}
+	return b, nil
+}
+
+var coder{{.Name}}PackedSliceIface = ifaceCoderFuncs{
+	size:      size{{.Name}}PackedSliceIface,
+	marshal:   append{{.Name}}PackedSliceIface,
+	unmarshal: consume{{.Name}}SliceIface,
+}
+{{end}}
+
 {{end -}}
 {{end -}}
 

+ 6 - 1
internal/impl/codec_extension.go

@@ -29,7 +29,12 @@ func (mi *MessageInfo) extensionFieldInfo(xt pref.ExtensionType) *extensionField
 		return e
 	}
 
-	wiretag := wire.EncodeTag(xt.Number(), wireTypes[xt.Kind()])
+	var wiretag uint64
+	if !xt.IsPacked() {
+		wiretag = wire.EncodeTag(xt.Number(), wireTypes[xt.Kind()])
+	} else {
+		wiretag = wire.EncodeTag(xt.Number(), wire.BytesType)
+	}
 	e = &extensionFieldInfo{
 		wiretag: wiretag,
 		tagsize: wire.SizeVarint(wiretag),

+ 43 - 0
internal/impl/codec_field.go

@@ -698,6 +698,49 @@ var coderEnumSliceIface = ifaceCoderFuncs{
 	unmarshal: consumeEnumSliceIface,
 }
 
+func sizeEnumPackedSliceIface(ival interface{}, tagsize int, opts marshalOptions) (size int) {
+	return sizeEnumPackedSliceReflect(reflect.ValueOf(ival).Elem(), tagsize, opts)
+}
+
+func sizeEnumPackedSliceReflect(s reflect.Value, tagsize int, _ marshalOptions) (size int) {
+	llen := s.Len()
+	if llen == 0 {
+		return 0
+	}
+	n := 0
+	for i := 0; i < llen; i++ {
+		n += wire.SizeVarint(uint64(s.Index(i).Int()))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+func appendEnumPackedSliceIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	return appendEnumPackedSliceReflect(b, reflect.ValueOf(ival).Elem(), wiretag, opts)
+}
+
+func appendEnumPackedSliceReflect(b []byte, s reflect.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	llen := s.Len()
+	if llen == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for i := 0; i < llen; i++ {
+		n += wire.SizeVarint(uint64(s.Index(i).Int()))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for i := 0; i < llen; i++ {
+		b = wire.AppendVarint(b, uint64(s.Index(i).Int()))
+	}
+	return b, nil
+}
+
+var coderEnumPackedSliceIface = ifaceCoderFuncs{
+	size:      sizeEnumPackedSliceIface,
+	marshal:   appendEnumPackedSliceIface,
+	unmarshal: consumeEnumSliceIface,
+}
+
 // Strings with UTF8 validation.
 
 func appendStringValidateUTF8(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {

+ 445 - 0
internal/impl/codec_gen.go

@@ -294,6 +294,43 @@ var coderBoolSliceIface = ifaceCoderFuncs{
 	unmarshal: consumeBoolSliceIface,
 }
 
+// sizeBoolPackedSliceIface returns the size of wire encoding a []bool value as a packed repeated Bool.
+func sizeBoolPackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]bool)
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeBool(v))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendBoolPackedSliceIface encodes a []bool value as a packed repeated Bool.
+func appendBoolPackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]bool)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeBool(v))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, wire.EncodeBool(v))
+	}
+	return b, nil
+}
+
+var coderBoolPackedSliceIface = ifaceCoderFuncs{
+	size:      sizeBoolPackedSliceIface,
+	marshal:   appendBoolPackedSliceIface,
+	unmarshal: consumeBoolSliceIface,
+}
+
 // sizeInt32 returns the size of wire encoding a int32 pointer as a Int32.
 func sizeInt32(p pointer, tagsize int, _ marshalOptions) (size int) {
 	v := *p.Int32()
@@ -575,6 +612,43 @@ var coderInt32SliceIface = ifaceCoderFuncs{
 	unmarshal: consumeInt32SliceIface,
 }
 
+// sizeInt32PackedSliceIface returns the size of wire encoding a []int32 value as a packed repeated Int32.
+func sizeInt32PackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int32)
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendInt32PackedSliceIface encodes a []int32 value as a packed repeated Int32.
+func appendInt32PackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int32)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderInt32PackedSliceIface = ifaceCoderFuncs{
+	size:      sizeInt32PackedSliceIface,
+	marshal:   appendInt32PackedSliceIface,
+	unmarshal: consumeInt32SliceIface,
+}
+
 // sizeSint32 returns the size of wire encoding a int32 pointer as a Sint32.
 func sizeSint32(p pointer, tagsize int, _ marshalOptions) (size int) {
 	v := *p.Int32()
@@ -856,6 +930,43 @@ var coderSint32SliceIface = ifaceCoderFuncs{
 	unmarshal: consumeSint32SliceIface,
 }
 
+// sizeSint32PackedSliceIface returns the size of wire encoding a []int32 value as a packed repeated Sint32.
+func sizeSint32PackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int32)
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeZigZag(int64(v)))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendSint32PackedSliceIface encodes a []int32 value as a packed repeated Sint32.
+func appendSint32PackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int32)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeZigZag(int64(v)))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, wire.EncodeZigZag(int64(v)))
+	}
+	return b, nil
+}
+
+var coderSint32PackedSliceIface = ifaceCoderFuncs{
+	size:      sizeSint32PackedSliceIface,
+	marshal:   appendSint32PackedSliceIface,
+	unmarshal: consumeSint32SliceIface,
+}
+
 // sizeUint32 returns the size of wire encoding a uint32 pointer as a Uint32.
 func sizeUint32(p pointer, tagsize int, _ marshalOptions) (size int) {
 	v := *p.Uint32()
@@ -1137,6 +1248,43 @@ var coderUint32SliceIface = ifaceCoderFuncs{
 	unmarshal: consumeUint32SliceIface,
 }
 
+// sizeUint32PackedSliceIface returns the size of wire encoding a []uint32 value as a packed repeated Uint32.
+func sizeUint32PackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]uint32)
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendUint32PackedSliceIface encodes a []uint32 value as a packed repeated Uint32.
+func appendUint32PackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]uint32)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderUint32PackedSliceIface = ifaceCoderFuncs{
+	size:      sizeUint32PackedSliceIface,
+	marshal:   appendUint32PackedSliceIface,
+	unmarshal: consumeUint32SliceIface,
+}
+
 // sizeInt64 returns the size of wire encoding a int64 pointer as a Int64.
 func sizeInt64(p pointer, tagsize int, _ marshalOptions) (size int) {
 	v := *p.Int64()
@@ -1418,6 +1566,43 @@ var coderInt64SliceIface = ifaceCoderFuncs{
 	unmarshal: consumeInt64SliceIface,
 }
 
+// sizeInt64PackedSliceIface returns the size of wire encoding a []int64 value as a packed repeated Int64.
+func sizeInt64PackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int64)
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendInt64PackedSliceIface encodes a []int64 value as a packed repeated Int64.
+func appendInt64PackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int64)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderInt64PackedSliceIface = ifaceCoderFuncs{
+	size:      sizeInt64PackedSliceIface,
+	marshal:   appendInt64PackedSliceIface,
+	unmarshal: consumeInt64SliceIface,
+}
+
 // sizeSint64 returns the size of wire encoding a int64 pointer as a Sint64.
 func sizeSint64(p pointer, tagsize int, _ marshalOptions) (size int) {
 	v := *p.Int64()
@@ -1699,6 +1884,43 @@ var coderSint64SliceIface = ifaceCoderFuncs{
 	unmarshal: consumeSint64SliceIface,
 }
 
+// sizeSint64PackedSliceIface returns the size of wire encoding a []int64 value as a packed repeated Sint64.
+func sizeSint64PackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int64)
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeZigZag(v))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendSint64PackedSliceIface encodes a []int64 value as a packed repeated Sint64.
+func appendSint64PackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int64)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeZigZag(v))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, wire.EncodeZigZag(v))
+	}
+	return b, nil
+}
+
+var coderSint64PackedSliceIface = ifaceCoderFuncs{
+	size:      sizeSint64PackedSliceIface,
+	marshal:   appendSint64PackedSliceIface,
+	unmarshal: consumeSint64SliceIface,
+}
+
 // sizeUint64 returns the size of wire encoding a uint64 pointer as a Uint64.
 func sizeUint64(p pointer, tagsize int, _ marshalOptions) (size int) {
 	v := *p.Uint64()
@@ -1980,6 +2202,43 @@ var coderUint64SliceIface = ifaceCoderFuncs{
 	unmarshal: consumeUint64SliceIface,
 }
 
+// sizeUint64PackedSliceIface returns the size of wire encoding a []uint64 value as a packed repeated Uint64.
+func sizeUint64PackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]uint64)
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(v)
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendUint64PackedSliceIface encodes a []uint64 value as a packed repeated Uint64.
+func appendUint64PackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]uint64)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(v)
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, v)
+	}
+	return b, nil
+}
+
+var coderUint64PackedSliceIface = ifaceCoderFuncs{
+	size:      sizeUint64PackedSliceIface,
+	marshal:   appendUint64PackedSliceIface,
+	unmarshal: consumeUint64SliceIface,
+}
+
 // sizeSfixed32 returns the size of wire encoding a int32 pointer as a Sfixed32.
 func sizeSfixed32(p pointer, tagsize int, _ marshalOptions) (size int) {
 
@@ -2249,6 +2508,37 @@ var coderSfixed32SliceIface = ifaceCoderFuncs{
 	unmarshal: consumeSfixed32SliceIface,
 }
 
+// sizeSfixed32PackedSliceIface returns the size of wire encoding a []int32 value as a packed repeated Sfixed32.
+func sizeSfixed32PackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int32)
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed32()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendSfixed32PackedSliceIface encodes a []int32 value as a packed repeated Sfixed32.
+func appendSfixed32PackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int32)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed32()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed32(b, uint32(v))
+	}
+	return b, nil
+}
+
+var coderSfixed32PackedSliceIface = ifaceCoderFuncs{
+	size:      sizeSfixed32PackedSliceIface,
+	marshal:   appendSfixed32PackedSliceIface,
+	unmarshal: consumeSfixed32SliceIface,
+}
+
 // sizeFixed32 returns the size of wire encoding a uint32 pointer as a Fixed32.
 func sizeFixed32(p pointer, tagsize int, _ marshalOptions) (size int) {
 
@@ -2518,6 +2808,37 @@ var coderFixed32SliceIface = ifaceCoderFuncs{
 	unmarshal: consumeFixed32SliceIface,
 }
 
+// sizeFixed32PackedSliceIface returns the size of wire encoding a []uint32 value as a packed repeated Fixed32.
+func sizeFixed32PackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]uint32)
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed32()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendFixed32PackedSliceIface encodes a []uint32 value as a packed repeated Fixed32.
+func appendFixed32PackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]uint32)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed32()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed32(b, v)
+	}
+	return b, nil
+}
+
+var coderFixed32PackedSliceIface = ifaceCoderFuncs{
+	size:      sizeFixed32PackedSliceIface,
+	marshal:   appendFixed32PackedSliceIface,
+	unmarshal: consumeFixed32SliceIface,
+}
+
 // sizeFloat returns the size of wire encoding a float32 pointer as a Float.
 func sizeFloat(p pointer, tagsize int, _ marshalOptions) (size int) {
 
@@ -2787,6 +3108,37 @@ var coderFloatSliceIface = ifaceCoderFuncs{
 	unmarshal: consumeFloatSliceIface,
 }
 
+// sizeFloatPackedSliceIface returns the size of wire encoding a []float32 value as a packed repeated Float.
+func sizeFloatPackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]float32)
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed32()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendFloatPackedSliceIface encodes a []float32 value as a packed repeated Float.
+func appendFloatPackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]float32)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed32()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed32(b, math.Float32bits(v))
+	}
+	return b, nil
+}
+
+var coderFloatPackedSliceIface = ifaceCoderFuncs{
+	size:      sizeFloatPackedSliceIface,
+	marshal:   appendFloatPackedSliceIface,
+	unmarshal: consumeFloatSliceIface,
+}
+
 // sizeSfixed64 returns the size of wire encoding a int64 pointer as a Sfixed64.
 func sizeSfixed64(p pointer, tagsize int, _ marshalOptions) (size int) {
 
@@ -3056,6 +3408,37 @@ var coderSfixed64SliceIface = ifaceCoderFuncs{
 	unmarshal: consumeSfixed64SliceIface,
 }
 
+// sizeSfixed64PackedSliceIface returns the size of wire encoding a []int64 value as a packed repeated Sfixed64.
+func sizeSfixed64PackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int64)
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed64()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendSfixed64PackedSliceIface encodes a []int64 value as a packed repeated Sfixed64.
+func appendSfixed64PackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int64)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed64()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed64(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderSfixed64PackedSliceIface = ifaceCoderFuncs{
+	size:      sizeSfixed64PackedSliceIface,
+	marshal:   appendSfixed64PackedSliceIface,
+	unmarshal: consumeSfixed64SliceIface,
+}
+
 // sizeFixed64 returns the size of wire encoding a uint64 pointer as a Fixed64.
 func sizeFixed64(p pointer, tagsize int, _ marshalOptions) (size int) {
 
@@ -3325,6 +3708,37 @@ var coderFixed64SliceIface = ifaceCoderFuncs{
 	unmarshal: consumeFixed64SliceIface,
 }
 
+// sizeFixed64PackedSliceIface returns the size of wire encoding a []uint64 value as a packed repeated Fixed64.
+func sizeFixed64PackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]uint64)
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed64()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendFixed64PackedSliceIface encodes a []uint64 value as a packed repeated Fixed64.
+func appendFixed64PackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]uint64)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed64()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed64(b, v)
+	}
+	return b, nil
+}
+
+var coderFixed64PackedSliceIface = ifaceCoderFuncs{
+	size:      sizeFixed64PackedSliceIface,
+	marshal:   appendFixed64PackedSliceIface,
+	unmarshal: consumeFixed64SliceIface,
+}
+
 // sizeDouble returns the size of wire encoding a float64 pointer as a Double.
 func sizeDouble(p pointer, tagsize int, _ marshalOptions) (size int) {
 
@@ -3594,6 +4008,37 @@ var coderDoubleSliceIface = ifaceCoderFuncs{
 	unmarshal: consumeDoubleSliceIface,
 }
 
+// sizeDoublePackedSliceIface returns the size of wire encoding a []float64 value as a packed repeated Double.
+func sizeDoublePackedSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]float64)
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed64()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendDoublePackedSliceIface encodes a []float64 value as a packed repeated Double.
+func appendDoublePackedSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]float64)
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed64()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed64(b, math.Float64bits(v))
+	}
+	return b, nil
+}
+
+var coderDoublePackedSliceIface = ifaceCoderFuncs{
+	size:      sizeDoublePackedSliceIface,
+	marshal:   appendDoublePackedSliceIface,
+	unmarshal: consumeDoubleSliceIface,
+}
+
 // sizeString returns the size of wire encoding a string pointer as a String.
 func sizeString(p pointer, tagsize int, _ marshalOptions) (size int) {
 	v := *p.String()

+ 3 - 26
internal/impl/codec_reflect.go

@@ -104,35 +104,12 @@ var coderEnumSlice = pointerCoderFuncs{
 	unmarshal: consumeEnumSlice,
 }
 
-func sizeEnumPackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
-	s := p.v.Elem()
-	slen := s.Len()
-	if slen == 0 {
-		return 0
-	}
-	n := 0
-	for i := 0; i < slen; i++ {
-		n += wire.SizeVarint(uint64(s.Index(i).Int()))
-	}
-	return tagsize + wire.SizeBytes(n)
+func sizeEnumPackedSlice(p pointer, tagsize int, opts marshalOptions) (size int) {
+	return sizeEnumPackedSliceReflect(p.v.Elem(), tagsize, opts)
 }
 
 func appendEnumPackedSlice(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
-	s := p.v.Elem()
-	slen := s.Len()
-	if slen == 0 {
-		return b, nil
-	}
-	b = wire.AppendVarint(b, wiretag)
-	n := 0
-	for i := 0; i < slen; i++ {
-		n += wire.SizeVarint(uint64(s.Index(i).Int()))
-	}
-	b = wire.AppendVarint(b, uint64(n))
-	for i := 0; i < slen; i++ {
-		b = wire.AppendVarint(b, uint64(s.Index(i).Int()))
-	}
-	return b, nil
+	return appendEnumPackedSliceReflect(b, p.v.Elem(), wiretag, opts)
 }
 
 var coderEnumPackedSlice = pointerCoderFuncs{

+ 62 - 0
internal/impl/codec_tables.go

@@ -499,6 +499,68 @@ func encoderFuncsForValue(fd pref.FieldDescriptor, ft reflect.Type) ifaceCoderFu
 			return coderGroupSliceIface
 		}
 	case fd.Cardinality() == pref.Repeated && fd.IsPacked():
+		if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
+			break
+		}
+		ft := ft.Elem().Elem()
+		switch fd.Kind() {
+		case pref.BoolKind:
+			if ft.Kind() == reflect.Bool {
+				return coderBoolPackedSliceIface
+			}
+		case pref.EnumKind:
+			if ft.Kind() == reflect.Int32 {
+				return coderEnumPackedSliceIface
+			}
+		case pref.Int32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderInt32PackedSliceIface
+			}
+		case pref.Sint32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSint32PackedSliceIface
+			}
+		case pref.Uint32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderUint32PackedSliceIface
+			}
+		case pref.Int64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderInt64PackedSliceIface
+			}
+		case pref.Sint64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSint64PackedSliceIface
+			}
+		case pref.Uint64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderUint64PackedSliceIface
+			}
+		case pref.Sfixed32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSfixed32PackedSliceIface
+			}
+		case pref.Fixed32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderFixed32PackedSliceIface
+			}
+		case pref.FloatKind:
+			if ft.Kind() == reflect.Float32 {
+				return coderFloatPackedSliceIface
+			}
+		case pref.Sfixed64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSfixed64PackedSliceIface
+			}
+		case pref.Fixed64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderFixed64PackedSliceIface
+			}
+		case pref.DoubleKind:
+			if ft.Kind() == reflect.Float64 {
+				return coderDoublePackedSliceIface
+			}
+		}
 	default:
 		switch fd.Kind() {
 		case pref.BoolKind:

File diff suppressed because it is too large
+ 1341 - 367
internal/testprotos/test/test.pb.go


+ 76 - 0
internal/testprotos/test/test.proto

@@ -265,6 +265,82 @@ message TestWeak {
   optional goproto.proto.test.weak.WeakImportMessage weak_message = 1 [weak=true];
 }
 
+message TestPackedTypes {
+  repeated    int32 packed_int32    =  90 [packed = true];
+  repeated    int64 packed_int64    =  91 [packed = true];
+  repeated   uint32 packed_uint32   =  92 [packed = true];
+  repeated   uint64 packed_uint64   =  93 [packed = true];
+  repeated   sint32 packed_sint32   =  94 [packed = true];
+  repeated   sint64 packed_sint64   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32 =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64 =  99 [packed = true];
+  repeated    float packed_float    = 100 [packed = true];
+  repeated   double packed_double   = 101 [packed = true];
+  repeated     bool packed_bool     = 102 [packed = true];
+  repeated ForeignEnum packed_enum  = 103 [packed = true];
+}
+
+message TestUnpackedTypes {
+  repeated    int32 unpacked_int32    =  90 [packed = false];
+  repeated    int64 unpacked_int64    =  91 [packed = false];
+  repeated   uint32 unpacked_uint32   =  92 [packed = false];
+  repeated   uint64 unpacked_uint64   =  93 [packed = false];
+  repeated   sint32 unpacked_sint32   =  94 [packed = false];
+  repeated   sint64 unpacked_sint64   =  95 [packed = false];
+  repeated  fixed32 unpacked_fixed32  =  96 [packed = false];
+  repeated  fixed64 unpacked_fixed64  =  97 [packed = false];
+  repeated sfixed32 unpacked_sfixed32 =  98 [packed = false];
+  repeated sfixed64 unpacked_sfixed64 =  99 [packed = false];
+  repeated    float unpacked_float    = 100 [packed = false];
+  repeated   double unpacked_double   = 101 [packed = false];
+  repeated     bool unpacked_bool     = 102 [packed = false];
+  repeated ForeignEnum unpacked_enum  = 103 [packed = false];
+}
+
+message TestPackedExtensions {
+  extensions 1 to max;
+}
+
+extend TestPackedExtensions {
+  repeated    int32 packed_int32_extension    =  90 [packed = true];
+  repeated    int64 packed_int64_extension    =  91 [packed = true];
+  repeated   uint32 packed_uint32_extension   =  92 [packed = true];
+  repeated   uint64 packed_uint64_extension   =  93 [packed = true];
+  repeated   sint32 packed_sint32_extension   =  94 [packed = true];
+  repeated   sint64 packed_sint64_extension   =  95 [packed = true];
+  repeated  fixed32 packed_fixed32_extension  =  96 [packed = true];
+  repeated  fixed64 packed_fixed64_extension  =  97 [packed = true];
+  repeated sfixed32 packed_sfixed32_extension =  98 [packed = true];
+  repeated sfixed64 packed_sfixed64_extension =  99 [packed = true];
+  repeated    float packed_float_extension    = 100 [packed = true];
+  repeated   double packed_double_extension   = 101 [packed = true];
+  repeated     bool packed_bool_extension     = 102 [packed = true];
+  repeated ForeignEnum packed_enum_extension  = 103 [packed = true];
+}
+
+message TestUnpackedExtensions {
+  extensions 1 to max;
+}
+
+extend TestUnpackedExtensions {
+  repeated    int32 unpacked_int32_extension    =  90 [packed = false];
+  repeated    int64 unpacked_int64_extension    =  91 [packed = false];
+  repeated   uint32 unpacked_uint32_extension   =  92 [packed = false];
+  repeated   uint64 unpacked_uint64_extension   =  93 [packed = false];
+  repeated   sint32 unpacked_sint32_extension   =  94 [packed = false];
+  repeated   sint64 unpacked_sint64_extension   =  95 [packed = false];
+  repeated  fixed32 unpacked_fixed32_extension  =  96 [packed = false];
+  repeated  fixed64 unpacked_fixed64_extension  =  97 [packed = false];
+  repeated sfixed32 unpacked_sfixed32_extension =  98 [packed = false];
+  repeated sfixed64 unpacked_sfixed64_extension =  99 [packed = false];
+  repeated    float unpacked_float_extension    = 100 [packed = false];
+  repeated   double unpacked_double_extension   = 101 [packed = false];
+  repeated     bool unpacked_bool_extension     = 102 [packed = false];
+  repeated ForeignEnum unpacked_enum_extension  = 103 [packed = false];
+}
+
 // Test that RPC services work.
 message FooRequest  {}
 message FooResponse {}

+ 86 - 0
proto/decode_test.go

@@ -508,6 +508,92 @@ var testProtos = []testProto{
 			},
 		}.Marshal(),
 	},
+	{
+		desc: "packed repeated types",
+		decodeTo: []proto.Message{&testpb.TestPackedTypes{
+			PackedInt32:    []int32{1001, 2001},
+			PackedInt64:    []int64{1002, 2002},
+			PackedUint32:   []uint32{1003, 2003},
+			PackedUint64:   []uint64{1004, 2004},
+			PackedSint32:   []int32{1005, 2005},
+			PackedSint64:   []int64{1006, 2006},
+			PackedFixed32:  []uint32{1007, 2007},
+			PackedFixed64:  []uint64{1008, 2008},
+			PackedSfixed32: []int32{1009, 2009},
+			PackedSfixed64: []int64{1010, 2010},
+			PackedFloat:    []float32{1011.5, 2011.5},
+			PackedDouble:   []float64{1012.5, 2012.5},
+			PackedBool:     []bool{true, false},
+			PackedEnum: []testpb.ForeignEnum{
+				testpb.ForeignEnum_FOREIGN_FOO,
+				testpb.ForeignEnum_FOREIGN_BAR,
+			},
+		}, build(
+			&testpb.TestPackedExtensions{},
+			extend(testpb.E_PackedInt32Extension, []int32{1001, 2001}),
+			extend(testpb.E_PackedInt64Extension, []int64{1002, 2002}),
+			extend(testpb.E_PackedUint32Extension, []uint32{1003, 2003}),
+			extend(testpb.E_PackedUint64Extension, []uint64{1004, 2004}),
+			extend(testpb.E_PackedSint32Extension, []int32{1005, 2005}),
+			extend(testpb.E_PackedSint64Extension, []int64{1006, 2006}),
+			extend(testpb.E_PackedFixed32Extension, []uint32{1007, 2007}),
+			extend(testpb.E_PackedFixed64Extension, []uint64{1008, 2008}),
+			extend(testpb.E_PackedSfixed32Extension, []int32{1009, 2009}),
+			extend(testpb.E_PackedSfixed64Extension, []int64{1010, 2010}),
+			extend(testpb.E_PackedFloatExtension, []float32{1011.5, 2011.5}),
+			extend(testpb.E_PackedDoubleExtension, []float64{1012.5, 2012.5}),
+			extend(testpb.E_PackedBoolExtension, []bool{true, false}),
+			extend(testpb.E_PackedEnumExtension, []testpb.ForeignEnum{
+				testpb.ForeignEnum_FOREIGN_FOO,
+				testpb.ForeignEnum_FOREIGN_BAR,
+			}),
+		)},
+		wire: pack.Message{
+			pack.Tag{90, pack.BytesType}, pack.LengthPrefix{
+				pack.Varint(1001), pack.Varint(2001),
+			},
+			pack.Tag{91, pack.BytesType}, pack.LengthPrefix{
+				pack.Varint(1002), pack.Varint(2002),
+			},
+			pack.Tag{92, pack.BytesType}, pack.LengthPrefix{
+				pack.Uvarint(1003), pack.Uvarint(2003),
+			},
+			pack.Tag{93, pack.BytesType}, pack.LengthPrefix{
+				pack.Uvarint(1004), pack.Uvarint(2004),
+			},
+			pack.Tag{94, pack.BytesType}, pack.LengthPrefix{
+				pack.Svarint(1005), pack.Svarint(2005),
+			},
+			pack.Tag{95, pack.BytesType}, pack.LengthPrefix{
+				pack.Svarint(1006), pack.Svarint(2006),
+			},
+			pack.Tag{96, pack.BytesType}, pack.LengthPrefix{
+				pack.Uint32(1007), pack.Uint32(2007),
+			},
+			pack.Tag{97, pack.BytesType}, pack.LengthPrefix{
+				pack.Uint64(1008), pack.Uint64(2008),
+			},
+			pack.Tag{98, pack.BytesType}, pack.LengthPrefix{
+				pack.Int32(1009), pack.Int32(2009),
+			},
+			pack.Tag{99, pack.BytesType}, pack.LengthPrefix{
+				pack.Int64(1010), pack.Int64(2010),
+			},
+			pack.Tag{100, pack.BytesType}, pack.LengthPrefix{
+				pack.Float32(1011.5), pack.Float32(2011.5),
+			},
+			pack.Tag{101, pack.BytesType}, pack.LengthPrefix{
+				pack.Float64(1012.5), pack.Float64(2012.5),
+			},
+			pack.Tag{102, pack.BytesType}, pack.LengthPrefix{
+				pack.Bool(true), pack.Bool(false),
+			},
+			pack.Tag{103, pack.BytesType}, pack.LengthPrefix{
+				pack.Varint(int(testpb.ForeignEnum_FOREIGN_FOO)),
+				pack.Varint(int(testpb.ForeignEnum_FOREIGN_BAR)),
+			},
+		}.Marshal(),
+	},
 	{
 		desc: "repeated messages",
 		decodeTo: []proto.Message{&testpb.TestAllTypes{

Some files were not shown because too many files changed in this diff