podman

Форк
0
568 строк · 18.6 Кб
1
// Copyright 2018 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4

5
package impl
6

7
import (
8
	"fmt"
9
	"reflect"
10
	"strings"
11
	"sync"
12

13
	"google.golang.org/protobuf/internal/descopts"
14
	ptag "google.golang.org/protobuf/internal/encoding/tag"
15
	"google.golang.org/protobuf/internal/errors"
16
	"google.golang.org/protobuf/internal/filedesc"
17
	"google.golang.org/protobuf/internal/strs"
18
	"google.golang.org/protobuf/reflect/protoreflect"
19
	"google.golang.org/protobuf/runtime/protoiface"
20
)
21

22
// legacyWrapMessage wraps v as a protoreflect.Message,
23
// where v must be a *struct kind and not implement the v2 API already.
24
func legacyWrapMessage(v reflect.Value) protoreflect.Message {
25
	t := v.Type()
26
	if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
27
		return aberrantMessage{v: v}
28
	}
29
	mt := legacyLoadMessageInfo(t, "")
30
	return mt.MessageOf(v.Interface())
31
}
32

33
// legacyLoadMessageType dynamically loads a protoreflect.Type for t,
34
// where t must be not implement the v2 API already.
35
// The provided name is used if it cannot be determined from the message.
36
func legacyLoadMessageType(t reflect.Type, name protoreflect.FullName) protoreflect.MessageType {
37
	if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
38
		return aberrantMessageType{t}
39
	}
40
	return legacyLoadMessageInfo(t, name)
41
}
42

43
var legacyMessageTypeCache sync.Map // map[reflect.Type]*MessageInfo
44

45
// legacyLoadMessageInfo dynamically loads a *MessageInfo for t,
46
// where t must be a *struct kind and not implement the v2 API already.
47
// The provided name is used if it cannot be determined from the message.
48
func legacyLoadMessageInfo(t reflect.Type, name protoreflect.FullName) *MessageInfo {
49
	// Fast-path: check if a MessageInfo is cached for this concrete type.
50
	if mt, ok := legacyMessageTypeCache.Load(t); ok {
51
		return mt.(*MessageInfo)
52
	}
53

54
	// Slow-path: derive message descriptor and initialize MessageInfo.
55
	mi := &MessageInfo{
56
		Desc:          legacyLoadMessageDesc(t, name),
57
		GoReflectType: t,
58
	}
59

60
	var hasMarshal, hasUnmarshal bool
61
	v := reflect.Zero(t).Interface()
62
	if _, hasMarshal = v.(legacyMarshaler); hasMarshal {
63
		mi.methods.Marshal = legacyMarshal
64

65
		// We have no way to tell whether the type's Marshal method
66
		// supports deterministic serialization or not, but this
67
		// preserves the v1 implementation's behavior of always
68
		// calling Marshal methods when present.
69
		mi.methods.Flags |= protoiface.SupportMarshalDeterministic
70
	}
71
	if _, hasUnmarshal = v.(legacyUnmarshaler); hasUnmarshal {
72
		mi.methods.Unmarshal = legacyUnmarshal
73
	}
74
	if _, hasMerge := v.(legacyMerger); hasMerge || (hasMarshal && hasUnmarshal) {
75
		mi.methods.Merge = legacyMerge
76
	}
77

78
	if mi, ok := legacyMessageTypeCache.LoadOrStore(t, mi); ok {
79
		return mi.(*MessageInfo)
80
	}
81
	return mi
82
}
83

84
var legacyMessageDescCache sync.Map // map[reflect.Type]protoreflect.MessageDescriptor
85

