1 | // Copyright 2019 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 proto
|
---|
6 |
|
---|
7 | import (
|
---|
8 | "google.golang.org/protobuf/reflect/protoreflect"
|
---|
9 | )
|
---|
10 |
|
---|
11 | // HasExtension reports whether an extension field is populated.
|
---|
12 | // It returns false if m is invalid or if xt does not extend m.
|
---|
13 | func HasExtension(m Message, xt protoreflect.ExtensionType) bool {
|
---|
14 | // Treat nil message interface as an empty message; no populated fields.
|
---|
15 | if m == nil {
|
---|
16 | return false
|
---|
17 | }
|
---|
18 |
|
---|
19 | // As a special-case, we reports invalid or mismatching descriptors
|
---|
20 | // as always not being populated (since they aren't).
|
---|
21 | if xt == nil || m.ProtoReflect().Descriptor() != xt.TypeDescriptor().ContainingMessage() {
|
---|
22 | return false
|
---|
23 | }
|
---|
24 |
|
---|
25 | return m.ProtoReflect().Has(xt.TypeDescriptor())
|
---|
26 | }
|
---|
27 |
|
---|
28 | // ClearExtension clears an extension field such that subsequent
|
---|
29 | // HasExtension calls return false.
|
---|
30 | // It panics if m is invalid or if xt does not extend m.
|
---|
31 | func ClearExtension(m Message, xt protoreflect.ExtensionType) {
|
---|
32 | m.ProtoReflect().Clear(xt.TypeDescriptor())
|
---|
33 | }
|
---|
34 |
|
---|
35 | // GetExtension retrieves the value for an extension field.
|
---|
36 | // If the field is unpopulated, it returns the default value for
|
---|
37 | // scalars and an immutable, empty value for lists or messages.
|
---|
38 | // It panics if xt does not extend m.
|
---|
39 | func GetExtension(m Message, xt protoreflect.ExtensionType) interface{} {
|
---|
40 | // Treat nil message interface as an empty message; return the default.
|
---|
41 | if m == nil {
|
---|
42 | return xt.InterfaceOf(xt.Zero())
|
---|
43 | }
|
---|
44 |
|
---|
45 | return xt.InterfaceOf(m.ProtoReflect().Get(xt.TypeDescriptor()))
|
---|
46 | }
|
---|
47 |
|
---|
48 | // SetExtension stores the value of an extension field.
|
---|
49 | // It panics if m is invalid, xt does not extend m, or if type of v
|
---|
50 | // is invalid for the specified extension field.
|
---|
51 | func SetExtension(m Message, xt protoreflect.ExtensionType, v interface{}) {
|
---|
52 | xd := xt.TypeDescriptor()
|
---|
53 | pv := xt.ValueOf(v)
|
---|
54 |
|
---|
55 | // Specially treat an invalid list, map, or message as clear.
|
---|
56 | isValid := true
|
---|
57 | switch {
|
---|
58 | case xd.IsList():
|
---|
59 | isValid = pv.List().IsValid()
|
---|
60 | case xd.IsMap():
|
---|
61 | isValid = pv.Map().IsValid()
|
---|
62 | case xd.Message() != nil:
|
---|
63 | isValid = pv.Message().IsValid()
|
---|
64 | }
|
---|
65 | if !isValid {
|
---|
66 | m.ProtoReflect().Clear(xd)
|
---|
67 | return
|
---|
68 | }
|
---|
69 |
|
---|
70 | m.ProtoReflect().Set(xd, pv)
|
---|
71 | }
|
---|
72 |
|
---|
73 | // RangeExtensions iterates over every populated extension field in m in an
|
---|
74 | // undefined order, calling f for each extension type and value encountered.
|
---|
75 | // It returns immediately if f returns false.
|
---|
76 | // While iterating, mutating operations may only be performed
|
---|
77 | // on the current extension field.
|
---|
78 | func RangeExtensions(m Message, f func(protoreflect.ExtensionType, interface{}) bool) {
|
---|
79 | // Treat nil message interface as an empty message; nothing to range over.
|
---|
80 | if m == nil {
|
---|
81 | return
|
---|
82 | }
|
---|
83 |
|
---|
84 | m.ProtoReflect().Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
|
---|
85 | if fd.IsExtension() {
|
---|
86 | xt := fd.(protoreflect.ExtensionTypeDescriptor).Type()
|
---|
87 | vi := xt.InterfaceOf(v)
|
---|
88 | return f(xt, vi)
|
---|
89 | }
|
---|
90 | return true
|
---|
91 | })
|
---|
92 | }
|
---|