xref: /aosp_15_r20/external/golang-protobuf/internal/impl/message_reflect_field.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2018 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsenpackage impl
6*1c12ee1eSDan Willemsen
7*1c12ee1eSDan Willemsenimport (
8*1c12ee1eSDan Willemsen	"fmt"
9*1c12ee1eSDan Willemsen	"math"
10*1c12ee1eSDan Willemsen	"reflect"
11*1c12ee1eSDan Willemsen	"sync"
12*1c12ee1eSDan Willemsen
13*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/flags"
14*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
15*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoregistry"
16*1c12ee1eSDan Willemsen)
17*1c12ee1eSDan Willemsen
18*1c12ee1eSDan Willemsentype fieldInfo struct {
19*1c12ee1eSDan Willemsen	fieldDesc protoreflect.FieldDescriptor
20*1c12ee1eSDan Willemsen
21*1c12ee1eSDan Willemsen	// These fields are used for protobuf reflection support.
22*1c12ee1eSDan Willemsen	has        func(pointer) bool
23*1c12ee1eSDan Willemsen	clear      func(pointer)
24*1c12ee1eSDan Willemsen	get        func(pointer) protoreflect.Value
25*1c12ee1eSDan Willemsen	set        func(pointer, protoreflect.Value)
26*1c12ee1eSDan Willemsen	mutable    func(pointer) protoreflect.Value
27*1c12ee1eSDan Willemsen	newMessage func() protoreflect.Message
28*1c12ee1eSDan Willemsen	newField   func() protoreflect.Value
29*1c12ee1eSDan Willemsen}
30*1c12ee1eSDan Willemsen
31*1c12ee1eSDan Willemsenfunc fieldInfoForMissing(fd protoreflect.FieldDescriptor) fieldInfo {
32*1c12ee1eSDan Willemsen	// This never occurs for generated message types.
33*1c12ee1eSDan Willemsen	// It implies that a hand-crafted type has missing Go fields
34*1c12ee1eSDan Willemsen	// for specific protobuf message fields.
35*1c12ee1eSDan Willemsen	return fieldInfo{
36*1c12ee1eSDan Willemsen		fieldDesc: fd,
37*1c12ee1eSDan Willemsen		has: func(p pointer) bool {
38*1c12ee1eSDan Willemsen			return false
39*1c12ee1eSDan Willemsen		},
40*1c12ee1eSDan Willemsen		clear: func(p pointer) {
41*1c12ee1eSDan Willemsen			panic("missing Go struct field for " + string(fd.FullName()))
42*1c12ee1eSDan Willemsen		},
43*1c12ee1eSDan Willemsen		get: func(p pointer) protoreflect.Value {
44*1c12ee1eSDan Willemsen			return fd.Default()
45*1c12ee1eSDan Willemsen		},
46*1c12ee1eSDan Willemsen		set: func(p pointer, v protoreflect.Value) {
47*1c12ee1eSDan Willemsen			panic("missing Go struct field for " + string(fd.FullName()))
48*1c12ee1eSDan Willemsen		},
49*1c12ee1eSDan Willemsen		mutable: func(p pointer) protoreflect.Value {
50*1c12ee1eSDan Willemsen			panic("missing Go struct field for " + string(fd.FullName()))
51*1c12ee1eSDan Willemsen		},
52*1c12ee1eSDan Willemsen		newMessage: func() protoreflect.Message {
53*1c12ee1eSDan Willemsen			panic("missing Go struct field for " + string(fd.FullName()))
54*1c12ee1eSDan Willemsen		},
55*1c12ee1eSDan Willemsen		newField: func() protoreflect.Value {
56*1c12ee1eSDan Willemsen			if v := fd.Default(); v.IsValid() {
57*1c12ee1eSDan Willemsen				return v
58*1c12ee1eSDan Willemsen			}
59*1c12ee1eSDan Willemsen			panic("missing Go struct field for " + string(fd.FullName()))
60*1c12ee1eSDan Willemsen		},
61*1c12ee1eSDan Willemsen	}
62*1c12ee1eSDan Willemsen}
63*1c12ee1eSDan Willemsen
64*1c12ee1eSDan Willemsenfunc fieldInfoForOneof(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter, ot reflect.Type) fieldInfo {
65*1c12ee1eSDan Willemsen	ft := fs.Type
66*1c12ee1eSDan Willemsen	if ft.Kind() != reflect.Interface {
67*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("field %v has invalid type: got %v, want interface kind", fd.FullName(), ft))
68*1c12ee1eSDan Willemsen	}
69*1c12ee1eSDan Willemsen	if ot.Kind() != reflect.Struct {
70*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("field %v has invalid type: got %v, want struct kind", fd.FullName(), ot))
71*1c12ee1eSDan Willemsen	}
72*1c12ee1eSDan Willemsen	if !reflect.PtrTo(ot).Implements(ft) {
73*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("field %v has invalid type: %v does not implement %v", fd.FullName(), ot, ft))
74*1c12ee1eSDan Willemsen	}
75*1c12ee1eSDan Willemsen	conv := NewConverter(ot.Field(0).Type, fd)
76*1c12ee1eSDan Willemsen	isMessage := fd.Message() != nil
77*1c12ee1eSDan Willemsen
78*1c12ee1eSDan Willemsen	// TODO: Implement unsafe fast path?
79*1c12ee1eSDan Willemsen	fieldOffset := offsetOf(fs, x)
80*1c12ee1eSDan Willemsen	return fieldInfo{
81*1c12ee1eSDan Willemsen		// NOTE: The logic below intentionally assumes that oneof fields are
82*1c12ee1eSDan Willemsen		// well-formatted. That is, the oneof interface never contains a
83*1c12ee1eSDan Willemsen		// typed nil pointer to one of the wrapper structs.
84*1c12ee1eSDan Willemsen
85*1c12ee1eSDan Willemsen		fieldDesc: fd,
86*1c12ee1eSDan Willemsen		has: func(p pointer) bool {
87*1c12ee1eSDan Willemsen			if p.IsNil() {
88*1c12ee1eSDan Willemsen				return false
89*1c12ee1eSDan Willemsen			}
90*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
91*1c12ee1eSDan Willemsen			if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
92*1c12ee1eSDan Willemsen				return false
93*1c12ee1eSDan Willemsen			}
94*1c12ee1eSDan Willemsen			return true
95*1c12ee1eSDan Willemsen		},
96*1c12ee1eSDan Willemsen		clear: func(p pointer) {
97*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
98*1c12ee1eSDan Willemsen			if rv.IsNil() || rv.Elem().Type().Elem() != ot {
99*1c12ee1eSDan Willemsen				// NOTE: We intentionally don't check for rv.Elem().IsNil()
100*1c12ee1eSDan Willemsen				// so that (*OneofWrapperType)(nil) gets cleared to nil.
101*1c12ee1eSDan Willemsen				return
102*1c12ee1eSDan Willemsen			}
103*1c12ee1eSDan Willemsen			rv.Set(reflect.Zero(rv.Type()))
104*1c12ee1eSDan Willemsen		},
105*1c12ee1eSDan Willemsen		get: func(p pointer) protoreflect.Value {
106*1c12ee1eSDan Willemsen			if p.IsNil() {
107*1c12ee1eSDan Willemsen				return conv.Zero()
108*1c12ee1eSDan Willemsen			}
109*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
110*1c12ee1eSDan Willemsen			if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
111*1c12ee1eSDan Willemsen				return conv.Zero()
112*1c12ee1eSDan Willemsen			}
113*1c12ee1eSDan Willemsen			rv = rv.Elem().Elem().Field(0)
114*1c12ee1eSDan Willemsen			return conv.PBValueOf(rv)
115*1c12ee1eSDan Willemsen		},
116*1c12ee1eSDan Willemsen		set: func(p pointer, v protoreflect.Value) {
117*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
118*1c12ee1eSDan Willemsen			if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
119*1c12ee1eSDan Willemsen				rv.Set(reflect.New(ot))
120*1c12ee1eSDan Willemsen			}
121*1c12ee1eSDan Willemsen			rv = rv.Elem().Elem().Field(0)
122*1c12ee1eSDan Willemsen			rv.Set(conv.GoValueOf(v))
123*1c12ee1eSDan Willemsen		},
124*1c12ee1eSDan Willemsen		mutable: func(p pointer) protoreflect.Value {
125*1c12ee1eSDan Willemsen			if !isMessage {
126*1c12ee1eSDan Willemsen				panic(fmt.Sprintf("field %v with invalid Mutable call on field with non-composite type", fd.FullName()))
127*1c12ee1eSDan Willemsen			}
128*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
129*1c12ee1eSDan Willemsen			if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
130*1c12ee1eSDan Willemsen				rv.Set(reflect.New(ot))
131*1c12ee1eSDan Willemsen			}
132*1c12ee1eSDan Willemsen			rv = rv.Elem().Elem().Field(0)
133*1c12ee1eSDan Willemsen			if rv.Kind() == reflect.Ptr && rv.IsNil() {
134*1c12ee1eSDan Willemsen				rv.Set(conv.GoValueOf(protoreflect.ValueOfMessage(conv.New().Message())))
135*1c12ee1eSDan Willemsen			}
136*1c12ee1eSDan Willemsen			return conv.PBValueOf(rv)
137*1c12ee1eSDan Willemsen		},
138*1c12ee1eSDan Willemsen		newMessage: func() protoreflect.Message {
139*1c12ee1eSDan Willemsen			return conv.New().Message()
140*1c12ee1eSDan Willemsen		},
141*1c12ee1eSDan Willemsen		newField: func() protoreflect.Value {
142*1c12ee1eSDan Willemsen			return conv.New()
143*1c12ee1eSDan Willemsen		},
144*1c12ee1eSDan Willemsen	}
145*1c12ee1eSDan Willemsen}
146*1c12ee1eSDan Willemsen
147*1c12ee1eSDan Willemsenfunc fieldInfoForMap(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
148*1c12ee1eSDan Willemsen	ft := fs.Type
149*1c12ee1eSDan Willemsen	if ft.Kind() != reflect.Map {
150*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("field %v has invalid type: got %v, want map kind", fd.FullName(), ft))
151*1c12ee1eSDan Willemsen	}
152*1c12ee1eSDan Willemsen	conv := NewConverter(ft, fd)
153*1c12ee1eSDan Willemsen
154*1c12ee1eSDan Willemsen	// TODO: Implement unsafe fast path?
155*1c12ee1eSDan Willemsen	fieldOffset := offsetOf(fs, x)
156*1c12ee1eSDan Willemsen	return fieldInfo{
157*1c12ee1eSDan Willemsen		fieldDesc: fd,
158*1c12ee1eSDan Willemsen		has: func(p pointer) bool {
159*1c12ee1eSDan Willemsen			if p.IsNil() {
160*1c12ee1eSDan Willemsen				return false
161*1c12ee1eSDan Willemsen			}
162*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
163*1c12ee1eSDan Willemsen			return rv.Len() > 0
164*1c12ee1eSDan Willemsen		},
165*1c12ee1eSDan Willemsen		clear: func(p pointer) {
166*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
167*1c12ee1eSDan Willemsen			rv.Set(reflect.Zero(rv.Type()))
168*1c12ee1eSDan Willemsen		},
169*1c12ee1eSDan Willemsen		get: func(p pointer) protoreflect.Value {
170*1c12ee1eSDan Willemsen			if p.IsNil() {
171*1c12ee1eSDan Willemsen				return conv.Zero()
172*1c12ee1eSDan Willemsen			}
173*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
174*1c12ee1eSDan Willemsen			if rv.Len() == 0 {
175*1c12ee1eSDan Willemsen				return conv.Zero()
176*1c12ee1eSDan Willemsen			}
177*1c12ee1eSDan Willemsen			return conv.PBValueOf(rv)
178*1c12ee1eSDan Willemsen		},
179*1c12ee1eSDan Willemsen		set: func(p pointer, v protoreflect.Value) {
180*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
181*1c12ee1eSDan Willemsen			pv := conv.GoValueOf(v)
182*1c12ee1eSDan Willemsen			if pv.IsNil() {
183*1c12ee1eSDan Willemsen				panic(fmt.Sprintf("map field %v cannot be set with read-only value", fd.FullName()))
184*1c12ee1eSDan Willemsen			}
185*1c12ee1eSDan Willemsen			rv.Set(pv)
186*1c12ee1eSDan Willemsen		},
187*1c12ee1eSDan Willemsen		mutable: func(p pointer) protoreflect.Value {
188*1c12ee1eSDan Willemsen			v := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
189*1c12ee1eSDan Willemsen			if v.IsNil() {
190*1c12ee1eSDan Willemsen				v.Set(reflect.MakeMap(fs.Type))
191*1c12ee1eSDan Willemsen			}
192*1c12ee1eSDan Willemsen			return conv.PBValueOf(v)
193*1c12ee1eSDan Willemsen		},
194*1c12ee1eSDan Willemsen		newField: func() protoreflect.Value {
195*1c12ee1eSDan Willemsen			return conv.New()
196*1c12ee1eSDan Willemsen		},
197*1c12ee1eSDan Willemsen	}
198*1c12ee1eSDan Willemsen}
199*1c12ee1eSDan Willemsen
200*1c12ee1eSDan Willemsenfunc fieldInfoForList(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
201*1c12ee1eSDan Willemsen	ft := fs.Type
202*1c12ee1eSDan Willemsen	if ft.Kind() != reflect.Slice {
203*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("field %v has invalid type: got %v, want slice kind", fd.FullName(), ft))
204*1c12ee1eSDan Willemsen	}
205*1c12ee1eSDan Willemsen	conv := NewConverter(reflect.PtrTo(ft), fd)
206*1c12ee1eSDan Willemsen
207*1c12ee1eSDan Willemsen	// TODO: Implement unsafe fast path?
208*1c12ee1eSDan Willemsen	fieldOffset := offsetOf(fs, x)
209*1c12ee1eSDan Willemsen	return fieldInfo{
210*1c12ee1eSDan Willemsen		fieldDesc: fd,
211*1c12ee1eSDan Willemsen		has: func(p pointer) bool {
212*1c12ee1eSDan Willemsen			if p.IsNil() {
213*1c12ee1eSDan Willemsen				return false
214*1c12ee1eSDan Willemsen			}
215*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
216*1c12ee1eSDan Willemsen			return rv.Len() > 0
217*1c12ee1eSDan Willemsen		},
218*1c12ee1eSDan Willemsen		clear: func(p pointer) {
219*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
220*1c12ee1eSDan Willemsen			rv.Set(reflect.Zero(rv.Type()))
221*1c12ee1eSDan Willemsen		},
222*1c12ee1eSDan Willemsen		get: func(p pointer) protoreflect.Value {
223*1c12ee1eSDan Willemsen			if p.IsNil() {
224*1c12ee1eSDan Willemsen				return conv.Zero()
225*1c12ee1eSDan Willemsen			}
226*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type)
227*1c12ee1eSDan Willemsen			if rv.Elem().Len() == 0 {
228*1c12ee1eSDan Willemsen				return conv.Zero()
229*1c12ee1eSDan Willemsen			}
230*1c12ee1eSDan Willemsen			return conv.PBValueOf(rv)
231*1c12ee1eSDan Willemsen		},
232*1c12ee1eSDan Willemsen		set: func(p pointer, v protoreflect.Value) {
233*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
234*1c12ee1eSDan Willemsen			pv := conv.GoValueOf(v)
235*1c12ee1eSDan Willemsen			if pv.IsNil() {
236*1c12ee1eSDan Willemsen				panic(fmt.Sprintf("list field %v cannot be set with read-only value", fd.FullName()))
237*1c12ee1eSDan Willemsen			}
238*1c12ee1eSDan Willemsen			rv.Set(pv.Elem())
239*1c12ee1eSDan Willemsen		},
240*1c12ee1eSDan Willemsen		mutable: func(p pointer) protoreflect.Value {
241*1c12ee1eSDan Willemsen			v := p.Apply(fieldOffset).AsValueOf(fs.Type)
242*1c12ee1eSDan Willemsen			return conv.PBValueOf(v)
243*1c12ee1eSDan Willemsen		},
244*1c12ee1eSDan Willemsen		newField: func() protoreflect.Value {
245*1c12ee1eSDan Willemsen			return conv.New()
246*1c12ee1eSDan Willemsen		},
247*1c12ee1eSDan Willemsen	}
248*1c12ee1eSDan Willemsen}
249*1c12ee1eSDan Willemsen
250*1c12ee1eSDan Willemsenvar (
251*1c12ee1eSDan Willemsen	nilBytes   = reflect.ValueOf([]byte(nil))
252*1c12ee1eSDan Willemsen	emptyBytes = reflect.ValueOf([]byte{})
253*1c12ee1eSDan Willemsen)
254*1c12ee1eSDan Willemsen
255*1c12ee1eSDan Willemsenfunc fieldInfoForScalar(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
256*1c12ee1eSDan Willemsen	ft := fs.Type
257*1c12ee1eSDan Willemsen	nullable := fd.HasPresence()
258*1c12ee1eSDan Willemsen	isBytes := ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8
259*1c12ee1eSDan Willemsen	if nullable {
260*1c12ee1eSDan Willemsen		if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
261*1c12ee1eSDan Willemsen			// This never occurs for generated message types.
262*1c12ee1eSDan Willemsen			// Despite the protobuf type system specifying presence,
263*1c12ee1eSDan Willemsen			// the Go field type cannot represent it.
264*1c12ee1eSDan Willemsen			nullable = false
265*1c12ee1eSDan Willemsen		}
266*1c12ee1eSDan Willemsen		if ft.Kind() == reflect.Ptr {
267*1c12ee1eSDan Willemsen			ft = ft.Elem()
268*1c12ee1eSDan Willemsen		}
269*1c12ee1eSDan Willemsen	}
270*1c12ee1eSDan Willemsen	conv := NewConverter(ft, fd)
271*1c12ee1eSDan Willemsen
272*1c12ee1eSDan Willemsen	// TODO: Implement unsafe fast path?
273*1c12ee1eSDan Willemsen	fieldOffset := offsetOf(fs, x)
274*1c12ee1eSDan Willemsen	return fieldInfo{
275*1c12ee1eSDan Willemsen		fieldDesc: fd,
276*1c12ee1eSDan Willemsen		has: func(p pointer) bool {
277*1c12ee1eSDan Willemsen			if p.IsNil() {
278*1c12ee1eSDan Willemsen				return false
279*1c12ee1eSDan Willemsen			}
280*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
281*1c12ee1eSDan Willemsen			if nullable {
282*1c12ee1eSDan Willemsen				return !rv.IsNil()
283*1c12ee1eSDan Willemsen			}
284*1c12ee1eSDan Willemsen			switch rv.Kind() {
285*1c12ee1eSDan Willemsen			case reflect.Bool:
286*1c12ee1eSDan Willemsen				return rv.Bool()
287*1c12ee1eSDan Willemsen			case reflect.Int32, reflect.Int64:
288*1c12ee1eSDan Willemsen				return rv.Int() != 0
289*1c12ee1eSDan Willemsen			case reflect.Uint32, reflect.Uint64:
290*1c12ee1eSDan Willemsen				return rv.Uint() != 0
291*1c12ee1eSDan Willemsen			case reflect.Float32, reflect.Float64:
292*1c12ee1eSDan Willemsen				return rv.Float() != 0 || math.Signbit(rv.Float())
293*1c12ee1eSDan Willemsen			case reflect.String, reflect.Slice:
294*1c12ee1eSDan Willemsen				return rv.Len() > 0
295*1c12ee1eSDan Willemsen			default:
296*1c12ee1eSDan Willemsen				panic(fmt.Sprintf("field %v has invalid type: %v", fd.FullName(), rv.Type())) // should never happen
297*1c12ee1eSDan Willemsen			}
298*1c12ee1eSDan Willemsen		},
299*1c12ee1eSDan Willemsen		clear: func(p pointer) {
300*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
301*1c12ee1eSDan Willemsen			rv.Set(reflect.Zero(rv.Type()))
302*1c12ee1eSDan Willemsen		},
303*1c12ee1eSDan Willemsen		get: func(p pointer) protoreflect.Value {
304*1c12ee1eSDan Willemsen			if p.IsNil() {
305*1c12ee1eSDan Willemsen				return conv.Zero()
306*1c12ee1eSDan Willemsen			}
307*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
308*1c12ee1eSDan Willemsen			if nullable {
309*1c12ee1eSDan Willemsen				if rv.IsNil() {
310*1c12ee1eSDan Willemsen					return conv.Zero()
311*1c12ee1eSDan Willemsen				}
312*1c12ee1eSDan Willemsen				if rv.Kind() == reflect.Ptr {
313*1c12ee1eSDan Willemsen					rv = rv.Elem()
314*1c12ee1eSDan Willemsen				}
315*1c12ee1eSDan Willemsen			}
316*1c12ee1eSDan Willemsen			return conv.PBValueOf(rv)
317*1c12ee1eSDan Willemsen		},
318*1c12ee1eSDan Willemsen		set: func(p pointer, v protoreflect.Value) {
319*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
320*1c12ee1eSDan Willemsen			if nullable && rv.Kind() == reflect.Ptr {
321*1c12ee1eSDan Willemsen				if rv.IsNil() {
322*1c12ee1eSDan Willemsen					rv.Set(reflect.New(ft))
323*1c12ee1eSDan Willemsen				}
324*1c12ee1eSDan Willemsen				rv = rv.Elem()
325*1c12ee1eSDan Willemsen			}
326*1c12ee1eSDan Willemsen			rv.Set(conv.GoValueOf(v))
327*1c12ee1eSDan Willemsen			if isBytes && rv.Len() == 0 {
328*1c12ee1eSDan Willemsen				if nullable {
329*1c12ee1eSDan Willemsen					rv.Set(emptyBytes) // preserve presence
330*1c12ee1eSDan Willemsen				} else {
331*1c12ee1eSDan Willemsen					rv.Set(nilBytes) // do not preserve presence
332*1c12ee1eSDan Willemsen				}
333*1c12ee1eSDan Willemsen			}
334*1c12ee1eSDan Willemsen		},
335*1c12ee1eSDan Willemsen		newField: func() protoreflect.Value {
336*1c12ee1eSDan Willemsen			return conv.New()
337*1c12ee1eSDan Willemsen		},
338*1c12ee1eSDan Willemsen	}
339*1c12ee1eSDan Willemsen}
340*1c12ee1eSDan Willemsen
341*1c12ee1eSDan Willemsenfunc fieldInfoForWeakMessage(fd protoreflect.FieldDescriptor, weakOffset offset) fieldInfo {
342*1c12ee1eSDan Willemsen	if !flags.ProtoLegacy {
343*1c12ee1eSDan Willemsen		panic("no support for proto1 weak fields")
344*1c12ee1eSDan Willemsen	}
345*1c12ee1eSDan Willemsen
346*1c12ee1eSDan Willemsen	var once sync.Once
347*1c12ee1eSDan Willemsen	var messageType protoreflect.MessageType
348*1c12ee1eSDan Willemsen	lazyInit := func() {
349*1c12ee1eSDan Willemsen		once.Do(func() {
350*1c12ee1eSDan Willemsen			messageName := fd.Message().FullName()
351*1c12ee1eSDan Willemsen			messageType, _ = protoregistry.GlobalTypes.FindMessageByName(messageName)
352*1c12ee1eSDan Willemsen			if messageType == nil {
353*1c12ee1eSDan Willemsen				panic(fmt.Sprintf("weak message %v for field %v is not linked in", messageName, fd.FullName()))
354*1c12ee1eSDan Willemsen			}
355*1c12ee1eSDan Willemsen		})
356*1c12ee1eSDan Willemsen	}
357*1c12ee1eSDan Willemsen
358*1c12ee1eSDan Willemsen	num := fd.Number()
359*1c12ee1eSDan Willemsen	return fieldInfo{
360*1c12ee1eSDan Willemsen		fieldDesc: fd,
361*1c12ee1eSDan Willemsen		has: func(p pointer) bool {
362*1c12ee1eSDan Willemsen			if p.IsNil() {
363*1c12ee1eSDan Willemsen				return false
364*1c12ee1eSDan Willemsen			}
365*1c12ee1eSDan Willemsen			_, ok := p.Apply(weakOffset).WeakFields().get(num)
366*1c12ee1eSDan Willemsen			return ok
367*1c12ee1eSDan Willemsen		},
368*1c12ee1eSDan Willemsen		clear: func(p pointer) {
369*1c12ee1eSDan Willemsen			p.Apply(weakOffset).WeakFields().clear(num)
370*1c12ee1eSDan Willemsen		},
371*1c12ee1eSDan Willemsen		get: func(p pointer) protoreflect.Value {
372*1c12ee1eSDan Willemsen			lazyInit()
373*1c12ee1eSDan Willemsen			if p.IsNil() {
374*1c12ee1eSDan Willemsen				return protoreflect.ValueOfMessage(messageType.Zero())
375*1c12ee1eSDan Willemsen			}
376*1c12ee1eSDan Willemsen			m, ok := p.Apply(weakOffset).WeakFields().get(num)
377*1c12ee1eSDan Willemsen			if !ok {
378*1c12ee1eSDan Willemsen				return protoreflect.ValueOfMessage(messageType.Zero())
379*1c12ee1eSDan Willemsen			}
380*1c12ee1eSDan Willemsen			return protoreflect.ValueOfMessage(m.ProtoReflect())
381*1c12ee1eSDan Willemsen		},
382*1c12ee1eSDan Willemsen		set: func(p pointer, v protoreflect.Value) {
383*1c12ee1eSDan Willemsen			lazyInit()
384*1c12ee1eSDan Willemsen			m := v.Message()
385*1c12ee1eSDan Willemsen			if m.Descriptor() != messageType.Descriptor() {
386*1c12ee1eSDan Willemsen				if got, want := m.Descriptor().FullName(), messageType.Descriptor().FullName(); got != want {
387*1c12ee1eSDan Willemsen					panic(fmt.Sprintf("field %v has mismatching message descriptor: got %v, want %v", fd.FullName(), got, want))
388*1c12ee1eSDan Willemsen				}
389*1c12ee1eSDan Willemsen				panic(fmt.Sprintf("field %v has mismatching message descriptor: %v", fd.FullName(), m.Descriptor().FullName()))
390*1c12ee1eSDan Willemsen			}
391*1c12ee1eSDan Willemsen			p.Apply(weakOffset).WeakFields().set(num, m.Interface())
392*1c12ee1eSDan Willemsen		},
393*1c12ee1eSDan Willemsen		mutable: func(p pointer) protoreflect.Value {
394*1c12ee1eSDan Willemsen			lazyInit()
395*1c12ee1eSDan Willemsen			fs := p.Apply(weakOffset).WeakFields()
396*1c12ee1eSDan Willemsen			m, ok := fs.get(num)
397*1c12ee1eSDan Willemsen			if !ok {
398*1c12ee1eSDan Willemsen				m = messageType.New().Interface()
399*1c12ee1eSDan Willemsen				fs.set(num, m)
400*1c12ee1eSDan Willemsen			}
401*1c12ee1eSDan Willemsen			return protoreflect.ValueOfMessage(m.ProtoReflect())
402*1c12ee1eSDan Willemsen		},
403*1c12ee1eSDan Willemsen		newMessage: func() protoreflect.Message {
404*1c12ee1eSDan Willemsen			lazyInit()
405*1c12ee1eSDan Willemsen			return messageType.New()
406*1c12ee1eSDan Willemsen		},
407*1c12ee1eSDan Willemsen		newField: func() protoreflect.Value {
408*1c12ee1eSDan Willemsen			lazyInit()
409*1c12ee1eSDan Willemsen			return protoreflect.ValueOfMessage(messageType.New())
410*1c12ee1eSDan Willemsen		},
411*1c12ee1eSDan Willemsen	}
412*1c12ee1eSDan Willemsen}
413*1c12ee1eSDan Willemsen
414*1c12ee1eSDan Willemsenfunc fieldInfoForMessage(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
415*1c12ee1eSDan Willemsen	ft := fs.Type
416*1c12ee1eSDan Willemsen	conv := NewConverter(ft, fd)
417*1c12ee1eSDan Willemsen
418*1c12ee1eSDan Willemsen	// TODO: Implement unsafe fast path?
419*1c12ee1eSDan Willemsen	fieldOffset := offsetOf(fs, x)
420*1c12ee1eSDan Willemsen	return fieldInfo{
421*1c12ee1eSDan Willemsen		fieldDesc: fd,
422*1c12ee1eSDan Willemsen		has: func(p pointer) bool {
423*1c12ee1eSDan Willemsen			if p.IsNil() {
424*1c12ee1eSDan Willemsen				return false
425*1c12ee1eSDan Willemsen			}
426*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
427*1c12ee1eSDan Willemsen			if fs.Type.Kind() != reflect.Ptr {
428*1c12ee1eSDan Willemsen				return !isZero(rv)
429*1c12ee1eSDan Willemsen			}
430*1c12ee1eSDan Willemsen			return !rv.IsNil()
431*1c12ee1eSDan Willemsen		},
432*1c12ee1eSDan Willemsen		clear: func(p pointer) {
433*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
434*1c12ee1eSDan Willemsen			rv.Set(reflect.Zero(rv.Type()))
435*1c12ee1eSDan Willemsen		},
436*1c12ee1eSDan Willemsen		get: func(p pointer) protoreflect.Value {
437*1c12ee1eSDan Willemsen			if p.IsNil() {
438*1c12ee1eSDan Willemsen				return conv.Zero()
439*1c12ee1eSDan Willemsen			}
440*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
441*1c12ee1eSDan Willemsen			return conv.PBValueOf(rv)
442*1c12ee1eSDan Willemsen		},
443*1c12ee1eSDan Willemsen		set: func(p pointer, v protoreflect.Value) {
444*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
445*1c12ee1eSDan Willemsen			rv.Set(conv.GoValueOf(v))
446*1c12ee1eSDan Willemsen			if fs.Type.Kind() == reflect.Ptr && rv.IsNil() {
447*1c12ee1eSDan Willemsen				panic(fmt.Sprintf("field %v has invalid nil pointer", fd.FullName()))
448*1c12ee1eSDan Willemsen			}
449*1c12ee1eSDan Willemsen		},
450*1c12ee1eSDan Willemsen		mutable: func(p pointer) protoreflect.Value {
451*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
452*1c12ee1eSDan Willemsen			if fs.Type.Kind() == reflect.Ptr && rv.IsNil() {
453*1c12ee1eSDan Willemsen				rv.Set(conv.GoValueOf(conv.New()))
454*1c12ee1eSDan Willemsen			}
455*1c12ee1eSDan Willemsen			return conv.PBValueOf(rv)
456*1c12ee1eSDan Willemsen		},
457*1c12ee1eSDan Willemsen		newMessage: func() protoreflect.Message {
458*1c12ee1eSDan Willemsen			return conv.New().Message()
459*1c12ee1eSDan Willemsen		},
460*1c12ee1eSDan Willemsen		newField: func() protoreflect.Value {
461*1c12ee1eSDan Willemsen			return conv.New()
462*1c12ee1eSDan Willemsen		},
463*1c12ee1eSDan Willemsen	}
464*1c12ee1eSDan Willemsen}
465*1c12ee1eSDan Willemsen
466*1c12ee1eSDan Willemsentype oneofInfo struct {
467*1c12ee1eSDan Willemsen	oneofDesc protoreflect.OneofDescriptor
468*1c12ee1eSDan Willemsen	which     func(pointer) protoreflect.FieldNumber
469*1c12ee1eSDan Willemsen}
470*1c12ee1eSDan Willemsen
471*1c12ee1eSDan Willemsenfunc makeOneofInfo(od protoreflect.OneofDescriptor, si structInfo, x exporter) *oneofInfo {
472*1c12ee1eSDan Willemsen	oi := &oneofInfo{oneofDesc: od}
473*1c12ee1eSDan Willemsen	if od.IsSynthetic() {
474*1c12ee1eSDan Willemsen		fs := si.fieldsByNumber[od.Fields().Get(0).Number()]
475*1c12ee1eSDan Willemsen		fieldOffset := offsetOf(fs, x)
476*1c12ee1eSDan Willemsen		oi.which = func(p pointer) protoreflect.FieldNumber {
477*1c12ee1eSDan Willemsen			if p.IsNil() {
478*1c12ee1eSDan Willemsen				return 0
479*1c12ee1eSDan Willemsen			}
480*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
481*1c12ee1eSDan Willemsen			if rv.IsNil() { // valid on either *T or []byte
482*1c12ee1eSDan Willemsen				return 0
483*1c12ee1eSDan Willemsen			}
484*1c12ee1eSDan Willemsen			return od.Fields().Get(0).Number()
485*1c12ee1eSDan Willemsen		}
486*1c12ee1eSDan Willemsen	} else {
487*1c12ee1eSDan Willemsen		fs := si.oneofsByName[od.Name()]
488*1c12ee1eSDan Willemsen		fieldOffset := offsetOf(fs, x)
489*1c12ee1eSDan Willemsen		oi.which = func(p pointer) protoreflect.FieldNumber {
490*1c12ee1eSDan Willemsen			if p.IsNil() {
491*1c12ee1eSDan Willemsen				return 0
492*1c12ee1eSDan Willemsen			}
493*1c12ee1eSDan Willemsen			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
494*1c12ee1eSDan Willemsen			if rv.IsNil() {
495*1c12ee1eSDan Willemsen				return 0
496*1c12ee1eSDan Willemsen			}
497*1c12ee1eSDan Willemsen			rv = rv.Elem()
498*1c12ee1eSDan Willemsen			if rv.IsNil() {
499*1c12ee1eSDan Willemsen				return 0
500*1c12ee1eSDan Willemsen			}
501*1c12ee1eSDan Willemsen			return si.oneofWrappersByType[rv.Type().Elem()]
502*1c12ee1eSDan Willemsen		}
503*1c12ee1eSDan Willemsen	}
504*1c12ee1eSDan Willemsen	return oi
505*1c12ee1eSDan Willemsen}
506*1c12ee1eSDan Willemsen
507*1c12ee1eSDan Willemsen// isZero is identical to reflect.Value.IsZero.
508*1c12ee1eSDan Willemsen// TODO: Remove this when Go1.13 is the minimally supported Go version.
509*1c12ee1eSDan Willemsenfunc isZero(v reflect.Value) bool {
510*1c12ee1eSDan Willemsen	switch v.Kind() {
511*1c12ee1eSDan Willemsen	case reflect.Bool:
512*1c12ee1eSDan Willemsen		return !v.Bool()
513*1c12ee1eSDan Willemsen	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
514*1c12ee1eSDan Willemsen		return v.Int() == 0
515*1c12ee1eSDan Willemsen	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
516*1c12ee1eSDan Willemsen		return v.Uint() == 0
517*1c12ee1eSDan Willemsen	case reflect.Float32, reflect.Float64:
518*1c12ee1eSDan Willemsen		return math.Float64bits(v.Float()) == 0
519*1c12ee1eSDan Willemsen	case reflect.Complex64, reflect.Complex128:
520*1c12ee1eSDan Willemsen		c := v.Complex()
521*1c12ee1eSDan Willemsen		return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
522*1c12ee1eSDan Willemsen	case reflect.Array:
523*1c12ee1eSDan Willemsen		for i := 0; i < v.Len(); i++ {
524*1c12ee1eSDan Willemsen			if !isZero(v.Index(i)) {
525*1c12ee1eSDan Willemsen				return false
526*1c12ee1eSDan Willemsen			}
527*1c12ee1eSDan Willemsen		}
528*1c12ee1eSDan Willemsen		return true
529*1c12ee1eSDan Willemsen	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
530*1c12ee1eSDan Willemsen		return v.IsNil()
531*1c12ee1eSDan Willemsen	case reflect.String:
532*1c12ee1eSDan Willemsen		return v.Len() == 0
533*1c12ee1eSDan Willemsen	case reflect.Struct:
534*1c12ee1eSDan Willemsen		for i := 0; i < v.NumField(); i++ {
535*1c12ee1eSDan Willemsen			if !isZero(v.Field(i)) {
536*1c12ee1eSDan Willemsen				return false
537*1c12ee1eSDan Willemsen			}
538*1c12ee1eSDan Willemsen		}
539*1c12ee1eSDan Willemsen		return true
540*1c12ee1eSDan Willemsen	default:
541*1c12ee1eSDan Willemsen		panic(&reflect.ValueError{"reflect.Value.IsZero", v.Kind()})
542*1c12ee1eSDan Willemsen	}
543*1c12ee1eSDan Willemsen}
544