86
// LegacyLoadMessageDesc returns an MessageDescriptor derived from the Go type,
87
// which should be a *struct kind and must not implement the v2 API already.
88
//
89
// This is exported for testing purposes.
90
func LegacyLoadMessageDesc(t reflect.Type) protoreflect.MessageDescriptor {
91
	return legacyLoadMessageDesc(t, "")
92
}
93
func legacyLoadMessageDesc(t reflect.Type, name protoreflect.FullName) protoreflect.MessageDescriptor {
94
	// Fast-path: check if a MessageDescriptor is cached for this concrete type.
95
	if mi, ok := legacyMessageDescCache.Load(t); ok {
96
		return mi.(protoreflect.MessageDescriptor)
97
	}
98

99
	// Slow-path: initialize MessageDescriptor from the raw descriptor.
100
	mv := reflect.Zero(t).Interface()
101
	if _, ok := mv.(protoreflect.ProtoMessage); ok {
102
		panic(fmt.Sprintf("%v already implements proto.Message", t))
103
	}
104
	mdV1, ok := mv.(messageV1)
105
	if !ok {
106
		return aberrantLoadMessageDesc(t, name)
107
	}
108

109
	// If this is a dynamic message type where there isn't a 1-1 mapping between
110
	// Go and protobuf types, calling the Descriptor method on the zero value of
111
	// the message type isn't likely to work. If it panics, swallow the panic and
112
	// continue as if the Descriptor method wasn't present.
113
	b, idxs := func() ([]byte, []int) {
114
		defer func() {
115
			recover()
116
		}()
117
		return mdV1.Descriptor()
118
	}()
119
	if b == nil {
120
		return aberrantLoadMessageDesc(t, name)
121
	}
122

123
	// If the Go type has no fields, then this might be a proto3 empty message
124
	// from before the size cache was added. If there are any fields, check to
125
	// see that at least one of them looks like something we generated.
126
	if t.Elem().Kind() == reflect.Struct {
127
		if nfield := t.Elem().NumField(); nfield > 0 {
128
			hasProtoField := false
129
			for i := 0; i < nfield; i++ {
130
				f := t.Elem().Field(i)
131
				if f.Tag.Get("protobuf") != "" || f.Tag.Get("protobuf_oneof") != "" || strings.HasPrefix(f.Name, "XXX_") {
132
					hasProtoField = true
133
					break
134
				}
135
			}
136
			if !hasProtoField {
137
				return aberrantLoadMessageDesc(t, name)
138
			}
139
		}
140
	}
141

142
	md := legacyLoadFileDesc(b).Messages().Get(idxs[0])
143
	for _, i := range idxs[1:] {
144
		md = md.Messages().Get(i)
145
	}
146
	if name != "" && md.FullName() != name {
147
		panic(fmt.Sprintf("mismatching message name: got %v, want %v", md.FullName(), name))
148
	}
149
	if md, ok := legacyMessageDescCache.LoadOrStore(t, md); ok {
150
		return md.(protoreflect.MessageDescriptor)
151
	}
152
	return md
153
}
154

155
var (
156
	aberrantMessageDescLock  sync.Mutex
157
	aberrantMessageDescCache map[reflect.Type]protoreflect.MessageDescriptor
158
)
159

160
// aberrantLoadMessageDesc returns an MessageDescriptor derived from the Go type,
161
// which must not implement protoreflect.ProtoMessage or messageV1.
162
//
163
// This is a best-effort derivation of the message descriptor using the protobuf
164
// tags on the struct fields.
165
func aberrantLoadMessageDesc(t reflect.Type, name protoreflect.FullName) protoreflect.MessageDescriptor {
166
	aberrantMessageDescLock.Lock()
167
	defer aberrantMessageDescLock.Unlock()
168
	if aberrantMessageDescCache == nil {
169
		aberrantMessageDescCache = make(map[reflect.Type]protoreflect.MessageDescriptor)
170
	}
171
	return aberrantLoadMessageDescReentrant(t, name)
172
}
173
func aberrantLoadMessageDescReentrant(t reflect.Type, name protoreflect.FullName) protoreflect.MessageDescriptor {
174
	// Fast-path: check if an MessageDescriptor is cached for this concrete type.
175
	if md, ok := aberrantMessageDescCache[t]; ok {
176
		return md
177
	}
178

179
	// Slow-path: construct a descriptor from the Go struct type (best-effort).
180
	// Cache the MessageDescriptor early on so that we can resolve internal
181
	// cyclic references.
182
	md := &filedesc.Message{L2: new(filedesc.MessageL2)}
183
	md.L0.FullName = aberrantDeriveMessageName(t, name)
184
	md.L0.ParentFile = filedesc.SurrogateProto2
185
	aberrantMessageDescCache[t] = md
186

187
	if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
188
		return md
189
	}
