Bläddra i källkod

internal/impl: store extension values as Values

Change the storage type of ExtensionField from interface{} to
protoreflect.Value.

Replace the codec functions operating on interface{}s with ones
operating on Values.

Values are potentially more efficient, since they can represent
non-pointer types without allocation. This also reduces the number of
types used to represent field values.

Additionally, this change lays groundwork for changing the
user-visible representation of repeated extension fields from
*[]T to []T. The storage type for extension fields must support mutation
(thus *[]T currently); changing the storage type to a Value permits this
without the need to introduce yet another view on field values.

Change-Id: Ida336be14112bb940f655236eb58df21bf312525
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/192218
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Damien Neil 6 år sedan
förälder
incheckning
68b81c3117

+ 104 - 85
internal/cmd/generate-types/impl.go

@@ -39,6 +39,16 @@ wire.Size{{.WireType}}({{.FromGoType}})
 {{- end -}}
 {{- end -}}
 
+{{- define "SizeValue" -}}
+{{- if .WireType.ConstSize -}}
+wire.Size{{.WireType}}()
+{{- else if eq .WireType "Bytes" -}}
+wire.SizeBytes(len({{.FromValue}}))
+{{- else -}}
+wire.Size{{.WireType}}({{.FromValue}})
+{{- end -}}
+{{- end -}}
+
 {{- /*
   Append is a set of statements appending 'v' to 'b'.
 */ -}}
@@ -50,6 +60,14 @@ b = wire.Append{{.WireType}}(b, {{.FromGoType}})
 {{- end -}}
 {{- end -}}
 
+{{- define "AppendValue" -}}
+{{- if eq .Name "String" -}}
+b = wire.AppendString(b, {{.FromValue}})
+{{- else -}}
+b = wire.Append{{.WireType}}(b, {{.FromValue}})
+{{- end -}}
+{{- end -}}
+
 {{- define "Consume" -}}
 {{- if eq .Name "String" -}}
 wire.ConsumeString(b)
@@ -59,6 +77,7 @@ wire.Consume{{.WireType}}(b)
 {{- end -}}
 
 {{- range .}}
