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
97 package gostring
98
99 import (
100 "fmt"
101 "os"
102 "strconv"
103 "strings"
104
105 "github.com/gogo/protobuf/gogoproto"
106 "github.com/gogo/protobuf/protoc-gen-gogo/generator"
107 )
108
109 type gostring struct {
110 *generator.Generator
111 generator.PluginImports
112 atleastOne bool
113 localName string
114 overwrite bool
115 }
116
117 func NewGoString() *gostring {
118 return &gostring{}
119 }
120
121 func (p *gostring) Name() string {
122 return "gostring"
123 }
124
125 func (p *gostring) Overwrite() {
126 p.overwrite = true
127 }
128
129 func (p *gostring) Init(g *generator.Generator) {
130 p.Generator = g
131 }
132
133 func (p *gostring) Generate(file *generator.FileDescriptor) {
134 proto3 := gogoproto.IsProto3(file.FileDescriptorProto)
135 p.PluginImports = generator.NewPluginImports(p.Generator)
136 p.atleastOne = false
137
138 p.localName = generator.FileName(file)
139
140 fmtPkg := p.NewImport("fmt")
141 stringsPkg := p.NewImport("strings")
142 protoPkg := p.NewImport("github.com/gogo/protobuf/proto")
143 if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
144 protoPkg = p.NewImport("github.com/golang/protobuf/proto")
145 }
146 sortPkg := p.NewImport("sort")
147 strconvPkg := p.NewImport("strconv")
148 reflectPkg := p.NewImport("reflect")
149 sortKeysPkg := p.NewImport("github.com/gogo/protobuf/sortkeys")
150
151 extensionToGoStringUsed := false
152 for _, message := range file.Messages() {
153 if !p.overwrite && !gogoproto.HasGoString(file.FileDescriptorProto, message.DescriptorProto) {
154 continue
155 }
156 if message.DescriptorProto.GetOptions().GetMapEntry() {
157 continue
158 }
159 p.atleastOne = true
160 packageName := file.GoPackageName()
161
162 ccTypeName := generator.CamelCaseSlice(message.TypeName())
163 p.P(`func (this *`, ccTypeName, `) GoString() string {`)
164 p.In()
165 p.P(`if this == nil {`)
166 p.In()
167 p.P(`return "nil"`)
168 p.Out()
169 p.P(`}`)
170
171 p.P(`s := make([]string, 0, `, strconv.Itoa(len(message.Field)+4), `)`)
172 p.P(`s = append(s, "&`, packageName, ".", ccTypeName, `{")`)
173
174 oneofs := make(map[string]struct{})
175 for _, field := range message.Field {
176 nullable := gogoproto.IsNullable(field)
177 repeated := field.IsRepeated()
178 fieldname := p.GetFieldName(message, field)
179 oneof := field.OneofIndex != nil
180 if oneof {
181 if _, ok := oneofs[fieldname]; ok {
182 continue
183 } else {
184 oneofs[fieldname] = struct{}{}
185 }
186 p.P(`if this.`, fieldname, ` != nil {`)
187 p.In()
188 p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `) + ",\n")`)
189 p.Out()
190 p.P(`}`)
191 } else if p.IsMap(field) {
192 m := p.GoMapType(nil, field)
193 mapgoTyp, keyField, keyAliasField := m.GoType, m.KeyField, m.KeyAliasField
194 keysName := `keysFor` + fieldname
195 keygoTyp, _ := p.GoType(nil, keyField)
196 keygoTyp = strings.Replace(keygoTyp, "*", "", 1)
197 keygoAliasTyp, _ := p.GoType(nil, keyAliasField)
198 keygoAliasTyp = strings.Replace(keygoAliasTyp, "*", "", 1)
199 keyCapTyp := generator.CamelCase(keygoTyp)
200 p.P(keysName, ` := make([]`, keygoTyp, `, 0, len(this.`, fieldname, `))`)
201 p.P(`for k, _ := range this.`, fieldname, ` {`)
202 p.In()
203 if keygoAliasTyp == keygoTyp {
204 p.P(keysName, ` = append(`, keysName, `, k)`)
205 } else {
206 p.P(keysName, ` = append(`, keysName, `, `, keygoTyp, `(k))`)
207 }
208 p.Out()
209 p.P(`}`)
210 p.P(sortKeysPkg.Use(), `.`, keyCapTyp, `s(`, keysName, `)`)
211 mapName := `mapStringFor` + fieldname
212 p.P(mapName, ` := "`, mapgoTyp, `{"`)
213 p.P(`for _, k := range `, keysName, ` {`)
214 p.In()
215 if keygoAliasTyp == keygoTyp {
216 p.P(mapName, ` += fmt.Sprintf("%#v: %#v,", k, this.`, fieldname, `[k])`)
217 } else {
218 p.P(mapName, ` += fmt.Sprintf("%#v: %#v,", k, this.`, fieldname, `[`, keygoAliasTyp, `(k)])`)
219 }
220 p.Out()
221 p.P(`}`)
222 p.P(mapName, ` += "}"`)
223 p.P(`if this.`, fieldname, ` != nil {`)
224 p.In()
225 p.P(`s = append(s, "`, fieldname, `: " + `, mapName, `+ ",\n")`)
226 p.Out()
227 p.P(`}`)
228 } else if (field.IsMessage() && !gogoproto.IsCustomType(field) && !gogoproto.IsStdType(field)) || p.IsGroup(field) {
229 if nullable || repeated {
230 p.P(`if this.`, fieldname, ` != nil {`)
231 p.In()
232 }
233 if nullable {
234 p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `) + ",\n")`)
235 } else if repeated {
236 if nullable {
237 p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `) + ",\n")`)
238 } else {
239 goTyp, _ := p.GoType(message, field)
240 goTyp = strings.Replace(goTyp, "[]", "", 1)
241 p.P("vs := make([]", goTyp, ", len(this.", fieldname, "))")
242 p.P("for i := range vs {")
243 p.In()
244 p.P("vs[i] = this.", fieldname, "[i]")
245 p.Out()
246 p.P("}")
247 p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", vs) + ",\n")`)
248 }
249 } else {
250 p.P(`s = append(s, "`, fieldname, `: " + `, stringsPkg.Use(), `.Replace(this.`, fieldname, `.GoString()`, ",`&`,``,1)", ` + ",\n")`)
251 }
252 if nullable || repeated {
253 p.Out()
254 p.P(`}`)
255 }
256 } else {
257 if !proto3 && (nullable || repeated) {
258 p.P(`if this.`, fieldname, ` != nil {`)
259 p.In()
260 }
261 if field.IsEnum() {
262 if nullable && !repeated && !proto3 {
263 goTyp, _ := p.GoType(message, field)
264 p.P(`s = append(s, "`, fieldname, `: " + valueToGoString`, p.localName, `(this.`, fieldname, `,"`, generator.GoTypeToName(goTyp), `"`, `) + ",\n")`)
265 } else {
266 p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `) + ",\n")`)
267 }
268 } else {
269 if nullable && !repeated && !proto3 {
270 goTyp, _ := p.GoType(message, field)
271 p.P(`s = append(s, "`, fieldname, `: " + valueToGoString`, p.localName, `(this.`, fieldname, `,"`, generator.GoTypeToName(goTyp), `"`, `) + ",\n")`)
272 } else {
273 p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `) + ",\n")`)
274 }
275 }
276 if !proto3 && (nullable || repeated) {
277 p.Out()
278 p.P(`}`)
279 }
280 }
281 }
282 if message.DescriptorProto.HasExtension() {
283 if gogoproto.HasExtensionsMap(file.FileDescriptorProto, message.DescriptorProto) {
284 p.P(`s = append(s, "XXX_InternalExtensions: " + extensionToGoString`, p.localName, `(this) + ",\n")`)
285 extensionToGoStringUsed = true
286 } else {
287 p.P(`if this.XXX_extensions != nil {`)
288 p.In()
289 p.P(`s = append(s, "XXX_extensions: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.XXX_extensions) + ",\n")`)
290 p.Out()
291 p.P(`}`)
292 }
293 }
294 if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) {
295 p.P(`if this.XXX_unrecognized != nil {`)
296 p.In()
297 p.P(`s = append(s, "XXX_unrecognized:" + `, fmtPkg.Use(), `.Sprintf("%#v", this.XXX_unrecognized) + ",\n")`)
298 p.Out()
299 p.P(`}`)
300 }
301
302 p.P(`s = append(s, "}")`)
303 p.P(`return `, stringsPkg.Use(), `.Join(s, "")`)
304 p.Out()
305 p.P(`}`)
306
307
308 for _, field := range message.Field {
309 oneof := field.OneofIndex != nil
310 if !oneof {
311 continue
312 }
313 ccTypeName := p.OneOfTypeName(message, field)
314 p.P(`func (this *`, ccTypeName, `) GoString() string {`)
315 p.In()
316 p.P(`if this == nil {`)
317 p.In()
318 p.P(`return "nil"`)
319 p.Out()
320 p.P(`}`)
321 fieldname := p.GetOneOfFieldName(message, field)
322 outStr := strings.Join([]string{
323 "s := ",
324 stringsPkg.Use(), ".Join([]string{`&", packageName, ".", ccTypeName, "{` + \n",
325 "`", fieldname, ":` + ", fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `)`,
326 " + `}`",
327 `}`,
328 `,", "`,
329 `)`}, "")
330 p.P(outStr)
331 p.P(`return s`)
332 p.Out()
333 p.P(`}`)
334 }
335 }
336
337 if !p.atleastOne {
338 return
339 }
340
341 p.P(`func valueToGoString`, p.localName, `(v interface{}, typ string) string {`)
342 p.In()
343 p.P(`rv := `, reflectPkg.Use(), `.ValueOf(v)`)
344 p.P(`if rv.IsNil() {`)
345 p.In()
346 p.P(`return "nil"`)
347 p.Out()
348 p.P(`}`)
349 p.P(`pv := `, reflectPkg.Use(), `.Indirect(rv).Interface()`)
350 p.P(`return `, fmtPkg.Use(), `.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)`)
351 p.Out()
352 p.P(`}`)
353
354 if extensionToGoStringUsed {
355 if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
356 fmt.Fprintf(os.Stderr, "The GoString plugin for messages with extensions requires importing gogoprotobuf. Please see file %s", file.GetName())
357 os.Exit(1)
358 }
359 p.P(`func extensionToGoString`, p.localName, `(m `, protoPkg.Use(), `.Message) string {`)
360 p.In()
361 p.P(`e := `, protoPkg.Use(), `.GetUnsafeExtensionsMap(m)`)
362 p.P(`if e == nil { return "nil" }`)
363 p.P(`s := "proto.NewUnsafeXXX_InternalExtensions(map[int32]proto.Extension{"`)
364 p.P(`keys := make([]int, 0, len(e))`)
365 p.P(`for k := range e {`)
366 p.In()
367 p.P(`keys = append(keys, int(k))`)
368 p.Out()
369 p.P(`}`)
370 p.P(sortPkg.Use(), `.Ints(keys)`)
371 p.P(`ss := []string{}`)
372 p.P(`for _, k := range keys {`)
373 p.In()
374 p.P(`ss = append(ss, `, strconvPkg.Use(), `.Itoa(k) + ": " + e[int32(k)].GoString())`)
375 p.Out()
376 p.P(`}`)
377 p.P(`s+=`, stringsPkg.Use(), `.Join(ss, ",") + "})"`)
378 p.P(`return s`)
379 p.Out()
380 p.P(`}`)
381 }
382 }
383
384 func init() {
385 generator.RegisterPlugin(NewGoString())
386 }
387
View as plain text