internal/impl: abstract away ExtensionDescV1 as the underlying descriptor
Add ExtensionField.{SetType,GetType} to hide the fact that the underlying
descriptor is actually an ExtensionDescV1.
Change-Id: I1d0595484ced0a88d2df0852a732fdf0fe9aa232
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/180538
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/impl/codec_extension.go b/internal/impl/codec_extension.go
index 714dec7..69d5a96 100644
--- a/internal/impl/codec_extension.go
+++ b/internal/impl/codec_extension.go
@@ -5,7 +5,11 @@
package impl
import (
+ "sync"
+ "sync/atomic"
+
"google.golang.org/protobuf/internal/encoding/wire"
+ pref "google.golang.org/protobuf/reflect/protoreflect"
piface "google.golang.org/protobuf/runtime/protoiface"
)
@@ -15,29 +19,109 @@
funcs ifaceCoderFuncs
}
-func (mi *MessageInfo) extensionFieldInfo(desc *piface.ExtensionDescV1) *extensionFieldInfo {
+func (mi *MessageInfo) extensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
// As of this time (Go 1.12, linux/amd64), an RWMutex benchmarks as faster
// than a sync.Map.
mi.extensionFieldInfosMu.RLock()
- e, ok := mi.extensionFieldInfos[desc]
+ e, ok := mi.extensionFieldInfos[xt]
mi.extensionFieldInfosMu.RUnlock()
if ok {
return e
}
- etype := extensionTypeFromDesc(desc)
- wiretag := wire.EncodeTag(etype.Number(), wireTypes[etype.Kind()])
+ wiretag := wire.EncodeTag(xt.Number(), wireTypes[xt.Kind()])
e = &extensionFieldInfo{
wiretag: wiretag,
tagsize: wire.SizeVarint(wiretag),
- funcs: encoderFuncsForValue(etype, etype.GoType()),
+ funcs: encoderFuncsForValue(xt, xt.GoType()),
}
mi.extensionFieldInfosMu.Lock()
if mi.extensionFieldInfos == nil {
- mi.extensionFieldInfos = make(map[*piface.ExtensionDescV1]*extensionFieldInfo)
+ mi.extensionFieldInfos = make(map[pref.ExtensionType]*extensionFieldInfo)
}
- mi.extensionFieldInfos[desc] = e
+ mi.extensionFieldInfos[xt] = e
mi.extensionFieldInfosMu.Unlock()
return e
}
+
+type ExtensionField struct {
+ // Desc is the descriptor information for the extension field.
+ // It must be populated if value is populated.
+ Desc *piface.ExtensionDescV1 // TODO: unexport and switch to protoreflect.ExtensionType
+
+ // value is either the value of GetValue,
+ // or a *lazyExtensionValue that then returns the value of GetValue.
+ value interface{} // TODO: switch to protoreflect.Value
+}
+
+func (f ExtensionField) HasType() bool {
+ return f.Desc != nil
+}
+func (f ExtensionField) GetType() pref.ExtensionType {
+ return legacyExtensionTypeFromDesc(f.Desc)
+}
+func (f *ExtensionField) SetType(t pref.ExtensionType) {
+ f.Desc = legacyExtensionDescFromType(t)
+}
+
+// HasValue reports whether a value is set for the extension field.
+// This may be called concurrently.
+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
+func (f ExtensionField) GetValue() interface{} {
+ if f, ok := f.value.(*lazyExtensionValue); ok {
+ return f.GetValue()
+ }
+ return 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
+}
+
+// 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}
+}
+
+type lazyExtensionValue struct {
+ once uint32 // atomically set if value is valid
+ mu sync.Mutex // protects value
+ value interface{} // either the value itself or a func() interface{}
+}
+
+func (v *lazyExtensionValue) GetValue() interface{} {
+ if atomic.LoadUint32(&v.once) == 0 {
+ v.mu.Lock()
+ if f, ok := v.value.(func() interface{}); ok {
+ v.value = f()
+ }
+ atomic.StoreUint32(&v.once, 1)
+ v.mu.Unlock()
+ }
+ return v.value
+}
diff --git a/internal/impl/encode.go b/internal/impl/encode.go
index e3ba7cf..52ad799 100644
--- a/internal/impl/encode.go
+++ b/internal/impl/encode.go
@@ -130,21 +130,21 @@
return b, nerr.E
}
-func (mi *MessageInfo) sizeExtensions(ext *legacyExtensionMap, opts marshalOptions) (n int) {
+func (mi *MessageInfo) sizeExtensions(ext *map[int32]ExtensionField, opts marshalOptions) (n int) {
if ext == nil {
return 0
}
- for _, e := range *ext {
- ei := mi.extensionFieldInfo(e.Desc)
- if ei.funcs.size == nil {
+ for _, x := range *ext {
+ xi := mi.extensionFieldInfo(x.GetType())
+ if xi.funcs.size == nil {
continue
}
- n += ei.funcs.size(e.value, ei.tagsize, opts)
+ n += xi.funcs.size(x.GetValue(), xi.tagsize, opts)
}
return n
}
-func (mi *MessageInfo) appendExtensions(b []byte, ext *legacyExtensionMap, opts marshalOptions) ([]byte, error) {
+func (mi *MessageInfo) appendExtensions(b []byte, ext *map[int32]ExtensionField, opts marshalOptions) ([]byte, error) {
if ext == nil {
return b, nil
}
@@ -155,9 +155,9 @@
case 1:
// Fast-path for one extension: Don't bother sorting the keys.
var err error
- for _, e := range *ext {
- ei := mi.extensionFieldInfo(e.Desc)
- b, err = ei.funcs.marshal(b, e.value, ei.wiretag, opts)
+ for _, x := range *ext {
+ xi := mi.extensionFieldInfo(x.GetType())
+ b, err = xi.funcs.marshal(b, x.GetValue(), xi.wiretag, opts)
}
return b, err
default:
@@ -171,9 +171,9 @@
var err error
var nerr errors.NonFatal
for _, k := range keys {
- e := (*ext)[int32(k)]
- ei := mi.extensionFieldInfo(e.Desc)
- b, err = ei.funcs.marshal(b, e.value, ei.wiretag, opts)
+ x := (*ext)[int32(k)]
+ xi := mi.extensionFieldInfo(x.GetType())
+ b, err = xi.funcs.marshal(b, x.GetValue(), xi.wiretag, opts)
if !nerr.Merge(err) {
return b, err
}
diff --git a/internal/impl/legacy_extension_test.go b/internal/impl/legacy_extension_test.go
index 13a2c6d..6ccfa40 100644
--- a/internal/impl/legacy_extension_test.go
+++ b/internal/impl/legacy_extension_test.go
@@ -18,7 +18,7 @@
type legacyExtendedMessage struct {
XXX_unrecognized []byte
- XXX_InternalExtensions map[int32]pimpl.ExtensionFieldV1
+ XXX_InternalExtensions map[int32]pimpl.ExtensionField
}
func (*legacyExtendedMessage) Reset() {}
diff --git a/internal/impl/legacy_test.go b/internal/impl/legacy_test.go
index d6ca941..c1ba55e 100644
--- a/internal/impl/legacy_test.go
+++ b/internal/impl/legacy_test.go
@@ -27,7 +27,7 @@
type legacyTestMessage struct {
XXX_unrecognized []byte
- XXX_InternalExtensions map[int32]pimpl.ExtensionFieldV1
+ XXX_InternalExtensions map[int32]pimpl.ExtensionField
}
func (*legacyTestMessage) Reset() {}
diff --git a/internal/impl/message.go b/internal/impl/message.go
index d64ee7f..6db60f1 100644
--- a/internal/impl/message.go
+++ b/internal/impl/message.go
@@ -48,7 +48,7 @@
sizecacheOffset offset
unknownOffset offset
extensionFieldInfosMu sync.RWMutex
- extensionFieldInfos map[*piface.ExtensionDescV1]*extensionFieldInfo
+ extensionFieldInfos map[pref.ExtensionType]*extensionFieldInfo
}
var prefMessageType = reflect.TypeOf((*pref.Message)(nil)).Elem()
diff --git a/internal/impl/message_field_extension.go b/internal/impl/message_field_extension.go
index 3c403af..b537775 100644
--- a/internal/impl/message_field_extension.go
+++ b/internal/impl/message_field_extension.go
@@ -6,11 +6,8 @@
import (
"reflect"
- "sync"
- "sync/atomic"
pref "google.golang.org/protobuf/reflect/protoreflect"
- piface "google.golang.org/protobuf/runtime/protoiface"
)
func makeLegacyExtensionFieldsFunc(t reflect.Type) func(p *messageDataType) pref.KnownFields {
@@ -26,7 +23,7 @@
}
}
-var extType = reflect.TypeOf(map[int32]ExtensionFieldV1{})
+var extType = reflect.TypeOf(map[int32]ExtensionField{})
func makeLegacyExtensionMapFunc(t reflect.Type) func(*messageDataType) *legacyExtensionMap {
fx, _ := t.FieldByName("XXX_extensions")
@@ -40,7 +37,7 @@
fieldOffset := offsetOf(fx)
return func(p *messageDataType) *legacyExtensionMap {
v := p.p.Apply(fieldOffset).AsValueOf(fx.Type).Interface()
- return (*legacyExtensionMap)(v.(*map[int32]ExtensionFieldV1))
+ return (*legacyExtensionMap)(v.(*map[int32]ExtensionField))
}
}
@@ -50,7 +47,7 @@
}
func (p legacyExtensionFields) Len() (n int) {
- p.x.Range(func(num pref.FieldNumber, _ ExtensionFieldV1) bool {
+ p.x.Range(func(num pref.FieldNumber, _ ExtensionField) bool {
if p.Has(pref.FieldNumber(num)) {
n++
}
@@ -64,7 +61,7 @@
if !x.HasValue() {
return false
}
- t := extensionTypeFromDesc(x.Desc)
+ t := x.GetType()
d := t.Descriptor()
if d.IsList() {
return t.ValueOf(x.GetValue()).List().Len() > 0
@@ -74,10 +71,10 @@
func (p legacyExtensionFields) Get(n pref.FieldNumber) pref.Value {
x := p.x.Get(n)
- if x.Desc == nil {
+ if !x.HasType() {
return pref.Value{}
}
- t := extensionTypeFromDesc(x.Desc)
+ t := x.GetType()
d := t.Descriptor()
if !x.HasValue() {
// NOTE: x.Value is never nil for Lists since they are always populated
@@ -92,20 +89,20 @@
func (p legacyExtensionFields) Set(n pref.FieldNumber, v pref.Value) {
x := p.x.Get(n)
- if x.Desc == nil {
+ if !x.HasType() {
panic("no extension descriptor registered")
}
- t := extensionTypeFromDesc(x.Desc)
+ t := x.GetType()
x.SetEagerValue(t.InterfaceOf(v))
p.x.Set(n, x)
}
func (p legacyExtensionFields) Clear(n pref.FieldNumber) {
x := p.x.Get(n)
- if x.Desc == nil {
+ if !x.HasType() {
return
}
- t := extensionTypeFromDesc(x.Desc)
+ t := x.GetType()
d := t.Descriptor()
if d.IsList() {
t.ValueOf(x.GetValue()).List().Truncate(0)
@@ -120,7 +117,7 @@
}
func (p legacyExtensionFields) Range(f func(pref.FieldNumber, pref.Value) bool) {
- p.x.Range(func(n pref.FieldNumber, x ExtensionFieldV1) bool {
+ p.x.Range(func(n pref.FieldNumber, x ExtensionField) bool {
if p.Has(n) {
return f(n, p.Get(n))
}
@@ -130,10 +127,10 @@
func (p legacyExtensionFields) NewMessage(n pref.FieldNumber) pref.Message {
x := p.x.Get(n)
- if x.Desc == nil {
+ if !x.HasType() {
panic("no extension descriptor registered")
}
- xt := extensionTypeFromDesc(x.Desc)
+ xt := x.GetType()
return xt.New().Message()
}
@@ -144,8 +141,8 @@
type legacyExtensionTypes legacyExtensionFields
func (p legacyExtensionTypes) Len() (n int) {
- p.x.Range(func(_ pref.FieldNumber, x ExtensionFieldV1) bool {
- if x.Desc != nil {
+ p.x.Range(func(_ pref.FieldNumber, x ExtensionField) bool {
+ if x.HasType() {
n++
}
return true
@@ -162,10 +159,10 @@
panic("invalid extension field number")
}
x := p.x.Get(d.Number())
- if x.Desc != nil {
+ if x.HasType() {
panic("extension descriptor already registered")
}
- x.Desc = extensionDescFromType(t)
+ x.SetType(t)
if d.IsList() {
// If the field is repeated, initialize the entry with an empty list
// so that future Get operations can return a mutable and concrete list.
@@ -195,16 +192,16 @@
func (p legacyExtensionTypes) ByNumber(n pref.FieldNumber) pref.ExtensionType {
x := p.x.Get(n)
- if x.Desc != nil {
- return extensionTypeFromDesc(x.Desc)
+ if x.HasType() {
+ return x.GetType()
}
return nil
}
func (p legacyExtensionTypes) ByName(s pref.FullName) (t pref.ExtensionType) {
- p.x.Range(func(_ pref.FieldNumber, x ExtensionFieldV1) bool {
- if x.Desc != nil && x.Desc.Name == string(s) {
- t = extensionTypeFromDesc(x.Desc)
+ p.x.Range(func(_ pref.FieldNumber, x ExtensionField) bool {
+ if x.HasType() && x.GetType().FullName() == s {
+ t = x.GetType()
return false
}
return true
@@ -213,9 +210,9 @@
}
func (p legacyExtensionTypes) Range(f func(pref.ExtensionType) bool) {
- p.x.Range(func(_ pref.FieldNumber, x ExtensionFieldV1) bool {
- if x.Desc != nil {
- if !f(extensionTypeFromDesc(x.Desc)) {
+ p.x.Range(func(_ pref.FieldNumber, x ExtensionField) bool {
+ if x.HasType() {
+ if !f(x.GetType()) {
return false
}
}
@@ -223,106 +220,7 @@
})
}
-func extensionDescFromType(typ pref.ExtensionType) *piface.ExtensionDescV1 {
- if xt, ok := typ.(interface {
- ProtoLegacyExtensionDesc() *piface.ExtensionDescV1
- }); ok {
- if desc := xt.ProtoLegacyExtensionDesc(); desc != nil {
- return desc
- }
- }
- return Export{}.ExtensionDescFromType(typ)
-}
-
-func extensionTypeFromDesc(desc *piface.ExtensionDescV1) pref.ExtensionType {
- if desc.Type != nil {
- return desc.Type
- }
- return Export{}.ExtensionTypeFromDesc(desc)
-}
-
-type ExtensionFieldV1 struct {
- // TODO: We should turn this into a type alias to an unnamed type,
- // which means that v1 can have the same struct, and we no longer have to
- // export this from the v2 API.
-
- // When an extension is stored in a message using SetExtension
- // only desc and value are set. When the message is marshaled
- // Raw will be set to the encoded form of the message.
- //
- // When a message is unmarshaled and contains extensions, each
- // extension will have only Raw set. When such an extension is
- // accessed using GetExtension (or GetExtensions) desc and value
- // will be set.
- Desc *piface.ExtensionDescV1 // TODO: switch to protoreflect.ExtensionType
-
- // value is either the value of GetValue,
- // or a *lazyExtensionValue that then returns the value of GetValue.
- value interface{}
-}
-
-// HasValue reports whether a value is set for the extension field.
-// This may be called concurrently.
-func (f ExtensionFieldV1) 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
-func (f ExtensionFieldV1) GetValue() interface{} {
- if f, ok := f.value.(*lazyExtensionValue); ok {
- return f.GetValue()
- }
- return f.value
-}
-
-// SetEagerValue sets the current value of the extension.
-// This must not be called concurrently.
-func (f *ExtensionFieldV1) SetEagerValue(v interface{}) {
- f.value = v
-}
-
-// 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 *ExtensionFieldV1) SetLazyValue(v func() interface{}) {
- f.value = &lazyExtensionValue{value: v}
-}
-
-type lazyExtensionValue struct {
- once uint32 // atomically set if value is valid
- mu sync.Mutex // protects value
- value interface{} // either the value itself or a func() interface{}
-}
-
-func (v *lazyExtensionValue) GetValue() interface{} {
- if atomic.LoadUint32(&v.once) == 0 {
- v.mu.Lock()
- if f, ok := v.value.(func() interface{}); ok {
- v.value = f()
- }
- atomic.StoreUint32(&v.once, 1)
- v.mu.Unlock()
- }
- return v.value
-}
-
-type legacyExtensionMap map[int32]ExtensionFieldV1
+type legacyExtensionMap map[int32]ExtensionField
func (m legacyExtensionMap) Len() int {
return len(m)
@@ -331,19 +229,19 @@
_, ok := m[int32(n)]
return ok
}
-func (m legacyExtensionMap) Get(n pref.FieldNumber) ExtensionFieldV1 {
+func (m legacyExtensionMap) Get(n pref.FieldNumber) ExtensionField {
return m[int32(n)]
}
-func (m *legacyExtensionMap) Set(n pref.FieldNumber, x ExtensionFieldV1) {
+func (m *legacyExtensionMap) Set(n pref.FieldNumber, x ExtensionField) {
if *m == nil {
- *m = make(map[int32]ExtensionFieldV1)
+ *m = make(map[int32]ExtensionField)
}
(*m)[int32(n)] = x
}
func (m *legacyExtensionMap) Clear(n pref.FieldNumber) {
delete(*m, int32(n))
}
-func (m legacyExtensionMap) Range(f func(pref.FieldNumber, ExtensionFieldV1) bool) {
+func (m legacyExtensionMap) Range(f func(pref.FieldNumber, ExtensionField) bool) {
for n, x := range m {
if !f(pref.FieldNumber(n), x) {
return
diff --git a/internal/impl/pointer_reflect.go b/internal/impl/pointer_reflect.go
index b851b1b..207c20b 100644
--- a/internal/impl/pointer_reflect.go
+++ b/internal/impl/pointer_reflect.go
@@ -98,8 +98,8 @@
func (p pointer) StringSlice() *[]string { return p.v.Interface().(*[]string) }
func (p pointer) Bytes() *[]byte { return p.v.Interface().(*[]byte) }
func (p pointer) BytesSlice() *[][]byte { return p.v.Interface().(*[][]byte) }
-func (p pointer) Extensions() *legacyExtensionMap {
- return (*legacyExtensionMap)(p.v.Interface().(*map[int32]ExtensionFieldV1))
+func (p pointer) Extensions() *map[int32]ExtensionField {
+ return p.v.Interface().(*map[int32]ExtensionField)
}
func (p pointer) Elem() pointer {
diff --git a/internal/impl/pointer_unsafe.go b/internal/impl/pointer_unsafe.go
index f04a561..39f1995 100644
--- a/internal/impl/pointer_unsafe.go
+++ b/internal/impl/pointer_unsafe.go
@@ -73,33 +73,33 @@
return p.AsValueOf(t).Interface()
}
-func (p pointer) Bool() *bool { return (*bool)(p.p) }
-func (p pointer) BoolPtr() **bool { return (**bool)(p.p) }
-func (p pointer) BoolSlice() *[]bool { return (*[]bool)(p.p) }
-func (p pointer) Int32() *int32 { return (*int32)(p.p) }
-func (p pointer) Int32Ptr() **int32 { return (**int32)(p.p) }
-func (p pointer) Int32Slice() *[]int32 { return (*[]int32)(p.p) }
-func (p pointer) Int64() *int64 { return (*int64)(p.p) }
-func (p pointer) Int64Ptr() **int64 { return (**int64)(p.p) }
-func (p pointer) Int64Slice() *[]int64 { return (*[]int64)(p.p) }
-func (p pointer) Uint32() *uint32 { return (*uint32)(p.p) }
-func (p pointer) Uint32Ptr() **uint32 { return (**uint32)(p.p) }
-func (p pointer) Uint32Slice() *[]uint32 { return (*[]uint32)(p.p) }
-func (p pointer) Uint64() *uint64 { return (*uint64)(p.p) }
-func (p pointer) Uint64Ptr() **uint64 { return (**uint64)(p.p) }
-func (p pointer) Uint64Slice() *[]uint64 { return (*[]uint64)(p.p) }
-func (p pointer) Float32() *float32 { return (*float32)(p.p) }
-func (p pointer) Float32Ptr() **float32 { return (**float32)(p.p) }
-func (p pointer) Float32Slice() *[]float32 { return (*[]float32)(p.p) }
-func (p pointer) Float64() *float64 { return (*float64)(p.p) }
-func (p pointer) Float64Ptr() **float64 { return (**float64)(p.p) }
-func (p pointer) Float64Slice() *[]float64 { return (*[]float64)(p.p) }
-func (p pointer) String() *string { return (*string)(p.p) }
-func (p pointer) StringPtr() **string { return (**string)(p.p) }
-func (p pointer) StringSlice() *[]string { return (*[]string)(p.p) }
-func (p pointer) Bytes() *[]byte { return (*[]byte)(p.p) }
-func (p pointer) BytesSlice() *[][]byte { return (*[][]byte)(p.p) }
-func (p pointer) Extensions() *legacyExtensionMap { return (*legacyExtensionMap)(p.p) }
+func (p pointer) Bool() *bool { return (*bool)(p.p) }
+func (p pointer) BoolPtr() **bool { return (**bool)(p.p) }
+func (p pointer) BoolSlice() *[]bool { return (*[]bool)(p.p) }
+func (p pointer) Int32() *int32 { return (*int32)(p.p) }
+func (p pointer) Int32Ptr() **int32 { return (**int32)(p.p) }
+func (p pointer) Int32Slice() *[]int32 { return (*[]int32)(p.p) }
+func (p pointer) Int64() *int64 { return (*int64)(p.p) }
+func (p pointer) Int64Ptr() **int64 { return (**int64)(p.p) }
+func (p pointer) Int64Slice() *[]int64 { return (*[]int64)(p.p) }
+func (p pointer) Uint32() *uint32 { return (*uint32)(p.p) }
+func (p pointer) Uint32Ptr() **uint32 { return (**uint32)(p.p) }
+func (p pointer) Uint32Slice() *[]uint32 { return (*[]uint32)(p.p) }
+func (p pointer) Uint64() *uint64 { return (*uint64)(p.p) }
+func (p pointer) Uint64Ptr() **uint64 { return (**uint64)(p.p) }
+func (p pointer) Uint64Slice() *[]uint64 { return (*[]uint64)(p.p) }
+func (p pointer) Float32() *float32 { return (*float32)(p.p) }
+func (p pointer) Float32Ptr() **float32 { return (**float32)(p.p) }
+func (p pointer) Float32Slice() *[]float32 { return (*[]float32)(p.p) }
+func (p pointer) Float64() *float64 { return (*float64)(p.p) }
+func (p pointer) Float64Ptr() **float64 { return (**float64)(p.p) }
+func (p pointer) Float64Slice() *[]float64 { return (*[]float64)(p.p) }
+func (p pointer) String() *string { return (*string)(p.p) }
+func (p pointer) StringPtr() **string { return (**string)(p.p) }
+func (p pointer) StringSlice() *[]string { return (*[]string)(p.p) }
+func (p pointer) Bytes() *[]byte { return (*[]byte)(p.p) }
+func (p pointer) BytesSlice() *[][]byte { return (*[][]byte)(p.p) }
+func (p pointer) Extensions() *map[int32]ExtensionField { return (*map[int32]ExtensionField)(p.p) }
func (p pointer) Elem() pointer {
return pointer{p: *(*unsafe.Pointer)(p.p)}
diff --git a/runtime/protoimpl/impl.go b/runtime/protoimpl/impl.go
index fac3cfc..e28bfc2 100644
--- a/runtime/protoimpl/impl.go
+++ b/runtime/protoimpl/impl.go
@@ -62,11 +62,11 @@
FileBuilder = fileinit.FileBuilder
// TODO: Change these to more efficient data structures.
- ExtensionFields = map[int32]impl.ExtensionFieldV1
+ ExtensionFields = map[int32]impl.ExtensionField
UnknownFields = []byte
SizeCache = int32
- ExtensionFieldV1 = impl.ExtensionFieldV1
+ ExtensionFieldV1 = impl.ExtensionField
)
var X impl.Export