Sync from internal version:
          - packed repeated field support
          - more useful ErrRequiredNotSet
          - decoding simplification using append

R=r
CC=golang-dev
http://codereview.appspot.com/3337042
diff --git a/proto/all_test.go b/proto/all_test.go
index 03f5369..b56d9be 100644
--- a/proto/all_test.go
+++ b/proto/all_test.go
@@ -40,6 +40,8 @@
 	"bytes"
 	"fmt"
 	"os"
+	"reflect"
+	"strings"
 	"testing"
 
 	. "goprotobuf.googlecode.com/hg/proto"
@@ -427,8 +429,11 @@
 func TestRequiredBit(t *testing.T) {
 	o := old()
 	pb := new(GoTest)
-	if o.Marshal(pb) != ErrRequiredNotSet {
-		t.Errorf("did not catch missing required fields")
+	err := o.Marshal(pb)
+	if err == nil {
+		t.Error("did not catch missing required fields")
+	} else if strings.Index(err.String(), "GoTest") < 0 {
+		t.Error("wrong error type:", err)
 	}
 }
 
@@ -747,10 +752,10 @@
 			"ea0106"+"7361696c6f72"+ // field 29, encoding 2, string "sailor"
 			"ca0c03"+"626967"+ // field 201, encoding 2, string "big"
 			"ca0c04"+"6e6f7365"+ // field 201, encoding 2, string "nose"
-			"d00c40"+ // field 202, encoding 0, value 64
-			"d00c3f"+ // field 202, encoding 0, value 63
-			"d80c8001"+ // field 203, encoding 0, value 128
-			"d80c7f"+ // field 203, encoding 0, value 127
+			"d00c40"+ // field 202, encoding 0, value 32
+			"d00c3f"+ // field 202, encoding 0, value -32
+			"d80c8001"+ // field 203, encoding 0, value 64
+			"d80c7f"+ // field 203, encoding 0, value -64
 			"c00201"+ // field 40, encoding 0, value 1
 			"c80220"+ // field 41, encoding 0, value 32
 			"d00240"+ // field 42, encoding 0, value 64
@@ -776,13 +781,68 @@
 
 }
 
