1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
93 package stringer
94
95 import (
96 "github.com/gogo/protobuf/gogoproto"
97 "github.com/gogo/protobuf/protoc-gen-gogo/generator"
98 "strings"
99 )
100
101 type stringer struct {
102 *generator.Generator
103 generator.PluginImports
104 atleastOne bool
105 localName string
106 }
107
108 func NewStringer() *stringer {
109 return &stringer{}
110 }
111
112 func (p *stringer) Name() string {
113 return "stringer"
114 }
115
116 func (p *stringer) Init(g *generator.Generator) {
117 p.Generator = g
118 }
119
120 func (p *stringer) Generate(file *generator.FileDescriptor) {
121 proto3 := gogoproto.IsProto3(file.FileDescriptorProto)
122 p.PluginImports = generator.NewPluginImports(p.Generator)
123 p.atleastOne = false
124
125 p.localName = generator.FileName(file)
126
127 fmtPkg := p.NewImport("fmt")
128 stringsPkg := p.NewImport("strings")
129 reflectPkg := p.NewImport("reflect")
130 sortKeysPkg := p.NewImport("github.com/gogo/protobuf/sortkeys")
131 protoPkg := p.NewImport("github.com/gogo/protobuf/proto")
132 for _, message := range file.Messages() {
133 if !gogoproto.IsStringer(file.FileDescriptorProto, message.DescriptorProto) {
134 continue
135 }
136 if gogoproto.EnabledGoStringer(file.FileDescriptorProto, message.DescriptorProto) {
137 panic("old string method needs to be disabled, please use gogoproto.goproto_stringer or gogoproto.goproto_stringer_all and set it to false")
138 }
139 if message.DescriptorProto.GetOptions().GetMapEntry() {
140 continue
141 }
142 p.atleastOne = true
143 ccTypeName := generator.CamelCaseSlice(message.TypeName())
144 p.P(`func (this *`, ccTypeName, `) String() string {`)
145 p.In()
146 p.P(`if this == nil {`)
147 p.In()
148 p.P(`return "nil"`)
149 p.Out()
150 p.P(`}`)
151 for _, field := range message.Field {
152 if p.IsMap(field) || !field.IsRepeated() {
153 continue
154 }
155 if (field.IsMessage() && !gogoproto.IsCustomType(field)) || p.IsGroup(field) {
156 nullable := gogoproto.IsNullable(field)
157 desc := p.ObjectNamed(field.GetTypeName())
158 msgname := p.TypeName(desc)
159 msgnames := strings.Split(msgname, ".")
160 typeName := msgnames[len(msgnames)-1]
161 fieldMessageDesc := file.GetMessage(msgname)
162 gogoStringer := false
163 if fieldMessageDesc != nil {
164 gogoStringer = gogoproto.IsStringer(file.FileDescriptorProto, fieldMessageDesc)
165 }
166 fieldname := p.GetFieldName(message, field)
167 stringfunc := fmtPkg.Use() + `.Sprintf("%v", f)`
168 if gogoStringer {
169 stringfunc = `f.String()`
170 }
171 repeatedName := `repeatedStringFor` + fieldname
172 if nullable {
173 p.P(repeatedName, ` := "[]*`, typeName, `{"`)
174 } else {
175 p.P(repeatedName, ` := "[]`, typeName, `{"`)
176 }
177
178 p.P(`for _, f := range `, `this.`, fieldname, ` {`)
179 p.In()
180 if nullable {
181 p.P(repeatedName, " += ", stringsPkg.Use(), `.Replace(`, stringfunc, `, "`, typeName, `","`, msgname, `"`, ", 1)", ` + ","`)
182 } else if gogoStringer {
183 p.P(repeatedName, " += ", stringsPkg.Use(), `.Replace(`, stringsPkg.Use(), `.Replace(`, stringfunc, `, "`, typeName, `","`, msgname, `"`, ", 1),`&`,``,1)", ` + ","`)
184 } else {
185 p.P(repeatedName, " += ", stringfunc, ` + ","`)
186 }
187 p.Out()
188 p.P(`}`)
189 p.P(repeatedName, ` += "}"`)
190 }
191 }
192 for _, field := range message.Field {
193 if !p.IsMap(field) {
194 continue
195 }
196 fieldname := p.GetFieldName(message, field)
197
198 m := p.GoMapType(nil, field)
199 mapgoTyp, keyField, keyAliasField := m.GoType, m.KeyField, m.KeyAliasField
200 keysName := `keysFor` + fieldname
201 keygoTyp, _ := p.GoType(nil, keyField)
202 keygoTyp = strings.Replace(keygoTyp, "*", "", 1)
203 keygoAliasTyp, _ := p.GoType(nil, keyAliasField)
204 keygoAliasTyp = strings.Replace(keygoAliasTyp, "*", "", 1)
205 keyCapTyp := generator.CamelCase(keygoTyp)
206 p.P(keysName, ` := make([]`, keygoTyp, `, 0, len(this.`, fieldname, `))`)
207 p.P(`for k, _ := range this.`, fieldname, ` {`)
208 p.In()
209 if keygoAliasTyp == keygoTyp {
210 p.P(keysName, ` = append(`, keysName, `, k)`)
211 } else {
212 p.P(keysName, ` = append(`, keysName, `, `, keygoTyp, `(k))`)
213 }
214 p.Out()
215 p.P(`}`)
216 p.P(sortKeysPkg.Use(), `.`, keyCapTyp, `s(`, keysName, `)`)
217 mapName := `mapStringFor` + fieldname
218 p.P(mapName, ` := "`, mapgoTyp, `{"`)
219 p.P(`for _, k := range `, keysName, ` {`)
220 p.In()
221 if keygoAliasTyp == keygoTyp {
222 p.P(mapName, ` += fmt.Sprintf("%v: %v,", k, this.`, fieldname, `[k])`)
223 } else {
224 p.P(mapName, ` += fmt.Sprintf("%v: %v,", k, this.`, fieldname, `[`, keygoAliasTyp, `(k)])`)
225 }
226 p.Out()
227 p.P(`}`)
228 p.P(mapName, ` += "}"`)
229 }
230 p.P("s := ", stringsPkg.Use(), ".Join([]string{`&", ccTypeName, "{`,")
231 oneofs := make(map[string]struct{})
232 for _, field := range message.Field {
233 nullable := gogoproto.IsNullable(field)
234 repeated := field.IsRepeated()
235 fieldname := p.GetFieldName(message, field)
236 oneof := field.OneofIndex != nil
237 if oneof {
238 if _, ok := oneofs[fieldname]; ok {
239 continue
240 } else {
241 oneofs[fieldname] = struct{}{}
242 }
243 p.P("`", fieldname, ":`", ` + `, fmtPkg.Use(), `.Sprintf("%v", this.`, fieldname, ") + `,", "`,")
244 } else if p.IsMap(field) {
245 mapName := `mapStringFor` + fieldname
246 p.P("`", fieldname, ":`", ` + `, mapName, " + `,", "`,")
247 } else if (field.IsMessage() && !gogoproto.IsCustomType(field)) || p.IsGroup(field) {
248 desc := p.ObjectNamed(field.GetTypeName())
249 msgname := p.TypeName(desc)
250 msgnames := strings.Split(msgname, ".")
251 typeName := msgnames[len(msgnames)-1]
252 fieldMessageDesc := file.GetMessage(msgname)
253 gogoStringer := false
254 if fieldMessageDesc != nil {
255 gogoStringer = gogoproto.IsStringer(file.FileDescriptorProto, fieldMessageDesc)
256 }
257 stringfunc := fmtPkg.Use() + `.Sprintf("%v", this.` + fieldname + `)`
258 if gogoStringer {
259 stringfunc = `this.` + fieldname + `.String()`
260 }
261 if nullable && !repeated {
262 p.P("`", fieldname, ":`", ` + `, stringsPkg.Use(), `.Replace(`, stringfunc, `, "`, typeName, `","`, msgname, `"`, ", 1) + `,", "`,")
263 } else if repeated {
264 repeatedName := `repeatedStringFor` + fieldname
265 p.P("`", fieldname, ":`", ` + `, repeatedName, " + `,", "`,")
266 } else {
267 p.P("`", fieldname, ":`", ` + `, stringsPkg.Use(), `.Replace(`, stringsPkg.Use(), `.Replace(`, stringfunc, `, "`, typeName, `","`, msgname, `"`, ", 1),`&`,``,1) + `,", "`,")
268 }
269 } else {
270 if nullable && !repeated && !proto3 {
271 p.P("`", fieldname, ":`", ` + valueToString`, p.localName, `(this.`, fieldname, ") + `,", "`,")
272 } else {
273 p.P("`", fieldname, ":`", ` + `, fmtPkg.Use(), `.Sprintf("%v", this.`, fieldname, ") + `,", "`,")
274 }
275 }
276 }
277 if message.DescriptorProto.HasExtension() {
278 if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) {
279 p.P("`XXX_InternalExtensions:` + ", protoPkg.Use(), ".StringFromInternalExtension(this) + `,`,")
280 } else {
281 p.P("`XXX_extensions:` + ", protoPkg.Use(), ".StringFromExtensionsBytes(this.XXX_extensions) + `,`,")
282 }
283 }
284 if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) {
285 p.P("`XXX_unrecognized:` + ", fmtPkg.Use(), `.Sprintf("%v", this.XXX_unrecognized) + `, "`,`,")
286 }
287 p.P("`}`,")
288 p.P(`}`, `,""`, ")")
289 p.P(`return s`)
290 p.Out()
291 p.P(`}`)
292
293
294 for _, field := range message.Field {
295 oneof := field.OneofIndex != nil
296 if !oneof {
297 continue
298 }
299 ccTypeName := p.OneOfTypeName(message, field)
300 p.P(`func (this *`, ccTypeName, `) String() string {`)
301 p.In()
302 p.P(`if this == nil {`)
303 p.In()
304 p.P(`return "nil"`)
305 p.Out()
306 p.P(`}`)
307 p.P("s := ", stringsPkg.Use(), ".Join([]string{`&", ccTypeName, "{`,")
308 fieldname := p.GetOneOfFieldName(message, field)
309 if field.IsMessage() || p.IsGroup(field) {
310 desc := p.ObjectNamed(field.GetTypeName())
311 msgname := p.TypeName(desc)
312 msgnames := strings.Split(msgname, ".")
313 typeName := msgnames[len(msgnames)-1]
314 p.P("`", fieldname, ":`", ` + `, stringsPkg.Use(), `.Replace(`, fmtPkg.Use(), `.Sprintf("%v", this.`, fieldname, `), "`, typeName, `","`, msgname, `"`, ", 1) + `,", "`,")
315 } else {
316 p.P("`", fieldname, ":`", ` + `, fmtPkg.Use(), `.Sprintf("%v", this.`, fieldname, ") + `,", "`,")
317 }
318 p.P("`}`,")
319 p.P(`}`, `,""`, ")")
320 p.P(`return s`)
321 p.Out()
322 p.P(`}`)
323 }
324 }
325
326 if !p.atleastOne {
327 return
328 }
329
330 p.P(`func valueToString`, p.localName, `(v interface{}) string {`)
331 p.In()
332 p.P(`rv := `, reflectPkg.Use(), `.ValueOf(v)`)
333 p.P(`if rv.IsNil() {`)
334 p.In()
335 p.P(`return "nil"`)
336 p.Out()
337 p.P(`}`)
338 p.P(`pv := `, reflectPkg.Use(), `.Indirect(rv).Interface()`)
339 p.P(`return `, fmtPkg.Use(), `.Sprintf("*%v", pv)`)
340 p.Out()
341 p.P(`}`)
342
343 }
344
345 func init() {
346 generator.RegisterPlugin(NewStringer())
347 }
348
View as plain text