1 | // Copyright 2010 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 | "fmt"
|
---|
9 | "reflect"
|
---|
10 | "strconv"
|
---|
11 | "strings"
|
---|
12 | "sync"
|
---|
13 |
|
---|
14 | "google.golang.org/protobuf/reflect/protoreflect"
|
---|
15 | "google.golang.org/protobuf/runtime/protoimpl"
|
---|
16 | )
|
---|
17 |
|
---|
18 | // StructProperties represents protocol buffer type information for a
|
---|
19 | // generated protobuf message in the open-struct API.
|
---|
20 | //
|
---|
21 | // Deprecated: Do not use.
|
---|
22 | type StructProperties struct {
|
---|
23 | // Prop are the properties for each field.
|
---|
24 | //
|
---|
25 | // Fields belonging to a oneof are stored in OneofTypes instead, with a
|
---|
26 | // single Properties representing the parent oneof held here.
|
---|
27 | //
|
---|
28 | // The order of Prop matches the order of fields in the Go struct.
|
---|
29 | // Struct fields that are not related to protobufs have a "XXX_" prefix
|
---|
30 | // in the Properties.Name and must be ignored by the user.
|
---|
31 | Prop []*Properties
|
---|
32 |
|
---|
33 | // OneofTypes contains information about the oneof fields in this message.
|
---|
34 | // It is keyed by the protobuf field name.
|
---|
35 | OneofTypes map[string]*OneofProperties
|
---|
36 | }
|
---|
37 |
|
---|
38 | // Properties represents the type information for a protobuf message field.
|
---|
39 | //
|
---|
40 | // Deprecated: Do not use.
|
---|
41 | type Properties struct {
|
---|
42 | // Name is a placeholder name with little meaningful semantic value.
|
---|
43 | // If the name has an "XXX_" prefix, the entire Properties must be ignored.
|
---|
44 | Name string
|
---|
45 | // OrigName is the protobuf field name or oneof name.
|
---|
46 | OrigName string
|
---|
47 | // JSONName is the JSON name for the protobuf field.
|
---|
48 | JSONName string
|
---|
49 | // Enum is a placeholder name for enums.
|
---|
50 | // For historical reasons, this is neither the Go name for the enum,
|
---|
51 | // nor the protobuf name for the enum.
|
---|
52 | Enum string // Deprecated: Do not use.
|
---|
53 | // Weak contains the full name of the weakly referenced message.
|
---|
54 | Weak string
|
---|
55 | // Wire is a string representation of the wire type.
|
---|
56 | Wire string
|
---|
57 | // WireType is the protobuf wire type for the field.
|
---|
58 | WireType int
|
---|
59 | // Tag is the protobuf field number.
|
---|
60 | Tag int
|
---|
61 | // Required reports whether this is a required field.
|
---|
62 | Required bool
|
---|
63 | // Optional reports whether this is a optional field.
|
---|
64 | Optional bool
|
---|
65 | // Repeated reports whether this is a repeated field.
|
---|
66 | Repeated bool
|
---|
67 | // Packed reports whether this is a packed repeated field of scalars.
|
---|
68 | Packed bool
|
---|
69 | // Proto3 reports whether this field operates under the proto3 syntax.
|
---|
70 | Proto3 bool
|
---|
71 | // Oneof reports whether this field belongs within a oneof.
|
---|
72 | Oneof bool
|
---|
73 |
|
---|
74 | // Default is the default value in string form.
|
---|
75 | Default string
|
---|
76 | // HasDefault reports whether the field has a default value.
|
---|
77 | HasDefault bool
|
---|
78 |
|
---|
79 | // MapKeyProp is the properties for the key field for a map field.
|
---|
80 | MapKeyProp *Properties
|
---|
81 | // MapValProp is the properties for the value field for a map field.
|
---|
82 | MapValProp *Properties
|
---|
83 | }
|
---|
84 |
|
---|
85 | // OneofProperties represents the type information for a protobuf oneof.
|
---|
86 | //
|
---|
87 | // Deprecated: Do not use.
|
---|
88 | type OneofProperties struct {
|
---|
89 | // Type is a pointer to the generated wrapper type for the field value.
|
---|
90 | // This is nil for messages that are not in the open-struct API.
|
---|
91 | Type reflect.Type
|
---|
92 | // Field is the index into StructProperties.Prop for the containing oneof.
|
---|
93 | Field int
|
---|
94 | // Prop is the properties for the field.
|
---|
95 | Prop *Properties
|
---|
96 | }
|
---|
97 |
|
---|
98 | // String formats the properties in the protobuf struct field tag style.
|
---|
99 | func (p *Properties) String() string {
|
---|
100 | s := p.Wire
|
---|
101 | s += "," + strconv.Itoa(p.Tag)
|
---|
102 | if p.Required {
|
---|
103 | s += ",req"
|
---|
104 | }
|
---|
105 | if p.Optional {
|
---|
106 | s += ",opt"
|
---|
107 | }
|
---|
108 | if p.Repeated {
|
---|
109 | s += ",rep"
|
---|
110 | }
|
---|
111 | if p.Packed {
|
---|
112 | s += ",packed"
|
---|
113 | }
|
---|
114 | s += ",name=" + p.OrigName
|
---|
115 | if p.JSONName != "" {
|
---|
116 | s += ",json=" + p.JSONName
|
---|
117 | }
|
---|
118 | if len(p.Enum) > 0 {
|
---|
119 | s += ",enum=" + p.Enum
|
---|
120 | }
|
---|
121 | if len(p.Weak) > 0 {
|
---|
122 | s += ",weak=" + p.Weak
|
---|
123 | }
|
---|
124 | if p.Proto3 {
|
---|
125 | s += ",proto3"
|
---|
126 | }
|
---|
127 | if p.Oneof {
|
---|
128 | s += ",oneof"
|
---|
129 | }
|
---|
130 | if p.HasDefault {
|
---|
131 | s += ",def=" + p.Default
|
---|
132 | }
|
---|
133 | return s
|
---|
134 | }
|
---|
135 |
|
---|
136 | // Parse populates p by parsing a string in the protobuf struct field tag style.
|
---|
137 | func (p *Properties) Parse(tag string) {
|
---|
138 | // For example: "bytes,49,opt,name=foo,def=hello!"
|
---|
139 | for len(tag) > 0 {
|
---|
140 | i := strings.IndexByte(tag, ',')
|
---|
141 | if i < 0 {
|
---|
142 | i = len(tag)
|
---|
143 | }
|
---|
144 | switch s := tag[:i]; {
|
---|
145 | case strings.HasPrefix(s, "name="):
|
---|
146 | p.OrigName = s[len("name="):]
|
---|
147 | case strings.HasPrefix(s, "json="):
|
---|
148 | p.JSONName = s[len("json="):]
|
---|
149 | case strings.HasPrefix(s, "enum="):
|
---|
150 | p.Enum = s[len("enum="):]
|
---|
151 | case strings.HasPrefix(s, "weak="):
|
---|
152 | p.Weak = s[len("weak="):]
|
---|
153 | case strings.Trim(s, "0123456789") == "":
|
---|
154 | n, _ := strconv.ParseUint(s, 10, 32)
|
---|
155 | p.Tag = int(n)
|
---|
156 | case s == "opt":
|
---|
157 | p.Optional = true
|
---|
158 | case s == "req":
|
---|
159 | p.Required = true
|
---|
160 | case s == "rep":
|
---|
161 | p.Repeated = true
|
---|
162 | case s == "varint" || s == "zigzag32" || s == "zigzag64":
|
---|
163 | p.Wire = s
|
---|
164 | p.WireType = WireVarint
|
---|
165 | case s == "fixed32":
|
---|
166 | p.Wire = s
|
---|
167 | p.WireType = WireFixed32
|
---|
168 | case s == "fixed64":
|
---|
169 | p.Wire = s
|
---|
170 | p.WireType = WireFixed64
|
---|
171 | case s == "bytes":
|
---|
172 | p.Wire = s
|
---|
173 | p.WireType = WireBytes
|
---|
174 | case s == "group":
|
---|
175 | p.Wire = s
|
---|
176 | p.WireType = WireStartGroup
|
---|
177 | case s == "packed":
|
---|
178 | p.Packed = true
|
---|
179 | case s == "proto3":
|
---|
180 | p.Proto3 = true
|
---|
181 | case s == "oneof":
|
---|
182 | p.Oneof = true
|
---|
183 | case strings.HasPrefix(s, "def="):
|
---|
184 | // The default tag is special in that everything afterwards is the
|
---|
185 | // default regardless of the presence of commas.
|
---|
186 | p.HasDefault = true
|
---|
187 | p.Default, i = tag[len("def="):], len(tag)
|
---|
188 | }
|
---|
189 | tag = strings.TrimPrefix(tag[i:], ",")
|
---|
190 | }
|
---|
191 | }
|
---|
192 |
|
---|
193 | // Init populates the properties from a protocol buffer struct tag.
|
---|
194 | //
|
---|
195 | // Deprecated: Do not use.
|
---|
196 | func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
|
---|
197 | p.Name = name
|
---|
198 | p.OrigName = name
|
---|
199 | if tag == "" {
|
---|
200 | return
|
---|
201 | }
|
---|
202 | p.Parse(tag)
|
---|
203 |
|
---|
204 | if typ != nil && typ.Kind() == reflect.Map {
|
---|
205 | p.MapKeyProp = new(Properties)
|
---|
206 | p.MapKeyProp.Init(nil, "Key", f.Tag.Get("protobuf_key"), nil)
|
---|
207 | p.MapValProp = new(Properties)
|
---|
208 | p.MapValProp.Init(nil, "Value", f.Tag.Get("protobuf_val"), nil)
|
---|
209 | }
|
---|
210 | }
|
---|
211 |
|
---|
212 | var propertiesCache sync.Map // map[reflect.Type]*StructProperties
|
---|
213 |
|
---|
214 | // GetProperties returns the list of properties for the type represented by t,
|
---|
215 | // which must be a generated protocol buffer message in the open-struct API,
|
---|
216 | // where protobuf message fields are represented by exported Go struct fields.
|
---|
217 | //
|
---|
218 | // Deprecated: Use protobuf reflection instead.
|
---|
219 | func GetProperties(t reflect.Type) *StructProperties {
|
---|
220 | if p, ok := propertiesCache.Load(t); ok {
|
---|
221 | return p.(*StructProperties)
|
---|
222 | }
|
---|
223 | p, _ := propertiesCache.LoadOrStore(t, newProperties(t))
|
---|
224 | return p.(*StructProperties)
|
---|
225 | }
|
---|
226 |
|
---|
227 | func newProperties(t reflect.Type) *StructProperties {
|
---|
228 | if t.Kind() != reflect.Struct {
|
---|
229 | panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
|
---|
230 | }
|
---|
231 |
|
---|
232 | var hasOneof bool
|
---|
233 | prop := new(StructProperties)
|
---|
234 |
|
---|
235 | // Construct a list of properties for each field in the struct.
|
---|
236 | for i := 0; i < t.NumField(); i++ {
|
---|
237 | p := new(Properties)
|
---|
238 | f := t.Field(i)
|
---|
239 | tagField := f.Tag.Get("protobuf")
|
---|
240 | p.Init(f.Type, f.Name, tagField, &f)
|
---|
241 |
|
---|
242 | tagOneof := f.Tag.Get("protobuf_oneof")
|
---|
243 | if tagOneof != "" {
|
---|
244 | hasOneof = true
|
---|
245 | p.OrigName = tagOneof
|
---|
246 | }
|
---|
247 |
|
---|
248 | // Rename unrelated struct fields with the "XXX_" prefix since so much
|
---|
249 | // user code simply checks for this to exclude special fields.
|
---|
250 | if tagField == "" && tagOneof == "" && !strings.HasPrefix(p.Name, "XXX_") {
|
---|
251 | p.Name = "XXX_" + p.Name
|
---|
252 | p.OrigName = "XXX_" + p.OrigName
|
---|
253 | } else if p.Weak != "" {
|
---|
254 | p.Name = p.OrigName // avoid possible "XXX_" prefix on weak field
|
---|
255 | }
|
---|
256 |
|
---|
257 | prop.Prop = append(prop.Prop, p)
|
---|
258 | }
|
---|
259 |
|
---|
260 | // Construct a mapping of oneof field names to properties.
|
---|
261 | if hasOneof {
|
---|
262 | var oneofWrappers []interface{}
|
---|
263 | if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok {
|
---|
264 | oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{})
|
---|
265 | }
|
---|
266 | if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok {
|
---|
267 | oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{})
|
---|
268 | }
|
---|
269 | if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(protoreflect.ProtoMessage); ok {
|
---|
270 | if m, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *protoimpl.MessageInfo }); ok {
|
---|
271 | oneofWrappers = m.ProtoMessageInfo().OneofWrappers
|
---|
272 | }
|
---|
273 | }
|
---|
274 |
|
---|
275 | prop.OneofTypes = make(map[string]*OneofProperties)
|
---|
276 | for _, wrapper := range oneofWrappers {
|
---|
277 | p := &OneofProperties{
|
---|
278 | Type: reflect.ValueOf(wrapper).Type(), // *T
|
---|
279 | Prop: new(Properties),
|
---|
280 | }
|
---|
281 | f := p.Type.Elem().Field(0)
|
---|
282 | p.Prop.Name = f.Name
|
---|
283 | p.Prop.Parse(f.Tag.Get("protobuf"))
|
---|
284 |
|
---|
285 | // Determine the struct field that contains this oneof.
|
---|
286 | // Each wrapper is assignable to exactly one parent field.
|
---|
287 | var foundOneof bool
|
---|
288 | for i := 0; i < t.NumField() && !foundOneof; i++ {
|
---|
289 | if p.Type.AssignableTo(t.Field(i).Type) {
|
---|
290 | p.Field = i
|
---|
291 | foundOneof = true
|
---|
292 | }
|
---|
293 | }
|
---|
294 | if !foundOneof {
|
---|
295 | panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
|
---|
296 | }
|
---|
297 | prop.OneofTypes[p.Prop.OrigName] = p
|
---|
298 | }
|
---|
299 | }
|
---|
300 |
|
---|
301 | return prop
|
---|
302 | }
|
---|
303 |
|
---|
304 | func (sp *StructProperties) Len() int { return len(sp.Prop) }
|
---|
305 | func (sp *StructProperties) Less(i, j int) bool { return false }
|
---|
306 | func (sp *StructProperties) Swap(i, j int) { return }
|
---|