190

191
	// Try to determine if the message is using proto3 by checking scalars.
192
	for i := 0; i < t.Elem().NumField(); i++ {
193
		f := t.Elem().Field(i)
194
		if tag := f.Tag.Get("protobuf"); tag != "" {
195
			switch f.Type.Kind() {
196
			case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
197
				md.L0.ParentFile = filedesc.SurrogateProto3
198
			}
199
			for _, s := range strings.Split(tag, ",") {
200
				if s == "proto3" {
201
					md.L0.ParentFile = filedesc.SurrogateProto3
202
				}
203
			}
204
		}
205
	}
206

207
	// Obtain a list of oneof wrapper types.
208
	var oneofWrappers []reflect.Type
209
	methods := make([]reflect.Method, 0, 2)
210
	if m, ok := t.MethodByName("XXX_OneofFuncs"); ok {
211
		methods = append(methods, m)
212
	}
213
	if m, ok := t.MethodByName("XXX_OneofWrappers"); ok {
214
		methods = append(methods, m)
215
	}
216
	for _, fn := range methods {
217
		for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) {
218
			if vs, ok := v.Interface().([]interface{}); ok {
219
				for _, v := range vs {
220
					oneofWrappers = append(oneofWrappers, reflect.TypeOf(v))
221
				}
222
			}
223
		}
224
	}
225

226
	// Obtain a list of the extension ranges.
227
	if fn, ok := t.MethodByName("ExtensionRangeArray"); ok {
228
		vs := fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0]
229
		for i := 0; i < vs.Len(); i++ {
230
			v := vs.Index(i)
231
			md.L2.ExtensionRanges.List = append(md.L2.ExtensionRanges.List, [2]protoreflect.FieldNumber{
232
				protoreflect.FieldNumber(v.FieldByName("Start").Int()),
233
				protoreflect.FieldNumber(v.FieldByName("End").Int() + 1),
234
			})
235
			md.L2.ExtensionRangeOptions = append(md.L2.ExtensionRangeOptions, nil)
236
		}
237
	}
238

239
	// Derive the message fields by inspecting the struct fields.
240
	for i := 0; i < t.Elem().NumField(); i++ {
241
		f := t.Elem().Field(i)
242
		if tag := f.Tag.Get("protobuf"); tag != "" {
243
			tagKey := f.Tag.Get("protobuf_key")
244
			tagVal := f.Tag.Get("protobuf_val")
245
			aberrantAppendField(md, f.Type, tag, tagKey, tagVal)
246
		}
247
		if tag := f.Tag.Get("protobuf_oneof"); tag != "" {
248
			n := len(md.L2.Oneofs.List)
249
			md.L2.Oneofs.List = append(md.L2.Oneofs.List, filedesc.Oneof{})
250
			od := &md.L2.Oneofs.List[n]
251
			od.L0.FullName = md.FullName().Append(protoreflect.Name(tag))
252
			od.L0.ParentFile = md.L0.ParentFile
253
			od.L0.Parent = md
254
			od.L0.Index = n
255

256
			for _, t := range oneofWrappers {
257
				if t.Implements(f.Type) {
258
					f := t.Elem().Field(0)
259
					if tag := f.Tag.Get("protobuf"); tag != "" {
260
						aberrantAppendField(md, f.Type, tag, "", "")
261
						fd := &md.L2.Fields.List[len(md.L2.Fields.List)-1]
262
						fd.L1.ContainingOneof = od
263
						od.L1.Fields.List = append(od.L1.Fields.List, fd)
264
					}
265
				}
266
			}
267
		}
268
	}
269

270
	return md
271
}
272

273
func aberrantDeriveMessageName(t reflect.Type, name protoreflect.FullName) protoreflect.FullName {
274
	if name.IsValid() {
275
		return name
276
	}
277
	func() {
278
		defer func() { recover() }() // swallow possible nil panics
279
		if m, ok := reflect.Zero(t).Interface().(interface{ XXX_MessageName() string }); ok {
280
			name = protoreflect.FullName(m.XXX_MessageName())
281
		}
282
	}()
283
	if name.IsValid() {
284
		return name
285
	}
286
	if t.Kind() == reflect.Ptr {
287
		t = t.Elem()
288
	}
289
	return AberrantDeriveFullName(t)
290
}
291

