github.com/ronaksoft/rony@v0.16.26-0.20230807065236-1743dbfe6959/cmd/protoc-gen-gorony/helper/gen.go (about)

     1  package helper
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"text/template"
     7  
     8  	"github.com/ronaksoft/rony/internal/codegen"
     9  	"google.golang.org/protobuf/compiler/protogen"
    10  )
    11  
    12  /*
    13     Creation Time: 2021 - Mar - 02
    14     Created by:  (ehsan)
    15     Maintainers:
    16        1.  Ehsan N. Moosa (E2)
    17     Auditor: Ehsan N. Moosa (E2)
    18     Copyright Ronak Software Group 2020
    19  */
    20  
    21  func GenFunc(g *protogen.GeneratedFile, opt *codegen.PluginOptions, files ...*protogen.File) error {
    22  	initBlock := &strings.Builder{}
    23  	appendToInit := func(x string) {
    24  		initBlock.WriteString(x)
    25  		initBlock.WriteRune('\n')
    26  	}
    27  	g.P("package ", files[0].GoPackageName)
    28  	g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: "sync"})
    29  	g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: "github.com/ronaksoft/rony/registry"})
    30  	g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: "google.golang.org/protobuf/proto"})
    31  	g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: "google.golang.org/protobuf/encoding/protojson"})
    32  	g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: "github.com/ronaksoft/rony/pools"})
    33  	if !opt.NoEdgeDependency {
    34  		g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: "github.com/ronaksoft/rony/edge"})
    35  	}
    36  
    37  	g.P("var _ = pools.Imported")
    38  	for _, f := range files {
    39  		templateArg := codegen.GenTemplateArg(f)
    40  		for _, arg := range templateArg.Messages {
    41  			for _, f := range arg.Fields {
    42  				if f.Pkg() != "" {
    43  					g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: f.ImportPath})
    44  				}
    45  			}
    46  			appendToInit(fmt.Sprintf("registry.Register(%d, %q, factory%s)", arg.C, arg.Name(), arg.Name()))
    47  			g.P(codegen.ExecTemplate(template.Must(template.New("genPool").Parse(genPool)), arg))
    48  			g.P(codegen.ExecTemplate(template.Must(template.New("genDeepCopy").Parse(genDeepCopy)), arg))
    49  			g.P(codegen.ExecTemplate(template.Must(template.New("genClone").Parse(genClone)), arg))
    50  			g.P(codegen.ExecTemplate(template.Must(template.New("genSerializers").Parse(genSerializers)), arg))
    51  			if arg.IsEnvelope() {
    52  				g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: "github.com/goccy/go-json"})
    53  			}
    54  			g.P(codegen.ExecTemplate(template.Must(template.New("genFactory").Parse(genFactory)), arg))
    55  
    56  			if !opt.NoEdgeDependency {
    57  				g.P(codegen.ExecTemplate(template.Must(template.New("genPushToContext").Parse(genPushToContext)), arg))
    58  			}
    59  		}
    60  		for _, arg := range templateArg.Services {
    61  			for _, m := range arg.Methods {
    62  				if m.Output.Pkg() != "" {
    63  					g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: m.Output.ImportPath})
    64  				}
    65  				if m.Input.Pkg() != "" {
    66  					g.QualifiedGoIdent(protogen.GoIdent{GoName: "", GoImportPath: m.Input.ImportPath})
    67  				}
    68  				appendToInit(fmt.Sprintf("registry.Register(%d, %q, factory%s)", m.C, m.Fullname(), m.Input.Name()))
    69  				g.P("const C_", m.Fullname(), " uint64 = ", fmt.Sprintf("%d", m.C))
    70  			}
    71  		}
    72  
    73  		if initBlock.Len() > 0 {
    74  			g.P("// register constructors of the messages to the registry package")
    75  			g.P("func init() {")
    76  			g.P(initBlock.String())
    77  			g.P("}")
    78  		}
    79  	}
    80  
    81  	return nil
    82  }
    83  
    84  const genPool = `
    85  const C_{{.Name}} uint64 = {{.C}}
    86  type pool{{.Name}} struct {
    87  	pool sync.Pool
    88  }
    89  
    90  func (p *pool{{.Name}}) Get() *{{.Name}} {
    91  	x, ok := p.pool.Get().(*{{.Name}})
    92  	if !ok {
    93  		x = &{{.Name}}{}
    94  	}
    95  	{{ range .Fields }}
    96  	{{- if and (eq .Cardinality "optional") (eq .Kind "message") }}
    97  		{{- if ne .Pkg ""}}
    98  			x.{{.Name}} = {{.Pkg}}.Pool{{.Type}}.Get()
    99  		{{- else}}
   100  			x.{{.Name}} = Pool{{.Type}}.Get()
   101  		{{- end}}
   102  	{{- end }}
   103  	{{ end }}
   104  	return x
   105  }
   106  
   107  func (p *pool{{.Name}}) Put(x *{{.Name}}) {
   108  	if x == nil {
   109  		return
   110  	}
   111  	
   112  	{{ range .Fields }}
   113  		{{- if eq .Cardinality "repeated" }}
   114  			{{- if eq .Kind "message" }}
   115  				for _, z := range x.{{.Name}} {
   116  					{{- if ne .Pkg ""}}
   117  						{{.Pkg}}.Pool{{.Type}}.Put(z)
   118  					{{- else}}
   119  						Pool{{.Type}}.Put(z)
   120  					{{- end}}
   121  				}
   122  				x.{{.Name}} = x.{{.Name}}[:0]
   123  			{{- else if eq .Kind "bytes" }}
   124  				for _, z := range x.{{.Name}} {
   125  					pools.Bytes.Put(z)
   126  				}
   127  				x.{{.Name}} = x.{{.Name}}[:0]
   128  			{{- else }}
   129  				x.{{- .Name}} = x.{{.Name}}[:0]
   130  			{{- end }}
   131  		{{- else }}
   132  			{{- if eq .Kind "bytes" }}
   133  				x.{{.Name}} = x.{{.Name}}[:0]
   134  			{{- else if eq .Kind "message" }}
   135  				{{- if ne .Pkg ""}}
   136  					{{.Pkg}}.Pool{{.Type}}.Put(x.{{.Name}})
   137  				{{- else}}
   138  					Pool{{.Type}}.Put(x.{{.Name}})
   139  				{{- end}}
   140  			{{- else }}
   141  				x.{{.Name}} = {{.ZeroValue}}
   142  			{{- end }}
   143  		{{- end }}
   144  	{{- end }}
   145  	
   146  	p.pool.Put(x)
   147  }
   148  
   149  var Pool{{.Name}} = pool{{.Name}}{}
   150  `
   151  
   152  const genDeepCopy = `
   153  func (x *{{.Name}}) DeepCopy(z *{{.Name}}) {
   154  	{{- range .Fields -}}
   155  		{{- if eq .Cardinality "repeated" }}
   156  			{{- if eq .Kind "message" }}
   157  				for idx := range x.{{.Name}} {
   158  					if x.{{.Name}}[idx] == nil {
   159  						continue
   160  					}
   161  					{{- if eq .Pkg "" }}
   162  						xx := Pool{{.Type}}.Get()
   163  					{{- else }}
   164  						xx := {{.Pkg}}.Pool{{.Type}}.Get()
   165  					{{- end }}
   166  					x.{{.Name}}[idx].DeepCopy(xx)
   167  					z.{{.Name}} = append(z.{{.Name}}, xx)
   168  				}
   169  			{{- else if eq .Kind "bytes" }}
   170  				z.{{.Name}} = z.{{.Name}}[:0]
   171  				zl := len(z.{{.Name}})
   172  				for idx := range x.{{.Name}} {
   173  					if idx <  zl {
   174  						z.{{.Name}} = append(z.{{.Name}}, append(z.{{.Name}}[idx][:0], x.{{.Name}}[idx]...))
   175  					} else {
   176  						zb := pools.Bytes.GetCap(len(x.{{.Name}}[idx]))
   177  						z.{{.Name}} = append(z.{{.Name}}, append(zb, x.{{.Name}}[idx]...))
   178  					}
   179  				}
   180  			{{- else }}
   181  				z.{{.Name}} = append(z.{{.Name}}[:0], x.{{.Name}}...)
   182  			{{- end }}
   183  		{{- else }}
   184  			{{- if eq .Kind "message" }}
   185  				if x.{{.Name}} != nil {
   186  					if z.{{.Name}} == nil {
   187  						{{- if eq .Pkg "" }}
   188  							z.{{.Name}} = Pool{{.Type}}.Get()
   189  						{{- else }}
   190  							z.{{.Name}} = {{.Pkg}}.Pool{{.Type}}.Get()
   191  						{{- end }}
   192  					}
   193  					x.{{.Name}}.DeepCopy(z.{{.Name}})
   194  				} else {
   195  					{{- if eq .Pkg "" }}
   196  						Pool{{.Type}}.Put(z.{{.Name}})
   197  					{{- else }}
   198  						{{.Pkg}}.Pool{{.Type}}.Put(z.{{.Name}})
   199  					{{- end }}
   200  					z.{{.Name}} = nil 
   201  				}
   202  			{{- else if eq .Kind "bytes" }}
   203  				z.{{.Name}} = append(z.{{.Name}}[:0], x.{{.Name}}...)
   204  			{{- else }}
   205  				z.{{.Name}} = x.{{.Name}}
   206  			{{- end }}
   207  		{{- end }}
   208  	{{- end }}
   209  }
   210  
   211  `
   212  
   213  const genClone = `
   214  func (x *{{.Name}}) Clone() *{{.Name}} {
   215  	z := &{{.Name}}{}
   216  	x.DeepCopy(z)
   217  	return z
   218  }
   219  
   220  `
   221  
   222  const genPushToContext = `
   223  	func (x *{{.Name}}) PushToContext(ctx *edge.RequestCtx) {
   224  		ctx.PushMessage({{.CName}}, x)
   225  	}
   226  `
   227  
   228  const genSerializers = `
   229  	func (x *{{.Name}}) Unmarshal(b []byte) error {
   230  		return proto.UnmarshalOptions{Merge: true}.Unmarshal(b, x)
   231  	}
   232  
   233  	func (x *{{.Name}}) Marshal() ([]byte, error)  {
   234  		return proto.Marshal(x)
   235  	}
   236  
   237  	{{ if not .SkipJson }}
   238  		func (x *{{.Name}}) UnmarshalJSON(b []byte) error {
   239  		{{- if and .IsEnvelope }}
   240  			je := registry.JSONEnvelope{}
   241  			err := go_json.Unmarshal(b, &je)
   242  			if err != nil {
   243  				return err
   244  			}
   245  		
   246  			x.Constructor = registry.N(je.Constructor)
   247  		
   248  			m, err := registry.Get(x.Constructor)
   249  			if err != nil {
   250  				return err
   251  			}
   252  		
   253  			err = m.UnmarshalJSON(je.Message)
   254  			if err != nil {
   255  				return err
   256  			}
   257  		
   258  			x.Message, err = proto.Marshal(m)
   259  			if err != nil {
   260  				return err
   261  			}
   262  		
   263  			return nil
   264  		{{- else }}
   265  			return protojson.Unmarshal(b, x)
   266  		{{- end }}
   267  		}
   268  	
   269  		func (x *{{.Name}}) MarshalJSON() ([]byte, error)  {
   270  		{{- if .IsEnvelope }}
   271  			m, err := registry.UnwrapJSON(x)
   272  			if err != nil {
   273  				return nil, err
   274  			}
   275  		
   276  			je := registry.JSONEnvelope{
   277  				Constructor: registry.C(x.Constructor),
   278  			}
   279  		
   280  			je.Message, err = m.MarshalJSON()
   281  			if err != nil {
   282  				return nil, err
   283  			}
   284  		
   285  			return go_json.Marshal(je)
   286  		{{- else }}
   287  			return protojson.Marshal(x)
   288  		{{- end }}
   289  		}
   290  	{{- end }}
   291  `
   292  
   293  const genFactory = `
   294  func factory{{.Name}} () registry.Message {
   295  	return &{{.Name}}{}
   296  }
   297  `