+// All required fields set, all packed repeated fields given two values.
+func TestEncodeDecode6(t *testing.T) {
+	pb := initGoTest(false)
+	pb.F_BoolRepeatedPacked = []bool{false, true}
+	pb.F_Int32RepeatedPacked = []int32{32, 33}
+	pb.F_Int64RepeatedPacked = []int64{64, 65}
+	pb.F_Fixed32RepeatedPacked = []uint32{3232, 3333}
+	pb.F_Fixed64RepeatedPacked = []uint64{6464, 6565}
+	pb.F_Uint32RepeatedPacked = []uint32{323232, 333333}
+	pb.F_Uint64RepeatedPacked = []uint64{646464, 656565}
+	pb.F_FloatRepeatedPacked = []float32{32., 33.}
+	pb.F_DoubleRepeatedPacked = []float64{64., 65.}
+	pb.F_Sint32RepeatedPacked = []int32{32, -32}
+	pb.F_Sint64RepeatedPacked = []int64{64, -64}
+
+	overify(t, pb,
+		"0807"+ // field 1, encoding 0, value 7
+			"220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField)
+			"5001"+ // field 10, encoding 0, value 1
+			"5803"+ // field 11, encoding 0, value 3
+			"6006"+ // field 12, encoding 0, value 6
+			"6d20000000"+ // field 13, encoding 5, value 32
+			"714000000000000000"+ // field 14, encoding 1, value 64
+			"78a019"+ // field 15, encoding 0, value 3232
+			"8001c032"+ // field 16, encoding 0, value 6464
+			"8d0100004a45"+ // field 17, encoding 5, value 3232.0
+			"9101000000000040b940"+ // field 18, encoding 1, value 6464.0
+			"9a0106"+"737472696e67"+ // field 19, encoding 2 string "string"
+			"aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes"
+			"b0063f"+ // field 102, encoding 0, 0x3f zigzag32
+			"b8067f"+ // field 103, encoding 0, 0x7f zigzag64
+			"9203020001"+ // field 50, encoding 2, 2 bytes, value 0, value 1
+			"9a03022021"+ // field 51, encoding 2, 2 bytes, value 32, value 33
+			"a203024041"+ // field 52, encoding 2, 2 bytes, value 64, value 65
+			"aa0308"+ // field 53, encoding 2, 8 bytes
+			"a00c0000050d0000"+ // value 3232, value 3333
+			"b20310"+ // field 54, encoding 2, 16 bytes
+			"4019000000000000a519000000000000"+ // value 6464, value 6565
+			"ba0306"+ // field 55, encoding 2, 6 bytes
+			"a0dd1395ac14"+ // value 323232, value 333333
+			"c20306"+ // field 56, encoding 2, 6 bytes
+			"c0ba27b58928"+ // value 646464, value 656565
+			"ca0308"+ // field 57, encoding 2, 8 bytes
+			"0000004200000442"+ // value 32.0, value 33.0
+			"d20310"+ // field 58, encoding 2, 16 bytes
+			"00000000000050400000000000405040"+ // value 64.0, value 65.0
+			"b21f02"+ // field 502, encoding 2, 2 bytes
+			"403f"+ // value 32, value -32
+			"ba1f03"+ // field 503, encoding 2, 3 bytes
+			"80017f"+ // value 64, value -64
+			"b304"+ // start group field 70 level 1
+			"ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required"
+			"b404") // end group field 70 level 1
+}
+
 // Test that we can encode empty bytes fields.
 func TestEncodeDecodeBytes1(t *testing.T) {
 	pb := initGoTest(false)
 
 	// Create our bytes
 	pb.F_BytesRequired = []byte{}
-	pb.F_BytesRepeated = [][]byte{ []byte{} }
+	pb.F_BytesRepeated = [][]byte{[]byte{}}
 	pb.F_BytesOptional = []byte{}
 
 	d, err := Marshal(pb)
@@ -812,10 +872,10 @@
 	pb := initGoTest(false)
 
 	// Create our bytes
-	pb.F_BytesRepeated = [][]byte{ nil }
+	pb.F_BytesRepeated = [][]byte{nil}
 
 	d, err := Marshal(pb)
-	if err != nil  {
+	if err != nil {
 		t.Errorf(err.String())
 	}
 
@@ -1018,6 +1078,35 @@
 	}
 }
 