292
func aberrantAppendField(md *filedesc.Message, goType reflect.Type, tag, tagKey, tagVal string) {
293
	t := goType
294
	isOptional := t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct
295
	isRepeated := t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
296
	if isOptional || isRepeated {
297
		t = t.Elem()
298
	}
299
	fd := ptag.Unmarshal(tag, t, placeholderEnumValues{}).(*filedesc.Field)
300

301
	// Append field descriptor to the message.
302
	n := len(md.L2.Fields.List)
303
	md.L2.Fields.List = append(md.L2.Fields.List, *fd)
304
	fd = &md.L2.Fields.List[n]
305
	fd.L0.FullName = md.FullName().Append(fd.Name())
306
	fd.L0.ParentFile = md.L0.ParentFile
307
	fd.L0.Parent = md
308
	fd.L0.Index = n
309

310
	if fd.L1.IsWeak || fd.L1.HasPacked {
311
		fd.L1.Options = func() protoreflect.ProtoMessage {
312
			opts := descopts.Field.ProtoReflect().New()
313
			if fd.L1.IsWeak {
314
				opts.Set(opts.Descriptor().Fields().ByName("weak"), protoreflect.ValueOfBool(true))
315
			}
316
			if fd.L1.HasPacked {
317
				opts.Set(opts.Descriptor().Fields().ByName("packed"), protoreflect.ValueOfBool(fd.L1.IsPacked))
318
			}
319
			return opts.Interface()
320
		}
321
	}
322

323
	// Populate Enum and Message.
324
	if fd.Enum() == nil && fd.Kind() == protoreflect.EnumKind {
325
		switch v := reflect.Zero(t).Interface().(type) {
326
		case protoreflect.Enum:
327
			fd.L1.Enum = v.Descriptor()
328
		default:
329
			fd.L1.Enum = LegacyLoadEnumDesc(t)
330
		}
331
	}
332
	if fd.Message() == nil && (fd.Kind() == protoreflect.MessageKind || fd.Kind() == protoreflect.GroupKind) {
333
		switch v := reflect.Zero(t).Interface().(type) {
334
		case protoreflect.ProtoMessage:
335
			fd.L1.Message = v.ProtoReflect().Descriptor()
336
		case messageV1:
337
			fd.L1.Message = LegacyLoadMessageDesc(t)
338
		default:
339
			if t.Kind() == reflect.Map {
340
				n := len(md.L1.Messages.List)
341
				md.L1.Messages.List = append(md.L1.Messages.List, filedesc.Message{L2: new(filedesc.MessageL2)})
342
				md2 := &md.L1.Messages.List[n]
343
				md2.L0.FullName = md.FullName().Append(protoreflect.Name(strs.MapEntryName(string(fd.Name()))))
344
				md2.L0.ParentFile = md.L0.ParentFile
345
				md2.L0.Parent = md
346
				md2.L0.Index = n
347

348
				md2.L1.IsMapEntry = true
349
				md2.L2.Options = func() protoreflect.ProtoMessage {
350
					opts := descopts.Message.ProtoReflect().New()
351
					opts.Set(opts.Descriptor().Fields().ByName("map_entry"), protoreflect.ValueOfBool(true))
352
					return opts.Interface()
353
				}
354

355
				aberrantAppendField(md2, t.Key(), tagKey, "", "")
356
				aberrantAppendField(md2, t.Elem(), tagVal, "", "")
357

358
				fd.L1.Message = md2
359
				break
360
			}
361
			fd.L1.Message = aberrantLoadMessageDescReentrant(t, "")
362
		}
363
	}
364
}
365

366
type placeholderEnumValues struct {
367
	protoreflect.EnumValueDescriptors
368
}
369

370
func (placeholderEnumValues) ByNumber(n protoreflect.EnumNumber) protoreflect.EnumValueDescriptor {
371
	return filedesc.PlaceholderEnumValue(protoreflect.FullName(fmt.Sprintf("UNKNOWN_%d", n)))
372
}
373

374
// legacyMarshaler is the proto.Marshaler interface superseded by protoiface.Methoder.
375
type legacyMarshaler interface {
376
	Marshal() ([]byte, error)
377
}
378

