Skip to content

Commit aacd6d4

Browse files
committed
protoveneer: the protoveneer tool
This tool was written to facilitate writing the Gemini API clients in: - github.com/googleapis/google-cloud-go/vertexai - github.com/google/generative-ai-go Change-Id: Ieb1c3d8abec5f06f2fd10604daa22dcaffa13ca0 Reviewed-on: https://go-review.googlesource.com/c/exp/+/549635 Run-TryBot: Jonathan Amsterdam <[email protected]> Reviewed-by: Eli Bendersky <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent f3f8817 commit aacd6d4

File tree

12 files changed

+1802
-0
lines changed

12 files changed

+1802
-0
lines changed

protoveneer/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# The protoveneer tool
2+
3+
Protoveneer is an experimental tool that generates idiomatic Go types that
4+
correspond to protocol buffer messages and enums -- a veneer on top of the proto
5+
layer.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright 2023 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 main
6+
7+
import (
8+
"errors"
9+
"fmt"
10+
"os"
11+
12+
"gopkg.in/yaml.v3"
13+
)
14+
15+
// config holds the configuration for a package.
16+
type config struct {
17+
Package string
18+
ProtoImportPath string `yaml:"protoImportPath"`
19+
// Import path for the support package needed by the generated code.
20+
SupportImportPath string `yaml:"supportImportPath"`
21+
22+
// The types to process. Only these types and the types they depend
23+
// on will be output.
24+
// The key is the name of the proto type.
25+
Types map[string]*typeConfig
26+
// Omit the types in this list, even if they would normally be output.
27+
// Elements can be globs.
28+
OmitTypes []string `yaml:"omitTypes"`
29+
// Converter functions for types not in the proto package.
30+
// Each value should be "tofunc, fromfunc"
31+
Converters map[string]string
32+
}
33+
34+
type typeConfig struct {
35+
// The name for the veneer type, if different.
36+
Name string
37+
// The prefix of the proto enum values. It will be removed.
38+
ProtoPrefix string `yaml:"protoPrefix"`
39+
// The prefix for the veneer enum values, if different from the type name.
40+
VeneerPrefix string `yaml:"veneerPrefix"`
41+
// Overrides for enum values.
42+
ValueNames map[string]string `yaml:"valueNames"`
43+
// Overrides for field types. Map key is proto field name.
44+
Fields map[string]fieldConfig
45+
// Custom conversion functions: "tofunc, fromfunc"
46+
ConvertToFrom string `yaml:"convertToFrom"`
47+
// Doc string for the type, omitting the initial type name.
48+
Doc string
49+
// Verb to place after type name in doc. Default: "is".
50+
// Ignored if Doc is non-empty.
51+
DocVerb string `yaml:"docVerb"`
52+
}
53+
54+
type fieldConfig struct {
55+
Name string // veneer name
56+
Type string // veneer type
57+
// Omit from output.
58+
Omit bool
59+
}
60+
61+
func (c *config) init() {
62+
for protoName, tc := range c.Types {
63+
if tc == nil {
64+
tc = &typeConfig{Name: protoName}
65+
c.Types[protoName] = tc
66+
}
67+
if tc.Name == "" {
68+
tc.Name = protoName
69+
}
70+
tc.init()
71+
}
72+
}
73+
74+
func (tc *typeConfig) init() {
75+
if tc.VeneerPrefix == "" {
76+
tc.VeneerPrefix = tc.Name
77+
}
78+
}
79+
80+
func readConfigFile(filename string) (*config, error) {
81+
if filename == "" {
82+
return nil, errors.New("missing config file")
83+
}
84+
f, err := os.Open(filename)
85+
if err != nil {
86+
return nil, err
87+
}
88+
defer f.Close()
89+
dec := yaml.NewDecoder(f)
90+
dec.KnownFields(true)
91+
92+
var c config
93+
if err := dec.Decode(&c); err != nil {
94+
return nil, fmt.Errorf("reading %s: %w", filename, err)
95+
}
96+
c.init()
97+
return &c, nil
98+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// Copyright 2023 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 main
6+
7+
import "fmt"
8+
9+
// A converter generates code to convert between a proto type and a veneer type.
10+
type converter interface {
11+
// genFrom returns code to convert from proto to veneer.
12+
genFrom(string) string
13+
// genTo returns code to convert to proto from veneer.
14+
genTo(string) string
15+
// These return the function argument to Transform{Slice,MapValues}, or "" if we don't need it.
16+
genTransformFrom() string
17+
genTransformTo() string
18+
}
19+
20+
// An identityConverter does no conversion.
21+
type identityConverter struct{}
22+
23+
func (identityConverter) genFrom(arg string) string { return arg }
24+
func (identityConverter) genTo(arg string) string { return arg }
25+
func (identityConverter) genTransformFrom() string { return "" }
26+
func (identityConverter) genTransformTo() string { return "" }
27+
28+
// A derefConverter converts between T in the veneer and *T in the proto.
29+
type derefConverter struct{}
30+
31+
func (derefConverter) genFrom(arg string) string { return fmt.Sprintf("support.DerefOrZero(%s)", arg) }
32+
func (derefConverter) genTo(arg string) string { return fmt.Sprintf("support.AddrOrNil(%s)", arg) }
33+
func (derefConverter) genTransformFrom() string { panic("can't handle deref slices") }
34+
func (derefConverter) genTransformTo() string { panic("can't handle deref slices") }
35+
36+
type enumConverter struct {
37+
protoName, veneerName string
38+
}
39+
40+
func (c enumConverter) genFrom(arg string) string {
41+
return fmt.Sprintf("%s(%s)", c.veneerName, arg)
42+
}
43+
44+
func (c enumConverter) genTransformFrom() string {
45+
return fmt.Sprintf("func(p pb.%s) %s { return %s }", c.protoName, c.veneerName, c.genFrom("p"))
46+
}
47+
48+
func (c enumConverter) genTo(arg string) string {
49+
return fmt.Sprintf("pb.%s(%s)", c.protoName, arg)
50+
}
51+
52+
func (c enumConverter) genTransformTo() string {
53+
return fmt.Sprintf("func(v %s) pb.%s { return %s }", c.veneerName, c.protoName, c.genTo("v"))
54+
}
55+
56+
type protoConverter struct {
57+
veneerName string
58+
}
59+
60+
func (c protoConverter) genFrom(arg string) string {
61+
return fmt.Sprintf("(%s{}).fromProto(%s)", c.veneerName, arg)
62+
}
63+
64+
func (c protoConverter) genTransformFrom() string {
65+
return fmt.Sprintf("(%s{}).fromProto", c.veneerName)
66+
}
67+
68+
func (c protoConverter) genTo(arg string) string {
69+
return fmt.Sprintf("%s.toProto()", arg)
70+
}
71+
72+
func (c protoConverter) genTransformTo() string {
73+
return fmt.Sprintf("(*%s).toProto", c.veneerName)
74+
}
75+
76+
type customConverter struct {
77+
toFunc, fromFunc string
78+
}
79+
80+
func (c customConverter) genFrom(arg string) string {
81+
return fmt.Sprintf("%s(%s)", c.fromFunc, arg)
82+
}
83+
84+
func (c customConverter) genTransformFrom() string { return c.fromFunc }
85+
86+
func (c customConverter) genTo(arg string) string {
87+
return fmt.Sprintf("%s(%s)", c.toFunc, arg)
88+
}
89+
90+
func (c customConverter) genTransformTo() string { return c.toFunc }
91+
92+
type sliceConverter struct {
93+
eltConverter converter
94+
}
95+
96+
func (c sliceConverter) genFrom(arg string) string {
97+
if fn := c.eltConverter.genTransformFrom(); fn != "" {
98+
return fmt.Sprintf("support.TransformSlice(%s, %s)", arg, fn)
99+
}
100+
return c.eltConverter.genFrom(arg)
101+
}
102+
103+
func (c sliceConverter) genTo(arg string) string {
104+
if fn := c.eltConverter.genTransformTo(); fn != "" {
105+
return fmt.Sprintf("support.TransformSlice(%s, %s)", arg, fn)
106+
}
107+
return c.eltConverter.genTo(arg)
108+
}
109+
110+
func (c sliceConverter) genTransformTo() string {
111+
panic("sliceConverter.genToSlice called")
112+
}
113+
114+
func (c sliceConverter) genTransformFrom() string {
115+
panic("sliceConverter.genFromSlice called")
116+
}
117+
118+
// Only the values are converted.
119+
type mapConverter struct {
120+
valueConverter converter
121+
}
122+
123+
func (c mapConverter) genFrom(arg string) string {
124+
if fn := c.valueConverter.genTransformFrom(); fn != "" {
125+
return fmt.Sprintf("support.TransformMapValues(%s, %s)", arg, fn)
126+
}
127+
return c.valueConverter.genFrom(arg)
128+
}
129+
130+
func (c mapConverter) genTo(arg string) string {
131+
if fn := c.valueConverter.genTransformTo(); fn != "" {
132+
return fmt.Sprintf("support.TransformMapValues(%s, %s)", arg, fn)
133+
}
134+
return c.valueConverter.genTo(arg)
135+
}
136+
137+
func (c mapConverter) genTransformTo() string {
138+
panic("mapConverter.genToSlice called")
139+
}
140+
141+
func (c mapConverter) genTransformFrom() string {
142+
panic("mapConverter.genFromSlice called")
143+
}

0 commit comments

Comments
 (0)