1
2
3
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
19
20
21
22 type StructProperties struct {
23
24
25
26
27
28
29
30
31 Prop []*Properties
32
33
34
35 OneofTypes map[string]*OneofProperties
36 }
37
38
39
40
41 type Properties struct {
42
43
44 Name string
45
46 OrigName string
47
48 JSONName string
49
50
51
52 Enum string
53
54 Weak string
55
56 Wire string
57
58 WireType int
59
60 Tag int
61
62 Required bool
63
64 Optional bool
65
66 Repeated bool
67
68 Packed bool
69
70 Proto3 bool
71
72 Oneof bool
73
74
75 Default string
76
77 HasDefault bool
78
79
80 MapKeyProp *Properties
81
82 MapValProp *Properties
83 }
84
85
86
87
88 type OneofProperties struct {
89
90
91 Type reflect.Type
92
93 Field int
94
95 Prop *Properties
96 }
97
98
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
137 func (p *Properties) Parse(tag string) {
138
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
185
186 p.HasDefault = true
187 p.Default, i = tag[len("def="):], len(tag)
188 }
189 tag = strings.TrimPrefix(tag[i:], ",")
190 }
191 }
192
193
194
195
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
213
214
215
216
217
218
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
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
249
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
255 }
256
257 prop.Prop = append(prop.Prop, p)
258 }
259
260
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(),
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
286
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 }
307
View as plain text