379
// legacyUnmarshaler is the proto.Unmarshaler interface superseded by protoiface.Methoder.
380
type legacyUnmarshaler interface {
381
	Unmarshal([]byte) error
382
}
383

384
// legacyMerger is the proto.Merger interface superseded by protoiface.Methoder.
385
type legacyMerger interface {
386
	Merge(protoiface.MessageV1)
387
}
388

389
var aberrantProtoMethods = &protoiface.Methods{
390
	Marshal:   legacyMarshal,
391
	Unmarshal: legacyUnmarshal,
392
	Merge:     legacyMerge,
393

394
	// We have no way to tell whether the type's Marshal method
395
	// supports deterministic serialization or not, but this
396
	// preserves the v1 implementation's behavior of always
397
	// calling Marshal methods when present.
398
	Flags: protoiface.SupportMarshalDeterministic,
399
}
400

401
func legacyMarshal(in protoiface.MarshalInput) (protoiface.MarshalOutput, error) {
402
	v := in.Message.(unwrapper).protoUnwrap()
403
	marshaler, ok := v.(legacyMarshaler)
404
	if !ok {
405
		return protoiface.MarshalOutput{}, errors.New("%T does not implement Marshal", v)
406
	}
407
	out, err := marshaler.Marshal()
408
	if in.Buf != nil {
409
		out = append(in.Buf, out...)
410
	}
411
	return protoiface.MarshalOutput{
412
		Buf: out,
413
	}, err
414
}
415

416
func legacyUnmarshal(in protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) {
417
	v := in.Message.(unwrapper).protoUnwrap()
418
	unmarshaler, ok := v.(legacyUnmarshaler)
419
	if !ok {
420
		return protoiface.UnmarshalOutput{}, errors.New("%T does not implement Unmarshal", v)
421
	}
422
	return protoiface.UnmarshalOutput{}, unmarshaler.Unmarshal(in.Buf)
423
}
424

425
func legacyMerge(in protoiface.MergeInput) protoiface.MergeOutput {
426
	// Check whether this supports the legacy merger.
427
	dstv := in.Destination.(unwrapper).protoUnwrap()
428
	merger, ok := dstv.(legacyMerger)
429
	if ok {
430
		merger.Merge(Export{}.ProtoMessageV1Of(in.Source))
431
		return protoiface.MergeOutput{Flags: protoiface.MergeComplete}
432
	}
433

434
	// If legacy merger is unavailable, implement merge in terms of
435
	// a marshal and unmarshal operation.
436
	srcv := in.Source.(unwrapper).protoUnwrap()
437
	marshaler, ok := srcv.(legacyMarshaler)
438
	if !ok {
439
		return protoiface.MergeOutput{}
440
	}
441
	dstv = in.Destination.(unwrapper).protoUnwrap()
442
	unmarshaler, ok := dstv.(legacyUnmarshaler)
443
	if !ok {
444
		return protoiface.MergeOutput{}
445
	}
446
	if !in.Source.IsValid() {
447
		// Legacy Marshal methods may not function on nil messages.
448
		// Check for a typed nil source only after we confirm that
449
		// legacy Marshal/Unmarshal methods are present, for
450
		// consistency.
451
		return protoiface.MergeOutput{Flags: protoiface.MergeComplete}
452
	}
453
	b, err := marshaler.Marshal()
454
	if err != nil {
455
		return protoiface.MergeOutput{}
456
	}
457
	err = unmarshaler.Unmarshal(b)
458
	if err != nil {
459
		return protoiface.MergeOutput{}
460
	}
461
	return protoiface.MergeOutput{Flags: protoiface.MergeComplete}
462
}
463

464
// aberrantMessageType implements MessageType for all types other than pointer-to-struct.
465
type aberrantMessageType struct {
466
	t reflect.Type
467
}
468