+func encodeDecode(t *testing.T, in, out interface{}, msg string) {
+	buf, err := Marshal(in)
+	if err != nil {
+		t.Fatalf("failed marshaling %v: %v", msg, err)
+	}
+	if err := Unmarshal(buf, out); err != nil {
+		t.Fatalf("failed unmarshaling %v: %v", msg, err)
+	}
+}
+
+func TestPackedNonPackedDecoderSwitching(t *testing.T) {
+	np, p := new(NonPackedTest), new(PackedTest)
+
+	// non-packed -> packed
+	np.A = []int32{0, 1, 1, 2, 3, 5}
+	encodeDecode(t, np, p, "non-packed -> packed")
+	if !reflect.DeepEqual(np.A, p.B) {
+		t.Errorf("failed non-packed -> packed; np.A=%+v, p.B=%+v", np.A, p.B)
+	}
+
+	// packed -> non-packed
+	np.Reset()
+	p.B = []int32{3, 1, 4, 1, 5, 9}
+	encodeDecode(t, p, np, "packed -> non-packed")
+	if !reflect.DeepEqual(p.B, np.A) {
+		t.Errorf("failed packed -> non-packed; p.B=%+v, np.A=%+v", p.B, np.A)
+	}
+}
+
 func TestProto1RepeatedGroup(t *testing.T) {
 	pb := &MessageList{
 		Message: []*MessageList_Message{
@@ -1060,8 +1149,10 @@
 func TestRequiredFieldEnforcement(t *testing.T) {
 	pb := new(GoTestField)
 	_, err := Marshal(pb)
-	if err == nil || err != ErrRequiredNotSet {
-		t.Errorf("marshal: expected %q, got %q", ErrRequiredNotSet, err)
+	if err == nil {
+		t.Error("marshal: expected error, got nil")
+	} else if strings.Index(err.String(), "GoTestField") < 0 {
+		t.Errorf("marshal: bad error type: %v", err)
 	}
 
 	// A slightly sneaky, yet valid, proto. It encodes the same required field twice,
@@ -1069,8 +1160,10 @@
 	// field 1, encoding 2, value "hi"
 	buf := []byte("\x0A\x02hi\x0A\x02hi")
 	err = Unmarshal(buf, pb)
-	if err == nil || err != ErrRequiredNotSet {
-		t.Errorf("unmarshal: expected %q, got %q", ErrRequiredNotSet, err)
+	if err == nil {
+		t.Error("unmarshal: expected error, got nil")
+	} else if strings.Index(err.String(), "GoTestField") < 0 {
+		t.Errorf("unmarshal: bad error type: %v", err)
 	}
 }
 
diff --git a/proto/decode.go b/proto/decode.go
index 1019d2a..5423895 100644
--- a/proto/decode.go
+++ b/proto/decode.go
@@ -372,11 +372,17 @@
 			fmt.Fprintf(os.Stderr, "no protobuf decoder for %s.%s\n", t, st.Field(fieldnum).Name)
 			continue
 		}
+		dec := p.dec
 		if wire != WireStartGroup && wire != p.WireType {
-			err = ErrWrongType
-			continue
+			if wire == WireBytes && p.packedDec != nil {
+				// a packable field
+				dec = p.packedDec
+			} else {
+				err = ErrWrongType
+				continue
+			}
 		}
-		err = p.dec(o, p, base, sbase)
+		err = dec(o, p, base, sbase)
 		if err == nil && p.Required {
 			// Successfully decoded a required field.
 			if tag <= 64 {
@@ -401,7 +407,7 @@
 			return io.ErrUnexpectedEOF
 		}
 		if required > 0 {
-			return ErrRequiredNotSet
+			return &ErrRequiredNotSet{st}
 		}
 	}
 	return err
@@ -415,6 +421,17 @@
 	sp.Cap = startSize
 }
 
+// Make *pslice have base address base, length 0, and capacity max(startSize, n).
+func initSlicen(pslice unsafe.Pointer, base uintptr, n int) {
+	if n < startSize {
+		n = startSize
+	}
+	sp := (*reflect.SliceHeader)(pslice)
+	sp.Data = base
+	sp.Len = 0
+	sp.Cap = n
+}
+
 // Individual type decoders
 // For each,
 //	u is the decoded value,
@@ -483,30 +500,12 @@
 	x := (*[]uint8)(unsafe.Pointer(base + p.offset))
 
 	y := *x
-	c := cap(y)
-	if c == 0 {
+	if cap(y) == 0 {
 		initSlice(unsafe.Pointer(x), sbase+p.scratch)
 		y = *x
-		c = cap(y)
 	}
 
-	l := len(y)
-	lb := len(b)
-	if l+lb > c {
-		// incremental growth is max(len(slice)*1.5, len(slice)+len(bytes))
-		g := l * 3 / 2
-		if l+lb > g {
-			g = l + lb
-		}
-		z := make([]uint8, l, g)
-		copy(z, y)
-		y = z
-	}
-
-	y = y[0 : l+lb]
-	copy(y[l:l+lb], b)
-
-	*x = y
+	*x = append(y, b...)
 	return nil
 }
 
@@ -519,21 +518,42 @@
 	x := (*[]bool)(unsafe.Pointer(base + p.offset))
 
 	y := *x
-	c := cap(y)
-	if c == 0 {
+	if cap(y) == 0 {
 		initSlice(unsafe.Pointer(x), sbase+p.scratch)
 		y = *x
-		c = cap(y)
 	}
-	l := len(y)
-	if l >= c {
-		g := l * 3 / 2
-		z := make([]bool, l, g)
-		copy(z, y)
-		y = z
+
+	*x = append(y, u != 0)
+	return nil
+}
+
+// Decode a slice of bools ([]bool) in packed format.
+func (o *Buffer) dec_slice_packed_bool(p *Properties, base uintptr, sbase uintptr) os.Error {
+	x := (*[]bool)(unsafe.Pointer(base + p.offset))
+
+	nn, err := o.DecodeVarint()
+	if err != nil {
+		return err
 	}
-	y = y[0 : l+1]
-	y[l] = u != 0
+	nb := int(nn) // number of bytes of encoded bools
+
+	y := *x
+	if cap(y) == 0 {
+		// Packed fields are usually only encoded once,
+		// so this branch is almost always executed.
+		// The append in the loop below takes care of other cases.
+		initSlicen(unsafe.Pointer(x), sbase+p.scratch, nb)
+		y = *x
+	}
+
+	for i := 0; i < nb; i++ {
+		u, err := p.valDec(o)
+		if err != nil {
+			return err
+		}
+		y = append(y, u != 0)
+	}
+
 	*x = y
 	return nil
 }
@@ -547,21 +567,43 @@
 	x := (*[]int32)(unsafe.Pointer(base + p.offset))
 
 	y := *x
-	c := cap(y)
-	if c == 0 {
+	if cap(y) == 0 {
 		initSlice(unsafe.Pointer(x), sbase+p.scratch)
 		y = *x
-		c = cap(y)
 	}
-	l := len(y)
-	if l >= c {
-		g := l * 3 / 2
-		z := make([]int32, l, g)
-		copy(z, y)
-		y = z
+
+	*x = append(y, int32(u))
+	return nil
+}
+
+// Decode a slice of int32s ([]int32) in packed format.
+func (o *Buffer) dec_slice_packed_int32(p *Properties, base uintptr, sbase uintptr) os.Error {
+	x := (*[]int32)(unsafe.Pointer(base + p.offset))
+
+	nn, err := o.DecodeVarint()
+	if err != nil {
+		return err
 	}
-	y = y[0 : l+1]
-	y[l] = int32(u)
+	nb := int(nn) // number of bytes of encoded int32s
+
+	y := *x
+	if cap(y) == 0 {
+		// Packed fields are usually only encoded once,
+		// so this branch is almost always executed.
+		// The append in the loop below takes care of other cases.
+		initSlicen(unsafe.Pointer(x), sbase+p.scratch, nb)
+		y = *x
+	}
+
+	fin := o.index + nb
+	for o.index < fin {
+		u, err := p.valDec(o)
+		if err != nil {
+			return err
+		}
+		y = append(y, int32(u))
+	}
+
 	*x = y
 	return nil
 }
@@ -575,21 +617,43 @@
 	x := (*[]int64)(unsafe.Pointer(base + p.offset))
 
 	y := *x
-	c := cap(y)
-	if c == 0 {
+	if cap(y) == 0 {
 		initSlice(unsafe.Pointer(x), sbase+p.scratch)
 		y = *x
-		c = cap(y)
 	}
-	l := len(y)
-	if l >= c {
-		g := l * 3 / 2
-		z := make([]int64, l, g)
-		copy(z, y)
-		y = z
+
+	*x = append(y, int64(u))
+	return nil
+}
+
+// Decode a slice of int64s ([]int64) in packed format.
+func (o *Buffer) dec_slice_packed_int64(p *Properties, base uintptr, sbase uintptr) os.Error {
+	x := (*[]int64)(unsafe.Pointer(base + p.offset))
+
+	nn, err := o.DecodeVarint()
+	if err != nil {
+		return err
 	}
-	y = y[0 : l+1]
-	y[l] = int64(u)
+	nb := int(nn) // number of bytes of encoded int64s
+
+	y := *x
+	if cap(y) == 0 {
+		// Packed fields are usually only encoded once,
+		// so this branch is almost always executed.
+		// The append in the loop below takes care of other cases.
+		initSlicen(unsafe.Pointer(x), sbase+p.scratch, nb)
+		y = *x
+	}
+
+	fin := o.index + nb
+	for o.index < fin {
+		u, err := p.valDec(o)
+		if err != nil {
+			return err
+		}
+		y = append(y, int64(u))
+	}
+
 	*x = y
 	return nil
 }
@@ -603,22 +667,12 @@
 	x := (*[]string)(unsafe.Pointer(base + p.offset))
 
 	y := *x
-	c := cap(y)
-	if c == 0 {
+	if cap(y) == 0 {
 		initSlice(unsafe.Pointer(x), sbase+p.scratch)
 		y = *x
-		c = cap(y)
 	}
-	l := len(y)
-	if l >= c {
-		g := l * 3 / 2
-		z := make([]string, l, g)
-		copy(z, y)
-		y = z
-	}
-	y = y[0 : l+1]
-	y[l] = s
-	*x = y
+
+	*x = append(y, s)
 	return nil
 }
 
@@ -631,22 +685,12 @@
 	x := (*[][]byte)(unsafe.Pointer(base + p.offset))
 
 	y := *x
-	c := cap(y)
-	if c == 0 {
+	if cap(y) == 0 {
 		initSlice(unsafe.Pointer(x), sbase+p.scratch)
 		y = *x
-		c = cap(y)
 	}
-	l := len(y)
-	if l >= c {
-		g := l * 3 / 2
-		z := make([][]byte, l, g)
-		copy(z, y)
-		y = z
-	}
-	y = y[0 : l+1]
-	y[l] = b
-	*x = y
+
+	*x = append(y, b)
 	return nil
 }
 
@@ -709,28 +753,16 @@
 
 	x := (*[]*struct{})(unsafe.Pointer(base + p.offset))
 	y := *x
-	c := cap(y)
-	if c == 0 {
+	if cap(y) == 0 {
 		initSlice(unsafe.Pointer(x), sbase+p.scratch)
 		y = *x
-		c = cap(y)
 	}
 
-	l := len(y)
-	if l >= c {
-		// Create a new slice with 1.5X the capacity.
-		g := l * 3 / 2
-		z := make([]*struct{}, l, g)
-		copy(z, y)
-		y = z
-	}
-	y = y[0 : l+1]
-	*x = y
-
 	typ := p.stype.Elem().(*reflect.StructType)
 	structv := unsafe.New(typ)
 	bas := uintptr(structv)
-	y[l] = (*struct{})(structv)
+	y = append(y, (*struct{})(structv))
+	*x = y
 
 	if is_group {
 		err := o.unmarshalType(p.stype, is_group, bas)
@@ -743,7 +775,7 @@
 	}
 
 	// If the object can unmarshal itself, let it.
-	iv := unsafe.Unreflect(p.stype, unsafe.Pointer(&y[l]))
+	iv := unsafe.Unreflect(p.stype, unsafe.Pointer(&y[len(y)-1]))
 	if u, ok := iv.(Unmarshaler); ok {
 		return u.Unmarshal(raw)
 	}
diff --git a/proto/encode.go b/proto/encode.go
index 37c572c..13fd835 100644
--- a/proto/encode.go
+++ b/proto/encode.go
@@ -48,7 +48,13 @@
 // all been initialized. It is also the error returned if Unmarshal is
 // called with an encoded protocol buffer that does not include all the
 // required fields.
-var ErrRequiredNotSet = os.NewError("required fields not set")
+type ErrRequiredNotSet struct {
+	t reflect.Type
+}
+
+func (e *ErrRequiredNotSet) String() string {
+	return "required fields not set in " + e.t.String()
+}
 
 // ErrRepeatedHasNil is the error returned if Marshal is called with
 // a protocol buffer struct with a repeated field containing a nil element.
@@ -361,6 +367,24 @@
 	return nil
 }
 
+// Encode a slice of bools ([]bool) in packed format.
+func (o *Buffer) enc_slice_packed_bool(p *Properties, base uintptr) os.Error {
+	s := *(*[]uint8)(unsafe.Pointer(base + p.offset))
+	l := len(s)
+	if l == 0 {
+		return ErrNil
+	}
+	o.buf = append(o.buf, p.tagcode...)
+	o.EncodeVarint(uint64(l)) // each bool takes exactly one byte
+	for _, x := range s {
+		if x != 0 {
+			x = 1
+		}
+		p.valEnc(o, uint64(x))
+	}
+	return nil
+}
+
 // Encode a slice of bytes ([]byte).
 func (o *Buffer) enc_slice_byte(p *Properties, base uintptr) os.Error {
 	s := *(*[]uint8)(unsafe.Pointer(base + p.offset))
@@ -387,6 +411,25 @@
 	return nil
 }
 
+// Encode a slice of int32s ([]int32) in packed format.
+func (o *Buffer) enc_slice_packed_int32(p *Properties, base uintptr) os.Error {
+	s := *(*[]uint32)(unsafe.Pointer(base + p.offset))
+	l := len(s)
+	if l == 0 {
+		return ErrNil
+	}
+	// TODO: Reuse a Buffer.
+	buf := NewBuffer(nil)
+	for i := 0; i < l; i++ {
+		p.valEnc(buf, uint64(s[i]))
+	}
+
+	o.buf = append(o.buf, p.tagcode...)
+	o.EncodeVarint(uint64(len(buf.buf)))
+	o.buf = append(o.buf, buf.buf...)
+	return nil
+}
+
 // Encode a slice of int64s ([]int64).
 func (o *Buffer) enc_slice_int64(p *Properties, base uintptr) os.Error {
 	s := *(*[]uint64)(unsafe.Pointer(base + p.offset))
@@ -402,6 +445,25 @@
 	return nil
 }
 
+// Encode a slice of int64s ([]int64) in packed format.
+func (o *Buffer) enc_slice_packed_int64(p *Properties, base uintptr) os.Error {
+	s := *(*[]uint64)(unsafe.Pointer(base + p.offset))
+	l := len(s)
+	if l == 0 {
+		return ErrNil
+	}
+	// TODO: Reuse a Buffer.
+	buf := NewBuffer(nil)
+	for i := 0; i < l; i++ {
+		p.valEnc(buf, s[i])
+	}
+
+	o.buf = append(o.buf, p.tagcode...)
+	o.EncodeVarint(uint64(len(buf.buf)))
+	o.buf = append(o.buf, buf.buf...)
+	return nil
+}
+
 // Encode a slice of slice of bytes ([][]byte).
 func (o *Buffer) enc_slice_slice_byte(p *Properties, base uintptr) os.Error {
 	ss := *(*[][]uint8)(unsafe.Pointer(base + p.offset))
@@ -535,7 +597,7 @@
 	}
 	// See if we encoded all required fields.
 	if required > 0 {
-		return ErrRequiredNotSet
+		return &ErrRequiredNotSet{t}
 	}
 
 	return nil
diff --git a/proto/properties.go b/proto/properties.go
index b6e5526..4d15b28 100644
--- a/proto/properties.go
+++ b/proto/properties.go
@@ -95,6 +95,7 @@
 	Required   bool
 	Optional   bool
 	Repeated   bool
+	Packed     bool   // relevant for repeated primitives only
 	Enum       string // set for enum types only
 	Default    string // default value
 	def_uint64 uint64
@@ -111,6 +112,9 @@
 	scratch uintptr
 	sizeof  int // calculations of scratch space
 	alignof int
+
+	// If this is a packable field, this will be the decoder for the packed version of the field.
+	packedDec decoder
 }
 
 // String formats the properties in the "PB(...)" struct tag style.
@@ -127,6 +131,9 @@
 	if p.Repeated {
 		s += ",rep"
 	}
+	if p.Packed {
+		s += ",packed"
+	}
 	if p.OrigName != p.Name {
 		s += ",name=" + p.OrigName
 	}
@@ -193,6 +200,8 @@
 			p.Optional = true
 		case f == "rep":
 			p.Repeated = true
+		case f == "packed":
+			p.Packed = true
 		case len(f) >= 5 && f[0:5] == "name=":
 			p.OrigName = f[5:len(f)]
 		case len(f) >= 5 && f[0:5] == "enum=":
@@ -291,20 +300,35 @@
 			fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
 			break
 		case *reflect.BoolType:
-			p.enc = (*Buffer).enc_slice_bool
+			if p.Packed {
+				p.enc = (*Buffer).enc_slice_packed_bool
+			} else {
+				p.enc = (*Buffer).enc_slice_bool
+			}
 			p.dec = (*Buffer).dec_slice_bool
+			p.packedDec = (*Buffer).dec_slice_packed_bool
 			p.alignof = unsafe.Alignof(vbool)
 			p.sizeof = startSize * unsafe.Sizeof(vbool)
 		case *reflect.IntType, *reflect.UintType:
 			switch t2.Bits() {
 			case 32:
-				p.enc = (*Buffer).enc_slice_int32
+				if p.Packed {
+					p.enc = (*Buffer).enc_slice_packed_int32
+				} else {
+					p.enc = (*Buffer).enc_slice_int32
+				}
 				p.dec = (*Buffer).dec_slice_int32
+				p.packedDec = (*Buffer).dec_slice_packed_int32
 				p.alignof = unsafe.Alignof(vint32)
 				p.sizeof = startSize * unsafe.Sizeof(vint32)
 			case 64:
-				p.enc = (*Buffer).enc_slice_int64
+				if p.Packed {
+					p.enc = (*Buffer).enc_slice_packed_int64
+				} else {
+					p.enc = (*Buffer).enc_slice_int64
+				}
 				p.dec = (*Buffer).dec_slice_int64
+				p.packedDec = (*Buffer).dec_slice_packed_int64
 				p.alignof = unsafe.Alignof(vint64)
 				p.sizeof = startSize * unsafe.Sizeof(vint64)
 			case 8:
@@ -320,13 +344,25 @@
 		case *reflect.FloatType:
 			switch t2.Bits() {
 			case 32:
-				p.enc = (*Buffer).enc_slice_int32 // can just treat them as bits
+				// can just treat them as bits
+				if p.Packed {
+					p.enc = (*Buffer).enc_slice_packed_int32
+				} else {
+					p.enc = (*Buffer).enc_slice_int32
+				}
 				p.dec = (*Buffer).dec_slice_int32
+				p.packedDec = (*Buffer).dec_slice_packed_int32
 				p.alignof = unsafe.Alignof(vfloat32)
 				p.sizeof = startSize * unsafe.Sizeof(vfloat32)
 			case 64:
-				p.enc = (*Buffer).enc_slice_int64 // can just treat them as bits
+				// can just treat them as bits
+				if p.Packed {
+					p.enc = (*Buffer).enc_slice_packed_int64
+				} else {
+					p.enc = (*Buffer).enc_slice_int64
+				}
 				p.dec = (*Buffer).dec_slice_int64
+				p.packedDec = (*Buffer).dec_slice_packed_int64
 				p.alignof = unsafe.Alignof(vfloat64)
 				p.sizeof = startSize * unsafe.Sizeof(vfloat64)
 			default:
@@ -368,7 +404,11 @@
 	}
 
 	// precalculate tag code
-	x := p.Tag<<3 | p.WireType
+	wire := p.WireType
+	if p.Packed {
+		wire = WireBytes
+	}
+	x := p.Tag<<3 | wire
 	i := 0
 	for i = 0; x > 127; i++ {
 		p.tagbuf[i] = 0x80 | uint8(x&0x7F)
diff --git a/proto/testdata/test.pb.go b/proto/testdata/test.pb.go
index 8fe742f..a1fe1de 100644
--- a/proto/testdata/test.pb.go
+++ b/proto/testdata/test.pb.go
@@ -173,6 +173,17 @@
 	F_BytesDefaulted	[]byte	"PB(bytes,401,opt,name=F_Bytes_defaulted,def=Bignose)"
 	F_Sint32Defaulted	*int32	"PB(zigzag32,402,opt,name=F_Sint32_defaulted,def=-32)"
 	F_Sint64Defaulted	*int64	"PB(zigzag64,403,opt,name=F_Sint64_defaulted,def=-64)"
+	F_BoolRepeatedPacked	[]bool	"PB(varint,50,rep,packed,name=F_Bool_repeated_packed)"
+	F_Int32RepeatedPacked	[]int32	"PB(varint,51,rep,packed,name=F_Int32_repeated_packed)"
+	F_Int64RepeatedPacked	[]int64	"PB(varint,52,rep,packed,name=F_Int64_repeated_packed)"
+	F_Fixed32RepeatedPacked	[]uint32	"PB(fixed32,53,rep,packed,name=F_Fixed32_repeated_packed)"
+	F_Fixed64RepeatedPacked	[]uint64	"PB(fixed64,54,rep,packed,name=F_Fixed64_repeated_packed)"
+	F_Uint32RepeatedPacked	[]uint32	"PB(varint,55,rep,packed,name=F_Uint32_repeated_packed)"
+	F_Uint64RepeatedPacked	[]uint64	"PB(varint,56,rep,packed,name=F_Uint64_repeated_packed)"
+	F_FloatRepeatedPacked	[]float32	"PB(fixed32,57,rep,packed,name=F_Float_repeated_packed)"
+	F_DoubleRepeatedPacked	[]float64	"PB(fixed64,58,rep,packed,name=F_Double_repeated_packed)"
+	F_Sint32RepeatedPacked	[]int32	"PB(zigzag32,502,rep,packed,name=F_Sint32_repeated_packed)"
+	F_Sint64RepeatedPacked	[]int64	"PB(zigzag64,503,rep,packed,name=F_Sint64_repeated_packed)"
 	Requiredgroup	*GoTest_RequiredGroup	"PB(group,70,req,name=requiredgroup)"
 	Repeatedgroup	[]*GoTest_RepeatedGroup	"PB(group,80,rep,name=repeatedgroup)"
 	Optionalgroup	*GoTest_OptionalGroup	"PB(group,90,opt,name=optionalgroup)"
@@ -240,6 +251,22 @@
 	*this = GoSkipTest_SkipGroup{}
 }
 
+type NonPackedTest struct {
+	A	[]int32	"PB(varint,1,rep,name=a)"
+	XXX_unrecognized	[]byte
+}
+func (this *NonPackedTest) Reset() {
+	*this = NonPackedTest{}
+}
+
+type PackedTest struct {
+	B	[]int32	"PB(varint,1,rep,packed,name=b)"
+	XXX_unrecognized	[]byte
+}
+func (this *PackedTest) Reset() {
+	*this = PackedTest{}
+}
+
 type InnerMessage struct {
 	Host	*string	"PB(bytes,1,req,name=host)"
 	Port	*int32	"PB(varint,2,opt,name=port,def=4000)"
diff --git a/proto/testdata/test.proto b/proto/testdata/test.proto
index 474ec39..58582d6 100644
--- a/proto/testdata/test.proto
+++ b/proto/testdata/test.proto
@@ -142,6 +142,19 @@
   optional sint32 F_Sint32_defaulted = 402 [default = -32];
   optional sint64 F_Sint64_defaulted = 403 [default = -64];
 
+  // Packed repeated fields (no string or bytes).
+  repeated bool F_Bool_repeated_packed = 50 [packed=true];
+  repeated int32 F_Int32_repeated_packed = 51 [packed=true];
+  repeated int64 F_Int64_repeated_packed = 52 [packed=true];
+  repeated fixed32 F_Fixed32_repeated_packed = 53 [packed=true];
+  repeated fixed64 F_Fixed64_repeated_packed = 54 [packed=true];
+  repeated uint32 F_Uint32_repeated_packed = 55 [packed=true];
+  repeated uint64 F_Uint64_repeated_packed = 56 [packed=true];
+  repeated float F_Float_repeated_packed = 57 [packed=true];
+  repeated double F_Double_repeated_packed = 58 [packed=true];
+  repeated sint32 F_Sint32_repeated_packed = 502 [packed=true];
+  repeated sint64 F_Sint64_repeated_packed = 503 [packed=true];
+
   // Required, repeated, and optional groups.
   required group RequiredGroup = 70 {
     required string RequiredField = 71;
@@ -170,6 +183,16 @@
   }
 }
 
+// For testing packed/non-packed decoder switching.
+// A serialized instance of one should be deserializable as the other.
+message NonPackedTest {
+  repeated int32 a = 1;
+}
+
+message PackedTest {
+  repeated int32 b = 1 [packed=true];
+}
+
 // Smaller tests for ASCII formatting.
 
 message InnerMessage {