+
 {{- if .FromGoType }}
 // size{{.Name}} returns the size of wire encoding a {{.GoType}} pointer as a {{.Name}}.
 func size{{.Name}}(p pointer, tagsize int, _ marshalOptions) (size int) {
@@ -405,184 +424,184 @@ var coder{{.Name}}PackedSlice = pointerCoderFuncs{
 }
 {{end}}
 
-// size{{.Name}}Iface returns the size of wire encoding a {{.GoType}} value as a {{.Name}}.
-func size{{.Name}}Iface(ival interface{}, tagsize int, _ marshalOptions) int {
-	{{- if not .WireType.ConstSize}}
-	v := ival.({{.GoType}})
-	{{end -}}
-	return tagsize + {{template "Size" .}}
+{{end -}}
+
+{{- if not .NoValueCodec}}
+// size{{.Name}}Value returns the size of wire encoding a {{.GoType}} value as a {{.Name}}.
+func size{{.Name}}Value(v protoreflect.Value, tagsize int, _ marshalOptions) int {
+	return tagsize + {{template "SizeValue" .}}
 }
 
-// append{{.Name}}Iface encodes a {{.GoType}} value as a {{.Name}}.
-func append{{.Name}}Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
-	v := ival.({{.GoType}})
+// append{{.Name}}Value encodes a {{.GoType}} value as a {{.Name}}.
+func append{{.Name}}Value(b []byte, v protoreflect.Value, wiretag uint64, _ marshalOptions) ([]byte, error) {
 	b = wire.AppendVarint(b, wiretag)
-	{{template "Append" .}}
+	{{template "AppendValue" .}}
 	return b, nil
 }
 
-// consume{{.Name}}Iface decodes a {{.GoType}} value as a {{.Name}}.
-func consume{{.Name}}Iface(b []byte, _ interface{}, _ wire.Number, wtyp wire.Type, _ unmarshalOptions) (interface{}, int, error) {
+// consume{{.Name}}Value decodes a {{.GoType}} value as a {{.Name}}.
+func consume{{.Name}}Value(b []byte, _ protoreflect.Value, _ wire.Number, wtyp wire.Type, _ unmarshalOptions) (protoreflect.Value, int, error) {
 	if wtyp != {{.WireType.Expr}} {
-		return nil, 0, errUnknown
+		return protoreflect.Value{}, 0, errUnknown
 	}
 	v, n := {{template "Consume" .}}
 	if n < 0 {
-		return nil, 0, wire.ParseError(n)
+		return protoreflect.Value{}, 0, wire.ParseError(n)
 	}
-	return {{.ToGoType}}, n, nil
+	return {{.ToValue}}, n, nil
 }
 
-var coder{{.Name}}Iface = ifaceCoderFuncs{
-	size:    size{{.Name}}Iface,
-	marshal: append{{.Name}}Iface,
-	unmarshal: consume{{.Name}}Iface,
+var coder{{.Name}}Value = valueCoderFuncs{
+	size:    size{{.Name}}Value,
+	marshal: append{{.Name}}Value,
+	unmarshal: consume{{.Name}}Value,
 }
 
 {{if or (eq .Name "Bytes") (eq .Name "String")}}
-// append{{.Name}}IfaceValidateUTF8 encodes a {{.GoType}} value as a {{.Name}}.
-func append{{.Name}}IfaceValidateUTF8(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
-	v := ival.({{.GoType}})
+// append{{.Name}}ValueValidateUTF8 encodes a {{.GoType}} value as a {{.Name}}.
+func append{{.Name}}ValueValidateUTF8(b []byte, v protoreflect.Value, wiretag uint64, _ marshalOptions) ([]byte, error) {
 	b = wire.AppendVarint(b, wiretag)
-	{{template "Append" .}}
-	if !utf8.Valid{{if eq .Name "String"}}String{{end}}(v) {
+	{{template "AppendValue" .}}
+	if !utf8.Valid{{if eq .Name "String"}}String{{end}}({{.FromValue}}) {
 		return b, errInvalidUTF8{}
 	}
 	return b, nil
 }
 
-// consume{{.Name}}IfaceValidateUTF8 decodes a {{.GoType}} value as a {{.Name}}.
-func consume{{.Name}}IfaceValidateUTF8(b []byte, _ interface{}, _ wire.Number, wtyp wire.Type, _ unmarshalOptions) (interface{}, int, error) {
+// consume{{.Name}}ValueValidateUTF8 decodes a {{.GoType}} value as a {{.Name}}.
+func consume{{.Name}}ValueValidateUTF8(b []byte, _ protoreflect.Value, _ wire.Number, wtyp wire.Type, _ unmarshalOptions) (protoreflect.Value, int, error) {
 	if wtyp != {{.WireType.Expr}} {
-		return nil, 0, errUnknown
+		return protoreflect.Value{}, 0, errUnknown
 	}
 	v, n := {{template "Consume" .}}
 	if n < 0 {
-		return nil, 0, wire.ParseError(n)
+		return protoreflect.Value{}, 0, wire.ParseError(n)
 	}
 	if !utf8.Valid{{if eq .Name "String"}}String{{end}}(v) {
-		return nil, 0, errInvalidUTF8{}
+		return protoreflect.Value{}, 0, errInvalidUTF8{}
 	}
-	return {{.ToGoType}}, n, nil
+	return {{.ToValue}}, n, nil
 }
 
-var coder{{.Name}}IfaceValidateUTF8 = ifaceCoderFuncs{
-	size:    size{{.Name}}Iface,
-	marshal: append{{.Name}}IfaceValidateUTF8,
-	unmarshal: consume{{.Name}}IfaceValidateUTF8,
+var coder{{.Name}}ValueValidateUTF8 = valueCoderFuncs{
+	size:      size{{.Name}}Value,
+	marshal:   append{{.Name}}ValueValidateUTF8,
+	unmarshal: consume{{.Name}}ValueValidateUTF8,
 }
 {{end}}
 
-// size{{.Name}}SliceIface returns the size of wire encoding a []{{.GoType}} value as a repeated {{.Name}}.
-func size{{.Name}}SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
-	s := *ival.(*[]{{.GoType}})
+// size{{.Name}}SliceValue returns the size of wire encoding a []{{.GoType}} value as a repeated {{.Name}}.
+func size{{.Name}}SliceValue(listv protoreflect.Value, tagsize int, _ marshalOptions) (size int) {
+	list := listv.List()
 	{{if .WireType.ConstSize -}}
-	size = len(s) * (tagsize + {{template "Size" .}})
+	size = list.Len() * (tagsize + {{template "SizeValue" .}})
 	{{- else -}}
-	for _, v := range s {
-		size += tagsize + {{template "Size" .}}
+	for i, llen := 0, list.Len(); i < llen; i++ {
+		v := list.Get(i)
+		size += tagsize + {{template "SizeValue" .}}
 	}
 	{{- end}}
 	return size
 }
 
-// append{{.Name}}SliceIface encodes a []{{.GoType}} value as a repeated {{.Name}}.
-func append{{.Name}}SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
-	s := *ival.(*[]{{.GoType}})
-	for _, v := range s {
+// append{{.Name}}SliceValue encodes a []{{.GoType}} value as a repeated {{.Name}}.
+func append{{.Name}}SliceValue(b []byte, listv protoreflect.Value, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	list := listv.List()
+	for i, llen := 0, list.Len(); i < llen; i++ {
+		v := list.Get(i)
 		b = wire.AppendVarint(b, wiretag)
-		{{template "Append" .}}
+		{{template "AppendValue" .}}
 	}
 	return b, nil
 }
 
-// consume{{.Name}}SliceIface wire decodes a []{{.GoType}} value as a repeated {{.Name}}.
-func consume{{.Name}}SliceIface(b []byte, ival interface{}, _ wire.Number, wtyp wire.Type, _ unmarshalOptions) (_ interface{}, n int, err error) {
-	sp := ival.(*[]{{.GoType}})
+// consume{{.Name}}SliceValue wire decodes a []{{.GoType}} value as a repeated {{.Name}}.
+func consume{{.Name}}SliceValue(b []byte, listv protoreflect.Value, _ wire.Number, wtyp wire.Type, _ unmarshalOptions) (_ protoreflect.Value, n int, err error) {
+	list := listv.List()
 	{{- if .WireType.Packable}}
 	if wtyp == wire.BytesType {
-		s := *sp
 		b, n = wire.ConsumeBytes(b)
 		if n < 0 {
-			return nil, 0, wire.ParseError(n)
+			return protoreflect.Value{}, 0, wire.ParseError(n)
 		}
 		for len(b) > 0 {
 			v, n := {{template "Consume" .}}
 			if n < 0 {
-				return nil, 0, wire.ParseError(n)
+				return protoreflect.Value{}, 0, wire.ParseError(n)
 			}
-			s = append(s, {{.ToGoType}})
+			list.Append({{.ToValue}})
 			b = b[n:]
 		}
-		*sp = s
-		return ival, n, nil
+		return listv, n, nil
 	}
 	{{- end}}
 	if wtyp != {{.WireType.Expr}} {
-		return nil, 0, errUnknown
+		return protoreflect.Value{}, 0, errUnknown
 	}
 	v, n := {{template "Consume" .}}
 	if n < 0 {
-		return nil, 0, wire.ParseError(n)
+		return protoreflect.Value{}, 0, wire.ParseError(n)
 	}
-	*sp = append(*sp, {{.ToGoType}})
-	return ival, n, nil
+	list.Append({{.ToValue}})
+	return listv, n, nil
 }
 
-var coder{{.Name}}SliceIface = ifaceCoderFuncs{
-	size:      size{{.Name}}SliceIface,
-	marshal:   append{{.Name}}SliceIface,
-	unmarshal: consume{{.Name}}SliceIface,
+var coder{{.Name}}SliceValue = valueCoderFuncs{
+	size:      size{{.Name}}SliceValue,
+	marshal:   append{{.Name}}SliceValue,
+	unmarshal: consume{{.Name}}SliceValue,
 }
 
 {{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
-	}
+// size{{.Name}}PackedSliceValue returns the size of wire encoding a []{{.GoType}} value as a packed repeated {{.Name}}.
+func size{{.Name}}PackedSliceValue(listv protoreflect.Value, tagsize int, _ marshalOptions) (size int) {
+	list := listv.List()
 	{{if .WireType.ConstSize -}}
-	n := len(s) * {{template "Size" .}}
+	n := list.Len() * {{template "SizeValue" .}}
 	{{- else -}}
 	n := 0
-	for _, v := range s {
-		n += {{template "Size" .}}
+	for i, llen := 0, list.Len(); i < llen; i++ {
+		v := list.Get(i)
+		n += {{template "SizeValue" .}}
 	}
 	{{- 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 {
+// append{{.Name}}PackedSliceValue encodes a []{{.GoType}} value as a packed repeated {{.Name}}.
+func append{{.Name}}PackedSliceValue(b []byte, listv protoreflect.Value, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	list := listv.List()
+	llen := list.Len()
+	if llen == 0 {
 		return b, nil
 	}
 	b = wire.AppendVarint(b, wiretag)
 	{{if .WireType.ConstSize -}}
-	n := len(s) * {{template "Size" .}}
+	n := llen * {{template "SizeValue" .}}
 	{{- else -}}
 	n := 0
-	for _, v := range s {
-		n += {{template "Size" .}}
+	for i := 0; i < llen; i++ {
+		v := list.Get(i)
+		n += {{template "SizeValue" .}}
 	}
 	{{- end}}
 	b = wire.AppendVarint(b, uint64(n))
-	for _, v := range s {
-		{{template "Append" .}}
+	for i := 0; i < llen; i++ {
+		v := list.Get(i)
+		{{template "AppendValue" .}}
 	}
 	return b, nil
 }
 
-var coder{{.Name}}PackedSliceIface = ifaceCoderFuncs{
-	size:      size{{.Name}}PackedSliceIface,
-	marshal:   append{{.Name}}PackedSliceIface,
-	unmarshal: consume{{.Name}}SliceIface,
+var coder{{.Name}}PackedSliceValue = valueCoderFuncs{
+	size:      size{{.Name}}PackedSliceValue,
+	marshal:   append{{.Name}}PackedSliceValue,
+	unmarshal: consume{{.Name}}SliceValue,
 }
 {{end}}
 
-{{end -}}
+{{- end}}{{/* if not .NoValueCodec */}}
+
 {{end -}}
 
 // We append to an empty array rather than a nil []byte to get non-nil zero-length byte slices.

+ 60 - 40
internal/impl/codec_extension.go

@@ -16,7 +16,7 @@ type extensionFieldInfo struct {
 	wiretag             uint64
 	tagsize             int
 	unmarshalNeedsValue bool
-	funcs               ifaceCoderFuncs
+	funcs               valueCoderFuncs
 }
 
 func (mi *MessageInfo) extensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
@@ -66,60 +66,80 @@ type ExtensionField struct {
 
 	// value is either the value of GetValue,
 	// or a *lazyExtensionValue that then returns the value of GetValue.
-	value interface{} // TODO: switch to protoreflect.Value
+	value pref.Value
+	lazy  *lazyExtensionValue
 }
 
+// Set sets the type and value of the extension field.
+// This must not be called concurrently.
+func (f *ExtensionField) Set(t pref.ExtensionType, v pref.Value) {
+	f.typ = t
+	f.value = v
+}
+
+// SetLazy sets the type and a value that is to be lazily evaluated upon first use.
+// This must not be called concurrently.
+func (f *ExtensionField) SetLazy(t pref.ExtensionType, fn func() pref.Value) {
+	f.typ = t
+	f.lazy = &lazyExtensionValue{value: fn}
+}
+
+// Value returns the value of the extension field.
+// This may be called concurrently.
+func (f *ExtensionField) Value() pref.Value {
+	if f.lazy != nil {
+		return f.lazy.GetValue()
+	}
+	return f.value
+}
+
+// Type returns the type of the extension field.
+// This may be called concurrently.
+func (f ExtensionField) Type() pref.ExtensionType {
+	return f.typ
+}
+
+// IsSet returns whether the extension field is set.
+// This may be called concurrently.
+func (f ExtensionField) IsSet() bool {
+	return f.typ != nil
+}
+
+// Deprecated: Do not use.
 func (f ExtensionField) HasType() bool {
 	return f.typ != nil
 }
+
+// Deprecated: Do not use.
 func (f ExtensionField) GetType() pref.ExtensionType {
 	return f.typ
 }
+
+// Deprecated: Do not use.
 func (f *ExtensionField) SetType(t pref.ExtensionType) {
 	f.typ = t
 }
 
-// HasValue reports whether a value is set for the extension field.
-// This may be called concurrently.
+// Deprecated: Do not use.
 func (f ExtensionField) HasValue() bool {
-	return f.value != nil
-}
-
-// GetValue returns the concrete value for the extension field.
-// Let the type of Desc.ExtensionType be the "API type" and
-// the type of GetValue be the "storage type".
-// The API type and storage type are the same except:
-//	* for scalars (except []byte), where the API type uses *T,
-//	while the storage type uses T.
-//	* for repeated fields, where the API type uses []T,
-//	while the storage type uses *[]T.
-//
-// The reason for the divergence is so that the storage type more naturally
-// matches what is expected of when retrieving the values through the
-// protobuf reflection APIs.
-//
-// GetValue is only populated if Desc is also populated.
-// This may be called concurrently.
-//
-// TODO: switch interface{} to protoreflect.Value
+	return f.value.IsValid() || f.lazy != nil
+}
+
+// Deprecated: Do not use.
 func (f ExtensionField) GetValue() interface{} {
-	if f, ok := f.value.(*lazyExtensionValue); ok {
-		return f.GetValue()
-	}
-	return f.value
+	return f.typ.InterfaceOf(f.Value())
 }
 
-// SetEagerValue sets the current value of the extension.
-// This must not be called concurrently.
-func (f *ExtensionField) SetEagerValue(v interface{}) {
-	f.value = v
+// Deprecated: Do not use.
+func (f *ExtensionField) SetEagerValue(ival interface{}) {
+	f.value = f.typ.ValueOf(ival)
 }
 
-// SetLazyValue sets a value that is to be lazily evaluated upon first use.
-// The returned value must not be nil.
-// This must not be called concurrently.
-func (f *ExtensionField) SetLazyValue(v func() interface{}) {
-	f.value = &lazyExtensionValue{value: v}
+// Deprecated: Do not use.
+func (f *ExtensionField) SetLazyValue(fn func() interface{}) {
+	f.lazy = &lazyExtensionValue{value: func() interface{} {
+		return f.typ.ValueOf(fn())
+	}}
 }
 
 type lazyExtensionValue struct {
@@ -128,14 +148,14 @@ type lazyExtensionValue struct {
 	value interface{} // either the value itself or a func() interface{}
 }
 
-func (v *lazyExtensionValue) GetValue() interface{} {
+func (v *lazyExtensionValue) GetValue() pref.Value {
 	if atomic.LoadUint32(&v.once) == 0 {
 		v.mu.Lock()
-		if f, ok := v.value.(func() interface{}); ok {
+		if f, ok := v.value.(func() pref.Value); ok {
 			v.value = f()
 		}
 		atomic.StoreUint32(&v.once, 1)
 		v.mu.Unlock()
 	}
-	return v.value
+	return v.value.(pref.Value)
 }

+ 139 - 216
internal/impl/codec_field.go

@@ -170,32 +170,55 @@ func consumeMessage(b []byte, m proto.Message, wtyp wire.Type, opts unmarshalOpt
 	return n, nil
 }
 
-func sizeMessageIface(ival interface{}, tagsize int, opts marshalOptions) int {
-	m := Export{}.MessageOf(ival).Interface()
+func sizeMessageValue(v pref.Value, tagsize int, opts marshalOptions) int {
+	m := v.Message().Interface()
 	return sizeMessage(m, tagsize, opts)
 }
 
-func appendMessageIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
-	m := Export{}.MessageOf(ival).Interface()
+func appendMessageValue(b []byte, v pref.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	m := v.Message().Interface()
 	return appendMessage(b, m, wiretag, opts)
 }
 
-func consumeMessageIface(b []byte, ival interface{}, _ wire.Number, wtyp wire.Type, opts unmarshalOptions) (interface{}, int, error) {
-	m := Export{}.MessageOf(ival).Interface()
+func consumeMessageValue(b []byte, v pref.Value, _ wire.Number, wtyp wire.Type, opts unmarshalOptions) (pref.Value, int, error) {
+	m := v.Message().Interface()
 	n, err := consumeMessage(b, m, wtyp, opts)
-	return ival, n, err
+	return v, n, err
 }
 
-func isInitMessageIface(ival interface{}) error {
-	m := Export{}.MessageOf(ival).Interface()
+func isInitMessageValue(v pref.Value) error {
+	m := v.Message().Interface()
 	return proto.IsInitialized(m)
 }
 
-var coderMessageIface = ifaceCoderFuncs{
-	size:      sizeMessageIface,
-	marshal:   appendMessageIface,
-	unmarshal: consumeMessageIface,
-	isInit:    isInitMessageIface,
+var coderMessageValue = valueCoderFuncs{
+	size:      sizeMessageValue,
+	marshal:   appendMessageValue,
+	unmarshal: consumeMessageValue,
+	isInit:    isInitMessageValue,
+}
+
+func sizeGroupValue(v pref.Value, tagsize int, opts marshalOptions) int {
+	m := v.Message().Interface()
+	return sizeGroup(m, tagsize, opts)
+}
+
+func appendGroupValue(b []byte, v pref.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	m := v.Message().Interface()
+	return appendGroup(b, m, wiretag, opts)
+}
+
+func consumeGroupValue(b []byte, v pref.Value, num wire.Number, wtyp wire.Type, opts unmarshalOptions) (pref.Value, int, error) {
+	m := v.Message().Interface()
+	n, err := consumeGroup(b, m, num, wtyp, opts)
+	return v, n, err
+}
+
+var coderGroupValue = valueCoderFuncs{
+	size:      sizeGroupValue,
+	marshal:   appendGroupValue,
+	unmarshal: consumeGroupValue,
+	isInit:    isInitMessageValue,
 }
 
 func makeGroupFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
@@ -283,25 +306,6 @@ func consumeGroup(b []byte, m proto.Message, num wire.Number, wtyp wire.Type, op
 	return n, opts.Options().Unmarshal(b, m)
 }
 
-func makeGroupValueCoder(fd pref.FieldDescriptor, ft reflect.Type) ifaceCoderFuncs {
-	return ifaceCoderFuncs{
-		size: func(ival interface{}, tagsize int, opts marshalOptions) int {
-			m := Export{}.MessageOf(ival).Interface()
-			return sizeGroup(m, tagsize, opts)
-		},
-		marshal: func(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
-			m := Export{}.MessageOf(ival).Interface()
-			return appendGroup(b, m, wiretag, opts)
-		},
-		unmarshal: func(b []byte, ival interface{}, num wire.Number, wtyp wire.Type, opts unmarshalOptions) (interface{}, int, error) {
-			m := Export{}.MessageOf(ival).Interface()
-			n, err := consumeGroup(b, m, num, wtyp, opts)
-			return ival, n, err
-		},
-		isInit: isInitMessageIface,
-	}
-}
-
 func makeMessageSliceFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
 	if mi := getMessageInfo(ft); mi != nil {
 		return pointerCoderFuncs{
@@ -441,32 +445,116 @@ func isInitMessageSlice(p pointer, goType reflect.Type) error {
 
 // Slices of messages
 
-func sizeMessageSliceIface(ival interface{}, tagsize int, opts marshalOptions) int {
-	p := pointerOfIface(ival)
-	return sizeMessageSlice(p, reflect.TypeOf(ival).Elem().Elem(), tagsize, opts)
+func sizeMessageSliceValue(listv pref.Value, tagsize int, opts marshalOptions) int {
+	list := listv.List()
+	n := 0
+	for i, llen := 0, list.Len(); i < llen; i++ {
+		m := list.Get(i).Message().Interface()
+		n += wire.SizeBytes(proto.Size(m)) + tagsize
+	}
+	return n
+}
+
+func appendMessageSliceValue(b []byte, listv pref.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	list := listv.List()
+	mopts := opts.Options()
+	for i, llen := 0, list.Len(); i < llen; i++ {
+		m := list.Get(i).Message().Interface()
+		b = wire.AppendVarint(b, wiretag)
+		siz := proto.Size(m)
+		b = wire.AppendVarint(b, uint64(siz))
+		var err error
+		b, err = mopts.MarshalAppend(b, m)
+		if err != nil {
+			return b, err
+		}
+	}
+	return b, nil
+}
+
+func consumeMessageSliceValue(b []byte, listv pref.Value, _ wire.Number, wtyp wire.Type, opts unmarshalOptions) (pref.Value, int, error) {
+	list := listv.List()
+	if wtyp != wire.BytesType {
+		return pref.Value{}, 0, errUnknown
+	}
+	v, n := wire.ConsumeBytes(b)
+	if n < 0 {
+		return pref.Value{}, 0, wire.ParseError(n)
+	}
+	m := list.NewElement()
+	if err := opts.Options().Unmarshal(v, m.Message().Interface()); err != nil {
+		return pref.Value{}, 0, err
+	}
+	list.Append(m)
+	return listv, n, nil
+}
+
+func isInitMessageSliceValue(listv pref.Value) error {
+	list := listv.List()
+	for i, llen := 0, list.Len(); i < llen; i++ {
+		m := list.Get(i).Message().Interface()
+		if err := proto.IsInitialized(m); err != nil {
+			return err
+		}
+	}
+	return nil
 }
 
-func appendMessageSliceIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
-	p := pointerOfIface(ival)
-	return appendMessageSlice(b, p, wiretag, reflect.TypeOf(ival).Elem().Elem(), opts)
+var coderMessageSliceValue = valueCoderFuncs{
+	size:      sizeMessageSliceValue,
+	marshal:   appendMessageSliceValue,
+	unmarshal: consumeMessageSliceValue,
+	isInit:    isInitMessageSliceValue,
 }
 
-func consumeMessageSliceIface(b []byte, ival interface{}, _ wire.Number, wtyp wire.Type, opts unmarshalOptions) (interface{}, int, error) {
-	p := pointerOfIface(ival)
-	n, err := consumeMessageSlice(b, p, reflect.TypeOf(ival).Elem().Elem(), wtyp, opts)
-	return ival, n, err
+func sizeGroupSliceValue(listv pref.Value, tagsize int, opts marshalOptions) int {
+	list := listv.List()
+	n := 0
+	for i, llen := 0, list.Len(); i < llen; i++ {
+		m := list.Get(i).Message().Interface()
+		n += 2*tagsize + proto.Size(m)
+	}
+	return n
 }
 
-func isInitMessageSliceIface(ival interface{}) error {
-	p := pointerOfIface(ival)
-	return isInitMessageSlice(p, reflect.TypeOf(ival).Elem().Elem())
+func appendGroupSliceValue(b []byte, listv pref.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	list := listv.List()
+	mopts := opts.Options()
+	for i, llen := 0, list.Len(); i < llen; i++ {
+		m := list.Get(i).Message().Interface()
+		b = wire.AppendVarint(b, wiretag) // start group
+		var err error
+		b, err = mopts.MarshalAppend(b, m)
+		if err != nil {
+			return b, err
+		}
+		b = wire.AppendVarint(b, wiretag+1) // end group
+	}
+	return b, nil
+}
+
+func consumeGroupSliceValue(b []byte, listv pref.Value, num wire.Number, wtyp wire.Type, opts unmarshalOptions) (pref.Value, int, error) {
+	list := listv.List()
+	if wtyp != wire.StartGroupType {
+		return pref.Value{}, 0, errUnknown
+	}
+	b, n := wire.ConsumeGroup(num, b)
+	if n < 0 {
+		return pref.Value{}, 0, wire.ParseError(n)
+	}
+	m := list.NewElement()
+	if err := opts.Options().Unmarshal(b, m.Message().Interface()); err != nil {
+		return pref.Value{}, 0, err
+	}
+	list.Append(m)
+	return listv, n, nil
 }
 
-var coderMessageSliceIface = ifaceCoderFuncs{
-	size:      sizeMessageSliceIface,
-	marshal:   appendMessageSliceIface,
-	unmarshal: consumeMessageSliceIface,
-	isInit:    isInitMessageSliceIface,
+var coderGroupSliceValue = valueCoderFuncs{
+	size:      sizeGroupSliceValue,
+	marshal:   appendGroupSliceValue,
+	unmarshal: consumeGroupSliceValue,
+	isInit:    isInitMessageSliceValue,
 }
 
 func makeGroupSliceFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
@@ -581,171 +669,6 @@ func consumeGroupSliceInfo(b []byte, p pointer, num wire.Number, wtyp wire.Type,
 	return n, nil
 }
 
-func sizeGroupSliceIface(ival interface{}, tagsize int, opts marshalOptions) int {
-	p := pointerOfIface(ival)
-	return sizeGroupSlice(p, reflect.TypeOf(ival).Elem().Elem(), tagsize, opts)
-}
-
-func appendGroupSliceIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
-	p := pointerOfIface(ival)
-	return appendGroupSlice(b, p, wiretag, reflect.TypeOf(ival).Elem().Elem(), opts)
-}
-
-func consumeGroupSliceIface(b []byte, ival interface{}, num wire.Number, wtyp wire.Type, opts unmarshalOptions) (interface{}, int, error) {
-	p := pointerOfIface(ival)
-	n, err := consumeGroupSlice(b, p, num, wtyp, reflect.TypeOf(ival).Elem().Elem(), opts)
-	return ival, n, err
-}
-
-var coderGroupSliceIface = ifaceCoderFuncs{
-	size:      sizeGroupSliceIface,
-	marshal:   appendGroupSliceIface,
-	unmarshal: consumeGroupSliceIface,
-	isInit:    isInitMessageSliceIface,
-}
-
-// Enums
-
-func sizeEnumIface(ival interface{}, tagsize int, _ marshalOptions) (n int) {
-	v := reflect.ValueOf(ival).Int()
-	return wire.SizeVarint(uint64(v)) + tagsize
-}
-
-func appendEnumIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
-	v := reflect.ValueOf(ival).Int()
-	b = wire.AppendVarint(b, wiretag)
-	b = wire.AppendVarint(b, uint64(v))
-	return b, nil
-}
-
-func consumeEnumIface(b []byte, ival interface{}, _ wire.Number, wtyp wire.Type, _ unmarshalOptions) (interface{}, int, error) {
-	if wtyp != wire.VarintType {
-		return nil, 0, errUnknown
-	}
-	v, n := wire.ConsumeVarint(b)
-	if n < 0 {
-		return nil, 0, wire.ParseError(n)
-	}
-	rv := reflect.New(reflect.TypeOf(ival)).Elem()
-	rv.SetInt(int64(v))
-	return rv.Interface(), n, nil
-}
-
-var coderEnumIface = ifaceCoderFuncs{
-	size:      sizeEnumIface,
-	marshal:   appendEnumIface,
-	unmarshal: consumeEnumIface,
-}
-
-func sizeEnumSliceIface(ival interface{}, tagsize int, opts marshalOptions) (size int) {
-	return sizeEnumSliceReflect(reflect.ValueOf(ival).Elem(), tagsize, opts)
-}
-
-func sizeEnumSliceReflect(s reflect.Value, tagsize int, _ marshalOptions) (size int) {
-	for i, llen := 0, s.Len(); i < llen; i++ {
-		size += wire.SizeVarint(uint64(s.Index(i).Int())) + tagsize
-	}
-	return size
-}
-
-func appendEnumSliceIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
-	return appendEnumSliceReflect(b, reflect.ValueOf(ival).Elem(), wiretag, opts)
-}
-
-func appendEnumSliceReflect(b []byte, s reflect.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
-	for i, llen := 0, s.Len(); i < llen; i++ {
-		b = wire.AppendVarint(b, wiretag)
-		b = wire.AppendVarint(b, uint64(s.Index(i).Int()))
-	}
-	return b, nil
-}
-
-func consumeEnumSliceIface(b []byte, ival interface{}, _ wire.Number, wtyp wire.Type, opts unmarshalOptions) (interface{}, int, error) {
-	n, err := consumeEnumSliceReflect(b, reflect.ValueOf(ival), wtyp, opts)
-	return ival, n, err
-}
-
-func consumeEnumSliceReflect(b []byte, s reflect.Value, wtyp wire.Type, _ unmarshalOptions) (n int, err error) {
-	s = s.Elem() // *[]E -> []E
-	if wtyp == wire.BytesType {
-		b, n = wire.ConsumeBytes(b)
-		if n < 0 {
-			return 0, wire.ParseError(n)
-		}
-		for len(b) > 0 {
-			v, n := wire.ConsumeVarint(b)
-			if n < 0 {
-				return 0, wire.ParseError(n)
-			}
-			rv := reflect.New(s.Type().Elem()).Elem()
-			rv.SetInt(int64(v))
-			s.Set(reflect.Append(s, rv))
-			b = b[n:]
-		}
-		return n, nil
-	}
-	if wtyp != wire.VarintType {
-		return 0, errUnknown
-	}
-	v, n := wire.ConsumeVarint(b)
-	if n < 0 {
-		return 0, wire.ParseError(n)
-	}
-	rv := reflect.New(s.Type().Elem()).Elem()
-	rv.SetInt(int64(v))
-	s.Set(reflect.Append(s, rv))
-	return n, nil
-}
-
-var coderEnumSliceIface = ifaceCoderFuncs{
-	size:      sizeEnumSliceIface,
-	marshal:   appendEnumSliceIface,
-	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,
-}
-
 func asMessage(v reflect.Value) pref.ProtoMessage {
 	if m, ok := v.Interface().(pref.ProtoMessage); ok {
 		return m

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 438 - 319
internal/impl/codec_gen.go


+ 64 - 133
internal/impl/codec_map.go

@@ -5,11 +5,10 @@
 package impl
 
 import (
-	"fmt"
 	"reflect"
-	"sort"
 
 	"google.golang.org/protobuf/internal/encoding/wire"
+	"google.golang.org/protobuf/internal/mapsort"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 )
 
@@ -17,11 +16,10 @@ type mapInfo struct {
 	goType     reflect.Type
 	keyWiretag uint64
 	valWiretag uint64
-	keyFuncs   ifaceCoderFuncs
-	valFuncs   ifaceCoderFuncs
-	keyZero    interface{}
-	valZero    interface{}
-	newVal     func() interface{}
+	keyFuncs   valueCoderFuncs
+	valFuncs   valueCoderFuncs
+	keyZero    pref.Value
+	keyKind    pref.Kind
 }
 
 func encoderFuncsForMap(fd pref.FieldDescriptor, ft reflect.Type) (funcs pointerCoderFuncs) {
@@ -32,6 +30,7 @@ func encoderFuncsForMap(fd pref.FieldDescriptor, ft reflect.Type) (funcs pointer
 	valWiretag := wire.EncodeTag(2, wireTypes[valField.Kind()])
 	keyFuncs := encoderFuncsForValue(keyField, ft.Key())
 	valFuncs := encoderFuncsForValue(valField, ft.Elem())
+	conv := NewConverter(ft, fd)
 
 	mapi := &mapInfo{
 		goType:     ft,
@@ -39,30 +38,32 @@ func encoderFuncsForMap(fd pref.FieldDescriptor, ft reflect.Type) (funcs pointer
 		valWiretag: valWiretag,
 		keyFuncs:   keyFuncs,
 		valFuncs:   valFuncs,
-		keyZero:    reflect.Zero(ft.Key()).Interface(),
-		valZero:    reflect.Zero(ft.Elem()).Interface(),
-	}
-	switch valField.Kind() {
-	case pref.GroupKind, pref.MessageKind:
-		mapi.newVal = func() interface{} {
-			return reflect.New(ft.Elem().Elem()).Interface()
-		}
+		keyZero:    keyField.Default(),
+		keyKind:    keyField.Kind(),
 	}
 
 	funcs = pointerCoderFuncs{
 		size: func(p pointer, tagsize int, opts marshalOptions) int {
-			return sizeMap(p, tagsize, ft, keyFuncs, valFuncs, opts)
+			mapv := conv.PBValueOf(p.AsValueOf(ft).Elem()).Map()
+			return sizeMap(mapv, tagsize, mapi, opts)
 		},
 		marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
-			return appendMap(b, p, wiretag, keyWiretag, valWiretag, ft, keyFuncs, valFuncs, opts)
+			mapv := conv.PBValueOf(p.AsValueOf(ft).Elem()).Map()
+			return appendMap(b, mapv, wiretag, mapi, opts)
 		},
 		unmarshal: func(b []byte, p pointer, wtyp wire.Type, opts unmarshalOptions) (int, error) {
-			return consumeMap(b, p, wtyp, mapi, opts)
+			mp := p.AsValueOf(ft)
+			if mp.Elem().IsNil() {
+				mp.Elem().Set(reflect.MakeMap(mapi.goType))
+			}
+			mapv := conv.PBValueOf(mp.Elem()).Map()
+			return consumeMap(b, mapv, wtyp, mapi, opts)
 		},
 	}
 	if valFuncs.isInit != nil {
 		funcs.isInit = func(p pointer) error {
-			return isInitMap(p, ft, valFuncs.isInit)
+			mapv := conv.PBValueOf(p.AsValueOf(ft).Elem()).Map()
+			return isInitMap(mapv, mapi)
 		}
 	}
 	return funcs
@@ -73,13 +74,21 @@ const (
 	mapValTagSize = 1 // field 2, tag size 2.
 )
 
-func consumeMap(b []byte, p pointer, wtyp wire.Type, mapi *mapInfo, opts unmarshalOptions) (int, error) {
-	mp := p.AsValueOf(mapi.goType)
-	if mp.Elem().IsNil() {
-		mp.Elem().Set(reflect.MakeMap(mapi.goType))
+func sizeMap(mapv pref.Map, tagsize int, mapi *mapInfo, opts marshalOptions) int {
+	if mapv.Len() == 0 {
+		return 0
 	}
-	m := mp.Elem()
+	n := 0
+	mapv.Range(func(key pref.MapKey, value pref.Value) bool {
+		n += tagsize + wire.SizeBytes(
+			mapi.keyFuncs.size(key.Value(), mapKeyTagSize, opts)+
+				mapi.valFuncs.size(value, mapValTagSize, opts))
+		return true
+	})
+	return n
+}
 
+func consumeMap(b []byte, mapv pref.Map, wtyp wire.Type, mapi *mapInfo, opts unmarshalOptions) (int, error) {
 	if wtyp != wire.BytesType {
 		return 0, errUnknown
 	}
@@ -89,11 +98,8 @@ func consumeMap(b []byte, p pointer, wtyp wire.Type, mapi *mapInfo, opts unmarsh
 	}
 	var (
 		key = mapi.keyZero
-		val = mapi.valZero
+		val = mapv.NewValue()
 	)
-	if mapi.newVal != nil {
-		val = mapi.newVal()
-	}
 	for len(b) > 0 {
 		num, wtyp, n := wire.ConsumeTag(b)
 		if n < 0 {
@@ -103,14 +109,14 @@ func consumeMap(b []byte, p pointer, wtyp wire.Type, mapi *mapInfo, opts unmarsh
 		err := errUnknown
 		switch num {
 		case 1:
-			var v interface{}
+			var v pref.Value
 			v, n, err = mapi.keyFuncs.unmarshal(b, key, num, wtyp, opts)
 			if err != nil {
 				break
 			}
 			key = v
 		case 2:
-			var v interface{}
+			var v pref.Value
 			v, n, err = mapi.valFuncs.unmarshal(b, val, num, wtyp, opts)
 			if err != nil {
 				break
@@ -127,119 +133,44 @@ func consumeMap(b []byte, p pointer, wtyp wire.Type, mapi *mapInfo, opts unmarsh
 		}
 		b = b[n:]
 	}
-	m.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(val))
+	mapv.Set(key.MapKey(), val)
 	return n, nil
 }
 
-func sizeMap(p pointer, tagsize int, goType reflect.Type, keyFuncs, valFuncs ifaceCoderFuncs, opts marshalOptions) int {
-	m := p.AsValueOf(goType).Elem()
-	n := 0
-	if m.Len() == 0 {
-		return 0
-	}
-	iter := mapRange(m)
-	for iter.Next() {
-		ki := iter.Key().Interface()
-		vi := iter.Value().Interface()
-		size := keyFuncs.size(ki, mapKeyTagSize, opts) + valFuncs.size(vi, mapValTagSize, opts)
-		n += wire.SizeBytes(size) + tagsize
-	}
-	return n
-}
-
-func appendMap(b []byte, p pointer, wiretag, keyWiretag, valWiretag uint64, goType reflect.Type, keyFuncs, valFuncs ifaceCoderFuncs, opts marshalOptions) ([]byte, error) {
-	m := p.AsValueOf(goType).Elem()
-	var err error
-
-	if m.Len() == 0 {
-		return b, nil
-	}
-
-	if opts.Deterministic() {
-		keys := m.MapKeys()
-		sort.Sort(mapKeys(keys))
-		for _, k := range keys {
-			b, err = appendMapElement(b, k, m.MapIndex(k), wiretag, keyWiretag, valWiretag, keyFuncs, valFuncs, opts)
-			if err != nil {
-				return b, err
-			}
-		}
+func appendMap(b []byte, mapv pref.Map, wiretag uint64, mapi *mapInfo, opts marshalOptions) ([]byte, error) {
+	if mapv.Len() == 0 {
 		return b, nil
 	}
-
-	iter := mapRange(m)
-	for iter.Next() {
-		b, err = appendMapElement(b, iter.Key(), iter.Value(), wiretag, keyWiretag, valWiretag, keyFuncs, valFuncs, opts)
+	var err error
+	fn := func(key pref.MapKey, value pref.Value) bool {
+		b = wire.AppendVarint(b, wiretag)
+		size := 0
+		size += mapi.keyFuncs.size(key.Value(), mapKeyTagSize, opts)
+		size += mapi.valFuncs.size(value, mapValTagSize, opts)
+		b = wire.AppendVarint(b, uint64(size))
+		b, err = mapi.keyFuncs.marshal(b, key.Value(), mapi.keyWiretag, opts)
 		if err != nil {
-			return b, err
+			return false
 		}
-	}
-	return b, nil
-}
-
-func appendMapElement(b []byte, key, value reflect.Value, wiretag, keyWiretag, valWiretag uint64, keyFuncs, valFuncs ifaceCoderFuncs, opts marshalOptions) ([]byte, error) {
-	ki := key.Interface()
-	vi := value.Interface()
-	b = wire.AppendVarint(b, wiretag)
-	size := keyFuncs.size(ki, mapKeyTagSize, opts) + valFuncs.size(vi, mapValTagSize, opts)
-	b = wire.AppendVarint(b, uint64(size))
-	b, err := keyFuncs.marshal(b, ki, keyWiretag, opts)
-	if err != nil {
-		return b, err
-	}
-	b, err = valFuncs.marshal(b, vi, valWiretag, opts)
-	if err != nil {
-		return b, err
-	}
-	return b, nil
-}
-
-func isInitMap(p pointer, goType reflect.Type, isInit func(interface{}) error) error {
-	m := p.AsValueOf(goType).Elem()
-	if m.Len() == 0 {
-		return nil
-	}
-	iter := mapRange(m)
-	for iter.Next() {
-		if err := isInit(iter.Value().Interface()); err != nil {
-			return err
+		b, err = mapi.valFuncs.marshal(b, value, mapi.valWiretag, opts)
+		if err != nil {
+			return false
 		}
+		return true
 	}
-	return nil
-}
-
-// mapKeys returns a sort.Interface to be used for sorting the map keys.
-// Map fields may have key types of non-float scalars, strings and enums.
-func mapKeys(vs []reflect.Value) sort.Interface {
-	s := mapKeySorter{vs: vs}
-
-	// Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps.
-	if len(vs) == 0 {
-		return s
-	}
-	switch vs[0].Kind() {
-	case reflect.Int32, reflect.Int64:
-		s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() }
-	case reflect.Uint32, reflect.Uint64:
-		s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() }
-	case reflect.Bool:
-		s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true
-	case reflect.String:
-		s.less = func(a, b reflect.Value) bool { return a.String() < b.String() }
-	default:
-		panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind()))
+	if opts.Deterministic() {
+		mapsort.Range(mapv, mapi.keyKind, fn)
+	} else {
+		mapv.Range(fn)
 	}
-
-	return s
+	return b, err
 }
 
-type mapKeySorter struct {
-	vs   []reflect.Value
-	less func(a, b reflect.Value) bool
-}
-
-func (s mapKeySorter) Len() int      { return len(s.vs) }
-func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] }
-func (s mapKeySorter) Less(i, j int) bool {
-	return s.less(s.vs[i], s.vs[j])
+func isInitMap(mapv pref.Map, mapi *mapInfo) error {
+	var err error
+	mapv.Range(func(_ pref.MapKey, value pref.Value) bool {
+		err = mapi.valFuncs.isInit(value)
+		return err == nil
+	})
+	return err
 }

+ 2 - 2
internal/impl/codec_messageset.go

@@ -39,7 +39,7 @@ func sizeMessageSet(mi *MessageInfo, p pointer, tagsize int, opts marshalOptions
 		}
 		num, _ := wire.DecodeTag(xi.wiretag)
 		n += messageset.SizeField(num)
-		n += xi.funcs.size(x.GetValue(), wire.SizeTag(messageset.FieldMessage), opts)
+		n += xi.funcs.size(x.Value(), wire.SizeTag(messageset.FieldMessage), opts)
 	}
 	return n
 }
@@ -88,7 +88,7 @@ func marshalMessageSetField(mi *MessageInfo, b []byte, x ExtensionField, opts ma
 	xi := mi.extensionFieldInfo(x.GetType())
 	num, _ := wire.DecodeTag(xi.wiretag)
 	b = messageset.AppendFieldStart(b, num)
-	b, err := xi.funcs.marshal(b, x.GetValue(), wire.EncodeTag(messageset.FieldMessage, wire.BytesType), opts)
+	b, err := xi.funcs.marshal(b, x.Value(), wire.EncodeTag(messageset.FieldMessage, wire.BytesType), opts)
 	if err != nil {
 		return b, err
 	}

+ 65 - 5
internal/impl/codec_reflect.go

@@ -87,15 +87,52 @@ var coderEnumPtr = pointerCoderFuncs{
 }
 
 func sizeEnumSlice(p pointer, tagsize int, opts marshalOptions) (size int) {
-	return sizeEnumSliceReflect(p.v.Elem(), tagsize, opts)
+	s := p.v.Elem()
+	for i, llen := 0, s.Len(); i < llen; i++ {
+		size += wire.SizeVarint(uint64(s.Index(i).Int())) + tagsize
+	}
+	return size
 }
 
 func appendEnumSlice(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
-	return appendEnumSliceReflect(b, p.v.Elem(), wiretag, opts)
+	s := p.v.Elem()
+	for i, llen := 0, s.Len(); i < llen; i++ {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, uint64(s.Index(i).Int()))
+	}
+	return b, nil
 }
 
 func consumeEnumSlice(b []byte, p pointer, wtyp wire.Type, opts unmarshalOptions) (n int, err error) {
-	return consumeEnumSliceReflect(b, p.v, wtyp, opts)
+	s := p.v.Elem()
+	if wtyp == wire.BytesType {
+		b, n = wire.ConsumeBytes(b)
+		if n < 0 {
+			return 0, wire.ParseError(n)
+		}
+		for len(b) > 0 {
+			v, n := wire.ConsumeVarint(b)
+			if n < 0 {
+				return 0, wire.ParseError(n)
+			}
+			rv := reflect.New(s.Type().Elem()).Elem()
+			rv.SetInt(int64(v))
+			s.Set(reflect.Append(s, rv))
+			b = b[n:]
+		}
+		return n, nil
+	}
+	if wtyp != wire.VarintType {
+		return 0, errUnknown
+	}
+	v, n := wire.ConsumeVarint(b)
+	if n < 0 {
+		return 0, wire.ParseError(n)
+	}
+	rv := reflect.New(s.Type().Elem()).Elem()
+	rv.SetInt(int64(v))
+	s.Set(reflect.Append(s, rv))
+	return n, nil
 }
 
 var coderEnumSlice = pointerCoderFuncs{
@@ -105,11 +142,34 @@ var coderEnumSlice = pointerCoderFuncs{
 }
 
 func sizeEnumPackedSlice(p pointer, tagsize int, opts marshalOptions) (size int) {
-	return sizeEnumPackedSliceReflect(p.v.Elem(), tagsize, opts)
+	s := p.v.Elem()
+	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 appendEnumPackedSlice(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
-	return appendEnumPackedSliceReflect(b, p.v.Elem(), wiretag, opts)
+	s := p.v.Elem()
+	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 coderEnumPackedSlice = pointerCoderFuncs{

+ 64 - 63
internal/impl/codec_tables.go

@@ -21,12 +21,12 @@ type pointerCoderFuncs struct {
 	isInit    func(p pointer) error
 }
 
-// ifaceCoderFuncs is a set of interface{} encoding functions.
-type ifaceCoderFuncs struct {
-	size      func(ival interface{}, tagsize int, opts marshalOptions) int
-	marshal   func(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error)
-	unmarshal func(b []byte, ival interface{}, num wire.Number, wtyp wire.Type, opts unmarshalOptions) (interface{}, int, error)
-	isInit    func(ival interface{}) error
+// valueCoderFuncs is a set of protoreflect.Value encoding functions.
+type valueCoderFuncs struct {
+	size      func(v pref.Value, tagsize int, opts marshalOptions) int
+	marshal   func(b []byte, v pref.Value, wiretag uint64, opts marshalOptions) ([]byte, error)
+	unmarshal func(b []byte, v pref.Value, num wire.Number, wtyp wire.Type, opts unmarshalOptions) (pref.Value, int, error)
+	isInit    func(v pref.Value) error
 }
 
 // fieldCoder returns pointer functions for a field, used for operating on
@@ -428,7 +428,7 @@ func fieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
 
 // encoderFuncsForValue returns interface{} value functions for a field, used for
 // extension values and map encoding.
-func encoderFuncsForValue(fd pref.FieldDescriptor, ft reflect.Type) ifaceCoderFuncs {
+func encoderFuncsForValue(fd pref.FieldDescriptor, ft reflect.Type) valueCoderFuncs {
 	switch {
 	case fd.Cardinality() == pref.Repeated && !fd.IsPacked():
 		if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
@@ -438,78 +438,78 @@ func encoderFuncsForValue(fd pref.FieldDescriptor, ft reflect.Type) ifaceCoderFu
 		switch fd.Kind() {
 		case pref.BoolKind:
 			if ft.Kind() == reflect.Bool {
-				return coderBoolSliceIface
+				return coderBoolSliceValue
 			}
 		case pref.EnumKind:
 			if ft.Kind() == reflect.Int32 {
-				return coderEnumSliceIface
+				return coderEnumSliceValue
 			}
 		case pref.Int32Kind:
 			if ft.Kind() == reflect.Int32 {
-				return coderInt32SliceIface
+				return coderInt32SliceValue
 			}
 		case pref.Sint32Kind:
 			if ft.Kind() == reflect.Int32 {
-				return coderSint32SliceIface
+				return coderSint32SliceValue
 			}
 		case pref.Uint32Kind:
 			if ft.Kind() == reflect.Uint32 {
-				return coderUint32SliceIface
+				return coderUint32SliceValue
 			}
 		case pref.Int64Kind:
 			if ft.Kind() == reflect.Int64 {
-				return coderInt64SliceIface
+				return coderInt64SliceValue
 			}
 		case pref.Sint64Kind:
 			if ft.Kind() == reflect.Int64 {
-				return coderSint64SliceIface
+				return coderSint64SliceValue
 			}
 		case pref.Uint64Kind:
 			if ft.Kind() == reflect.Uint64 {
-				return coderUint64SliceIface
+				return coderUint64SliceValue
 			}
 		case pref.Sfixed32Kind:
 			if ft.Kind() == reflect.Int32 {
-				return coderSfixed32SliceIface
+				return coderSfixed32SliceValue
 			}
 		case pref.Fixed32Kind:
 			if ft.Kind() == reflect.Uint32 {
-				return coderFixed32SliceIface
+				return coderFixed32SliceValue
 			}
 		case pref.FloatKind:
 			if ft.Kind() == reflect.Float32 {
-				return coderFloatSliceIface
+				return coderFloatSliceValue
 			}
 		case pref.Sfixed64Kind:
 			if ft.Kind() == reflect.Int64 {
-				return coderSfixed64SliceIface
+				return coderSfixed64SliceValue
 			}
 		case pref.Fixed64Kind:
 			if ft.Kind() == reflect.Uint64 {
-				return coderFixed64SliceIface
+				return coderFixed64SliceValue
 			}
 		case pref.DoubleKind:
 			if ft.Kind() == reflect.Float64 {
-				return coderDoubleSliceIface
+				return coderDoubleSliceValue
 			}
 		case pref.StringKind:
 			if ft.Kind() == reflect.String {
-				return coderStringSliceIface
+				return coderStringSliceValue
 			}
 			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
-				return coderBytesSliceIface
+				return coderBytesSliceValue
 			}
 		case pref.BytesKind:
 			if ft.Kind() == reflect.String {
-				return coderStringSliceIface
+				return coderStringSliceValue
 			}
 			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
-				return coderBytesSliceIface
+				return coderBytesSliceValue
 			}
 		case pref.MessageKind:
-			return coderMessageSliceIface
+			return coderMessageSliceValue
 		case pref.GroupKind:
-			return coderGroupSliceIface
+			return coderGroupSliceValue
 		}
 	case fd.Cardinality() == pref.Repeated && fd.IsPacked():
 		if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
@@ -519,143 +519,144 @@ func encoderFuncsForValue(fd pref.FieldDescriptor, ft reflect.Type) ifaceCoderFu
 		switch fd.Kind() {
 		case pref.BoolKind:
 			if ft.Kind() == reflect.Bool {
-				return coderBoolPackedSliceIface
+				return coderBoolPackedSliceValue
 			}
 		case pref.EnumKind:
 			if ft.Kind() == reflect.Int32 {
-				return coderEnumPackedSliceIface
+				return coderEnumPackedSliceValue
 			}
 		case pref.Int32Kind:
 			if ft.Kind() == reflect.Int32 {
-				return coderInt32PackedSliceIface
+				return coderInt32PackedSliceValue
 			}
 		case pref.Sint32Kind:
 			if ft.Kind() == reflect.Int32 {
-				return coderSint32PackedSliceIface
+				return coderSint32PackedSliceValue
 			}
 		case pref.Uint32Kind:
 			if ft.Kind() == reflect.Uint32 {
-				return coderUint32PackedSliceIface
+				return coderUint32PackedSliceValue
 			}
 		case pref.Int64Kind:
 			if ft.Kind() == reflect.Int64 {
-				return coderInt64PackedSliceIface
+				return coderInt64PackedSliceValue
 			}
 		case pref.Sint64Kind:
 			if ft.Kind() == reflect.Int64 {
-				return coderSint64PackedSliceIface
+				return coderSint64PackedSliceValue
 			}
 		case pref.Uint64Kind:
 			if ft.Kind() == reflect.Uint64 {
-				return coderUint64PackedSliceIface
+				return coderUint64PackedSliceValue
 			}
 		case pref.Sfixed32Kind:
 			if ft.Kind() == reflect.Int32 {
-				return coderSfixed32PackedSliceIface
+				return coderSfixed32PackedSliceValue
 			}
 		case pref.Fixed32Kind:
 			if ft.Kind() == reflect.Uint32 {
-				return coderFixed32PackedSliceIface
+				return coderFixed32PackedSliceValue
 			}
 		case pref.FloatKind:
 			if ft.Kind() == reflect.Float32 {
-				return coderFloatPackedSliceIface
+				return coderFloatPackedSliceValue
 			}
 		case pref.Sfixed64Kind:
 			if ft.Kind() == reflect.Int64 {
-				return coderSfixed64PackedSliceIface
+				return coderSfixed64PackedSliceValue
 			}
 		case pref.Fixed64Kind:
 			if ft.Kind() == reflect.Uint64 {
-				return coderFixed64PackedSliceIface
+				return coderFixed64PackedSliceValue
 			}
 		case pref.DoubleKind:
 			if ft.Kind() == reflect.Float64 {
-				return coderDoublePackedSliceIface
+				return coderDoublePackedSliceValue
 			}
 		}
 	default:
 		switch fd.Kind() {
+		default:
 		case pref.BoolKind:
 			if ft.Kind() == reflect.Bool {
-				return coderBoolIface
+				return coderBoolValue
 			}
 		case pref.EnumKind:
 			if ft.Kind() == reflect.Int32 {
-				return coderEnumIface
+				return coderEnumValue
 			}
 		case pref.Int32Kind:
 			if ft.Kind() == reflect.Int32 {
-				return coderInt32Iface
+				return coderInt32Value
 			}
 		case pref.Sint32Kind:
 			if ft.Kind() == reflect.Int32 {
-				return coderSint32Iface
+				return coderSint32Value
 			}
 		case pref.Uint32Kind:
 			if ft.Kind() == reflect.Uint32 {
-				return coderUint32Iface
+				return coderUint32Value
 			}
 		case pref.Int64Kind:
 			if ft.Kind() == reflect.Int64 {
-				return coderInt64Iface
+				return coderInt64Value
 			}
 		case pref.Sint64Kind:
 			if ft.Kind() == reflect.Int64 {
-				return coderSint64Iface
+				return coderSint64Value
 			}
 		case pref.Uint64Kind:
 			if ft.Kind() == reflect.Uint64 {
-				return coderUint64Iface
+				return coderUint64Value
 			}
 		case pref.Sfixed32Kind:
 			if ft.Kind() == reflect.Int32 {
-				return coderSfixed32Iface
+				return coderSfixed32Value
 			}
 		case pref.Fixed32Kind:
 			if ft.Kind() == reflect.Uint32 {
-				return coderFixed32Iface
+				return coderFixed32Value
 			}
 		case pref.FloatKind:
 			if ft.Kind() == reflect.Float32 {
-				return coderFloatIface
+				return coderFloatValue
 			}
 		case pref.Sfixed64Kind:
 			if ft.Kind() == reflect.Int64 {
-				return coderSfixed64Iface
+				return coderSfixed64Value
 			}
 		case pref.Fixed64Kind:
 			if ft.Kind() == reflect.Uint64 {
-				return coderFixed64Iface
+				return coderFixed64Value
 			}
 		case pref.DoubleKind:
 			if ft.Kind() == reflect.Float64 {
-				return coderDoubleIface
+				return coderDoubleValue
 			}
 		case pref.StringKind:
 			if ft.Kind() == reflect.String && strs.EnforceUTF8(fd) {
-				return coderStringIfaceValidateUTF8
+				return coderStringValueValidateUTF8
 			}
 			if ft.Kind() == reflect.String {
-				return coderStringIface
+				return coderStringValue
 			}
 			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 && strs.EnforceUTF8(fd) {
-				return coderBytesIfaceValidateUTF8
+				return coderBytesValueValidateUTF8
 			}
 			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
-				return coderBytesIface
+				return coderBytesValue
 			}
 		case pref.BytesKind:
 			if ft.Kind() == reflect.String {
-				return coderStringIface
+				return coderStringValue
 			}
 			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
-				return coderBytesIface
+				return coderBytesValue
 			}
 		case pref.MessageKind:
-			return coderMessageIface
+			return coderMessageValue
 		case pref.GroupKind:
-			return makeGroupValueCoder(fd, ft)
+			return coderGroupValue
 		}
 	}
 	panic(fmt.Errorf("invalid type: no encoder for %v %v %v/%v", fd.FullName(), fd.Cardinality(), fd.Kind(), ft))

+ 6 - 7
internal/impl/convert_map.go

@@ -90,13 +90,12 @@ func (ms *mapReflect) Clear(k pref.MapKey) {
 	ms.v.SetMapIndex(rk, reflect.Value{})
 }
 func (ms *mapReflect) Range(f func(pref.MapKey, pref.Value) bool) {
-	for _, k := range ms.v.MapKeys() {
-		if v := ms.v.MapIndex(k); v.IsValid() {
-			pk := ms.keyConv.PBValueOf(k).MapKey()
-			pv := ms.valConv.PBValueOf(v)
-			if !f(pk, pv) {
-				return
-			}
+	iter := mapRange(ms.v)
+	for iter.Next() {
+		k := ms.keyConv.PBValueOf(iter.Key()).MapKey()
+		v := ms.valConv.PBValueOf(iter.Value())
+		if !f(k, v) {
+			return
 		}
 	}
 }

+ 4 - 5
internal/impl/decode.go

@@ -145,24 +145,23 @@ func (mi *MessageInfo) unmarshalExtension(b []byte, num wire.Number, wtyp wire.T
 			}
 			return 0, err
 		}
-		x.SetType(xt)
 	}
 	xi := mi.extensionFieldInfo(xt)
 	if xi.funcs.unmarshal == nil {
 		return 0, errUnknown
 	}
-	ival := x.GetValue()
-	if ival == nil && xi.unmarshalNeedsValue {
+	ival := x.Value()
+	if !ival.IsValid() && xi.unmarshalNeedsValue {
 		// Create a new message, list, or map value to fill in.
 		// For enums, create a prototype value to let the unmarshal func know the
 		// concrete type.
-		ival = xt.InterfaceOf(xt.New())
+		ival = xt.New()
 	}
 	v, n, err := xi.funcs.unmarshal(b, ival, num, wtyp, opts)
 	if err != nil {
 		return 0, err
 	}
-	x.SetEagerValue(v)
+	x.Set(xt, v)
 	exts[int32(num)] = x
 	return n, nil
 }

+ 6 - 6
internal/impl/encode.go

@@ -144,11 +144,11 @@ func (mi *MessageInfo) sizeExtensions(ext *map[int32]ExtensionField, opts marsha
 		return 0
 	}
 	for _, x := range *ext {
-		xi := mi.extensionFieldInfo(x.GetType())
+		xi := mi.extensionFieldInfo(x.Type())
 		if xi.funcs.size == nil {
 			continue
 		}
-		n += xi.funcs.size(x.GetValue(), xi.tagsize, opts)
+		n += xi.funcs.size(x.Value(), xi.tagsize, opts)
 	}
 	return n
 }
@@ -165,8 +165,8 @@ func (mi *MessageInfo) appendExtensions(b []byte, ext *map[int32]ExtensionField,
 		// Fast-path for one extension: Don't bother sorting the keys.
 		var err error
 		for _, x := range *ext {
-			xi := mi.extensionFieldInfo(x.GetType())
-			b, err = xi.funcs.marshal(b, x.GetValue(), xi.wiretag, opts)
+			xi := mi.extensionFieldInfo(x.Type())
+			b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
 		}
 		return b, err
 	default:
@@ -180,8 +180,8 @@ func (mi *MessageInfo) appendExtensions(b []byte, ext *map[int32]ExtensionField,
 		var err error
 		for _, k := range keys {
 			x := (*ext)[int32(k)]
-			xi := mi.extensionFieldInfo(x.GetType())
-			b, err = xi.funcs.marshal(b, x.GetValue(), xi.wiretag, opts)
+			xi := mi.extensionFieldInfo(x.Type())
+			b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
 			if err != nil {
 				return b, err
 			}

+ 3 - 3
internal/impl/isinit.go

@@ -66,12 +66,12 @@ func (mi *MessageInfo) isInitExtensions(ext *map[int32]ExtensionField) error {
 		return nil
 	}
 	for _, x := range *ext {
-		ei := mi.extensionFieldInfo(x.GetType())
+		ei := mi.extensionFieldInfo(x.Type())
 		if ei.funcs.isInit == nil {
 			continue
 		}
-		v := x.GetValue()
-		if v == nil {
+		v := x.Value()
+		if !v.IsValid() {
 			continue
 		}
 		if err := ei.funcs.isInit(v); err != nil {

+ 7 - 5
internal/impl/message_reflect.go

@@ -119,7 +119,7 @@ func (m *extensionMap) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
 	if m != nil {
 		for _, x := range *m {
 			xt := x.GetType()
-			if !f(xt.TypeDescriptor(), xt.ValueOf(x.GetValue())) {
+			if !f(xt.TypeDescriptor(), x.Value()) {
 				return
 			}
 		}
@@ -138,18 +138,20 @@ func (m *extensionMap) Get(xt pref.ExtensionType) pref.Value {
 	xd := xt.TypeDescriptor()
 	if m != nil {
 		if x, ok := (*m)[int32(xd.Number())]; ok {
-			return xt.ValueOf(x.GetValue())
+			return x.Value()
 		}
 	}
 	return xt.Zero()
 }
 func (m *extensionMap) Set(xt pref.ExtensionType, v pref.Value) {
+	if !xt.IsValidValue(v) {
+		panic(fmt.Errorf("%v: assigning invalid value", xt.TypeDescriptor().FullName()))
+	}
 	if *m == nil {
 		*m = make(map[int32]ExtensionField)
 	}
 	var x ExtensionField
-	x.SetType(xt)
-	x.SetEagerValue(xt.InterfaceOf(v))
+	x.Set(xt, v)
 	(*m)[int32(xt.TypeDescriptor().Number())] = x
 }
 func (m *extensionMap) Mutable(xt pref.ExtensionType) pref.Value {
@@ -158,7 +160,7 @@ func (m *extensionMap) Mutable(xt pref.ExtensionType) pref.Value {
 		panic("invalid Mutable on field with non-composite type")
 	}
 	if x, ok := (*m)[int32(xd.Number())]; ok {
-		return xt.ValueOf(x.GetValue())
+		return x.Value()
 	}
 	v := xt.New()
 	m.Set(xt, v)

Vissa filer visades inte eftersom för många filer har ändrats