469
func (mt aberrantMessageType) New() protoreflect.Message {
470
	if mt.t.Kind() == reflect.Ptr {
471
		return aberrantMessage{reflect.New(mt.t.Elem())}
472
	}
473
	return aberrantMessage{reflect.Zero(mt.t)}
474
}
475
func (mt aberrantMessageType) Zero() protoreflect.Message {
476
	return aberrantMessage{reflect.Zero(mt.t)}
477
}
478
func (mt aberrantMessageType) GoType() reflect.Type {
479
	return mt.t
480
}
481
func (mt aberrantMessageType) Descriptor() protoreflect.MessageDescriptor {
482
	return LegacyLoadMessageDesc(mt.t)
483
}
484

485
// aberrantMessage implements Message for all types other than pointer-to-struct.
486
//
487
// When the underlying type implements legacyMarshaler or legacyUnmarshaler,
488
// the aberrant Message can be marshaled or unmarshaled. Otherwise, there is
489
// not much that can be done with values of this type.
490
type aberrantMessage struct {
491
	v reflect.Value
492
}
493

494
// Reset implements the v1 proto.Message.Reset method.
495
func (m aberrantMessage) Reset() {
496
	if mr, ok := m.v.Interface().(interface{ Reset() }); ok {
497
		mr.Reset()
498
		return
499
	}
500
	if m.v.Kind() == reflect.Ptr && !m.v.IsNil() {
501
		m.v.Elem().Set(reflect.Zero(m.v.Type().Elem()))
502
	}
503
}
504

505
func (m aberrantMessage) ProtoReflect() protoreflect.Message {
506
	return m
507
}
508

509
func (m aberrantMessage) Descriptor() protoreflect.MessageDescriptor {
510
	return LegacyLoadMessageDesc(m.v.Type())
511
}
512
func (m aberrantMessage) Type() protoreflect.MessageType {
513
	return aberrantMessageType{m.v.Type()}
514
}
515
func (m aberrantMessage) New() protoreflect.Message {
516
	if m.v.Type().Kind() == reflect.Ptr {
517
		return aberrantMessage{reflect.New(m.v.Type().Elem())}
518
	}
519
	return aberrantMessage{reflect.Zero(m.v.Type())}
520
}
521
func (m aberrantMessage) Interface() protoreflect.ProtoMessage {
522
	return m
523
}
524
func (m aberrantMessage) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
525
	return
526
}
527
func (m aberrantMessage) Has(protoreflect.FieldDescriptor) bool {
528
	return false
529
}
530
func (m aberrantMessage) Clear(protoreflect.FieldDescriptor) {
531
	panic("invalid Message.Clear on " + string(m.Descriptor().FullName()))
532
}
533
func (m aberrantMessage) Get(fd protoreflect.FieldDescriptor) protoreflect.Value {
534
	if fd.Default().IsValid() {
535
		return fd.Default()
536
	}
537
	panic("invalid Message.Get on " + string(m.Descriptor().FullName()))
538
}
539
func (m aberrantMessage) Set(protoreflect.FieldDescriptor, protoreflect.Value) {
540
	panic("invalid Message.Set on " + string(m.Descriptor().FullName()))
541
}
542
func (m aberrantMessage) Mutable(protoreflect.FieldDescriptor) protoreflect.Value {
543
	panic("invalid Message.Mutable on " + string(m.Descriptor().FullName()))
544
}
545
func (m aberrantMessage) NewField(protoreflect.FieldDescriptor) protoreflect.Value {
546
	panic("invalid Message.NewField on " + string(m.Descriptor().FullName()))
547
}
548
func (m aberrantMessage) WhichOneof(protoreflect.OneofDescriptor) protoreflect.FieldDescriptor {
549
	panic("invalid Message.WhichOneof descriptor on " + string(m.Descriptor().FullName()))
550
}
551
func (m aberrantMessage) GetUnknown() protoreflect.RawFields {
552
	return nil
553
}
554
func (m aberrantMessage) SetUnknown(protoreflect.RawFields) {
555
	// SetUnknown discards its input on messages which don't support unknown field storage.
556
}
557
func (m aberrantMessage) IsValid() bool {
558
	if m.v.Kind() == reflect.Ptr {
559
		return !m.v.IsNil()
560
	}
561
	return false
562
}
563
func (m aberrantMessage) ProtoMethods() *protoiface.Methods {
564
	return aberrantProtoMethods
565
}
566
func (m aberrantMessage) protoUnwrap() interface{} {
567
	return m.v.Interface()
568
}
569

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.